我有一个简单的C#函数:
public static double Floor(double value, double step)
{
return Math.Floor(value / step) * step;
}
计算更高的数字,低于或等于“值”,即“步数”的倍数。但它缺乏精确性,如下面的测试所示:
[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);
}
第一个和第二个断言都可以,但第三个断言失败,因为结果只等到第6个小数位。这是为什么?有没有办法纠正这个?
更新如果我调试测试,我看到值相等,直到第8个小数位而不是第6个,可能是因为Math.Round引入了一些不精确。
注意在我的测试代码中,我写了“F”后缀(显式浮点常量),其中我的意思是“D”(双),所以如果我改变它,我可以有更多的精度。
答案 0 :(得分:11)
我实际上希望他们没有为浮点数和双精度数实现==运算符。如果double或float等于任何其他值,那么几乎总是错误的做法。
答案 1 :(得分:8)
计算机上的浮点运算不是Exact Science :)。
如果您想要精确到预定义的小数位数,请使用Decimal而不是double或接受小的间隔。
答案 2 :(得分:6)
如果省略所有F后缀(即-12.1
而不是-12.1F
),您将获得更多相等的几位数。由于F
,您的常量(尤其是预期值)现在是浮点数。如果您是故意这样做,请解释。
但是对于其余的我同意比较双重或浮点值的其他答案的平等,它只是不可靠。
答案 3 :(得分:5)
http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
例如,0.1和0.01(二进制)的不可表示性意味着尝试平方0.1的结果既不是0.01也不是最接近它的可表示数字。
如果您需要机器对数字系统的解释(二进制),请仅使用浮点数。你不能代表10美分。
答案 4 :(得分:5)
如果需要precision,请使用System.Decimal。如果需要速度,请使用System.Double(或System.Float)。浮点数不是“无限精度”数,因此断言相等必须包含容差。只要您的数字具有合理的有效位数,就可以了。
请参阅this回答(也是我),详细分析精确度如何影响数学运算的结果。
答案 5 :(得分:3)
检查此问题的答案:Is it safe to check floating point values for equality to 0?
真的,只需检查“在......的容忍范围内”
答案 6 :(得分:1)
浮动和双打不能准确存储所有数字。这是IEEE浮点系统的限制。为了获得忠实的精确度,您需要使用更高级的数学库。
如果您不需要超过某一点的精度,那么也许十进制对您来说效果更好。它的精度高于双精度。
答案 7 :(得分:0)
对于类似的问题,我最终使用以下实现,这似乎是我测试用例的大部分成功(最多5位精度):
public static double roundValue(double rawValue, double valueTick)
{
if (valueTick <= 0.0) return 0.0;
Decimal val = new Decimal(rawValue);
Decimal step = new Decimal(valueTick);
Decimal modulo = Decimal.Round(Decimal.Divide(val,step));
return Decimal.ToDouble(Decimal.Multiply(modulo, step));
}
答案 8 :(得分:0)
有时结果比您对严格要求的结果更精确:FP IEEE 754。 那是因为HW使用更多位进行计算。 请参阅C# specification和this article
Java有strictfp关键字,C ++有编译器开关。我想念.NET中的那个选项