理解浮点问题

问题描述 投票:0回答:4

这里有人可以帮助我了解如何确定浮点限制何时会导致计算错误。例如下面的代码。

CalculateTotalTax = function (TaxRate, TaxFreePrice) {
     return ((parseFloat(TaxFreePrice) / 100) * parseFloat(TaxRate)).toFixed(4);
};

我无法输入任何两个值,这导致我的方法结果不正确。如果我删除 toFixed(4),我实际上可以看到计算开始失去准确性的位置(小数点后第六位左右)。话虽如此,我对浮点数的理解是,即使是很小的数字有时也可能无法表示或我误解了,并且小数点后 4 位(例如)总是可以准确表示。

MSDN 将浮动解释为 such...

这意味着他们无法持有准确的 任何数量的表示 不是二进制分数(形式为 k / (2 ^ n) 其中 k 和 n 是整数)

现在我假设这适用于所有浮点数(包括 javascript 中使用的浮点数)。

从根本上来说,我的问题可以归结为这一点。如何确定任何特定方法是否容易受到浮点运算错误的影响,这些错误将以什么精度出现,以及产生这些错误需要哪些输入?

希望我的问题是有道理的。

c# javascript vb.net floating-point
4个回答
10
投票

首先阅读每个计算机科学家应该了解的浮点知识https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

简短回答:双精度浮点数(JavaScript 中的默认值)具有大约 16 位十进制数字的精度。舍入可能因平台而异。如果绝对有必要得到始终正确的答案,那么您应该自己进行理性算术(这并不难——对于货币来说,也许您只需乘以 100 即可将美分的数量存储为整数)。

但是如果足以得到高精度的答案,浮点应该足够好,尤其是双精度。


4
投票

在处理浮动时,您现在应该注意两件重要的事情:

1- 您应该了解machine epsilon。了解您的精度有多高。

2- 您不应该假设如果两个值以 10 为基数相等,那么在具有精度限制的机器中,它们以 2 为基数也相等

if ((6.0 / 10.0) / 3.0 != .2) {
        cout << "gotcha" << endl;
}

数字 2 可能足以让您避免比较浮点数是否相等,而是可以使用阈值和大于或小于运算符进行比较


2
投票

其他答案指出了理解这个问题的良好资源。如果您实际上在代码中使用货币值(如您的示例),您应该更喜欢 Decimal 类型(.Net 中的 System.Decimal)。这些将避免使用浮点数带来的一些舍入问题并更好地匹配域。


1
投票

不,小数位数与可以表示的内容无关。

尝试 0.1 * 3,或 162.295 / 10,或 24.0 + 47.98。这些对我来说在 JS 中失败了。但是,24.0 * 47.98 不会失败。

因此,为了回答您的三个问题,任何精度的任何操作都可能容易受到攻击。给定的输入是否会是一个我不知道如何回答的问题,但我有预感有很多因素。 1) 实际答案与最接近的二进制分数有多接近。 2) 执行计算的引擎的精度。 3) 用于执行计算的方法(例如,通过位移位相乘可能会得到与通过重复加法相乘不同的结果)

© www.soinside.com 2019 - 2024. All rights reserved.