2013-10-06 8 views
5

が、非常に簡単にこれを行うことが可能である20ビットおよび32ビット整数に52ビットの整数に変換JavaScriptは:... 64ビット整数を表すことができ、他の言語で

How to store a 64 bit integer in two 32 bit integers and convert back again

How to store a 64 bit integer in two 32 bit integers in Ruby

// convert 64-bit n to two 32-bit x and y 
x = (n & 0xFFFFFFFF00000000) >> 32 
y = n & 0xFFFFFFFF 

しかし、JavaScriptが64ビット整数を表すことができません。それは問題なしでcan only represent 52-bit integersです。

今では、最初の場所でit is not even possible to have a 64-bit integerため、2つの32ビット整数に64ビット整数に変換することができないことを意味します。

しかし、まだ52ビット残っています。私の質問は、JavaScriptでこの52ビット整数を2つの32ビット整数(上位20ビットと下位32ビット)に分割する方法です。

20ビットと32ビットのビット操作を行うには、 JavaScriptのビット分割?

関連: How are 32 bit JavaScript numbers resulting from a bit-wise operation converted back to 64 bit numbers

+0

Javascriptに整数がまったくないので、これを使うのはわかりません。すべての数値は浮動小数点です。 –

+0

jsにUInt32sがありますが、https://github.com/silentmatt/javascript-bigintegerが必要です – dandavis

+0

@MikeW実際には32ビットを超えるビットフィールドを扱う必要があります。したがって、私はそのような方法で与えられた数を分割する必要があります。 – treecoder

答えて

11

我々はすべての

ファーストを開始する前に、あなたのlinkが ことを知らせるの軽微な不正確含む「2 未満の任意の全体数は、[...]安全JavaScriptの数に収まる」をしながらそれはjavascriptの数字が2 まで(ただし、2 1)すべての正の整数を格納できることをそれほど苦労せずに検証することができます。技術的に正しい、それはタイトバインドされていません。

前置き一部コード

、あなたが要求された機能、ボトム32ビット及び20上部ビットに52ビット数を分割:

function to_int52(hi, lo) { 
    /* range checking */ 
    if ((lo !== lo|0) && (lo !== (lo|0)+4294967296)) 
     throw new Error ("lo out of range: "+lo); 
    if (hi !== hi|0 && hi >= 1048576) 
     throw new Error ("hi out of range: "+hi); 

    if (lo < 0) 
    lo += 4294967296; 

    return hi * 4294967296 + lo; 
} 

function from_int52(i) { 
    var lo = i | 0; 
    if (lo < 0) 
    lo += 4294967296; 

    var hi = i - lo; 
    hi /= 4294967296; 
    if ((hi < 0) || (hi >= 1048576) 
     throw new Error ("not an int52: "+i); 
    return { lo: lo, hi: hi }; 
} 

Iを分割しますこれらを使用することを提案しませんでした。 Javascriptのビット単位の演算が署名されています(@dandavis:JSはではなくにUInt32sを持っています)。正の値が実際に必要なときに符号ビットが頭痛を起こします。 Plus V8では、31ビットで格納できる(符号付きの)最適化が行われています。これらの2つの事実を組み合わせると、V8の小さな整数( "smi")に収まる最大の正のサイズである30ビット以内で分割する必要があります。あなたはおそらく、しかしオブジェクトを作成することにしたくない

function int52_30_get(i) { 
    var lo = i & 0x3fffffff; 
    var hi = (i - lo)/0x40000000; 
    return { lo: lo, hi: hi }; 
} 

はここ30低ビットおよび22ビット高に数字を分割するためのコードです。 (あなたが実際にすべての機能を悩ませている場合)これらは、インライン化されるはずです:

function int52_30_get_lo(i) { 
    return i & 0x3fffffff; 
} 

function int52_30_get_hi(i) { 
    return (i - (i & 0x3fffffff))/0x40000000; 
} 

、低および高部品から数値を作成する:あなたはハイテク本当に確信している場合は

function int52_30_new_safe(hi, lo) { 
    return (hi & 0x3fffff) * 0x40000000 + (lo & 0x3fffffff); 
} 

:個別にハイとローパーツセット

function int52_30_new(hi, lo) { 
    return hi * 0x40000000 + lo; 
} 

:見よ、あなたはマスキングをスキップすることができます範囲であり、

あなたはHIとLOは範囲内にあることを確認している場合:

/* set high part of i to hi */ 
i = hi * 0x40000000 + (i & 0x3fffffff); 

/* set low part of i to lo */ 
i += lo - (i & 0x3fffffff); 

(彼らはiを変更するため、これらの関数ではありません。)

余分な楽しみのために、任意引き出すための機能ビットフィールド:

function int52_30_get_bits(i, lsb, nbits) { 
    while (lsb >= 32) { 
     i /= 4294967296; 
     lsb -= 32; 
    } 
    return (i/(1<<lsb)) & ((1<<nbits)-1); 
} 

NBITSが32である場合(NBITSが< = 31故障モードでなければならないが興味深い、およびのRHSオペランドのわずか5つの下位ビットに起因するものです<が重要であり、javacript仕様がx86 ISAと共有する欠陥です。)

52ビットを超えていますか?

それから-2 -1に整数として53ビットの2進数を記憶するために符号ビットを使用することが完全に可能です。私はこれをしていないが、それは十分に簡単でなければならない。その後、少し毛むくじゃくして、最終的に2になる前に十分な浮動小数点数(多くはNaNです)がないという事実にぶつかります。。フロートに63進数を梱包理論的になんとかであるべきであるが、読者の課題として残されている:)

その他

別のアプローチに接近すると、型付き配列を使用し、フロートビューとINTビューを作成することです。これにより、浮動小数点数の基礎となるバイナリ表現を直接操作することができます。しかし、あなたはendiannessなどを心配しなければなりません。

文字列操作を提案しているすべての人々はちょうど狂っています。

+0

この非常に精巧な答えをありがとう。 JSは実際には52 + 1ビットの整数を格納することができます。私は解決策を得ました。ありがとうございました。 – treecoder

+0

第53ビットが隠され、符号ビットは隠されます –

4

さてあなたはこのように数値的にそれを行うことができます。

function numeric(n) { 
    return { 
     hi: Math.floor(n/4294967296), 
     lo: (n & 0xFFFFFFFF) >>> 0 
    } 
} 

または文字列バージョンは次のようになります。多分

function strings(n) { 
    s = n.toString(16); 

    if (s.length > 8) { 

     return { 
      hi: parseInt(s.toString(16).slice(0, s.length - 8), 16), 
      lo: parseInt(s.toString(16).slice(s.length - 8), 16) 
     } 
    } else { 
     return { hi: 0, lo: n } 
    } 

} 

か...

function stringPad(n) { 
    s = "00000000000"+n.toString(16); 
    return { 
     hi: parseInt(s.toString(16).slice(0, s.length - 8), 16), 
     lo: parseInt(s.toString(16).slice(s.length - 8), 16) 
    } 
} 

今、これは速いです。私はここでテストベッドを設定することを確認する:http://jsfiddle.net/SpaceDog/ZTJ2p/(あなたもあなたのお気に入りのJSプロファイラを使用することができます)。

(100000回のコール用)結果:

Function: numeric completed in 146 ms 
Function: strings completed in 379 ms 
Function: stringPad completed in 459 ms 

私は思考文字列が速かったし、それがparseIntは呼び出したのか疑問に思ったが、何も持っていないだろう。

Function: stringPadNoParse completed in 386 ms 

さて、このISNそれは他の多くのものに依存するので(非常に正確ですが)、数字のバージョンが速いのと同じように見えます。テストするのに数回実行しました。

しかし、おそらく誰かが来て、それを行うための別の方法を提供します。

+0

コードをありがとう。 'numeric()'関数は完全に機能します。 – treecoder

+0

MB var hi = n >> 32; ??? – nim

関連する問題