【问题标题】:Wrong answer while calculating the nth root of number in cpp计算cpp中数字的第n个根时答案错误
【发布时间】:2014-06-08 10:47:47
【问题描述】:

我正在使用标准库方法 pow() 计算正整数的第 n 个根。这是我程序中的 sn-p:

double x,y;
x=pow(64,(1.0/3));
int z;
printf("x=%lf\n",x);
z=(int)x;
printf("%d\n",z);

但是在找到 64 的立方根时。X 打印为 4.000000 而 z 打印为 3。为什么会这样?

有人可以提出更好的算法吗?

【问题讨论】:

  • 类型很重要,确保你写的是64.0 (double) 而不是64 (integer),3 也是如此。另外,你有没有包括数学(我假设你有,但只是检查)。您的编译器是否向您提供任何警告?
  • 对于您的特定问题,我怀疑您的输出在 printf 中被四舍五入,但您的演员是地板。请改用int z = round(x);。
  • 可能 x 类似于 3.99999999999737 或接近 4 并被 printf 四舍五入,而转换为 int 只会截断它。
  • 这很可能是由于浮点精度。
  • z=round(x) 将给出 64 @ilent2 的第四根的错误答案

标签: c++ algorithm nth-root


【解决方案1】:

如果你在x上打印更多的数字,你会发现问题出在哪里(我随机选择了30个):

double x ;
x = pow(64, 1.0/3);
printf("x=%.30lf\n",x);

输出:

x=3.99999999...999600000000 

很明显,如果您将x 转换为int,它将变成3。

没有“完美”的解决方案。如果您只处理整数,您可以创建自己的根函数,但如果您希望能够使用浮点数,则需要处理由于浮点表示而导致的准确性问题。

也许有一些 C 库可以帮助您解决这类问题。

【讨论】:

【解决方案2】:

int 覆盖向下舍入。由于floating point operations are inaccurate,计算可能是3.999999...

使用round(x) 得到正确的结果。

由于您总是希望向下取整,您可以同时使用floor 和(int)——但是一旦浮点计算的不稳定性导致略微值较小 - 对于double 大小的计算,大约为 10-15。使用一个很小的 ​​epsilon 值来抵消它。

请注意,低于 的 epsilon“软糖”值与原始数字中的有效位数有关。对于较大的数字,您需要较小的 epsilon。

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

int main (void)
{
    double x;
    int z;

    x=pow(64,(1.0/3));
    printf("x=%lf\n",x);
    printf("x=%.30lf\n",x);

    z=(int)x;
    printf("%d\n",z);

    z=(int)(x+0.000000000000005);
    printf("%d\n",z);

    x=pow(64,(1.0/4));
    printf("x=%lf\n",x);
    printf("x=%.30lf\n",x);

    z=(int)x;
    printf("%d\n",z);

    z=(int)(x+0.0000000000000005);
    printf("%d\n",z);

    return 1;
}

1/3 和 1/4 次方的结果

x=4.000000
x=3.999999999999999555910790149937
3
4
x=2.828427
x=2.828427124746190290949243717478
2
2

【讨论】:

  • z=round(x) 将给出 64 @Jongware 的第 4 个根的错误答案
【解决方案3】:

正如@jongware 所说,int 覆盖向下舍入,浮点运算可能不准确。

虽然你总是可以这样做来规避这个问题

def invpow ( n , i):
    x = pow (n ,(1/i))
    if((int)pow((x+1) , i) <= n):
        x += 1;
    print(x)

或者您可以使用here 和here 描述的Newton - Raphson 方法编写自己的求幂方法

你也可以使用二分搜索,如果你对范围有正确的猜测,它会非常快 即(变量高和低)

def invpow( x, n, low, high){
    if(n==1)
        return x;
    mid=(low+high)/2;

    while(low<high){
        mid=(low+high)/2;

        raised=pw(mid,n);

        if(raised==x)
            break;

        if(raised>x)
            high=mid;
        else
            low=mid;

        if(low+1==high){
            mid=low;
            break;
            }

    }
    return mid;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-30
    • 1970-01-01
    • 1970-01-01
    • 2017-04-29
    相关资源
    最近更新 更多