C++ pow异常类型转换

C++ pow unusual type conversion

当我直接输出std::pow(10,2)时,我在做(long)(pow(10,2))时得到100得到99。有人可以解释一下吗?

cout<<pow(10,2)<<endl;
cout<<(long)(pow(10,2))<<endl;

main函数中的代码基本就是这样

编译器是 mingw32-g++.exe -std=c++11 使用 CodeBlocks Windows 8.1 如果有帮助

浮点数是近似值。偶尔你会得到一个可以精确表示的数字,但不要指望它。 100 应该是可表示的,但在本例中不是。有些东西注入了一个近似值并为大家毁了它。

当从浮点类型转换为整数时,整数不能包含任何小数值,所以它们被毫不客气地丢弃了。没有隐式四舍五入,分数被丢弃。 99.9 转换为 99. 99 在 99 之后加上一百万个 9。

所以在从浮点类型转换为整数之前,先将数字四舍五入,然后再转换。除非丢弃分数 你想要做的。

cout 和大多数输出​​例程,在打印前礼貌而安静地舍入浮点值,因此如果有一点近似值,用户不会为它烦恼。

这种不精确性也是您不应直接比较浮点值的原因。 X 可能不完全是 pi,但对于您的计算来说它可能足够接近,因此您使用 epsilon(一个软糖因子)进行比较,以判断您是否足够接近。

我觉得很有趣,并且花了很多时间试图解决这个问题,如果不是 using namespace std;,我什至不会看到这个问题。

(long)pow(10,2) 提供了预期结果 100。(long)std::pow(10,2) 没有。 powstd::pow 所采用的从 10,2 到 100 的路径存在一些差异,导致结果略有不同。通过将整个 std 命名空间拉入他们的文件,OP 不小心搬起石头砸了自己的脚。

这是为什么?

在文件的顶部我们有 using namespace std; 这意味着编译器在查找 pow 重载时不仅仅考虑 double pow(double, double),它还可以调用 std::powstd::pow 是一个漂亮的小模板,确保在使用 float 和 double 以外的数据类型调用时进行正确的转换,并且所有内容都是相同的类型。

(long)(pow(10,2))

不匹配

double pow(double, double)

以及它匹配

的模板实例化
double std::pow(int, int)

其中,据我所知可以解析为

return pow(double(10), double(2));

经过一些模板巫术。

有什么区别

pow(double(10), double(2))

pow(10, 2)

在对 pow 的调用中从 intdouble 的隐式转换,我不知道。打电话给语言律师,因为这很微妙。

如果这纯粹是一个舍入问题,那么

auto tempa = std::pow(10, 2);

应该容易受到攻击,因为 tempa 应该正是 std::pow returns

cout << tempa << endl; 
cout << (long) tempa << endl; 

输出应该是

100
99

我明白了

100
100

所以立即将 std::pow(10, 2) 的 return 转换为 long 不同于存储然后转换。诡异的。 auto tempa 不完全是 std::pow return 的意思,或者还有其他事情对我来说太深了。

这些是 std::pow 重载:

float       pow( float base, float exp );

double      pow( double base, double exp );

long double pow( long double base, long double exp );

float       pow( float base, int iexp );//(until C++11)

double      pow( double base, int iexp );//(until C++11)

long double pow( long double base, int iexp ); //(until C++11)

Promoted    pow( Arithmetic1 base, Arithmetic2 exp ); //(since C++11)

但是你的奇怪行为是 MINGW 对双重存储的怪异以及 windows 运行-time 不喜欢它的方式。我假设 windows 看到的是 99.9999 之类的东西,当它被转换为整数类型时,它会发言。

int a = 3/2; // a is = 1

mingw uses the Microsoft C run-time libraries and their implementation of printf does not support the 'long double' type. As a work-around, you could cast to 'double' and pass that to printf instead. Therefore, you need double double:

On the x86 architecture, most C compilers implement long double as the 80-bit extended precision type supported by x86 hardware (sometimes stored as 12 or 16 bytes to maintain data structure alignment), as specified in the C99 / C11 standards (IEC 60559 floating-point arithmetic (Annex F)). An exception is Microsoft Visual C++ for x86, which makes long double a synonym for double.[2] The Intel C++ compiler on Microsoft Windows supports extended precision, but requires the /Qlong‑double switch for long double to correspond to the hardware's extended precision format.[3]