pow()函数给出错误的答案

时间:2019-06-10 07:28:13

标签: c

我正在尝试将2、3位数字相乘。 我使用了2个循环(嵌套),并将num1的每个数字与num2相乘, 并使用pow()将每个结果移到适当的位置。 所以问题是pow(10,3)变成299而不是300。

我没有做太多尝试,但是使用printf来查找运行时实际发生的事情,这就是我所发现的。 移位后的tempR值应为
5,40,300,100,800,6000,1500,12000,90000
但作为
5,40,299,100,799,6000,1500,12000,89999

int main(void)
{
    int result; // final result 
    int  tempR; // temporary for each iteration
    char a[] = "345"; // number 1
    char b[] = "321"; // number 2
    for(int i = 2;i>= 0 ; i --)
    {
        for(int j = 2;j >= 0 ; j --)
        {
            int shift = abs(i-2 + j -2);
            printf("%d\n",shift);  //used to see the values of shift. 
                                      //and it is coming as expected
            tempR = (int)(b[i] - '0') * (int)(a[j] - '0');
            printf("%d \n",tempR);    // value to tempR is perfect
            tempR = tempR*pow(10,shift);        
            printf("%d \n",tempR);  // here the problem starts
            result += tempR;
        }
    }

    printf("%d",result);
}

4 个答案:

答案 0 :(得分:2)

尽管需要IEEE754(在台式机系统上无处不在)为某些运算符(例如加,乘,除和减)以及某些功能(例如sqrt)返回最佳的浮点值,但这确实不是适用于pow

pow(x, y)可以并且经常被实现为exp(y * ln (x))。希望您能看到,当pow与看似微不足道的整数参数一起使用时,结果可能会“消失”,并且结果被截断为int

那里有C实现比您拥有的pow更准确的实现,尤其是对于整数参数。如果需要这样的精度,则可以将工具集移至这样的实现。从受尊重的数学库中借用pow的实现也是一种选择,否则请自行承担。如果您了解我的意思,那么使用round也是一种技巧。

答案 1 :(得分:1)

切勿将浮点函数用于整数计算。您的战俘结果几乎永远不会是精确的。在这种情况下,它略低于300,而对整数的转换为299。

答案 2 :(得分:0)

pow函数用于双精度。双打使用有限精度。转换回整数,而不是四舍五入。

有限精度类似于将1/3表示为0.333333。如果您进行9 * 1/3并切成整数,则将得到2而不是3,因为9 * 1/3将给2.999997切成2。

这种四舍五入方法使您一筹莫展。您也可以在切成整数之前加0.5来取整,但我不建议这样做。

如果您希望得到确切的答案,请不要将整数传递给双精度数,也不能返回。

答案 3 :(得分:-1)

其他人提到pow不能产生准确的结果,如果将结果转换为整数,则很可能会损失精度。特别是因为如果将浮点类型分配给整数类型,结果将被截断而不是四舍五入。在此处阅读更多信息:Is floating math broken?

最方便的解决方案是编写您自己的pow的整数变体。看起来可能像这样:

int int_pow(int num, int e) 
{
    int ret = 1;
    while(e-- > 0) 
        ret *= num;

    return ret;
}

请注意,如果e为负或nume均为0时,它将不起作用。它也没有溢出保护。它只是说明了这个想法。

在您的特定情况下,您可以根据10写一个非常专业的变体:

unsigned int pow10(unsigned int e) 
{
    unsigned int ret = 1;
    while(e-- > 0) 
        ret *= 10;

    return ret;
}