C(++) 中双精度的排序/比较不稳定
Sorting/comparison of doubles in C(++) not stable?
我在双打方面遇到了一个非常奇怪的问题。我有一个按降序排序的浮点数(双精度)列表。然而,在我的程序后面,我发现它们不再完全排序了。例如:
0.65801139819
0.6545651031 <-- a
0.65456513001 <-- b
0.64422968678
中间的两个数字被翻转。有人可能会认为这个问题出在数字的表示上,它们只是打印错误。但是我使用与排序相同的运算符将每个数字与前一个数字进行比较 - 没有转换为基数 10 或类似的数字:
double last_pt = 0;
for (int i = 0; i < npoints; i++) {
if (last_pt && last_pt < track[i]->Pt()) {
cout << "ERROR: new value " << track[i]->Pt()
<< " is higher than previous value " << last_pt << endl;
}
last_pt = track[i]->Pt();
}
在排序过程中,这些值将按以下方式进行比较
bool moreThan(const Track& a, const Track& b) {
return a.Pt() > b.Pt();
}
我确保它们始终是双倍的,而不是转换为浮动。 Pt()
返回双精度值。列表中没有 NaN,排序后我不碰列表。
为什么会这样,这些数字有什么问题,以及(如何)对数字进行排序以使它们保持排序?
您确定在某个时候没有将double
转换为float
吗?让我们看一下这两个数字的二进制表示:
0 01111111110 0100111100100011001010000011110111010101101100010101
0 01111111110 0100111100100011001010010010010011111101011010001001
在double
中,我们有1位符号,11位指数和53位尾数,而在float
中有1位符号,8位指数和23位尾数。请注意,两个数字中的尾数在前 23 位是相同的。
根据舍入方法的不同,会有不同的行为。如果只是修剪了位>23,则这两个数字作为float
是相同的:
0 011111110 01001111001000110010100 (trim: 00011110111010101101100010101)
0 011111110 01001111001000110010100 (trim: 10010010011111101011010001001)
您正在比较函数的返回值。 浮点返回值在浮点寄存器中返回,浮点寄存器具有更高的精度比双倍。 当比较两个这样的值时(例如 a.Pt() >
b.Pt()
),编译器会调用其中一个函数,存储返回类型为 double
的未命名临时中的值(因此将结果到 double
),然后调用另一个函数,并比较其结果(仍在浮点寄存器中,未舍入为 double
) 与存储的值。 这意味着您最终可以得到a.Pt() > b.Pt()
和b.Pt() > a.Pt()
或a.Pt() >
a.Pt()
的情况。 这会导致sort
感到困惑。(正式地说,如果我们在这里谈论std::sort
,这会导致未定义的行为,我听说过它确实会导致核心的情况转储。
另一方面,您说Pt()
"只返回一个双精度字段"。如果Pt()
不计算什么;如果只是:
double Pt() const { return someDouble; }
,那么这应该不是问题(前提是someDouble
有类型 double
)。 扩展的精度可以表示所有可能的双精度正是值。
- shell排序中的交换和比较
- 使用自定义比较函数使用std::sort()对矢量字符串进行排序时出现问题
- C++ 如何比较n个排序的整数向量以找到互元素?
- 什么是自定义比较器以及如何在 C++ 的排序函数中使用它?
- 不正确的比较和交换计数器输出用于快速排序功能
- 对没有比较器或λ函数的向量进行排序?
- std::sort与不严格的弱排序比较器可以作为拓扑排序工作
- std::排序比较器,可以看到元素的(原始)索引
- 使用冒泡排序比较类对象
- 如何重载自定义标准::排序比较函数
- C(++) 中双精度的排序/比较不稳定
- stl排序比较类函数
- 排序比较函数
- 交换排序比较和交换的次数
- 自定义排序比较函数抛出编译错误
- 排序比较函数可以是成员函数上的指针
- 字符串向量的排序比较和删除
- 哈希函数用于6个整数的良好排序/比较
- ICU可以直接在大端机器上对UTF-16LE数据进行排序比较吗?
- 排序比较函数奇怪的行为