为什么使用大数字float.CompareTo()
不能按预期工作?
测试编号:
float a = 1000000000f;
float b = 1000000001f;
float c = 1000000002f;
float d = 999999999f;
结果:
a.CompareTo(a) = 0
a.CompareTo(b) = 0
a.CompareTo(c) = 0
a.CompareTo(d) = 0
文档说:
- 小于零:此实例在排序顺序中位于 obj 之前。
- 零:此实例在排序顺序中与 obj 相同的位置出现。
- 大于零:此实例在排序顺序中跟随 obj。
正如你所看到的,结果显示a,b,c和d是相同的。
但是,如果我使用较小的数字,例如:
float a = 100000f;
float b = 100001f;
float c = 100002f;
float d = 99999f;
结果:
a.CompareTo(a) = 0
a.CompareTo(b) = -1
a.CompareTo(c) = -1
a.CompareTo(d) = 1
正确比较数字。
我读了浮点数学坏了吗?我理解十进制数字时的精度错误。但是为什么没有小数的大数字会产生这种意想不到的结果呢?
上下文。为什么使用比较?
我正在研究一些寻路算法,如BFS,Dijkstra和A *,我最终在我的PriorityQueue类中使用了IComparable,然后在测试时我遇到了错误。虽然我解决了算法中的所有错误,但我想知道为什么会发生这种情况。
编辑
我按照@GSerg的建议测试打印值,并收到了更多问题。a.ToString("N0")
、b.ToString("N0")
、c.ToString("N0")
、d.ToString("N0")
,在第一种情况下,所有四个变量都打印:"1,000,000,000"
。在第二种情况下,打印正确的较小数字。
答
据我了解,这种行为的原因是因为一个大的浮点数以类似"科学记数法"的样式存储,使它们的小数失去精度。浮点数学坏了吗?解释道。
这是因为浮点数可以表示从 −16,777,216 到 16,777,216 的整数值。 https://en.wikipedia.org/wiki/Single-precision_floating-point_format#Precision_limitations_on_integer_values
使用双精度时,您会得到预期的结果。
double a = 1000000000;
double b = 1000000001;
double c = 1000000002;
double d = 999999999;