|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
#include <stdio.h>
#include <math.h>
double sum(int start , int end)
{
double ret = 0;
int i = start;
while (i < end)
{
ret = ret + pow(2,i);
i++;
}
return ret;
}
int main(void)
{
double result;
double weight;
result = sum(0,64);
weight = result / 25000;
printf("舍罕王应该给予达依尔%.0f粒麦子!\n",result);
printf("如果每25000粒麦子为1kg,那么应该给%.0fkg麦子!\n",weight);
return 0;
}
本帖最后由 jackz007 于 2025-4-17 01:00 编辑
应该是采用 double 数据类型累加所产生的计算误差。
请编译、运行下面的代码,这个代码会按长整型和双精度浮点数分别计算累加结果,从打印结果看,一开始,二者累加结果均一致,但是,当 i = 53 的时候,累加结果开始出现错位,双精度数的累加结果比长整型大 1。
- #include <math.h>
- double sum(int start , int end)
- {
- double ret1 = 0.0 ;
- unsigned long long ret2 = 0LL ;
- int i = start ;
- while (i < end)
- {
- ret1 += pow(2 , i) ;
- ret2 += 1LL << i ;
- printf("%2d , %.0lf , %llu\n" , i , ret1 , ret2) ;
- i ++ ;
- }
- return ret1 ;
- }
- int main(void)
- {
- double result , weight ;
- result = sum(0 , 64) ;
- weight = result / 25000 ;
- printf("舍罕王应该给予达依尔%.0lf粒麦子!\n" , result) ;
- printf("如果每25000粒麦子为1kg,那么应该给%.0lfkg麦子!\n",weight) ;
- return 0 ;
- }
复制代码
编译、运行实况:
- D:\[00.Exercise]\[C]>g++ -o x x.c
- D:\[00.Exercise]\[C]>x
- 0 , 1 , 1
- 1 , 3 , 3
- 2 , 7 , 7
- 3 , 15 , 15
- 4 , 31 , 31
- 5 , 63 , 63
- 6 , 127 , 127
- 7 , 255 , 255
- 8 , 511 , 511
- 9 , 1023 , 1023
- 10 , 2047 , 2047
- 11 , 4095 , 4095
- 12 , 8191 , 8191
- 13 , 16383 , 16383
- 14 , 32767 , 32767
- 15 , 65535 , 65535
- 16 , 131071 , 131071
- 17 , 262143 , 262143
- 18 , 524287 , 524287
- 19 , 1048575 , 1048575
- 20 , 2097151 , 2097151
- 21 , 4194303 , 4194303
- 22 , 8388607 , 8388607
- 23 , 16777215 , 16777215
- 24 , 33554431 , 33554431
- 25 , 67108863 , 67108863
- 26 , 134217727 , 134217727
- 27 , 268435455 , 268435455
- 28 , 536870911 , 536870911
- 29 , 1073741823 , 1073741823
- 30 , 2147483647 , 2147483647
- 31 , 4294967295 , 4294967295
- 32 , 8589934591 , 8589934591
- 33 , 17179869183 , 17179869183
- 34 , 34359738367 , 34359738367
- 35 , 68719476735 , 68719476735
- 36 , 137438953471 , 137438953471
- 37 , 274877906943 , 274877906943
- 38 , 549755813887 , 549755813887
- 39 , 1099511627775 , 1099511627775
- 40 , 2199023255551 , 2199023255551
- 41 , 4398046511103 , 4398046511103
- 42 , 8796093022207 , 8796093022207
- 43 , 17592186044415 , 17592186044415
- 44 , 35184372088831 , 35184372088831
- 45 , 70368744177663 , 70368744177663
- 46 , 140737488355327 , 140737488355327
- 47 , 281474976710655 , 281474976710655
- 48 , 562949953421311 , 562949953421311
- 49 , 1125899906842623 , 1125899906842623
- 50 , 2251799813685247 , 2251799813685247
- 51 , 4503599627370495 , 4503599627370495
- 52 , 9007199254740991 , 9007199254740991
- 53 , 18014398509481984 , 18014398509481983 <--- 【请注意这一行】
- 54 , 36028797018963968 , 36028797018963967
- 55 , 72057594037927936 , 72057594037927935
- 56 , 144115188075855872 , 144115188075855871
- 57 , 288230376151711744 , 288230376151711743
- 58 , 576460752303423488 , 576460752303423487
- 59 , 1152921504606846976 , 1152921504606846975
- 60 , 2305843009213693952 , 2305843009213693951
- 61 , 4611686018427387904 , 4611686018427387903
- 62 , 9223372036854775808 , 9223372036854775807
- 63 , 18446744073709551616 , 18446744073709551615
- 舍罕王应该给予达依尔18446744073709551616粒麦子!
- 如果每25000粒麦子为1kg,那么应该给737869762948382kg麦子!
- D:\[00.Exercise]\[C]>
复制代码
为了进一步证明是数据类型误差,本人编写了下面的代码:
- #include <stdio.h>
- int main(void)
- {
- double r1 ;
- unsigned long long r2 ;
- r1 = 9007199254740991.0 + 9007199254740992.0 ;
- r2 = 9007199254740991 + 9007199254740992 ;
- printf("%.0lf , %llu\n" , r1 , r2) ;
- }
复制代码
这个代码分别用双精度浮点数和无符号长整形计算 9007199254740991 + 9007199254740992,运算结果显示,双精度浮点数的计算结果与无符号长整形数的计算结果真的不同,很显然,双精度浮点数的计算结果是错误的,这也是楼主计算结果有误差的根本原因。
下面是编译、运行实况:
- D:\[00.Exercise]\[C]>g++ -o x x.c
- D:\[00.Exercise]\[C]>x
- 18014398509481984 , 18014398509481983
- D:\[00.Exercise]\[C]>
复制代码
所以,解决方案就是,对麦粒进行计数要使用 unsigned long long,避免使用 double,下面是参考代码:
- #include <stdio.h>
- int main(void)
- {
- unsigned long long result = 0LL ;
- double weight ;
- for(int i = 0 ; i < 64 ; i ++) result += 1LL << i ;
- weight = result / 25000 ;
- printf("舍罕王应该给予达依尔%llu粒麦子!\n" , result) ;
- printf("如果每25000粒麦子为1kg,那么应该给%.0lfkg麦子!\n",weight) ;
- return 0 ;
- }
复制代码
|
|