我有两个双打,我可以保证完全等于150个小数位 - 即。以下代码:
printf("***current line time is %5.150lf\n", current_line->time);
printf("***time for comparison is %5.150lf\n", (last_stage_four_print_time + FIVE_MINUTES_IN_DAYS));
...返回:
***current line time is 39346.526736111096397507935762405395507812500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
***time for comparison is 39346.526736111096397507935762405395507812500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
FIVE_MINUTES_IN_DAYS
是#defined,current_line->time
和last_stage_four_print_time
都是双打。
我的问题是我的调试代码的下一行:
printf("if condition is %d\n", (current_line->time >= (last_stage_four_print_time + FIVE_MINUTES_IN_DAYS)));
返回以下内容:
if condition is 0
谁能告诉我这里发生了什么?我知道floats
和doubles
的非十进制/不精确性质,但这些都不会出现任何错误(原始数据都是用sscanf
或#defined读取的并且都指定为10位小数)。
编辑:我的错误是假设printf
- 双精确地在内存中准确地表示了它们,这是错误的,因为正在计算一个值。将(last_stage_four_print_time + FIVE_MINUTES_IN_DAYS)
声明为threshold_time
并使用它来修复问题。我将确保使用epsilon进行比较 - 我知道这是要走的路,我只是为什么这些我(错误地)认为看起来相同的值明显不相等而感到困惑。
答案 0 :(得分:4)
Floats当然不准确到150位有效数字,所以我不确定从“视觉”比较中得出什么结论(如果有的话)。
另一方面,这些值显然不是相同的(并且它们怎么可能,因为其中一个是在现场计算加上?)。因此,您所看到的行为是出乎意料的并不是很清楚。
不要永远比较这样的浮点数,只需做差异与epsilon的标准比较。
答案 1 :(得分:4)
了解浮点表示(特别是http://en.wikipedia.org/wiki/IEEE_754-2008)。尝试将包含双精度的字节的实际内容打印为十六进制,并且它们不会逐位匹配。 浮子的正确比较是在Knuth(Seminumerical算法)中。简单(用int替换bool,用double替换float,用1替换true):
bool almostEqual(float x, float y, float epsilon)
{
if (x == 0.0 && y == 0.0) {
return true;
}
if (fabs(x) > fabs(y)) {
return fabs((x - y) / x) < epsilon;
} else {
return fabs((x - y) / y) < epsilon;
}
}
答案 2 :(得分:3)
您应始终使用EPSILON值来比较浮点数和双精度数以检查是否相等。即使看起来相同,内部表示也不能保证匹配,因为这些类型的数字以二进制形式表示。
您可以执行类似
的操作#define EPSILON 0.00001
...
if (fabs(a - b) <= EPSILON) return 1; // they are equal
return 0;
答案 3 :(得分:2)
耶稣对如何解决这个问题是对的。
至于为什么......在一种情况下,你读取一个常数值,在另一种情况下你执行一个加法运算。即使打印输出完全相同,二进制表示也可能略有不同。
尝试检查支持两个双精度的内存,看看是否有任何不同(会有差异)。
对于综合治疗,我建议
http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
答案 4 :(得分:1)
通常,您不应使用==来比较浮点数或双精度数。您应该检查差异是否小于某个小数字。
double second_number = last_stage_four_print_time + FIVE_MINUTES_IN_DAYS;
if (fabs(current_line->time - second_number) < 0.001 || current_line->time > second_number){
// your comparison code
}
答案 5 :(得分:1)
首先,双打只有15-16位小数(log_2为52位matissa)。
其次,如果你想比较,请使用已经提到过的epsilon。
第三,要进行调试,请打印十六进制值。