我正在编写一个物理模拟程序,最近我遇到了异常结果。我成功地调试了我的程序,错误是用一个大的int除以一个大的双,某种形式:
cout << my_large_double/my_large_int << endl
对于订单为-10^{9}的my_large_double,以及我的两个ints的乘积为10^{9},返回的是第一阶的正值。我通过将分母转换为双分母来修正它:
cout << my_large_double/( (double)my_large_int1*my_large_int2) << endl
但是,我想知道错误是从哪里来的,是否有办法防止这些错误的发生?
更新:我在第一个问题中跳过了一个重要的细节: int实际上是两个int的乘积。
发布于 2013-11-26 18:27:44
这取决于表达式是如何编写的。
如果你写这个:
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)
(为了对称和清晰,你最好把它们都投进去。)
发布于 2013-11-26 17:03:16
一个double
可以在不损失53位精度的情况下保存一个int
,而不是int
典型的31位。您的解决方案很好,可以提前转换为double
,这样就不会在乘法中遇到整数溢出。
https://stackoverflow.com/questions/20222737
复制相似问题