【问题标题】:Change float exponent without losing precision更改浮点指数而不损失精度
【发布时间】:2020-07-22 10:09:47
【问题描述】:

我想将 int64_t 值 [纳秒] 转换为浮点(或双精度)[秒] 值。

所以我尝试了以下方法:

int64_t elapsed_nano = 7079206912L;
printf("%f\n", float(elapsed_nano));
float elapsed_sec = float(elapsed_nano) / float(1000000000);
printf("%f\n", elapsed_sec);

这似乎切断了最后一点......可能是由于一些内部四舍五入。这里的输出:

7079206912.000000
7.079207

我尝试与 float(0.000000001) 相乘,但没有帮助。

我想最好的办法是改变浮点数的指数,尽管我没有找到任何关于如何做到这一点的文档。

我正在使用 gcc 4.8.5(由于不同的原因无法更新到更新的 gcc)

【问题讨论】:

  • 正如你所说,这似乎是最后一点的删减。您可以尝试使用 float_32 而不是使用浮点数,这可能会让您达到better precision
  • 在哪个标头中定义了 float_32 ?找不到有关该类型的任何信息。
  • @AbhayAravinda:乘以 1e-9 会增加舍入误差的数量:1e9 可以精确表示,但 1e-9 不能。所以x / 1e9f 只在除法中产生舍入错误,但x * 1e-9f 在将1e-9f 转换为float 时产生一个舍入错误,而在乘法中出现另一个舍入错误。
  • 使用float 和想要准确性是不兼容的选择。使用 double 会提高您获得有意义结果的机会。
  • 您不能“仅 [...] 更改指数”。至少不是以 10 为底。您的硬件使用二进制,并且指数也是基于二进制的。这样,您可以“更改指数”以使用 2 的任何幂进行乘/除,但您不能“更改指数”以使用 10 的幂来实现相同的结果。后面有一个 5 因子必须导致舍入误差。

标签: c floating-point exponent


【解决方案1】:

嗯,看起来也是格式问题。

要查看小数点后 9 位数字,请使用 printf("%.9f\n", elapsed_sec);

考虑使用printf("%.*g\n", DBL_DIG, elapsed_sec); 以获得更通用的方法。


使用double 而不是float。由于 float 的有限精度导致意外输出 - 在 6 个有效数字后,float 中的错误开始变得可见。


对于 |值|最多 224float 通常具有足够的精度来精确编码整数。

对于 |值|最多 253double 通常具有足够的精度来精确编码整数。

printf("%f\n", (double) elapsed_nano);
double elapsed_sec = elapsed_nano / 1000000000.0;
printf("%f\n", elapsed_sec);

看起来 OP 正在为 C 代码使用 C++ 编译器。

【讨论】:

  • 双倍的结果相同(应该提到我已经尝试过)。是的,我使用的是 C++ 编译器,这有关系吗?如果有解决问题的 C++ 方法,那也是非常受欢迎的!
  • 在这个编译器上测试过 (onlinegdb.com)。这行得通。但是您需要将 printf 从“%f”更改为“%1.9f”。
  • @AbhayAravinda 如果您想查看小数点后的 9 位数字,请使用printf("%.9f\n", elapsed_sec);,否则请考虑使用printf("%.*g\n", DBL_DIG, elapsed_sec); 以获得更通用的方法。
  • 重新“相当于大约 6 到 9 位十进制数字”:No.
  • 该答案是基于没有十进制数字等效性。小数精度的常见说法仍然适用。它就像一个行星轨道:它是一个圆,不是椭圆,不是带有扰动的椭圆,不是它不可解决的 n 体问题,... 6 到 9 位十进制数字用于合理介绍float。作为一种高级理解,您的 no 断言适用。
猜你喜欢
  • 1970-01-01
  • 2018-08-02
  • 2021-05-09
  • 1970-01-01
  • 2011-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多