如何判断一个Javascript数是否在单精度范围内?
How to determine if a Javascript Number is in single-precision range?
根据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
around a 4 byte ArrayBuffer
.
- 将
Number
值作为 32 位浮点数存储在缓冲区中。
- 从缓冲区中取回转换后的数字。
- 计算原值与转换值的相对误差
- 检查相对误差是否小于machine epsilon for floating point numbers, using
Number.EPSILON
。
一些评论:
- 我将其作为 Chrome 扩展的一部分来实现,浏览器兼容性并不是真正的问题。
- 是的,我已阅读 What Every Computer Scientist Should Know About Floating-Point Arithmetic。我的眼睛还没止血
以上逻辑是否符合我要实现的目标?是不是矫枉过正?有没有更惯用、更优雅或更高效的方法来做到这一点?
更新
同时我发现上面的做法是不正确的。对于范围广泛的值,如 1.001
、3.14159
等,它将失败。另一方面,将 epsilon 值更改为 32 位浮点数 (2−23) 的机器 epsilon 过于宽松,允许像 16777217
.
这样的值
仍在寻找一个好的解决方案,但目前正在使用下面的函数,该函数仅检查整数上限和下限 (224 和 -(2 24)).
validate: function(value) {
return typeof value === 'number' && Number.isFinite(value)
&& value >= -16777216 && value <= 16777216;
}
当您使用 ECMAScript 6 时,您可以使用 Math.fround
来检查它是否是单精度数:
function isfloat32(x) {
return isNaN(x) || x == Math.fround(x);
}
更新:我错过了关于 WebIDL float 是有限的部分(即不是 Inf 或 NaN)。那样的话,
function isfloat32(x) {
return isFinite(x) && x == Math.fround(x);
}
根据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
around a 4 byteArrayBuffer
. - 将
Number
值作为 32 位浮点数存储在缓冲区中。 - 从缓冲区中取回转换后的数字。
- 计算原值与转换值的相对误差
- 检查相对误差是否小于machine epsilon for floating point numbers, using
Number.EPSILON
。
一些评论:
- 我将其作为 Chrome 扩展的一部分来实现,浏览器兼容性并不是真正的问题。
- 是的,我已阅读 What Every Computer Scientist Should Know About Floating-Point Arithmetic。我的眼睛还没止血
以上逻辑是否符合我要实现的目标?是不是矫枉过正?有没有更惯用、更优雅或更高效的方法来做到这一点?
更新
同时我发现上面的做法是不正确的。对于范围广泛的值,如 1.001
、3.14159
等,它将失败。另一方面,将 epsilon 值更改为 32 位浮点数 (2−23) 的机器 epsilon 过于宽松,允许像 16777217
.
仍在寻找一个好的解决方案,但目前正在使用下面的函数,该函数仅检查整数上限和下限 (224 和 -(2 24)).
validate: function(value) {
return typeof value === 'number' && Number.isFinite(value)
&& value >= -16777216 && value <= 16777216;
}
当您使用 ECMAScript 6 时,您可以使用 Math.fround
来检查它是否是单精度数:
function isfloat32(x) {
return isNaN(x) || x == Math.fround(x);
}
更新:我错过了关于 WebIDL float 是有限的部分(即不是 Inf 或 NaN)。那样的话,
function isfloat32(x) {
return isFinite(x) && x == Math.fround(x);
}