快速计算出 32 位浮点表示和相关损耗的方法

Quick way to figure out 32-bit floating point representation and associated loss

提问人:Charles 提问时间:10/25/2023 更新时间:10/26/2023 访问量:37

问:

我正在处理来自高精度系统的给定范围(即朗度和滞后度)的实数,这将为我提供许多小数(通常以 15 为量级,当然还有逗号最多剩三位)。现在,这些小数点在多大程度上代表了实际的知识,我不知道,但我想把它们都用起来。

问题是,对于任何给定的数字,如何快速知道 32 位浮点表示是否会在小数位上产生任何损失,如果是,损失多少?有没有一些在线工具可以做到这一点,或者我可以在 excel 表格或其他东西中进行一些快速计算?

浮点 精度

评论

1赞 tinman 10/25/2023
这回答了你的问题吗?单精度浮点数精度(IEEE 754 标准)
0赞 Charles 10/25/2023
其实是的。它有一个脚注,上面有一个简洁的小公式:对于标准浮点数,我们有 21 位用于尾数 nad 所以 6.3...小数表示:那对我来说还不够!num_decimals_representable = log10(2^(num_bits_for_mantissa)

答:

0赞 chux - Reinstate Monica 10/26/2023 #1

最坏情况下的二进制损失是关于 和 的精度差异。通常为 29 位。十进制损失约为 29 * log10(2) 或 8.7 十进制数字损失。float64float32


对于特定值,有些值会完全转换为 .float32float64

与其试图找到十进制损失,不如让我们看一下二进制损失,因为常见的 float32float64 采用二进制浮点编码。

与这种角度的情况一样,范围不是什么大问题,请考虑提取 的有效位,并评估其与保留位相比的最低有效位。float64

#include <float.h>
#include <math.h>

#define DBL_FLT_DIG_DIFF (DBL_MANT_DIG - FLT_MANT_DIG)
#define DBL_FLT_DIG_DIFF_MOD (1ull << DBL_FLT_DIG_DIFF)

// Return loss in fraciton of a ULB of x as a float.
double double_to_float_loss(double x) {
  if (x < 0) {
    return double_to_float_loss(-x);
  const double scale = DBL_FLT_DIG_DIFF_MOD;
  // The frexp functions break a floating-point number into a normalized
  // fraction and an integer exponent
  int expo;
  long long ifraction = (long long) (frexp(x, &expo) * scale);
  long long loss = ifraction % DBL_FLT_DIG_DIFF_MOD;
  ifraction /= DBL_FLT_DIG_DIFF_MOD;
  // 0.5 as conversion from float64 to float32 typically rounds to nearest.
  return 0.5 * loss/ifraction;
}

小数点后位置的损失,

对于给定的,很简单,只需从上面评估小数位数即可。float64loss

...
long long loss = ifraction % DBL_FLT_DIG_DIFF_MOD;
int deimcal_loss = 0;
while (loss) {
  loss /= 10;
  decimal_loss++;
}

更糟糕的情况:log10(DBL_FLT_DIG_DIFF_MOD)