在.NET上的双精度问题
在.NET上的双精度问题
我有一个简单的C#函数:\n
public static double Floor(double value, double step) { return Math.Floor(value / step) * step; }
\n它计算出小于或等于\"value\"的最高数字,且是\"step\"的倍数。但是它缺乏精度,如下面的测试所示:\n
[TestMethod()] public void FloorTest() { int decimals = 6; double value = 5F; double step = 2F; double expected = 4F; double actual = Class.Floor(value, step); Assert.AreEqual(expected, actual); value = -11.5F; step = 1.1F; expected = -12.1F; actual = Class.Floor(value, step); Assert.AreEqual(Math.Round(expected, decimals),Math.Round(actual, decimals)); Assert.AreEqual(expected, actual); }
\n第一个和第二个断言是正确的,但是第三个断言失败了,因为结果只在小数点后6位相等。为什么会这样?有没有办法可以纠正这个问题?\n更新 如果我调试测试,我会发现值在小数点后8位相等,而不是6位,可能是因为Math.Round引入了一些不精确性。\n注意 在我的测试代码中,我写了\"F\"后缀(显式浮点常量),我本意是\"D\"(双精度),所以如果我更改一下,可以获得更高的精度。
Double precision problems on .NET
在.NET平台上的双精度问题
浮点数运算在计算机上并不是精确科学 :).
如果你想要精确到预定义的小数位数,使用Decimal而不是double,或者接受一个较小的间隔。
在IEEE规定的有效数字范围内,它是一门精确的科学。
为了强调上述观点:浮点数是精确的。你想要的数字可能无法表示为IEEE浮点数,这意味着你必须将该数字别名到最接近的一个,从而导致误差,但这并不意味着你可以表示的数字中有错误。
此外,Decimal也可能遇到与Double相同的问题,因为它们也是浮点数。它们可能会遇到相同的表示问题,但这种情况下的错误要少得多,因为它们的基数是10,而不是2,而我们习惯于处理十进制的表示问题(例如,1/3在十进制中是0.333333......)。
解决方法:
1. 使用Decimal类型来处理需要精确小数位数的计算,而不是使用Double类型。
示例代码:
decimal number1 = 0.1m; decimal number2 = 0.2m; decimal sum = number1 + number2; Console.WriteLine(sum); // 输出:0.3 double number3 = 0.1; double number4 = 0.2; double sum2 = number3 + number4; Console.WriteLine(sum2); // 输出:0.30000000000000004
2. 如果必须使用Double类型进行计算,可以通过舍入操作来减少误差。
示例代码:
double number1 = 0.1; double number2 = 0.2; double sum = number1 + number2; double roundedSum = Math.Round(sum, 2); Console.WriteLine(roundedSum); // 输出:0.3
这样可以将计算结果舍入到指定的小数位数,减少由于浮点数表示不精确而导致的误差。
通过以上两种方法,我们可以在.NET平台上处理双精度问题,并尽量减小计算中的误差。
Double precision problems on .NET
在.NET中出现双精度问题的原因是,浮点数(float和double)并不具有无限的精度,因此断言两个浮点数是否相等时,必须包含一个容差。只要你的数字具有合理数量的有效数字,这是可以接受的。
以下是一些使用浮点数(float和double)时需要注意的情况:
- 如果你要对非常大和非常小的数字进行数学运算,请不要使用浮点数。
- 如果你需要无限精度,请不要使用浮点数。
- 如果你要对大量的值进行聚合,请不要使用浮点数(误差会相互累积)。
- 如果你需要速度和大小,请使用浮点数。
浮点数的精度是基于二进制位数而不是十进制位数。因此,浮点数在十进制位数上可能存在精度问题。
整数是一种具有无限精度的类型。在数学运算中,整数不会丢失任何精度。虽然可以实现一个具有无限精度的十进制类型,但在.NET中没有提供该功能。
因此,浮点数的精度问题可以通过使用System.Decimal类型来解决。System.Decimal类型具有无限精度,可以用于需要精确计算的场景。
以上是浮点数在.NET中出现双精度问题的原因以及解决方法的相关内容。如果你想了解更详细的关于精度如何影响数学运算结果的分析,请参考这个回答。
注意:本文中的两位参与者之间的对话只是为了说明问题,具体的解决方法和建议应以上述内容为准。
(Double precision problems on .NET)
在.NET中,双精度问题是指浮点数(float和double)在进行比较时可能出现的问题。实际上,我有点希望他们没有为浮点数实现“==”操作符。因为几乎总是错误的去问一个double或者float是否等于任何其他值。
是的!是的!是的!我已经说了一段时间了。这就像是整个0.999... = 1.0问题一样。(1.0 - 0.000... = 1.0)。浮点数与整数完全不同。
浮点数在计算机中的表示方式与整数不同,因此在进行比较时会出现一些问题。这是由于浮点数的精度有限,无法精确表示某些小数。因此,当我们使用"=="操作符比较两个浮点数时,可能会得到错误的结果。
解决这个问题的方法是使用特定的比较函数,如Math.Abs方法来比较两个浮点数的差值是否小于某个阈值。这样可以避免直接比较浮点数的精确值。
例如,我们可以使用以下代码来比较两个浮点数的差值是否小于0.0001:
double a = 1.0;
double b = 0.9999;
if (Math.Abs(a - b) < 0.0001)
{
// 两个浮点数相等
}
else
{
// 两个浮点数不相等
}
通过使用这种比较方法,我们可以避免由于浮点数精度问题导致的错误比较结果。这种方法可以在任何使用浮点数比较的情况下都适用,帮助我们正确处理浮点数的相等性判断。