15

最近我写了一段代码:

const int sections = 10;

for(int t= 0; t < 5; t++){
   int i = pow(sections, 5- t -1);  
   cout << i << endl;
}

结果是错误的:

9999
1000
99
10
1

如果我只使用这段代码:

for(int t = 0; t < 5; t++){
    cout << pow(sections,5-t-1) << endl; 
}

问题不再出现:

10000
1000
100
10
1

有人给我解释吗?非常感谢你!

4

8 回答 8

12

由于浮点值的表示pow(10.0, 5)可能是 9999.9999999 或类似的东西。当您将其分配给被截断的整数时。

编辑:如果cout << pow(10.0, 5);输出看起来是四舍五入的,但我现在没有任何支持文件来证实这一点。

编辑 2:BoBTFish 的评论和这个问题证实了 when pow(10.0, 5)is used directly in coutthat is getting rounded.

于 2012-03-14T14:48:56.550 回答
2

这里

pow()函数:double pow (double base, double exponent);我们知道参数和返回值都是double类型。但是变量num,ires都是int上面代码中的类型,在转换intdoubledoubleint,可能会造成精度损失。例如(可能不严谨),浮点单元(FPU)计算pow(10, 4)=9999.99999999,然后int(9999.9999999)=9999在 C++ 中通过类型转换。

如何解决?

解决方案1

更改代码:

    常量 int 数 = 10;

    for(int i = 0; i < 5; ++i){
       双分辨率 = pow(num, i);
       cout << res << endl;
    }

解决方案2

替换类型中计算精度更高的浮点单元(FPU)double。例如,我们在 Windows CPU 中使用 SSE。在 Code::Block 13.12 中,我们可以执行以下步骤来达到目标​​:设置 -> 编译器设置 -> GNU GCC 编译 -> 其他选项,添加

-mfpmath=sse -msse3

图片如下:

添加 <code>-mfpmath=sse -msse3</code>
(来源:七牛网

于 2015-04-24T09:26:27.207 回答
2

当与分数指数一起使用时,pow(x,y) 通常被计算为exp(log(x)*y); 如果以无限精度进行评估,这样的公式在数学上是正确的,但实际上可能会导致舍入误差。正如其他人所指出的,将 9999.999999999 转换为整数时的值将产生 9999。一些语言和库在使用带有浮点指数的幂运算符时一直使用这种公式。其他人尝试识别指数何时为整数并在适当时使用迭代乘法。查找该pow函数的文档,它似乎应该在x为负且y没有小数部分时工作(当x为负且`y为偶数时,结果应该是pow(-x,y); 当y很奇怪,结果应该是-pow(-x,y)。似乎合乎逻辑的是,当y没有小数部分时,将遇到处理负值的麻烦的库x应该使用迭代乘法,但我不知道有任何规范规定它必须这样做。

在任何情况下,如果您试图将整数乘以幂,几乎可以肯定最好使用整数数学进行计算,或者,如果要提高的整数是常数或总是很小,只需使用查找表(以适合 64 位整数的任何幂将数字从 0 增加到 15 只需要 4,096 项表)。

于 2012-03-14T15:23:11.293 回答
1

发生的事情是 pow 函数返回一个 double 所以当你这样做时

int i = pow(sections, 5- t -1);  

十进制的 .99999 削减,你得到 9999。

而直接打印或将其与 10000 进行比较是没有问题的,因为它在某种意义上已经用完了。

于 2012-03-14T14:52:19.340 回答
1

如果您的第一个示例中的代码是您正在运行的确切代码,那么您有一个错误的库。不管你是接双打std::pow还是 C pow,即使选择了双打版本, 10 也完全可以表示为double. 因此,取幂完全可以表示为double。不应发生舍入或截断或类似的事情。

-ffast-math使用 g++ 4.5,即使使用and ,我也无法重现您的(奇怪)行为-O3

现在我怀疑正在发生的事情sections没有直接分配文字 10,而是在内部读取或计算它的值,使其值类似于9.9999999999999,当提高到四次方时会生成一个类似于 的数字9999.9999999。然后将其截断为显示的整数 9999。

根据您的需要,您可能希望在分配为 int 之前将源编号或最终编号四舍五入。例如:int i = pow(sections, 5- t -1) + 0.5; // Add 0.5 and truncate to round to nearest.

于 2012-03-14T16:30:45.330 回答
0

您将结果分配给一个 int。这会强制它,截断数字。

这应该可以正常工作:

for(int t= 0; t < 5; t++){
   double i = pow(sections, 5- t -1);  
   cout << i << endl;
}
于 2012-03-14T14:52:07.267 回答
0

全局命名空间中一定有一些损坏pow的函数。由于 ADL,然后std::pow在您的第二个示例中“自动”使用。

在您的第一个示例中,或者t实际上是一个浮点数,并且您遇到了舍入错误。

于 2012-03-14T14:47:20.697 回答
-1

发生的情况是您的答案实际上是 99.9999 而不是 100。这是因为pow是两倍。因此,您可以使用i = ceil(pow()).

您的代码应该是:

const int sections = 10;
for(int t= 0; t < 5; t++){
   int i = ceil(pow(sections, 5- t -1));  
   cout << i << endl;
}
于 2018-07-05T18:35:47.340 回答