精度损失

Loss of precision?

本文关键字:损失 精度      更新时间:2023-10-16

我有一个函数,如下所示:

double calc( double x );

我是否会因以下任何表达式而失去精度:

double y1 = calc( 1.0 / 3 );
double y2 = calc( 1.0 / 3.0 );

这些是否更准确:

double y3 = calc( static_cast<double>(1) / 3 )
double y4 = calc( static_cast<double>(1) / static_cast<double>(3) )

编辑

对不起,我这里的数字错误。

但是,我的意思是1.0将其解释为floatdouble,并且总是如此还是取决于某些编译器标志?如果它是一个float,那么1.0/3也将是一个float,然后才被转换成一个double。如果是这种情况,会导致精度损失,不是吗?

编辑 2

我已经用g++对此进行了测试,事实证明,如果程序使用-fsingle-precision-constant标志编译,您确实会失去精度。

#include <iostream>
#include <limits>
#include <typeinfo>
long double calc( long double val)
{
  return val;
}
int main() {
  std::cout.precision(std::numeric_limits< long double >::max_digits10);
  std::cout << calc(1.0/3.0) << std::endl;
  std::cout << calc(static_cast<float>(1)/3) << std::endl;
  std::cout << calc(static_cast<double>(1)/3) << std::endl;
  std::cout << calc(static_cast<long double>(1)/3) << std::endl;
  std::cout << typeid(1.0).name() << std::endl;
  return 0;
}

结果是,

0.333333343267440795898
0.333333343267440795898
0.33333333333333331483
0.333333333333333333342
f

所以,为了安全起见,我决定使用static_cast< long double >(1) / 3

您展示的任何替代方案都不会造成任何精度损失[至少如果编译器执行标准所说的应该做的事情,则不会]。也就是说,所有二元运算符,其中一个操作数是double,另一端会自动提升为double[通常,当两个操作数的大小不同时,它们被提升为较大的操作数]。

特别是,整数值[低于尾数的位数]总是精确表示。

[显然,我们不知道calc如何处理您的输入 - 这可能是任何和各种错误的根源,但我假设您实际上是在问在您建议的情况下3.0/8.0是否总是0.375 - 当然3/8会导致零,因为这在两边都是整数]

针对正在编辑的原始问题进行编辑:

如果代码说1.1.00.3.3,则为double。如果你写0.5f,那就是float。根据上述规则1.0/3将是double(1.0)/double(3.0)的结果。

从技术上讲,编译器可以只支持一种浮点类型,有 3 种不同的编写方式 - C 和 C++ 标准不要求doublefloat

No.y1的常量表达式隐转换为doubley2的常量表达式已经是一个double

你在y3y4中所做的是定义一个常量整数值并将其转换为double,此时您可以像已经做的那样简单地定义一个双精度浮点常量。