この記事では、-xを素早く計算する方法 ^x + 1
(not x + 1)を解説していきます。
ここでは、わかりやすいように、1始まり(個人的には0始まり、16進法が好きですが…コードの行数も0始まりがいい)、int8、big endian (十六と書くときは 0b0001_0000) で説明し、notは「^x」、n乗は「x ** n」と表記します。
最初に、intの仕組みを解説します。すでにご存じの方は、次の"\n\n"まで jmp してください。(次のブロックからお読みください)
正の数の場合は、2つ目から8つ目のビットを使って二進法で表します。
負の数の場合は、-(2 ** 7) + (2つ目から8つ目のビット)と表します。
1つ目のビットは-128の桁、2つ目から8つ目のビットはそれぞれ64、32、16、8、4、2、1の桁です。例えば -2 は 1111_1110 になります。
初めに、^x(not x)をコンピュータっぽくではなく、数学っぽく表現していきたいと思います。
まず、^x は (2 ** 8 - 1) - x です。0b1111_1111 - x の二進法での筆算を想像してください。notすることと同じになります。
これで、^x のシンプルな数学表記ができました!
符号ビット(1ビット目 • sign bit)と他のビット(2ビット目から8ビット目)を分けて、それぞれ s と t とします。t は任意の0から127までの整数で、s は正の場合は0、負の場合は-128を表します。
x が正の場合は s、(s = s)、負の場合は -t + (t - s)、(-t + (t - s) = -s)になりますね。
あとは、正負を反転させたときビット演算を使った速い方法も同じ結果になるということを証明するだけです。
(-正の数s = sの負の数バージョン)
-s = ^x + 1
= (2 ** 8 - 1 - x) + 1
(1ビット目と2から8ビットを分けて)= (-t + (2 ** 7 - 1 - s)) + 1
= -128 + 128 - 1 - s + 1
= -t + t - s
= -t + (t - s)
(ついでに)= -s
これで証明できました!やった!
最後まで読んでくださりありがとうございました!お役に立たればうれしいです!