4

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

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

我目前已经确定了以下方法:

validate: function(value) {
    if (typeof value !== 'number' || !Number.isFinite(value)) {
        return false;
    }

    if (value === 0) {
        return true;
    }

    var view = new DataView(new ArrayBuffer(4));

    view.setFloat32(0, value);

    var converted = view.getFloat32(0);
    var relativeError = Math.abs(value - converted) / value;

    return relativeError < Number.EPSILON;
}

本质上,我正在做的是:

  1. 将 a 包裹DataView在 4 字节左右ArrayBuffer
  2. 将该Number值作为 32 位浮点数存储在缓冲区中。
  3. 将转换后的数字从缓冲区中取出。
  4. 计算原始值和转换值之间的相对误差。
  5. 检查相对误差是否小于浮点数的机器 epsilonNumber.EPSILON ,使用.

一些评论:

上述逻辑是否适合我想要实现的目标?是不是矫枉过正?有没有更惯用、更优雅或更高效的方式来做到这一点?

更新

与此同时,我发现上述方法是不正确的。1.001对于大范围的值(例如、等),它将失败3.14159。另一方面,将 epsilon 值更改为 32 位浮点数 (2 −2316777217 ) 的机器 epsilon 过于宽松,允许使用.

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

validate: function(value) {
    return typeof value === 'number' && Number.isFinite(value)
            && value >= -16777216 && value <= 16777216;
}
4

1 回答 1

4

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

function isfloat32(x) {
  return isNaN(x) || x == Math.fround(x);
}

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

function isfloat32(x) {
  return isFinite(x) && x == Math.fround(x);
}
于 2015-09-08T09:35:05.607 回答