JavaScript支持64位整数吗?

96
我可以帮您进行翻译。以下是代码内容:

我有以下代码:

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

我得到了这个值: "4611686018427388000", 它是0x4000000000000060

我想知道JavaScript是否没有正确处理64位整数,或者是我的操作有误?


3个回答

103
JavaScript使用IEEE-754双精度(64位)格式表示数字。据我所知,这可以提供53位精度,即十五到十六个十进制数字。如果您的数字比JavaScript可以处理的更多,则会得到一个近似值,这并不是真正的“处理不当”,但显然如果您需要大数的完全精度,这并不是很有帮助。有一些JS库可以处理更大的数字,例如BigNumberInt64

2
Closure 的 goog.math.Long 也可能会有所帮助:http://docs.closure-library.googlecode.com/git/class_goog_math_Long.html - Jeremy Condit
51
据我了解,需要补充说明位级操作仅限于32位。 - sellibitze
2
goog.math.Long文档已移至:http://google.github.io/closure-library/api/class_goog_math_Long.html - benizi
5
很遗憾,ECMAScript 2015规范(第6版)没有官方支持UInt64;不过Mozilla已经增加了对UInt64的支持--不过这是非标准的。WebGL有类似的需求,但不幸的是没有Uint64Array,只有Uint32Array - falsarella
3
goog.math.Long 文档已经再次移动: https://google.github.io/closure-library/api/goog.math.Long.html(感谢 @Pacerier) - benizi
显示剩余9条评论

19

Chromium 57版本及以上原生支持任意精度整数。这被称为BigInt,并且其他浏览器也正在进行相应的开发工作。它比JavaScript实现快得多


此外,Opera 54+和Node.js也支援。如果启用了javascript.options.bigint标记,则Firefox 65+也支援其使用。 - David Callanan
这并不总是更快。比较以下两段代码的速度: console.time("go");for (var i=0;i<10000000;++i) {} console.timeEnd("go"); vs 64位数字 console.time("go");for (var i=0n;i<10000000n;++i) {} console.timeEnd("go"); - Cibo FATA8
4
他在谈论原生浏览器组件的BigInt与JavaScript实现的BigInt之间的区别。你正在比较JS数字,它们是带有大约53位精度(不是64位)的浮点数,与原生浏览器的BigInt(也不是64位)相比。 - hippietrail

10

也就是说,V8 JavaScript是一个源于Smalltalk的引擎(1980年至今)。Lisp和Smalltalk引擎使用或称为支持多精度算术。顺便提一下,谷歌的Dart团队大多数是前Smalltalk程序员,他们将自己的经验带到JS领域。

这些类型的数字具有无限精度,并且通常被用作构建块来提供对象,其中分子和分母可以是任何类型的数字,包括。通过这种方式,可以表示实数、虚数,并在像1/3这样的无理数上以完美的精度进行运算。

注:我长期实现和开发Smalltalk、JS和其他语言及其引擎和框架。

如果合适地完成,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的SELF工作的Animorphic Smalltalk,后来发展成为JVM,并由Lars在之后用于移动技术的V8引擎基础进行了重制。

我提到这一点是因为Animorphic Smalltalk和QKS Smalltalk都支持类型注释,这使得引擎和工具能够以类似TypeScript尝试JavaScript的方式来理解代码。

该注释提示及其在语言、工具和运行时引擎中的使用提供了支持多方法(而不是双分派)的能力,这是支持多精度算术类型提升和强制转换规则所必需的。

这反过来又是支持8/16/32/64 int/uints和许多其他数字类型在一个连贯框架中的关键。

来自QKS Smalltalk 1998的多方法示例

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> 的发展,JavaScript 对 UIn64/Int64 和其他结构或数值类型的支持将开始出现类似的模式。


历史部分点赞,有相关的论文吗? - user502187

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接