【问题标题】:Loss of precision when casting float to double将浮点数转换为双倍时精度损失
【发布时间】:2021-03-30 09:38:45
【问题描述】:

我想我的 c++ 程序遇到了精度问题。而且我不明白为什么我的价值观会得到不同的结果。

res 等于 1321.0000001192093 如果我写的话:

float sy = -0.207010582f;
double res = -1512.*((double)sy - (2. / 3.));

但 res2 等于 1320.9999999839999 如果我写的话:

double res2 = -1512.*(-0.207010582 - (2. / 3.));

当我写这个的时候,为什么 syd 和 syd2 都不一样:

double syd  = -0.207010582f;
double syd2 = -0.207010582000000000;

有人可以帮我把我的浮点数正确地转换成双精度并了解发生了什么吗?

【问题讨论】:

  • -0.207010582f 是一个浮点数,因此显然它不如 -0.207010582 精确,后者是一个双精度数。像(double)sy 这样的转换是正确的,虽然不是以 C++ 方式(应该是 static_cast<double>(sy)。但是向上转换并不会神奇地给你首先使用浮点数而失去的精度。为了避免这种情况,你必须使用双重权利从一开始
  • Sy 由外部 dll 提供,我无法更改其类型。我不明白为什么将这个浮点数转换成双重改变它的价值。
  • 如果你想要更高的精度,那么你应该试试 gmpxx
  • 这并没有解决问题,但不需要演员表。由于2. / 3.的类型是double,所以sy的值会被转换成double来匹配。无论有没有演员,计算都是一样的。

标签: c++ casting floating-point double precision


【解决方案1】:

-0.207010582f 是十进制浮点文字。但是您的计算机不使用十进制浮点,它使用二进制浮点。因此,该文字的值将四舍五入为float 精度。

同样,-0.207010582 被舍入到 double 精度。虽然更接近,但仍不等于 -0.207010582 十进制。

由于doublefloat 具有更高的精度,您将不会通过将float 转换为double 来丢失精度。任何舍入都会更早发生。

【讨论】:

  • -0.207010582f 的内部浮点表示并不严格等于字面量 -0.207010582000000000000 ?
  • @cyrilc:正确。如果以十进制表示,则为-0.20701058208942413330078125,或以位表示10111110010100111111101010010101
【解决方案2】:

单精度

正如其他人所说,float sy = -0.207010582f; 从单精度浮点字面量初始化单精度(32 位)浮点变量。

这将被视为(在存储和计算中)该格式中最接近的可表示数字。这个号码是-0.20701058208942413330078125

你的代码实际上是float sy = -0.20701058208942413330078125;

您可以通过查看相邻的单精度浮点数来确认这是最接近的可表示值。

-0.20701059699058532714843750   // std::nextafter( sy, std::numeric_limits<float>::lowest() )
-0.20701058208942413330078125   // sy
-0.20701056718826293945312500   // std::nextafter( sy, std::numeric_limits<float>::max() )

双精度

双精度浮点数的情况完全相同,只是它们的分辨率提高意味着差异很小。 例如double dy = -0.207010582;实际上代表值0.20701058199999999853702092877938412129878997802734375

同样,可以表示的相邻值是-

-0.2070105820000000262925965444082976318895816802978515625  // std::nextafter( dy, std::numeric_limits<double>::lowest() )
-0.2070105819999999985370209287793841212987899780273437500  // dy
-0.2070105819999999707814453131504706107079982757568359375  // std::nextafter( dy, std::numeric_limits<double>::max() )

单到双转换

所有单精度浮点值都可以用双精度精确表示。因此,从单精度到双精度的转换不会丢失任何内容。


以上所有内容均假设 IEEE754 浮点表示。

【讨论】:

    猜你喜欢
    • 2015-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-26
    • 1970-01-01
    • 1970-01-01
    • 2018-08-02
    • 1970-01-01
    相关资源
    最近更新 更多