| 
 | 
 
 
发表于 2021-11-29 23:13:21
|
显示全部楼层
 
 
 
问题在于一个是进行整数运算,一个是浮点数运算 
而浮点数运算是有精度损失的,进行运算的数越大,损失就越大 
 
看下面的代码 
- #include <stdio.h>
 
 - #include <math.h>
 
  
- int main(void) {
 
 -     int i;
 
 -     unsigned long long int mi = 0;
 
 -     unsigned long long int sum = 0;
 
 -     unsigned long long int x = 0;
 
 -     for(i = 0; i <= 64; i++) {
 
 -         mi = pow(2, i); sum += mi;
 
 -         x += pow(2,i);
 
 -         if(i == 51 || i == 52 || i == 53 || i == 54) {
 
 -             printf("%d: %llu\n", i, sum);
 
 -             printf("%d: %llu\n", i, x);
 
 -         }
 
 -     }
 
 -     printf("舍罕王应该给予达依尔%llu粒麦子!!!\n", x);
 
 -     printf("舍罕王应该给予达依尔%llu粒麦子!!!\n", sum);
 
 -     return 0;
 
 - }
 
 
  复制代码 
- $ ./main
 
 - 51: 4503599627370495
 
 - 51: 4503599627370495
 
 - 52: 9007199254740991
 
 - 52: 9007199254740991
 
 - 53: 18014398509481983
 
 - 53: 18014398509481984
 
 - 54: 36028797018963967
 
 - 54: 36028797018963968
 
 - 舍罕王应该给予达依尔0粒麦子!!!
 
 - 舍罕王应该给予达依尔18446744073709551615粒麦子!!!
 
 - $ 
 
  复制代码 
 
当 i 等于 52 的时候还是正常的,但是到 i 等于 53 的时候就开始出现问题了 
一个的结果是 
18014398509481983 
另一个是 
18014398509481984 
 
 
那最后为什么有一个输出的是 0 ? 
看下面的代码 
 
在看下面的代码之前,先看一下你的代码 
-         int i;
 
 -         unsigned long long int mi = 0;
 
 -         unsigned long long int sum = 0;
 
 -         for(i=0;i<=64;i++)
 
 -         {
 
 -                 mi = pow(2,i);
 
 -                 sum += mi;
 
 -                 
 
 - //                mi += pow(2,i);
 
 -         }
 
 - //        printf("舍罕王应该给予达依尔%llu粒麦子!!!",mi);
 
 -         printf("舍罕王应该给予达依尔%llu粒麦子!!!",sum);
 
  复制代码 
 
再看标准答案 
- #include <stdio.h>
 
 - #include <math.h>
 
  
- int main()
 
 - {
 
 -         unsigned long long sum = 0;
 
 -         unsigned long long temp;
 
 -         unsigned long long weight;
 
 -         int i;
 
  
-         for (i=0; i < 64; i++)
 
 -         {
 
 -                 temp = pow(2, i);
 
 -                 sum = sum + temp;
 
 -         }
 
  
-         weight = sum / 25000;
 
  
-         printf("舍罕王应该给予达依尔%llu粒麦子!\n", sum);
 
 -         printf("如果每25000粒麦子为1kg,那么应该给%llu公斤麦子!\n", weight);
 
  
-         return 0;
 
 - }
 
  复制代码 
 
看出哪里不一样了吗? 
 
- for (i=0; i < 64; i++)
 
 - for(i=0;i<=64;i++)
 
  复制代码 
 
看出来了吗? 
 
所以,代码改成这样 
- #include <stdio.h>
 
 - #include <math.h>
 
  
- int main(void) {
 
 -     int i;
 
 -     unsigned long long int mi = 0;
 
 -     unsigned long long int sum = 0;
 
 -     unsigned long long int x = 0;
 
 -     //for(i = 0; i <= 64; i++) {
 
 -     for(i = 0; i < 64; i++) {
 
 -         mi = pow(2, i); sum += mi;
 
 -         x += pow(2,i);
 
 -         if(i == 62) {
 
 -             printf("%d: %llu\n", i, x);
 
 -             unsigned long long int temp = pow(2, 63);
 
 -             printf("temp: %llu\n", temp);
 
 -             x += temp;
 
 -             printf("x: %llu\n", x);
 
 -         }
 
 -     }
 
 -     printf("舍罕王应该给予达依尔%llu粒麦子!!!\n", x);
 
 -     printf("舍罕王应该给予达依尔%llu粒麦子!!!\n", sum);
 
 -     return 0;
 
 - }
 
 
  复制代码- $ ./main
 
 - 62: 9223372036854775808
 
 - temp: 9223372036854775808
 
 - x: 0
 
 - 舍罕王应该给予达依尔9223372036854775808粒麦子!!!
 
 - 舍罕王应该给予达依尔18446744073709551615粒麦子!!!
 
 - $ 
 
  复制代码 
 
在第 62 次的时候 
x 的值是 9223372036854775808 
temp 是 9223372036854775808 
 
x + temp = 9223372036854775808 + 9223372036854775808 
= 18446744073709551616 
18446744073709551616 这个数字太大了,unsigned long long int 也放不下 
这个数字十进制形式不太明显,换成十六进制形式 
18446744073709551616 = 0x10000000000000000 
对于 unsigned long long int,正好最前面的 1 放不下,后面全是 0,所以最后输出的是 0 
 
 
那为什么 i 等于 64 的时候 sum 的值不是 0 ?看起来是个正确的值? 
就是这个代码 
 
- #include <stdio.h>
 
 - #include <math.h>
 
  
- int main(void) {
 
 -     int i;
 
 -     unsigned long long int mi = 0;
 
 -     unsigned long long int sum = 0;
 
 -     for(i = 0; i <= 64; i++) {
 
 -         mi = pow(2, i); sum += mi;
 
 -         if(i == 62 || i == 63 || i == 64) {
 
 -             printf("%d: %llu\n", i, sum);
 
 -         }
 
 -     }
 
 -     printf("舍罕王应该给予达依尔%llu粒麦子!!!\n", sum);
 
 -     return 0;
 
 - }
 
 
  复制代码 
- $ ./main
 
 - 62: 9223372036854775807
 
 - 63: 18446744073709551615
 
 - 64: 18446744073709551615
 
 - 舍罕王应该给予达依尔18446744073709551615粒麦子!!!
 
 - $ 
 
  复制代码 
 
现在的问题变成了 
为什么 i 等于 63 和 i 等于 64 的时候,sum 的值是一样的? 
 
- #include <stdio.h>
 
 - #include <math.h>
 
  
- int main(void) {
 
 -     int i = 64;
 
 -     unsigned long long int x = pow(2, i);
 
 -     printf("%llu\n", x);
 
 -     return 0;
 
 - }
 
 
  复制代码 
 
 
18446744073709551615 + 0 = 18446744073709551615 
所以一样 
 
为什么不把代码写成下面这样? 
- #include <stdio.h>
 
 - #include <math.h>
 
  
- int main(void) {
 
 -     unsigned long long int x = pow(2, 64);
 
 -     printf("%llu\n", x);
 
 -     return 0;
 
 - }
 
 
  复制代码 
- $ ./main
 
 - 18446744073709551615
 
  复制代码 
 
为什么输出这个? 
这我就不知道了,我感觉是编译器认为数字太大超范围了,就给 x 设置了一个 x 能表示的最大的数 
你需要知道的是 pow(2, 64),是编译器直接算出来的,不是调用 math.h 中的 pow 函数 
 
好了,没了,^_^ |   
 
 
 
 |