C 比较两倍的结果得出一个更小,另一个相等
因此,我有以下代码:C 比较两倍的结果得出一个更小,另一个相等,c,32bit-64bit,C,32bit 64bit,因此,我有以下代码: 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)]
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);
}
但是,如果我取消对其他if
语句的注释,我会得到min
的正确值,但是
less? 1
equal? 1
greater? 0
min = 1
我知道比较双精度可能很挑剔,我读到其中提到从80位寄存器移动到64位内存,所以我猜printf
语句可能会导致类似的情况。但是,
tuple[1]
既小于又等于tuple[0]
,这怎么可能呢*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]);
}
通过printf(%a)
得到的值是
tuple[0] = 0x1.2594a8056d275p+5
tuple[1] = 0x1.2594a8056d275p+5
tuple[2] = 0x1.fffffffffffffp+1023
实际上,存储在
tuple
中的结果的读取精度比预期的要高,导致一些比较产生了矛盾的结果
向编译器添加-ffloat-store
标志可以纠正这种情况,但正如注释中所述,它可能并不理想,而且显然不可移植
将tuple
声明为volatile
似乎可以做到这一点,但必须按照
volatile double *tuple = (double *)malloc(3 * sizeof(double));
然后
free((double *)tuple);
编辑:显然上述内容是不必要的,
使用volatile双元组[3]代码>就足够了。
为了仅在x32编译中使用它,
我在C++
中使用了以下typedef
:
#include <type_traits> // conditional
typedef std::conditional<sizeof(void*) == 4, volatile double, double>::type tuple_t;
tuple_t tuple[3];
#包含//条件
typedef std::conditional::type tuple\t;
tuple_t tuple[3];
您可以使用printf(“%a”)准确打印出双精度
也许您正在使用一个编译器选项,该选项旨在提供更快的DP算法,但会以您描述的偶尔异常为代价。有几个编译器提供了这样的选项。作为对您编辑的注释。printf
与此无关。精度没有损失。printf接收一个0或1的整数参数,it不参与比较。您要查找的gcc标志是-ffloat store
。但它使浮点运算速度非常慢。只需说该代码仅在amd64
和更新的计算机上受支持。缩小问题的思路:1)重新迭代:查看FP编译器选项2)使用易失性双元组[3]代码>强制编译器不使用扩展精度中间结果3)使用int lt=tuple[1]
强制(鼓励)在所有printf()之前进行比较计算。
s。4) 注意(lt+eq+gt)!=1
。依我看,问题要么是#1,要么是编译器错误,要么是代码中的UB。不要抛出malloc()
和friends的结果。这是不必要的,可以掩盖缺乏适当的原型。
free((double *)tuple);
#include <type_traits> // conditional
typedef std::conditional<sizeof(void*) == 4, volatile double, double>::type tuple_t;
tuple_t tuple[3];