C++ pow异常类型转换

问题描述 投票:0回答:2

enter image description here

当我直接输出

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

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

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

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

c++ floating-point type-conversion precision pow
2个回答
4
投票

浮点数是近似值。有时您会得到一个可以精确表示的数字,但不要指望它。 100 应该可以表示,但在本例中却不能。有些东西注入了近似值并毁掉了每个人。

从浮点类型转换为整数时,整数不能容纳任何小数值,因此它们会被毫不客气地丢弃。没有隐式舍入,分数被丢弃。 99.9 转换为 99. 99,在 99 后带有一百万个 9。

因此,在从浮点类型转换为整数之前,先对数字进行四舍五入,然后进行转换。除非丢弃分数你想要做的。

cout
,以及大多数输出例程,在打印之前礼貌地、默默地舍入浮点值,因此,如果有一点近似值,用户不会介意。

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

我觉得有趣的是,如果没有

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

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

这是为什么?

在文件顶部我们有

using namespace std;
,这意味着编译器在查找
double pow(double, double)
重载时不仅仅考虑
pow
,它还可以调用
std::pow
并且
std::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)

在调用

int
时从
double
pow
的隐含转换是,我不知道。打电话给语言律师,因为这是一些微妙的事情。

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

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

应该容易受到攻击,因为 tempa 应该正是

std::pow
返回的值

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

输出应该是

100
99

我明白了

100
100

因此立即将

std::pow(10, 2)
的返回值转换为
long
与存储然后转换不同。诡异的。
auto tempa
并不完全是
std::pow
返回的内容,或者还有其他事情发生,对我来说太深了。


0
投票

这些是 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 运行时不喜欢它。我假设 Windows 看到的是类似 99.9999 的东西,当它被转换为整数类型时,它就会占据地板。

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

mingw 使用 Microsoft C 运行时库,其 printf 的实现不支持“long double”类型。作为解决方法,您可以转换为“double”并将其传递给 printf。 因此,你需要 double double:

在 x86 架构上,大多数 C 编译器将 long double 实现为 x86 硬件支持的 80 位扩展精度类型(有时存储为 12 或 16 字节以保持数据结构对齐),如 C99 / C11 标准 (IEC 60559浮点运算(附录 F))。 Microsoft Visual C++ for x86 是一个例外,它使 long double 成为 double 的同义词。[2] Microsoft Windows 上的英特尔 C++ 编译器支持扩展精度,但需要使用 /Qlong‑double 开关来实现 long double,以对应于硬件的扩展精度格式。[3]

© www.soinside.com 2019 - 2024. All rights reserved.