前回までの「Python初体験」の続きです。
条件式を論理演算子and、or、notでつなぐだけですので、やや退屈ですね。
ただし、not(反転)を整数変数に与えるとどうなるかは興味があったので実験してみました。結果は(論理演算なのか)単にbool型として処理されるようです。ビット演算子の~(NOT・反転)との違いを表示するようにしました。
# andサンプル
age = 10 # 例として、10歳 身長120cmとする
height = 120
if 10 <= age and 120 <= height: # 例題では()で条件式が括ってあったが、無くても演算子順位から正常に動く
print("お乗りいただけます")
else:
print("ご遠慮ください")
# orサンプル
age = 90 # 年齢を90歳とする
if (age <= 10) or (80 <= age): # ()はなくともよい
print("ご遠慮ください")
else:
print("お乗りいただけます")
# notサンプル
age = 20 # 年齢は20歳
if not (age < 10):
print("お乗りいただけます。") #さて、問題です。(not age < 30) はTrueでしょうか?Falseでしょうか?
#(not age)が0なら、0 < 30はTrue、(age < 30)がTrueなら、not TrueはFalse
a = 10 # notを使うと、aの値が何であれ、0以外は0、0なら1になる。
b = not a
print("aの2進数値は", bin(a), "で、bの2進数値は", bin(b), "です。")
#(出力)aの2進数値は 0b1010 で、bの2進数値は 0b0 です。not ageも0になりますよ。
b = ~a # bは0b00001010なので、aは0b11110101になるはず(実際には32bit整数、64bit整数を使っていると考えられ、この8bitに更に+24bit、+56bitの'0'と'1'が付加される。以下同じ。↓の「2の補数表現を利用する方法」参照)
print("aの2進数値は", bin(a), "で、bの2進数値は", bin(b), "です。") # bが符号付整数になる為、実際には0b11110101が-0b1011になる。このように0b11110101が-0b1011になることを2の補数表現(0b11110101 + 0b00001011 = 0 ∴ 0b11110101 = -0b00001011)という。
#(出力)aの2進数値は 0b1010 で、bの2進数値は -0b1011 です。
b = ~a & 0b00001111 # bの下4桁だけを残すために0b00001111でマスクする。
print("aの2進数値は", bin(a), "で、bの2進数値は", bin(b), "です。") # 頭の0が取れて、0b101となる。
#(出力)aの2進数値は 0b1010 で、bの2進数値は0b101です。
いかがだったでしょうか?PCが8bit、16bit、32bit、64bitと発展してきたので、整数の2進数表現も、
0b00000000(8bit-16進数表現0x00)
0b0000000000000000(16bit-16進数表現0x0000)
0b00000000000000000000000000000000(32bit-16進数表現0x00000000)
0b0000000000000000000000000000000000000000000000000000000000000000(64bit-16進数表現0x0000000000000000)
になってしまい(反吐が出そうですが)、プログラミング言語の内部表現を考えるにはよい材料ですね。
ps. Pythonには符号なし整数は無いのかと調べてみた所、どのwebサイトでも次のCopilotの回答のような答えを得ました。
「Pythonには組み込みの符号なし型は存在しません。
しかし、符号付き整数を符号なし整数に変換する方法はいくつかあります。以下にいくつかのアプローチを示します。
(1)2の補数表現を利用する方法
Pythonの整数は、無限に広い2の補数表現を使用しているように見えます。この方法は、2の補数表現を念頭に置いています。具体的には、符号なし32ビット整数を得るために、整数に対して (unsigned long) を適用し、次に 2**32 を負の値に追加します。例えば、次のようにします。
i = -6884376
unsigned_value = (unsigned long)(i) + 2**32
この方法は、Pythonの整数が2の補数表現を使用していることを前提としています。
(2)ビット単位の演算を利用する方法
Pythonのビット単位の演算子は、2の補数の値で動作します。符号付き整数を符号なし整数に変換するには、適切なビットマスクを使用します。(32ビットの場合:)
i = -6884376
unsigned_value = i & 0xffffffff
または、64ビットの場合:
i = -6884376
unsigned_value = i & 0xffffffffffffffff
(3)ctypesモジュールを利用する方法
ctypes モジュールを使用して、プラットフォームCコンパイラの機能を複製することもできます。
import ctypes
i = -6884376
unsigned_value = ctypes.c_ulong(i).value
この方法は、Cの unsigned long と同等の値を取得します。」
ps of ps. 私が初めてSONYの「MSX(8bit パソコン)」で機械語を習った時には、2進数、16進数変換を次のように覚えました。
(2進数) 0000→1から4の位を「いち(1)、にー(2)、よん(4)、ぱー(8)」の位として覚える
1001→8+1=9(十進法)
1111→8+4+2+1=15(十進法)
(16進数)00→0からF(十進数の15-0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F)
09→9(十進法)
0F→15(十進法)
(2進数→16進数変換)
11111011→上位1111は8+4+2+1=15(十進法)なのでF
↓ ↓ 下位1011は8+2+1=11(十進法)なのでB
F B
まっこと、長閑だったですねぇ。
ps of ps of ps. 問題の答え。矢張りnotの演算順位は算術演算記号よりも低いために not age < 30はFalse("not (age < 30)"と等価)になりました。