如何确定 Javascript 数字是否在单精度范围内?

Rob*_*sen 6 javascript floating-point ieee-754 webidl floating-point-conversion

根据ECMAScript 规范,Javascript 数值对应于双精度 64 位二进制格式 IEEE 754 值。

\n\n

对于我目前正在开发的 WebIDL 验证器,我需要能够弄清楚给定的数值是否可以转换为WebIDL 浮点类型,即它是否可以表示为有限单精度 32 位 IEEE 754价值。

\n\n

我目前决定采用以下方法:

\n\n
validate: function(value) {\n    if (typeof value !== \'number\' || !Number.isFinite(value)) {\n        return false;\n    }\n\n    if (value === 0) {\n        return true;\n    }\n\n    var view = new DataView(new ArrayBuffer(4));\n\n    view.setFloat32(0, value);\n\n    var converted = view.getFloat32(0);\n    var relativeError = Math.abs(value - converted) / value;\n\n    return relativeError < Number.EPSILON;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

本质上,我正在做的是:

\n\n
    \n
  1. 将 a 包裹DataView在 4 字节周围ArrayBuffer
  2. \n
  3. 将值作为 32 位浮点数存储Number在缓冲区中。
  4. \n
  5. 从缓冲区中取出转换后的数字。
  6. \n
  7. 计算原始值与转换值之间的相对误差。
  8. \n
  9. 使用 来检查相对误差是否小于浮点数的机器 epsilonNumber.EPSILON
  10. \n
\n\n

几点评论:

\n\n\n\n

上述逻辑对于我想要实现的目标来说合理吗?是不是太过分了?有没有更惯用、更优雅或更高效的方法来做到这一点?

\n\n

更新

\n\n

我同时发现上述方法是错误的。它对于大范围的值(例如 、 等)都会1.001失败3.14159。另一方面,将 epsilon 值更改为 32 位浮点数的机器 epsilon (2 \xe2\x88\x9223 ) 过于宽松,并且允许诸如16777217.

\n\n

仍在寻找一个好的解决方案,但目前使用下面的函数,仅检查整数上限和下限(2 24和 -(2 24 ))。

\n\n
validate: function(value) {\n    return typeof value === \'number\' && Number.isFinite(value)\n            && value >= -16777216 && value <= 16777216;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

Sim*_*rne 5

当您使用 ECMAScript 6 时,您可以使用它Math.fround来检查它是否是单精度数字:

function isfloat32(x) {
  return isNaN(x) || x == Math.fround(x);
}
Run Code Online (Sandbox Code Playgroud)

更新:我错过了关于WebIDL 浮点是有限的(即不是 Inf 或 NaN)的部分。在这种情况下,

function isfloat32(x) {
  return isFinite(x) && x == Math.fround(x);
}
Run Code Online (Sandbox Code Playgroud)