【发布时间】:2011-05-13 11:47:15
【问题描述】:
例如,这些变量:
result (double)
a (double)
b (float)
c (float)
d (double)
一个简单的计算:
result = a * (b + c) * d
类型转换的方式和时间以及如何确定每次计算的执行精度?
【问题讨论】:
标签: c++ types floating-point type-conversion precision
例如,这些变量:
result (double)
a (double)
b (float)
c (float)
d (double)
一个简单的计算:
result = a * (b + c) * d
类型转换的方式和时间以及如何确定每次计算的执行精度?
【问题讨论】:
标签: c++ types floating-point type-conversion precision
如果你有:
float f;
double d;
...然后像f * d 这样的算术表达式会将两个操作数提升为更大的类型,在本例中为double。
因此,表达式a * (b + c) * d 的计算结果为double,然后存储在result 中,这也是double。这种类型提升是为了避免意外的精度损失。
如需了解更多信息,请阅读这篇关于常用arithmetic conversions 的文章。
【讨论】:
浮点数将向上转换为双精度数。显式转换值。
即,如果你想要双倍的结果,你会写:
result = a * double( b + c ) * d;
总是值得明确的。它会引起这样的误解,任何尝试使用您的代码的人都可以立即明白您的意思。
【讨论】:
b 或 c 都不会被提升为 double,它们将被添加为两个 float 。仅当与已经是 double 的值相乘时,结果才会提升为 double,即 a。
你有括号分隔浮动加法。 所以它会将 b + c 做为 float + float。将其转换为双精度以保持最大精度,然后将双精度值相乘。
但是,在您希望控制转化而不是猜测的情况下:
使用static_cast<>();
【讨论】:
所有操作都是在相同类型的对象上完成的(假设是正常的算术运算)。
如果您编写的程序使用不同的类型,那么编译器会自动升级 ONE 参数,使它们都相同。
在这种情况下,浮点数将升级为双精度数:
result = a * (b + c) * d
float tmp1 = b + c; // Plus operation done on floats.
// So the result is a float
double tmp2 = a * (double)tmp1; // Multiplication done on double (as `a` is double)
// so tmp1 will be up converted to a double.
double tmp3 = tmp2 * d; // Multiplication done on doubles.
// So result is a double
result = tmp3; // No conversion as tmp3 is same type as result.
【讨论】:
按照操作顺序,每个子表达式都被转换为它的类型(不确定这里的术语,可能是主要的?)类型。 double 优于 float,所以:
(b + c) // this is evaluated as a float, since both b and c are floats
a * (b + c) // this is evaluated as a double, since a is a double
a * (b + c) * d // this is evaluated as a double, since both "a * (b + c)" and d are doubles
【讨论】:
在您的示例中,当计算右侧公式时,所有 float 类型都被类型提升为 double。
至于它们是如何转换的:我所读到的关于浮点运算的内容是,大多数现代硬件在特殊硬件寄存器中使用扩展精度(80 位)长双精度来执行 FP 操作(至少我记得这是现代英特尔 x86/x87 处理器)。据我了解,float 和 double 通过特殊的 FP 指令在硬件中进行类型提升(如果我错了,请有人纠正我)。
【讨论】:
float 不会自动提升为 double。仅当它们出现在算术运算中时,它们才被转换为 double,而某些东西已经是 double。在这种情况下,b 和 c 在添加之前都不会转换为 double。
您必须区分类型转换和值转换。 C++ 标准(也包括 C)允许以扩展精度进行浮点计算。
“浮动操作数的值和浮动表达式的结果可以用比类型要求更高的精度和范围来表示;类型不会因此而改变。”
作为类型,b + c 是两个浮点数的加法。结果是一个浮点数。然后将结果类型提升为双精度,并且两次乘法作为双精度进行,结果为双精度。
但是,允许实现使用双精度(或更高精度)进行所有计算,包括 b + c。 事实上,我使用 Visual C++ 进行了尝试,它使用 x86 上可用的 80 位浮点堆栈完成了所有计算。
【讨论】: