为什么pow(n,2)在n = 5时返回24,使用我的编译器和操作系统?
#include <stdio.h> #include <stdlib.h> #include <math.h> int main() { int n,i,ele; n=5; ele=pow(n,2); printf("%d",ele); return 0; }
输出是24
。
我在Code :: Blocks中使用GNU / GCC。
发生什么事?
我知道pow
函数返回一个double
,但25
适合一个inttypes,为什么这个代码打印24
而不是25
? 如果n=4; n=6; n=3; n=2;
n=4; n=6; n=3; n=2;
代码的作品,但与五不。
这里是可能发生的事情。 您应该能够通过查看您的编译器的pow
函数的实现来确认这一点:
假设你有正确的#include
(所有以前的答案和评论都是正确的 – 不要把#include
文件理所当然),标准pow
函数的原型是这样的:
double pow(double, double);
你打电话像这样:
pow(5,2);
pow
函数通过algorithm(可能使用对数),从而使用浮点函数和值来计算功率值。
pow
函数没有经过一个天真的“乘以x的总数n次”,因为它也必须使用分数指数来计算pow
,而且你不能用这种方式来计算分数的幂。
所以使用参数5和2计算pow
可能性很小,导致略微的舍入误差。 当你分配给一个int
,你截断了小数值,从而产生24。
如果你使用整数,你也可以编写你自己的“intpow”或类似的函数,只需要将这个值乘以必要的次数即可。 这样做的好处是:
-
你不会进入你可能会使用
pow
来精细舍入错误的情况。 -
你的
intpow
函数的运行速度可能比等效的pow
调用要快得多。
你想从一个函数的int结果为双打。
你应该使用
ele=(int)(0.5 + pow(n,2)); /* ^ ^ */ /* casting and rounding */
如果你没有#include <math.h>
那么编译器不知道pow()
的参数types,它们都是double
而不是int
– 所以你得到一个未定义的结果。 你得到24,我得到了16418。
当你使用variablespow时,其结果是double
。 分配给一个int
截断它。
所以你可以通过赋值pow
的double
或float
variables来避免这个错误。
所以基本上
它转换为exp(log(x) * y)
,这将产生一个与x^y
不完全相同的结果 – 只是一个近似的浮点值。 所以例如5^2
将变成24.9999996
或25.00002
浮点运算不准确。
虽然小的值可以被精确地加减,但pow()
函数通常是通过乘以对数来工作的,所以即使input都是精确的,结果也不是。 指定int
总是截断,所以如果不精确性是负的,你会得到24而不是25。
这个故事的寓意是在整数上使用整数运算,当实际参数被提升或截断时,对<math.h>
函数持怀疑<math.h>
。 不幸的是,GCC不会警告,除非你添加-Wfloat-conversion
(它不在-Wall -Wextra
,可能是因为有很多情况下,这种转换是预期和想要的)。
对于整数幂来说,使用乘法(如果是负数除法)而不是pow()
会更安全和更快速 – 保留后者在需要的地方! 不过要注意溢出的风险。