javascriptの数値型は、64ビット浮動小数点型である。分解すると、符号部 1 ビット ・ 指数部 11 ビット ・ 仮数部 52 ビットである。
[3]から、
・符号部は0を正、負を1に。
・指数部は符号なしの2進数とし、倍精度の場合は1023をバイアスした値で表す。
(1023をバイアスとは、符号部に実際の符号に指定した数だけ足し、正数で負の数も表現すること)
・仮数部は、整数部分が1であるような小数。
・指数部、仮数部ともに 0 のときは 0 を表す。
[1]にあるx|0結果について考察してみる。
x=-123 → -123
-123をビットで表示すると、
123/2 = 61 .. 1
61/2 = 30 .. 1
30/2 = 15 .. 0
15/2 = 7 .. 1
7/2 = 3 .. 1
3/2 = 1 .. 1
よって、123 → 1,111,011
(128-(4+1)からも想像がつくが。)
・符号部は、マイナスなので1。
・1.11011*2^5
・1023をバイアスするので、5+1023
1023=2^10-1 5 = 2^2+1
10,000,000,000 & 100
だから、仮数部は10,000,000,100。
最終的には、
1 10,000,000,100 1,111,011,0000..
となる。
0は、
0 00,000,000,000 0,000,000,0000..
当然、-123|0は-123となる。
次は、x=9876543210 → 1286608618
9876543210をビット表示すると、
1,001,001,100,101,100,000,001,011,011,101,010
1286608618をビット表示すると、
1,001,100,101,100,000,001,011,011,101,010
9876543210の指数部は、(1.001...)*2^33から33。
1286608618の指数部は、(1.001...)*2^31から31。
・x|0を行ったとき、仮数部は、31桁しか読んでいない。
次は、x=123.45 → 123
123 は、さっきと同じで2^7-5から、1,111,011
クレバー方式から
0.45*2=0.9
0.9*2=1.8
0.8*2=1.6
0.6*2=1.2
0.2*2=0.4
0.4*2=0.8
よって、途中から1100の周期で、0.011,100,110,011,0011...
ここまできてやっとビット計算と浮動小数点で言いたいことが分かってきた。浮動小数点では、指数部と仮数部に分けているのでそのままビット計算を行うことができない。なので、ビット計算できる整数に置き換えて計算する必要がある。
その時、[1]で書かれているToInt32や、ToUint32(x)によって、ビット計算をできるようにしている。
ToInt32は、32ビットの整数に変換すること。負の場合は32桁目が1になる。
x & y ::= ToInt32(ToInt32(x) [&] ToInt32(y))
x | y ::= ToInt32(ToInt32(x) [|] ToInt32(y))
x ^ y ::= ToInt32(ToInt32(x) [^] ToInt32(y))
~x ::= ToInt32([~]ToInt32(x))
x << y ::= ToInt32(ToInt32(x) [<<] (ToUint32(y) [&] 0x1F))
x >> y ::= ToInt32(ToInt32(x) [>>] (ToUint32(y) [&] 0x1F))
x >>> y ::= ToUint32(ToUint32(x) [>>>] (ToUint32(y) [&] 0x1F))
[1]JavaScriptのビット演算の仕組みを理解する
x | y ::= ToInt32(ToInt32(x) [|] ToInt32(y))
x ^ y ::= ToInt32(ToInt32(x) [^] ToInt32(y))
~x ::= ToInt32([~]ToInt32(x))
x << y ::= ToInt32(ToInt32(x) [<<] (ToUint32(y) [&] 0x1F))
x >> y ::= ToInt32(ToInt32(x) [>>] (ToUint32(y) [&] 0x1F))
x >>> y ::= ToUint32(ToUint32(x) [>>>] (ToUint32(y) [&] 0x1F))
ここにきてやっと
小数を切り捨てる際に使われる。
x|0
は、ビット計算するときにxをToInt32(x)によって32ビットの整数に変換している。(x|0)自体は処理として数字は変わらないはずだが、ToInt32(x)によって小数を切り捨てている。
絶対値の高速化で使われる
h = (x ^ (x >> 31)) - (x >> 31);上の式でxを32ビットに変換してもしxが正なら(x>>31)は0で、x^0はxorだからそのままx。で、xが負ならすべて1になり、x ^ (x >> 31)で、1は0になり、0は1になる。また最初の符号部分にあたるところも1になる。つまりマイナス。-(x >> 31)は、最初が0で残りが1のものを足すから、絶対値を計算したことと同じようになる。
もちろんこの絶対値は小数には使えない。
小数の切り捨てと絶対値のビット計算の意味が分からず、浮動小数点も勉強しました。
0 件のコメント:
コメントを投稿