所以我有以下代码:
double which_min(const int i, const int j, const int nx,
const double step, const double local_cost,
double *D)
{
double tuple[3];
// DIAG, LEFT, UP
tuple[0] = (D[d2s(i-1, j-1, nx)] == NOT_VISITED) ? DBL_MAX : D[d2s(i-1, j-1, nx)] + step * local_cost;
tuple[1] = (D[d2s(i, j-1, nx)] == NOT_VISITED) ? DBL_MAX : D[d2s(i, j-1, nx)] + local_cost;
tuple[2] = (D[d2s(i-1, j, nx)] == NOT_VISITED) ? DBL_MAX : D[d2s(i-1, j, nx)] + local_cost;
/*
if (i == 83 && j == 124) printf("less? %d\n", tuple[1] < tuple[0]);
if (i == 83 && j == 124) printf("equal? %d\n", tuple[1] == tuple[0]);
if (i == 83 && j == 124) printf("greater? %d\n", tuple[1] > tuple[0]);
*/
int min = (tuple[0] <= tuple[1]) ? 0 : 1;
min = (tuple[min] <= tuple[2]) ? min : 2;
if (i == 83 && j == 124) printf("min = %d\n", min + 1);
return ((double) min + 1.0);
}
对于我正在使用的有问题的案例,step = 1
,i = 83
和j = 124
时,我正在
min = 2.
但是,如果我取消注释其他if
语句,我会得到min
的正确值,但是......
less? 1
equal? 1
greater? 0
min = 1
我知道比较双打可能很挑剔,我读this answer提到从80位寄存器移动到64位内存,所以我猜测printf
语句可能导致类似的东西。然而,
tuple[1]
更少且等于tuple[0]
仍然感觉违反直觉,这怎么可能?* 顺便说一句,这只发生在32位系统中,64位版本没有给我任何问题。
编辑:我猜第一个printf
导致精度下降,以便==
比较之后评估为1
,但主要问题是我是否可以制作结果一致。
EDIT2:确实,将if
陈述的顺序更改为
if (i == 83 && j == 124)
{
printf("equal? %d\n", tuple[1] == tuple[0]);
printf("less? %d\n", tuple[1] < tuple[0]);
printf("greater? %d\n", tuple[1] > tuple[0]);
}
结果
equal? 0
less? 0
greater? 0
min = 1
我使用printf(%a)
获得的值是
tuple[0] = 0x1.2594a8056d275p+5
tuple[1] = 0x1.2594a8056d275p+5
tuple[2] = 0x1.fffffffffffffp+1023
答案 0 :(得分:0)
确实,tuple
中存储的结果的读取精度高于预期,导致某些比较产生矛盾的结果。
将-ffloat-store
标志添加到编译器可以解决这种情况,但正如评论中所提到的,它可能并不理想,显然它不可移植。
将tuple
声明为volatile
似乎可以解决问题,但必须以
volatile double *tuple = (double *)malloc(3 * sizeof(double));
然后
free((double *)tuple);
编辑:显然上面没有必要,
使用volatile double tuple[3];
就足够了。
为了仅在x32编译中使用它,
我在typedef
中使用了以下C++
:
#include <type_traits> // conditional
typedef std::conditional<sizeof(void*) == 4, volatile double, double>::type tuple_t;
tuple_t tuple[3];