我试图解决一些涉及大数分裂的问题。我偶然发现某些情况,我使用以下方法得到了错误的结果:
LL结果=(LL)ceil((double)(a-b)/ c),其中a,b和c是长整数(LL)。
#include <stdio.h> /* printf */
#include <math.h> /* ceil */
#define LL long long
int main ()
{
LL a= 10000000000000000;
LL aa = 10000000000000000-1;
LL aaa = 10000000000000000+1;
int b = 1;
int c = 1;
printf ( "%Ld\n", (LL)ceil((double)(a-b)/c) );
printf ( "%Ld\n", (LL)ceil((double)(aa-b)/c) );
printf ( "%Ld\n", (LL)ceil((double)(aaa-b)/c) );
return 0;
}
Output:
10000000000000000
9999999999999998
10000000000000000
这开始发生在大于或等于10 ^ 16且可被10整除的整数上 长长的上限是~10 ^ 18 那么是什么导致了这个错误?
我在C ++ 14模式下使用GCC 5.1(在ideone.com上)。
答案 0 :(得分:2)
虽然它可以存储更大幅度的数字,但double
的典型实现只能维持大约15-16位精度。
浮点减法也可能是一个问题,特别是如果这两个数字的幅度几乎相同。如果两个输入都是(例如)50位,但前40位是相同的,那么它们将被取消,结果只有大约10位。
所以,首先,你可能希望用long long
进行所有数学计算,如果这是你想要的结果类型。其次,您可能至少要考虑重新安排(a-b)/c
到a/c-b/c
,以尽可能延迟减法。
答案 1 :(得分:0)
如果您知道两个值均为正数,则可以使用以下公式计算纯整数(或长整数)的ceil:
(x + y-1)/y
所以,在你的情况下:
(a - b + c-1)/c
处理负数是留给读者的练习(它可能有点繁琐地决定你想要它做什么,而你通常也不需要它。)