如何测试浮点数是否是“在机器精度内”的整数
How to test whether a float is an integer "within machine precision"?
我问题的简要版本是:
在决定浮点数
x
和Math.round(x)
何时被视为相等,从而允许浮点运算损失精度时,什么被认为是"最佳实践"?
冗长的版本是:
我经常需要决定一个给定的浮点值x
是否应该"被视为整数",或者更学究地说,应该"被视为整数的浮点表示"。
(例如,如果 n 是整数,则数学表达式
日志 10(10N)
是表示相同整数 n 的复杂方式。 正是这种想法促使人们说,类似的浮点计算的结果可以被视为"整数的表示"。
每当Math.round(x) == x
计算结果为 true
时,这个决定就很容易:在这种情况下,我们可以说x
确实是一个整数(浮点表示)。
但是测试Math.round(x) == x
在评估时没有定论 false
. 例如
function log10(x) { return Math.log(x)/Math.LN10; }
// -> function()
x = log10(Math.pow(10, -4))
// -> -3.999999999999999
Math.round(x) == x
// -> false
编辑:我经常看到的一个"解决方案"是选择一些任意公差,如ε = 1e-6
,并测试Math.abs(Math.round(x) - x) < ε
。 我认为这样的解决方案会产生比我认为可以接受的更多的误报。
正如您在示例中所看到的x
实际上根本不是一个整数。这是由于计算早期的舍入误差,因此您实际上不知道x
被定义为近整数还是被舍入误差弄得参差不齐下。
如果你想知道什么数字是一个或另一个,你需要使用你自己建议的限制aproach,或者使用足够高的pericion,这样你的数字就不会首先被锯齿状。最后一种方法并不适用于所有情况。
还可以符号地跟踪所有数学运算,即将1/3
存储为1/3
而不是0.3333
并按需评估它们,从而抵消可以像手动计算表达式时一样取消的因素,但这在几乎所有情况下都是矫枉过正。更不用说这样的系统会有多复杂。如果这是所需的解决方案,您可能可以与 MatLab 或 Mathematica 或其他东西进行交互以处理评估,除非您在浏览器中运行它,对于尝试 WolframAlpha API 的浏览器来说可能有点困难(为什么我第一次没有想到这一点?)。
不过;如果你能通过选择ε
来解决这个问题,你会得到一个令人满意的结果,这可能是最好的方法。如果静态ε
没有削减它,您可以尝试根据之前对手头的数字进行的计算类型动态选择它。即,相乘的数字往往比除以的数字产生更少的分数部分,依此类推。如果该数字除了加号、减号和乘法(不涉及分数)之外没有其他任何东西,您也可以知道它最多可以有多少位小数,因此可以选择一个合理的ε
。
假设x
不为零,我认为您应该查看比率Math.abs(x-Math.round(x))/x
。这涉及这样一个事实,即浮点类型每个存储固定数量的有效位,而不是小数点后的固定位数。
接下来,您需要确定计算的典型舍入误差。如果x
是简单计算的结果,那可能很容易。如果没有,请考虑从您知道确切答案的测试用例中收集一些统计信息。理想情况下,您会发现x
整数的比率最大值与不应被视为整数的x
的最小值之间存在显著差异。如果是这样,请在该范围内选择一个 epsilon。
这是一个有趣的问题,所以我不得不考虑一下。
这是一个单行解决方案,尽管它涉及在数字和字符串类型之间进行转换,所以我不知道它有多理想。但它比仅仅选择一个最小阈值并检查数字是否在该限制范围内要准确得多。
JavaScript 数字是双精度 64 位格式,其精度约为 16 个十进制数字。这是总位数,而不仅仅是小数点右侧的位数。
JavaScript 数字还有一个 toPrecision() 方法,可以将它们转换为字符串,四舍五入到给定的精度(总位数,非常适合您使用)。以下内容会将任何数字舍入到最接近的 15 位精度,然后将其转换回浮点数。
function roundToPrecision(number, precision) {
return parseFloat(number.toPrecision(precision));
}
x = roundToPrecision(x, 15);
那么你的例子实际上将是一个整数:-4。
编辑:经过一番思考,这将更快:
var integerDigits = (""+parseInt(Math.abs(x))).length,
threshold = 1e-16 * Math.pow(10, integerDigits);
Math.abs(Math.round(x) - x) < threshold
http://jsperf.com/number-precision-rounding
- toLocaleDateString和toLocaleString方法不尊重机器时区
- 有没有任何方法可以使用node-js从不同的机器打开浏览器
- 使用c#中的邮件附件javascript在客户端机器上获取服务器端导出的crystal报告路径.下面的
- Html5音频时间更新精度
- 节点JS:时间机器坏了——timekeeper.travel不做时间旅行
- javascript zip文件夹和客户端机器中的子文件夹
- 如何将此小数Regex解析为1-24,精度为0到23之间的2
- 来自康卡斯特本地机器的JavaScript和CORS
- V8 javascript 引擎是否将所有 javascript 编译为机器语言
- 如何使用Javascript使浮点数的精度相同
- JShint 在不同的机器上的行为不同,尽管代码、版本和配置相同
- 如何从我的机器提供HTML + JS + CSS网络应用程序,以便其他人可以查看它
- 我可以限制浮点精度吗?
- 我们可以用来确保Javascript中精确精度的最大数字
- 数字精度如何影响 JavaScript 的性能,或者会影响性能
- 为什么可以't我在我的网站上嵌入了一个来自本地机器的PDF
- 任意精度数字和Javascript,Google Web Toolkit
- HTML浮点数字字段具有高精度,但呈现四舍五入值
- 获取客户端机器's使用Asp/Javascript的精确IP地址(非公共IP)
- 如何测试浮点数是否是“在机器精度内”的整数