YJ_Li 发表于 2023-9-9 09:24:55

关于变量类型的问题

问题为舍罕王的失算,就是棋盘格子放米粒的故事那个
我的代码为:
#include <stdio.h>
#include <math.h>
int main()
{
    unsigned long long sum = 0;
    unsigned long long kg = 0;
    unsigned long long temp;
    int i;
    for (i=0;i<64;i++)
    {
      sum = sum + pow(2,i);   //有疑问的地方在这里

    }

    printf("结果是:%llu\n",sum);
    kg = sum/25000;
    printf("kg=%llu\n",kg);
   
    return 0;
}

输出结果:
结果是:0
kg=0

疑问:题目答案要求将pow(2,i)运算的结果先存放到定义的(unsigned long long)temp函数里,我猜想大概原因为数值太大溢出的问题,但前期i较小的时候数值应该不会溢出呀,为什么输出结果为0呢?
请大佬不吝赐教,感谢!

学习编程中的Ben 发表于 2023-9-9 09:25:10

问题分析:
你的代码存在一个问题,即 pow(2, i) 的结果并没有正确地存放到 temp 变量中,导致最终的计算结果为0。这个问题并不是因为数值溢出导致的,而是因为类型转换的问题。

解决方法:
要修正这个问题,你可以做以下修改:

1. 将 temp 的类型修改为 unsigned long long,以确保足够的位数来存储计算结果。

2. 在循环中,将 pow(2,i) 的结果直接赋值给 temp 变量。

3. 在计算 sum 的时候,将 temp 累加到 sum 中。

下面是按照以上修改建议进行改进后的代码:

#include <stdio.h>
#include <math.h>

int main()
{
    unsigned long long sum = 0;
    unsigned long long kg = 0;
    unsigned long long temp;
    int i;

    for (i = 0; i < 64; i++)
    {
      temp = (unsigned long long) pow(2, i); // 将计算结果赋值给temp
      sum = sum + temp;                      // 使用temp累加到sum中
    }

    printf("结果是:%llu\n", sum);
    kg = sum / 25000;
    printf("kg=%llu\n", kg);

    return 0;
}


现在再次编译和运行代码,应该会得到正确的输出结果。

注意事项:
虽然对于小的 i 值,pow(2, i) 的结果不会溢出,但是在较大的 i 值时,计算结果可能会超出 unsigned long long 类型的表示范围。所以,为了保证结果的正确性,建议在计算 sum 之前将计算结果直接赋值给 sum,而不是先存放到 temp 变量中。这样可以避免溢出问题。

如果回答对你有帮助,请给我一个最佳答案!{:10_254:}{:10_254:}{:10_254:}

陶远航 发表于 2023-9-9 09:25:11

您的代码中存在一个问题。在循环中,您使用了pow(2, i)来计算每个格子上的米粒数量,并将结果累加到sum变量上。然而,pow()函数返回的是一个浮点数,而不是一个整数。这意味着在计算过程中会存在精度丢失,从而导致结果不准确。

为了解决这个问题,您可以将pow()函数替换为左移运算符1 << i。左移运算符将二进制数向左移动指定的位数,等同于乘以2的指数次幂。这样可以避免浮点数计算和精度丢失的问题。

以下是修改后的代码:

#include <stdio.h>

int main() {
    unsigned long long sum = 0;
    unsigned long long kg = 0;
    unsigned long long temp;
    int i;

    for (i = 0; i < 64; i++) {
      temp = 1ULL << i;// 使用左移运算符进行计算
      sum += temp;
    }

    printf("结果是:%llu\n", sum);
    kg = sum / 25000;
    printf("kg=%llu\n", kg);

    return 0;
}


这样修改后,您应该能够得到正确的结果。祝您编程顺利!如果您还有其他问题,请随时提问。
如果问题已经解决,请设置最佳答案

Mike_python小 发表于 2023-9-9 09:25:12

问题解析:
根据你提供的代码和输出结果,可以推测出问题出在循环中的 sum = sum + pow(2,i); 这一行代码。你猜测到了一部分,确实是由于数值溢出导致的问题。

解决方法:
问题出在使用 pow() 函数计算 2 的幂的时候。pow() 函数返回的是一个浮点数,而你想要的是一个整数。当你在循环中进行大量的浮点数运算时,可能会导致精度丢失和计算错误。
为了解决这个问题,你可以尝试以下两种修改方案:

方案一:使用移位操作代替 pow() 函数
因为你要计算的是 2 的幂,你可以使用左移操作符 << 来代替 pow() 函数。左移操作符将二进制数向左移动指定的位数,相当于将该数乘以 2 的指定次幂。

修改后的代码如下:

#include <stdio.h>

int main() {
    unsigned long long sum = 0;
    unsigned long long kg = 0;
    int i;
   
    for (i = 0; i < 64; i++) {
      sum += 1ULL << i;
    }
   
    printf("结果是:%llu\n", sum);
    kg = sum / 25000;
    printf("kg=%llu\n", kg);
   
    return 0;
}


方案二:使用无符号整数类型
虽然使用移位操作符能够解决问题,但如果你仍然希望使用 pow() 函数,你可以将数据类型更改为无符号整数类型,以便容纳更大的数值。

修改后的代码如下:

#include <stdio.h>
#include <math.h>

int main() {
    unsigned long long sum = 0;
    unsigned long long kg = 0;
    int i;
   
    for (i = 0; i < 64; i++) {
      sum += (unsigned long long)pow(2, i);
    }
   
    printf("结果是:%llu\n", sum);
    kg = sum / 25000;
    printf("kg=%llu\n", kg);
   
    return 0;
}


通过以上两种修改方案之一,你应该能够正确计算并得到期望的结果。

希望能够帮助到你!如果还有其他问题,请随时提问。

球一个最佳答案谢谢啦!这对我非常重要!{:10_254:}{:10_254:}{:10_254:}

YJ_Li 发表于 2023-9-9 10:26:43

Mike_python小 发表于 2023-9-9 09:25
问题解析:
根据你提供的代码和输出结果,可以推测出问题出在循环中的 sum = sum + pow(2,i); 这一行代码。 ...

您好!我还是不太理解这其中的本质问题。
我目前的理解是pow(2,i)在计算i=63时溢出了,所以返回结果为0?但如果这样的话输出结果也应该有2^62之前的和
我尝试将for循环降低到<63,此时输出结果无误。
您说是pow()返回的是浮点数类型,多次计算会产生误差,但产生误差不应导致输出结果为0吧
目前问题:不清楚为什么输出结果为0
感谢回复!

Mike_python小 发表于 2023-9-9 10:39:43

YJ_Li 发表于 2023-9-9 07:26
您好!我还是不太理解这其中的本质问题。
我目前的理解是pow(2,i)在计算i=63时溢出了,所以返回结果 ...

您的理解基本正确,`pow(2, i)` 在计算 i = 63 时会溢出。因为 `pow()` 函数返回的是浮点数类型,而 `unsigned long long` 是整数类型,所以在进行类型转换时会导致数据截断,从而产生结果为 0。

产生这个问题的原因是,对于大整数的幂运算,使用浮点数类型往往无法准确表示,因为浮点数有一定的精度限制。在计算过程中,每次进行乘法和除法运算都有可能引入舍入误差,从而累积导致结果错误。

解决这个问题的方法是使用其他方式计算 2 的幂,例如使用位运算 `1 << i` 来代替 `pow(2, i)`。修改后的代码如下:


#include <stdio.h>
#include <math.h>

int main() {
    unsigned long long sum = 0;
    unsigned long long kg = 0;
    int i;

    for (i = 0; i < 64; i++) {
      sum += (unsigned long long)(1 << i);
    }

    printf("结果是:%llu\n", sum);

    kg = sum / 25000;
    printf("kg=%llu\n", kg);

    return 0;
}

通过使用位运算,可以避免精度问题,输出结果将正常计算。运行以上修改后的代码,您将得到正确的输出结果。
页: [1]
查看完整版本: 关于变量类型的问题