你能帮我理解 "significant digits" 在浮点数学中的含义吗?

Can you help me to understand what "significant digits" means in floating point math?

就我正在学习的内容而言,一旦我将浮点值转换为十进制值,我需要的 "significant digits" 就是一个固定数字(例如,17 表示双精度)。 17个总数:小数点前后分隔符。

例如这段代码:

typedef std::numeric_limits<double> dbl;

int main()
{
    std::cout.precision(dbl::max_digits10);
    //std::cout << std::fixed;    

    double value1 = 1.2345678912345678912345;
    double value2 = 123.45678912345678912345;
    double value3 = 123456789123.45678912345;

    std::cout << value1 << std::endl;
    std::cout << value2 << std::endl;
    std::cout << value3 << std::endl;
}

将正确 "show me" 17 个值:

1.2345678912345679
123.45678912345679
123456789123.45679

但是如果我提高 cout 的精度(即 std::cout.precision(100)),我可以看到在 17 范围之后还有其他数字:

1.2345678912345678934769921397673897445201873779296875
123.456789123456786683163954876363277435302734375
123456789123.456787109375

为什么要忽略它们?它们也存储在 variables/double 中,因此它们稍后会影响整个 "math"(除法、乘法、求和等)。

"significant digits"是什么意思?还有其他...

请记住,浮点值是不是实数。这些值之间存在差距,所有这些额外的数字虽然对实数有意义,但并不反映浮点值的任何差异。当您将浮点值转换为文本时,具有 std::numeric_limits<...>::max_digits10 位可确保您可以将文本字符串转换回浮点值并获得原始值。多余的数字不影响结果。

当您要求更多数字时,您看到的额外数字是转换算法试图按照您的要求执行的结果。该算法通常只是不断提取数字,直到达到所需的精度;它可以写成在写入 max_digits10 digits 后开始输出零,但这是一个额外的复杂问题,没有人会为此烦恼。它不会真的有帮助。

只是添加到 Pete Becker 的回答中,我认为你混淆了找到 exact 十进制表示的问题二进制尾数,问题是找到 some 十进制表示 uniquely 表示二进制尾数(给定一些固定的舍入方案)。

现在,关于第一个问题,您总是需要有限数量的十进制数字来准确表示二进制尾数(因为 2 除以 10)。

例如,你需要18位十进制数才能正好表示二进制1.0000000000000001,即十进制的1.00000762939453125

但是你只需要 17 位数字就可以将它唯一地表示为 1.0000076293945312 因为没有其他数字具有精确值 1.0000076293945312xyz... 其中 0<=x<5 可以作为双精度存在(更准确地说, next 和 prior 完全可表示的值是 1.00000762939453147204460492503130808472633361816406251.0000076293945310279553950749686919152736663818359375 ).

当然,这并不意味着给定一些十进制数,您可以忽略第 17 位之后的所有数字;这只是意味着如果您应用相同的舍入方案用于在第 17 个位置生成小数并将其分配回双精度,您将获得相同的原始双精度。

Can you help me to understand what “significant digits” means in floating point math?

对于 FP 数字,如数学实数,有效数字 是不以 0 开头的值的前导数字,然后根据上下文,到 1) 小数点,2) 最后一个非零数字,或 3) 最后一个打印的数字。

123.         // 3 significant decimal digits
123.125      // 6 significant decimal digits
0.0078125    // 5 significant decimal digits
0x0.00123p45 // 3 significant hexadecimal digits
123000.0     // 3, 6, or 7 significant decimal digits depending on context

当关注 十进制有效数字 double 等 FP 类型时。问题通常是 "How many decimal significant digits are needed or of concern?"

几乎所有 C FP 实现都使用 binary 编码,这样所有有限 FP 都是 exact 2 的幂和。每个有限 FP 准确。通用编码提供大多数 double 有 53 个二进制数字是它的有效数字 - 所以 53 有效二进制数字 。这如何显示为小数通常是混淆的根源。

// Example 0.1 is not an exact sum of powers of 2 so a nearby value is used.
double x = 0.1;
// x takes on the exact value of 
// 0.1000000000000000055511151231257827021181583404541015625
// aka 0x1.999999999999ap-4
// aka base2: 0.000110011001100110011001100110011001100110011001100110011010
// The preceding and subsequent doubles
// 0.09999999999999999167332731531132594682276248931884765625
// 0.10000000000000001942890293094023945741355419158935546875
//   123456789012345678901234567890123456789012345678901234567890

从上面看,可以说 x 有超过 50 十进制有效数字 。然而,该值匹配预期的 0.1 到 16 十进制有效数字。或者,由于前面和后面可能的 double 值在第 17 位不同,可以说 x 有 17 十进制有效数字 .

What does it means "significant digits"?

存在有效数字的各种含义,但对于 C,2 个常见的含义是:

  1. 十进制有效数字double 文本值按预期转换为所有double 的数目。这通常是 15。C 将其指定为 DBL_DIG 并且必须至少为 10.

  2. 文本值 double 需要打印的 十进制有效数字 的数量,以区别于另一个 double。这通常是 17。C 将其指定为 DBL_DECIMAL_DIG 并且必须至少为 10.

Why should ignore them?

这取决于编码目标。很少需要精确值的所有数字。 (DBL_TRUE_MIN 可能有 752 个。)对于大多数应用程序,DBL_DECIMAL_DIG 就足够了。在 select 个应用程序中,DBL_DIG 即可。所以通常,忽略 17 之后的数字不会造成问题。