|
发表于 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 函数
好了,没了,^_^ |
|