【问题标题】:JavaScript pack integers and calculate arbitrary precision float:JavaScript 打包整数并计算任意精度浮点数:
【发布时间】:2011-07-20 06:40:06
【问题描述】:

我需要在 JavaScript 中执行以下操作,但目前无法找到无缝执行此操作的解决方案:

  • 按特定顺序获取两个整数,然后像 Python 的 struct 模块一样打包它们。
  • 这个打包的值(支持与主机不同的字节序)将被转换为 64 位浮点数(双精度)。它们必须是任意的,因此我可能会得到整数的指数表示(例如,它们可能是 0xdeadbeef 和 500):

    以 exp 形式: 1.0883076389305e-311 1.0883076389305000 * 10 ^ - 311

  • 我需要将其转换为任意精度、非指数形式,所以:

    0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000108830763893050000000000000000000000000000000000000000000000000000000000000000000000000000

  • 那个数字转换成一个字符串:)

我还没有找到在 Javascript 中执行此操作的方法,我必须输出一些必须支持任意精度的数字,或者至少可以扩展到双精度数的 1024 指数(或者说 400) .

谢谢!!

注意:我确实需要“打包/解包”来忠实地表示这两个数字转换为双精度/64 位浮点数。但我不关心,比如说,导出到字符串或原始缓冲区。作为只要我得到一个任意精度的双精度表示就可以了。

【问题讨论】:

  • 哈哈,我会调用在服务器上执行此操作的 Web 服务。介意我问你为什么需要在 javascript 中这样做?
  • 因为这在技术上是一个挑战,而且如今由于 JIT,Javascript 比做整个服务器端处理要快得多。没有借口给服务器增加更多负担。
  • @soze - 在服务器上,打包两个 int 并将它们解压成一个 double 是微不足道的。
  • 在javascript上也是如此,我认为它会更复杂。对于这样一个简单的过程,所有计算和电信超载并不是微不足道的。这一切加起来远远超过它的价值(在客户端做)。

标签: javascript binary-data integer arbitrary-precision


【解决方案1】:

1:作为 WebGL TypedArray 要求的一部分,Khronos 有一个用于 DataView 接口的specification in progress,它与 Int32Array 结合使用Float64Array 可以让您将两个整数写入缓冲区,然后将它们作为双精度值读回。

不幸的是,浏览器对此的支持还不普遍 - 要测试您的浏览器,请访问 http://html5test.com/ 并查看标题为“本机二进制数据”的部分。

如果没有上面的 TypedArray 支持,我认为没有任何方法可以使用位旋转来做到这一点,因为 Javascript 的位运算符将数字视为 32 位无符号值,所以你会有无法访问高阶位。

2:double 变量没有任何特定的形式,IEE754 只是一种内部表示。

3:这是您可以尝试显示实际精度的点。不幸的是,内置方法,例如Number.toFixed(),不支持显示超过 20 位小数。您将需要解析指数形式并手动构造一个具有适当数量的前导零的字符串。

NB - 双精度的指数范围是 2^1024,而不是 10^1024,因此实际限制实际上是 ~1.0E±308 - 您的示例数字小于该范围。

EDIT 实际上,可能有办法,但我不能保证它的准确性:

  1. 把你的两个整数命名为hilo
  2. 提取指数 - exp = (hi >> 20) & 0x7ff
  3. 提取符号 - sign = (hi >> 31)
  4. 提取尾数 - ((hi & 0xfffff) * Math.pow(2, 32) + lo) / Math.pow(2, 52)
  5. result = (1 + m) * (Math.pow(2.0, exp - 1023))
  6. if (sign) result *= -1

编辑 2 - 有效!见http://jsfiddle.net/alnitak/assXS/

var hex2double = function(input) {

    var hi = parseInt(input.substring(0, 8), 16);
    var lo = parseInt(input.substring(8   ), 16);

    var p32 = 0x100000000;
    var p52 = 0x10000000000000;

    var exp = (hi >> 20) & 0x7ff;
    var sign = (hi >> 31);
    var m = 1 + ((hi & 0xfffff) * p32 + lo) / p52;
    m = exp ? (m + 1) : (m * 2.0);

    return (sign ? -1 : 1) * m * Math.pow(2, exp - 1023);
};

http://babbage.cs.qc.edu/IEEE-754/Decimal.html 处输入一个浮点数,从输出的底行获取生成的十六进制字符串,并将其传递给上面的函数。您应该会看到一个包含原始值的警报。

EDIT 3 代码修复了指数位全为零时的特殊情况。

【讨论】:

  • 我要求的是纯 JS 解决方案,我不能依赖其他任何东西 ;(
  • 哦,关于字符串表示,你为什么建议简单地用零作为前缀呢?我的意思是,* 10 ^300 的乘积肯定是一个很小的数字,前缀有尽可能多的零......但如果你能展示一个适用于任意数字的例子,我将不胜感激。
  • 内置JS类型不支持任意数字,只支持IEE754双精度格式。
  • 我只需要一个 64 位双精度...而且我只需要任意精度库将其转换为非指数表示以将其发送到 Web 服务,这就需要它。我在寻找处理这两个整数的打包/解包机制时仍然没有成功。
  • @soze 修复了 very 小数字的特殊情况。除 e 的数字外,该功能适用​​于所有数字
【解决方案2】:

我认为您需要一个大型 JavaScript 库,例如 http://jsfromhell.com/classes/bignumber

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-03
    • 2010-12-26
    • 2017-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-12
    相关资源
    最近更新 更多