簡體   English   中英

JavaScript 支持 64 位整數嗎?

[英]Does JavaScript support 64-bit integers?

我有以下代碼:

var str = "0x4000000000000000";   //4611686018427387904 decimal
var val = parseInt(str);
alert(val);

我得到這個值:“ 4611686018427388000 ”,即0x4000000000000060

我想知道 JavaScript 是否對 64 位整數處理不當,還是我做錯了什么?

JavaScript 使用IEEE-754雙精度(64 位)格式表示數字。 據我了解,這為您提供了 53 位精度,或十五到十六位十進制數字。 您的數字的位數超出了 JavaScript 的處理能力,因此您最終會得到一個近似值。

這並不是真正的“處理不當”,但顯然如果您需要大數字的全精度,這不是很有幫助。 有一些 JS 庫可以處理更大的數字,例如BigNumberInt64

Chromium 57 版及更高版本本身支持任意精度整數。 這稱為 BigInt,並且正在為其他瀏覽器工作 它比 JavaScript 實現快得多

即,V8 JavaScript 是 Smalltalk 派生引擎。 (1980 年代至今)Lisp 和 Smalltalk 引擎支持使用 <LargeInteger> 有時稱為 <BigInt> 的多精度算術。 劇透,Google 的Dart團隊主要是一群前 Smalltalkers,將他們的經驗匯集到 JS 領域。

這些類型的數字具有無限的精度,通常用作構建塊以提供 <Rational:Fraction> 對象,其分子和分母可以是任何類型的數字,包括 <BigInt>。 有了它,就可以表示實數、虛數,並且可以在無理數(如(1/3)上以完美的精度進行處理)。

注意:我是 Smalltalk、JS 和其他語言及其引擎和框架的長期實施者和開發者。

如果 <BigInt> 將多精度算術作為 JavaScript 的標准特性適當地完成,那么這將為大量操作打開大門,包括本機高效密碼學(這對於多精度數字很容易實現)。

例如,在我 1998 年的 smalltalk 引擎之一中,我剛剛在 2.3GHz cpu 上運行:

[10000 factorial] millisecondsToRun => 59ms
10000 factorial asString size => 35660 digits

[20000 factorial] millisecondsToRun => 271ms
20000 factorial asString size => 77338 digits

定義為:(說明<BigInt>多精度的作用)

factorial

   "Return the factorial of <self>."

   | factorial n |

    (n := self truncate) < 0 ifTrue: [^'negative factorial' throw].
    factorial := 1.
    2 to: n do:
    [:i |
        factorial := factorial * i.
    ].
   ^factorial

Lars Bak(我的當代作品)的 V8 引擎源自於 David Ungar 的來自 Smalltalk-80 的 SELF 作品的 Animorphic Smalltalk,隨后演變為 JVM,並由 Lars for Mobile 重做,后來成為 V8 引擎基礎。

我提到這一點是因為 Animorphic Smalltalk 和 QKS Smalltalk 都支持類型注釋,這使引擎和工具能夠以類似於 TypeScript 為 JavaScript 嘗試的方式來推理代碼。

注釋提示及其在語言、工具和運行時引擎中的使用提供了支持正確支持多精度算術類型提升和強制規則所需的多方法(而不是雙重分派)的能力。

反過來,這是在一個連貫的框架中支持 8/16/32/64 int/uint 和許多其他數字類型的關鍵。

來自 QKS Smalltalk 1998 的多方法<Magnitude|Number|UInt64>示例

Integer + <Integer> anObject

   "Handle any integer combined with any integer which should normalize
    away any combination of <Boolean|nil>."
   ^self asInteger + anObject asInteger

-- multi-method examples --

Integer + <Number> anObject

   "In our generic form, we normalize the receiver in case we are a
    <Boolean> or <nil>."
   ^self asInteger + anObject

-- FFI JIT and Marshaling to/from <UInt64>

UInt64 ffiMarshallFromFFV
   |flags| := __ffiFlags(). 
   |stackRetrieveLoc| := __ffiVoidRef().
    ""stdout.printf('`n%s [%x]@[%x] <%s>',thisMethod,flags,stackRetrieveLoc, __ffiIndirections()).
    if (flags & kFFI_isOutArg) [
        "" We should handle [Out],*,DIM[] cases here
        "" -----------------------------------------
        "" Is this a callout-ret-val or a callback-arg-val
        "" Is this a UInt64-by-ref or a UInt64-by-val
        "" Is this an [Out] or [InOut] callback-arg-val that needs 
        ""   to be updated when the callback returns, if so allocate callback
        ""   block to invoke for doing this on return, register it as a cleanup hook.
    ].
   ^(stackRetrieveLoc.uint32At(4) << 32) | stackRetrieveLoc.uint32At(0).

-- <Fraction> --

Fraction compareWith: <Real> aRealValue

   "Compare the receiver with the argument and return a result of 0
    if the received <self> is equal, -1 if less than, or 1 if
    greater than the argument <anObject>."
   ^(numerator * aRealValue denominator) compareWith:
            (denominator * aRealValue numerator)

Fraction compareWith: <Float> aRealValue

   "Compare the receiver with the argument and return a result of 0
    if the received <self> is equal, -1 if less than, or 1 if
    greater than the argument <anObject>."
   ^self asFloat compareWith: aRealValue

-- <Float> --

Float GetIntegralExpAndMantissaForBase(<[out]> mantissa, <const> radix, <const> mantissa_precision)
   |exp2| := GetRadix2ExpAndMantissa(&mantissa).
    if(radix = 2) ^exp2.

   |exp_scale| := 2.0.log(radix).
   |exp_radix| := exp2 * exp_scale.
   |exponent| := exp_radix".truncate".asInteger.
    if ((|exp_delta| := exp_radix - exponent) != 0) [
       |radix_exp_scale_factor| := (radix.asFloat ^^ exp_delta).asFraction.
        "" Limit it to the approximate precision of a floating point number
        if ((|scale_limit| := 53 - mantissa.highBit - radix.highBit) > 0) [
            "" Compute the scaling factor required to preserve a reasonable
            "" number of precision digits affected by the exponent scaling 
            "" roundoff losses. I.e., force mantissa to roughly 52 bits
            "" minus one radix decimal place.
           |mantissa_scale| := (scale_limit * exp_scale).ceiling.asInteger.     
            mantissa_scale timesRepeat: [mantissa :*= radix].
            exponent :-= mantissa_scale.
        ] else [
            "" If at the precision limit of a float, then check the
            "" last decimal place and follow a rounding up rule
            if(exp2 <= -52 and: [(mantissa % radix) >= (radix//2)]) [
                mantissa := (mantissa // radix)+1.
                exponent :+= 1.
            ].
        ].
        "" Scale the mantissa by the exp-delta factor using fractions
        mantissa := (mantissa * radix_exp_scale_factor).asInteger.
    ].

    "" Normalize to remove trailing zeroes as appropriate
    while(mantissa != 0 and: [(mantissa % radix) = 0]) [
        exponent :+= 1.
        mantissa ://= radix.
    ].
   ^exponent.

我希望隨着 <BigInt> 的發展,一些類似的模式將開始出現,以支持 UIIn64/Int64 和其他結構或數字類型的 JavaScript。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM