我正在编码物理模拟,最近我遇到了异常结果。我设法调试我的程序,错误是在一个大的双重划分由一个大的int,形式的东西:
cout << my_large_double/my_large_int << endl
使用命令-10 ^ {9}的my_large_double,并且我的两个整数的乘积是10 ^ {9}的顺序返回顺序为1的正数。 我通过在分母中加倍转换来修复它:
cout << my_large_double/( (double)my_large_int1*my_large_int2) << endl
但我想知道错误来自何处,是否有办法阻止它们发生?
更新:我在第一个问题中跳过了一个重要的细节:int实际上是两个整数的乘积。
答案 0 :(得分:4)
这取决于表达式的确切编写方式。
如果你这样写:
my_large_double / my_large_int1 / my_large_int2
然后它相当于:
(my_large_double / my_large_int1) / my_large_int2
应该给你合理准确的结果;在第一次分组之前,my_large_int1
被提升为double
,在第二次分组之前,my_large_int2
被提升为double
。
如果你这样写:
my_large_double / (my_large_int1 * my_large_int2)
然后乘法是在两个整数变量的类型中完成的,并且根据它们的值你可以有一个溢出(这可以给你一个比数学产品小得多的值 - 虽然严格来说有符号整数的行为溢出是未定义的。)
要记住的重要一点是,在大多数情况下,每个C表达式都是有效的单独评估;它的类型不受其出现的上下文的影响。表达式my_large_int1 * my_large_int2
是整数乘法,即使结果是浮点除法的操作数或分配给浮点变量。
操作数都是整数的任何操作都是整数运算。如果一个操作数为double
而另一个操作数为int
,则int
操作数将提升为double
。
即便如此:
double temp = my_large_int1 * my_large_int2;
... my_large_double / temp ...
在使用结果初始化temp
之前,将执行整数乘法,并且:
my_large_double / (double)(my_large_int1 * my_large_int2)
有同样的问题。
正如您所发现的,解决方案是将一个或两个整数操作数强制转换为double
:
my_large_double / ((double)my_large_int1 * (double)my_large_int2)
(你也可以投两者,只是为了对称和清晰。)
答案 1 :(得分:1)
IEEE format double
可以容纳int
而不会导致高达53位的精度损失,而int
的典型值为31位。你的解决方案很好,预先转换为double
,这样你就不会在乘法中遇到整数溢出。