【发布时间】:2015-09-08 02:03:49
【问题描述】:
根据ECMAScript specification,Javascript 数字值对应于双精度 64 位二进制格式 IEEE 754 值。
对于我目前正在研究的 WebIDL 验证器,我需要能够确定给定的数值是否可以转换为 WebIDL float 类型,即它是否可以表示为有限单精度 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;
}
本质上,我在做的是:
- 将
DataView包裹在一个4 字节的ArrayBuffer周围。 - 将
Number值作为 32 位浮点数存储在缓冲区中。 - 从缓冲区中取回转换后的数字。
- 计算原始值与转换值之间的相对误差。
- 使用
Number.EPSILON检查浮点数的相对误差是否小于machine epsilon。
几个cmets:
- 我将其作为 Chrome 扩展程序的一部分来实现,浏览器兼容性并不是真正的问题。
- 是的,我已阅读What Every Computer Scientist Should Know About Floating-Point Arithmetic。我的眼睛还没有止血。
上述逻辑是否符合我想要实现的目标?是不是矫枉过正?有没有更惯用、更优雅或更高效的方式来做到这一点?
更新
与此同时,我发现上述方法是不正确的。对于1.001、3.14159 等范围广泛的值,它将失败。另一方面,将 epsilon 值更改为机器 epsilon 以用于 32 位浮点数 (2−23) 过于宽松,允许使用像 16777217 这样的值。
仍在寻找一个好的解决方案,但目前正在使用下面的函数来检查整数上限和下限(224 和 -(224)) .
validate: function(value) {
return typeof value === 'number' && Number.isFinite(value)
&& value >= -16777216 && value <= 16777216;
}
【问题讨论】:
-
你可以创建一个缓冲区和它的 64 位视图,然后检查低位。
-
或
Math.fround()一步完成转换...blog.mozilla.org/javascript/2013/11/07/… -
如果您接受了一个字符串,您只需检查该数字是否不超过 6 个有效数字。
-
@zerkms 不起作用:例如转换为双精度时,最接近 1.1 的单精度数是 1.100000023841858
-
@zerkms 试试
Math.fround(1.1)
标签: javascript floating-point ieee-754 floating-point-conversion webidl