Hatena::ブログ(Diary)

fujidigの雑記

2009-10-15

[]JavaScript で 32bit int を扱う

追記 (2014/3/21)

最近ではMath.imulというものがあります。

signed int への変換: x | 0

unsigned int への変換: x >>> 0

これで大抵の場合はうまくいく。

IEEE64bit浮動小数点数では整数は2の53乗までしか正確に表現できない。(404 Not Found)

そのため掛け算の結果がそれを超える場合は結果が合わないことがある

ruby -e 'puts 123456789 * 123456789 & 0xffffffff'
2537071545 # 正しい結果
js -e 'print(123456789 * 123456789 >>> 0)'
2537071544 # 間違った結果

そういう場合は掛け算を自分で実装してしまえばいい。

function mul(a, b) {
	var result = 0;
	a >>>= 0;
	b >>>= 0;
	while (b) {
		if (b & 1) result = (result + a) >>> 0;
		a <<= 1;
		b >>>= 1;
	}
	return result;
}

mul(123456789,123456789); // => 2537071545

あと、FirefoxGoogle ChromeではRubyのFIXNUMのように絶対値が2^30-1以下の整数なら即値として最適化され、それより大きい場合はheapをとる模様。

結果が2^30-1より大きくなる場合は遅くなるので速度が要求される場面では二つの数値型変数に分けるなどの工夫をするとよい。

論理演算2 (mitsunari@cybozu labs)

分割してみる (mitsunari@cybozu labs)

追記 (2009-11-09T19:35:58+09:00)

no titleのソースを読んで掛け算は以下でいいことを知った。

function mul(a, b) {
	var a1 = a >>> 16, a2 = a & 0xffff;
	var b1 = b >>> 16, b2 = b & 0xffff;
	return (((a1 * b2 + a2 * b1) << 16) + a2 * b2) >>> 0;
}

なぜこれでうまくいくのかは掛け算の筆算を思い出してみればよく分かる。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/chaperatta/20091015/1255575869
Connection: close