递归解决小球落地问题

为什么第二个%g输出有误差,没有在小数位上四舍五入,第一个递归是算法上出了问题,还是每一次计算都有误差导致的呢?

img

img

img

img

img

该回答通过自己思路及引用到GPTᴼᴾᴱᴺᴬᴵ搜索,得到内容具体如下:

在你的代码中,存在以下问题:

  1. 输出格式问题:你使用了"%lf"来格式化输出double类型的值,但是应该使用"%g"来输出,与题目要求一致。

  2. 误差问题:第二个输出结果可能存在误差,这是由于浮点数的表示和计算精度限制所导致的。浮点数在计算机中以二进制表示,有些十进制小数无法精确表示,因而可能存在舍入误差。这是计算机浮点数运算的普遍问题。

针对这些问题,你需要进行以下修改:

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

double sum(int x, int y);

int main() {
    int n;
    double answer1, answer2;
    scanf("%d", &n);
    answer1 = n / (1024.0);
    printf("%g\n", sum(n, 10));
    answer2 = n * pow(0.5, 10);
    printf("%g", answer2);
    return 0;
}

double sum(int x, int y) {
    double c;
    if (y == 1)
        c = (double)x;
    else
        c = 2 * x * pow(0.5, y) + sum(x, y - 1);
    return c;
}

在修改后的代码中,我进行了以下更改:

  1. 将输出格式"%lf"改为"%g",以符合题目要求。

  2. 添加了对第10次弹跳高度的计算(answer2),并使用"%g"格式化输出。

请注意,浮点数计算存在舍入误差是正常的,而且在输出时不需要对精度特殊控制。使用"%g"格式化输出即可满足要求。


如果以上回答对您有所帮助,点击一下采纳该答案~谢谢

在第一个递归中,舍入误差可能会逐渐积累,导致结果不准确。这是因为每次乘以0.9时,浮点数的小数部分可能会变得更小,导致损失的精度更多。这是浮点数计算的常见问题,通常被称为“浮点数陷阱”。因为C语言的printf格式化符号%g会根据浮点数的值和大小来选择科学计数法或小数形式,以显示较简洁的表示。这可能会导致四舍五入或科学计数法表示,具体取决于浮点数的值。
使用适当的格式化选项(例如,%.7f表示保留两位小数)来控制输出的小数位数。

结合GPT给出回答如下请题主参考
首先,让我们看看递归解决小球落地问题的伪代码:

function calculateHeight(initialHeight, numberOfBounces):
    if numberOfBounces == 0:
        return initialHeight
    else:
        reboundHeight = initialHeight * 0.6
        return calculateHeight(reboundHeight, numberOfBounces - 1)

这个函数以初始高度和弹跳次数作为输入,并返回球在弹跳次数后的高度。代码中的递归实现的思路是每次球弹跳时高度减少了原来的40%(即减少了原来高度的60%),直到达到指定的弹跳次数为止。

现在,关于你的问题,第一个递归的计算是准确的。原因是因为在每一次递归中,我们将小球反弹的高度乘以0.6,这个过程是精确的。因此,第一个递归的计算是正确的,没有出现误差。

然而,第二个% g输出的误差是因为在这个语言中,浮点数的计算可能会产生精度误差。这种误差的产生可能是由于舍入错误或过多的计算等因素导致的。因此,为了使输出更加准确,可以使用一些近似方法,如四舍五入等。这里提供一种使用round函数进行四舍五入的方法来解决这个问题:

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

int main()
{
    int numberOfBounces = 10;
    double initialHeight = 100.0;
    double finalHeight = initialHeight * pow(0.6, numberOfBounces);

    printf("After %d bounces the height of the ball is %.2f meters\n", numberOfBounces, finalHeight);
    printf("After %d bounces the height of the ball is approximately %.2f meters\n", numberOfBounces, round(finalHeight * 100) / 100.0);

    return 0;
}

在示例代码中,我们使用round函数将最终高度的小数部分四舍五入到两位小数。这样,我们就可以得到更加准确的输出。

总之,递归求解小球落地问题的算法是可行的,但在处理浮点数数据时精度误差是一种常见问题。为了避免这种误差,我们可以使用方法来近似处理数据,以获得更加准确的结果。

你代码中的第一个递归没有问题,问题出在你对结果的处理上。

首先,第一个%g输出的正确,是因为你将n转换成double类型并除以1024,所以结果是一个小数。

第二个%g输出有误差,是因为你直接使用了递归函数sum返回的结果。这个结果可能会有误差,因为每次计算过程中都有浮点数的运算引起的误差。

解决方法是在递归函数中对结果进行四舍五入,可以使用round函数来实现四舍五入。

修改代码如下:

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

double sum(int x,int y);

int main(){
    int n;
    scanf("%d",&n);
    double answer1 = (double)n / (1024*1.0);
    double answer2 = round(sum(n,10) * 1000000) / 1000000; // 四舍五入保留小数点后6位
    printf("%g\n%g", answer2,answer1);
    return 0;
}

double sum(int x,int y){
    if(y==1) {
        return (double)x;
    }else{
        return 2 * x * pow(0.5,y) + sum(x, y - 1);
    }
}

这样就能得到正确的结果了。注意,我在第二个%g输出的结果前使用了四舍五入,保留了小数点后6位。你可以根据需要调整这个保留的位数。

img


#include <stdio.h>

int main() {
    int h;
    scanf("%d", &h);//20
    double distance = h; // 初始高度为 h
    double height = h; // 初始高度为 h
    for (int i = 1; i <= 10; i++) {
        height /= 2; // 每次反弹后的高度减半
        if (i == 10)
            break;
        distance += height * 2; // 每次落地前的距离增加两倍的高度
    }
    printf("%.4f\n", distance);
    printf("%.7f\n", height);
    return 0;
}

引用chatgpt内容作答:
运行结果:

img

以下是使用C语言编写的程序,用于计算球在第10次落地时经过的总距离和第10次弹跳的高度:

#include <stdio.h>

int main() {
    int h;          // 初始高度,单位米
    

    printf("请输入初始高度(米):");
    scanf("%d", &h);

    double totalDistance = h; // 累计距离,初始为0
    double currentHeight = h;       // 当前高度

    // 计算第10次落地时的总距离和第10次弹跳的高度
    for (int i = 1; i <= 10; i++) {
        currentHeight /= 2; // 每次反弹后的高度减半
        if (i == 10)
            break;
        totalDistance += currentHeight * 2; // 每次落地前的距离增加两倍的高度
    }

    // 输出结果
    printf("第10次落地时,共经过的米数:%.4f\n", totalDistance);
    printf("第10次弹跳的高度:%.7f\n", currentHeight);

    return 0;
}

在此程序中,我们使用一个循环模拟球的落地和弹跳过程,计算出第10次落地时的总距离和第10次弹跳的高度,并以双精度浮点数的格式输出结果。

【以下回答由 GPT 生成】

问题根源在于计算机浮点数的表示方式,导致了小数位的误差。使用浮点数来表示小数时,由于精度有限,可能会产生舍入误差。这种误差在多次递归计算中会不断累积,导致输出结果存在小数位的误差。

解决方案是可以使用一个合适的函数对输出结果进行四舍五入。在C语言中,可以使用round函数来实现四舍五入,将浮点数结果转换为整数再进行打印。同时,可以在递归过程中限制小数位的精度,避免误差的累积。

以下是修改后的代码:

#include <stdio.h>
#include <math.h> // 包含round函数的头文件

double calculateHeight(double initialHeight, int numBounces);

int main() {
    double initialHeight = 10.0;
    int numBounces = 5;

    double finalHeight = calculateHeight(initialHeight, numBounces);
    printf("Final height: %g\n", round(finalHeight * 10000) / 10000); // 使用round函数四舍五入,并限制小数位精度为4位

    return 0;
}

double calculateHeight(double initialHeight, int numBounces) {
    if (numBounces == 0) {
        return initialHeight;
    } else {
        double distance = initialHeight * 0.6;
        double remainingHeight = initialHeight - distance;
        return calculateHeight(remainingHeight, numBounces - 1);
    }
}

运行修改后的代码,输出结果应该没有小数位的误差了。

注意:这里使用了一个简单的粗略四舍五入方法,可能不够准确,仅作为示例。实际应用中,要根据具体需求使用更加精确的方法进行四舍五入,例如使用字符串流或者其他数值处理库。



【相关推荐】



如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^

该回答通过自己思路及引用 文心一言 搜索,具体回答如下:


#include <stdio.h>
#include <math.h>
 
double sum(int x, int y);
 
int main() {
    int n;
    double answer1, answer2;
    scanf("%d", &n);
    answer1 = n / (1024.0);
    printf("%g\n", sum(n, 10));
    answer2 = n * pow(0.5, 10);
    printf("%g", answer2);
    return 0;
}
 
double sum(int x, int y) {
    double c;
    if (y == 1)
        c = (double)x;
    else
        c = 2 * x * pow(0.5, y) + sum(x, y - 1);
    return c;
}

误差会逐渐增大吧

C语言解决小球自由落体求高度问题

    #include<stdio.h>
    
    float path=100; //小球经历的总路径,初始为100
    
    /*
    小球的路经path=第1次下落的高度100+第1次反弹的高度50+第2次下落的高度50+......
    high是小球第num-1次反弹的高度,也是小球第num次下落的的高度
    high=50,path=100,num=2
    */
    float algo(float high,int num){ 
        if(num==10)           //递归结束条件
            return high/2;    //第10次反弹的高度
        else{
            path+=2*high;     //path+=反弹的高度+下落的高度
            return algo(high/2,num+1); //第num+1次小球的反弹的高度是原来的一半
        }
    }
    
    void main(){
        int num=2;
        float high=100;
        high=high/2;
        high=algo(high,num); //调用函数前,小球第1次下落已计算在内,也就是说,从第1次反弹开始算起
        printf("小球第10次落地时共经历了%.5f米,小球第10次反弹的高度为%.5f米\n",path,high);
    }


这个是学c语言都会遇到的问题,网上思路已经很多了,自己格式化一下格式就行了!
下面是使用递归实现小球落地问题的C语言代码:

#include <stdio.h>

double fall_distance(int n);

int main()
{
    int n;
    double distance;

    printf("请输入落地次数:");
    scanf("%d", &n);

    distance = fall_distance(n);
    printf("第%d次落地,共经过%f米。\n", n, distance);

    return 0;
}

double fall_distance(int n)
{
    double distance;

    if(n == 1)
    {
        distance = 100;  //起始高度100米
    }
    else
    {
        distance = fall_distance(n-1) / 2;
    }

    return distance;
}

该程序通过递归方式计算小球落地经过的距离。在每一次落地时,小球都会弹起一半的高度,因此第n次落地时,小球经过的距离就是起始高度100米除以2^(n-1)。

img


本身在内存中的值是对的,只是C语言种%g的打印只会精确到小数点后6位,不会四舍五入就是截断。
格式说明符号g(G)在c标准中的说明是
g double Signed value printed in f or e format, whichever is more compact for the given value and precision. The e format is used only when the exponent of the value is less than –bai4 or greater than or equal to the precision argument. Trailing zeros are truncated, and the decimal point appears only if one or more digits follow it.
翻译过来就是
1.把输出的值按照%e或者%f类型中输出长度较小的方式输出,仅当数值的指数小于-4或大于等于精度参数(默认值为6)时按%e(E)输出(否则按%f输出)。
2.(在选择好输出格式之后)尾部的零会被缩减。
3.(在选择好输出格式之后且0被缩减后)当小数点后面有一个或多个数字时才显示小数点。

该回答引用ChatGPT,希望对题主有所帮助,如有帮助,还望采纳。


有误差的原因是浮点数在计算机内部使用二进制表示时,无法精确地表示一些十进制小数,会产生舍入误差。在第一个递归函数中,由于每次调用都会对浮点数进行一系列的运算,多次累积的误差会导致最终结果的不准确。而在第二个%g输出中,由于使用了printf函数,其默认四舍五入到小数点后6位,但实际上原始的浮点数可能已经有了误差,因此输出的结果也有误差。

有误差是数据精度的问题,在多次计算上出现了精度的损失。