最重要的十进制数字精度是否可以转换为二进制并返回到十进制而不会丢失重要性6或7.225?

时间:2015-06-06 23:01:52

标签: binary floating-point decimal floating-point-precision significant-digits

我遇到了两种不同的浮点数精度公式。

  

⌊(N-1)log 10 (2)⌋= 6位小数(单精度)

  

N log 10 (2)≈7.225十进制数字(单精度)

其中 N = 24 有效位(单精度)

第一个公式位于“IEEE Standard 754 for Binary Floating-Point Arithmetic”第4页的顶部,由 W. Kahan教授撰写

第二个公式可以在维基百科文章“Single-precision floating-point format”的 IEEE 754单精度二进制浮点格式:binary32 下找到。

对于第一个公式,W。Kahan教授说

  

如果是最多6 sig的十进制字符串。 dec。转换为Single,然后转换回相同数量的sig。十进制,   然后最后的字符串应与原始字符串匹配。

对于第二个公式,维基百科说

  

...总精度为24位(相当于log 10 (2 24 )≈ 7.225十进制数

两个公式(6和7.225十进制数字)的结果是不同的,我希望它们是相同的,因为我假设它们都是为了表示可以转换为浮点二进制的最高有效十进制数字和然后转换回十进制,其开头的有效十进制数字相同。

为什么这两个数字不同,哪些是最重要的十进制数字精度可以转换为二进制并返回十进制而不会失去重要性?

3 个答案:

答案 0 :(得分:13)

这些是关于两个略有不同的事情。

7.225 1 数字是一个可以存储内部的数字的精度。举一个例子,如果你用双精度数进行计算(所以你从15位数的精度开始),然后将它四舍五入为一个精度数,你在那个点留下的精度大约是7位数。

6位数字正在讨论通过从一串十进制数字到浮点数的往返转换,然后再返回到另一个十进制数字串的精度。

所以,我们假设我从一个像1.23456789这样的数字作为字符串开始,然后将其转换为float32,然后将结果转换回字符串。当我这样做时,我可以期待6位数完全匹配。第七位可能是圆形的,所以我不一定能指望它匹配(尽管它可能是原始字符串的+/- 1。

例如,请考虑以下代码:

#include <iostream>
#include <iomanip>

int main() {
    double init = 987.23456789;
    for (int i = 0; i < 100; i++) {
        float f = init + i / 100.0;
        std::cout << std::setprecision(10) << std::setw(20) << f;
    }
}

这会产生如下表格:

     987.2345581         987.2445679         987.2545776         987.2645874
     987.2745972         987.2845459         987.2945557         987.3045654
     987.3145752          987.324585         987.3345947         987.3445435
     987.3545532          987.364563         987.3745728         987.3845825
     987.3945923          987.404541         987.4145508         987.4245605
     987.4345703         987.4445801         987.4545898         987.4645386
     987.4745483         987.4845581         987.4945679         987.5045776
     987.5145874         987.5245972         987.5345459         987.5445557
     987.5545654         987.5645752          987.574585         987.5845947
     987.5945435         987.6045532          987.614563         987.6245728
     987.6345825         987.6445923          987.654541         987.6645508
     987.6745605         987.6845703         987.6945801         987.7045898
     987.7145386         987.7245483         987.7345581         987.7445679
     987.7545776         987.7645874         987.7745972         987.7845459
     987.7945557         987.8045654         987.8145752          987.824585
     987.8345947         987.8445435         987.8545532          987.864563
     987.8745728         987.8845825         987.8945923          987.904541
     987.9145508         987.9245605         987.9345703         987.9445801
     987.9545898         987.9645386         987.9745483         987.9845581
     987.9945679         988.0045776         988.0145874         988.0245972
     988.0345459         988.0445557         988.0545654         988.0645752
      988.074585         988.0845947         988.0945435         988.1045532
      988.114563         988.1245728         988.1345825         988.1445923
      988.154541         988.1645508         988.1745605         988.1845703
     988.1945801         988.2045898         988.2145386         988.2245483

如果我们仔细研究一下,我们可以看到前六个有效数字总是精确地跟随模式(即,每个结果正好比其前一个结果大0.01)。正如我们在原始double中看到的那样,该值实际上是98x.xx456 - 但是当我们将单精度浮点数转换为十进制时,我们可以经常看到7 th 数字不会被正确读回 - 因为后续数字大于5,它应该向上舍入到98x.xx46,但是某些值不会(例如,第一列中倒数第二项是{ {1}},它将向下舍入而不是向上,所以我们最终得到98x.xx45而不是988.154541。所以,即使值(存储的)精确到7位数(加上当我们通过转换为十进制和返回来往返时,我们不能再依赖于那个第七位正好匹配了(即使有足够的精度,它往往会更多)。

1.这基本上意味着7个数字,而8 th 数字将比没有更准确,但不是很多 - 例如,如果我们从{{1精度的46数字意味着最后一个数字与那里开始的数字大约为+/- .775(而没有1.2345678精度的数字,它基本上是+ / - 从那里开始的1)。 功能

答案 1 :(得分:3)

  

可以达到的最重要的十进制数字精度是多少   转换为二进制并返回十进制而不会失去意义?

可以转换为二进制并返回十进制而不会丢失重要性的最高有效十进制数字精度(对于单精度浮点数或24位)是6位十进制数。

  

为什么这两个数字不同......

数字6和7.225不同,因为它们定义了两个不同的东西。 6是可以往返的最多十进制数字。 7.225是24位二进制整数的近似小数位精度,因为24位二进制整数可以有7或8位十进制数,具体取决于其具体值。

使用特定的二进制整数公式找到7.225。

  

d spec = b·log 10 (2)(d spec   =特定的十进制数字,b =位)

但是,您通常需要知道的是b位整数的最小和最大十进制数字。以下公式用于查找特定二进制整数的最小和最大十进制数字(分别为24位的7和8)。

  

d min =⌈(b-1)·log 10 (2)⌉(d min   =最小十进制数,b =位,⌈x⌉=最小整数≥x)

     

d max =⌈b·log 10 (2)⌉(d max   =最大十进制数,b =位,⌈x⌉=最小整数≥x)

要了解有关如何推导出这些公式的更多信息,请阅读Rick Regan撰写的Number of Decimal Digits In a Binary Integer

这一切都很好,但你可能会问,如果你说24位数字的十进制数字的跨度是7到8,为什么6是往返转换的最多十进制数字?

答案是 - 因为上面的公式只适用于整数而不是浮点数!

每个十进制整数都有二进制的精确值。但是,对于每个十进制浮点数,不能说同样的情况。以.1为例。二进制文件中的.1是数字0.000110011001100...,它是重复或重复的二进制文件。这可能会产生舍入误差。

此外,表示十进制浮点数比表示相等有效的十进制整数需要多一位。这是因为浮点数越接近0就越精确,越接近0就越不精确。因此,在最小值和最大值范围附近有许多浮点数(e min < / sub> = -126和e max = +127(单精度)由于舍入误差而丢失1位精度。要直观地看到这一点,请查看由Josh Haberman撰写的What every computer programmer should know about floating point, part 1

此外,至少784,757个正七位十进制数在往返转换后无法保留其原始值。这种号码无法在往返行程中存活的一个例子是8.589973e9。这是不保留其原始值的最小正数。

以下是您应该使用的浮点数精度公式,它将为您提供往返转换的6位小数。

  

d max =⌊(b-1)·log 10 (2)⌋(d max   =最大十进制数,b =位,⌊x⌋=最大整数≤x)

要了解有关如何推导出此公式的更多信息,请阅读由Rick Regan撰写的Number of Digits Required For Round-Trip Conversions。 Rick在参考严格的证据时表现出了公式推导,做得非常出色。

因此,您可以以建设性的方式利用上述公式;如果您了解它们的工作原理,可以将它们应用于任何使用浮点数据类型的编程语言。您需要知道的是浮点数据类型具有的有效位数,并且您可以找到它们各自的小数位数,您可以指望它们在往返转换后没有任何重要性损失。

2017年6月18日更新:我希望在Rick Regan的新文章中添加一个链接,该文章会更详细,在我看来,这个问题比这里提供的任何答案更能回答这个问题。他的文章是“Decimal Precision of Binary Floating-Point Numbers”,可以在他的网站上找到www.exploringbinary.com

答案 2 :(得分:2)

请记住,它们是完全相同的公式。记住你的高中数学书籍身份:

    Log(x^y) == y * Log(x)

使用计算器实际计算N = 24的值是有帮助的:

  Kahan's:      23 * Log(2) = 6.924
  Wikipedia's:   Log(2^24)  = 7.225

由于地板(),卡汉被迫将6.924截断至6位数,令人失望。唯一的实际区别是Kahan使用了一点精度。

很难猜到为什么,教授可能依赖于旧笔记。写在IEEE-754之前,没有考虑到第24位精度是免费的。格式使用技巧,浮点值的最高位不是0并且总是1.因此它不需要存储。处理器在执行计算之前将其添加回来。将23位存储精度转换为24有效精度。

或者他考虑到从十进制字符串到二进制浮点值本身的转换会产生错误。许多好的圆形十进制值,如0.1,不能完美地转换为二进制。它有无穷无尽的数字,就像十进制的1/3。然而,这通过简单的舍入产生了偏离+/- 0.5位的结果。因此结果精确到23.5 * Log(2)= 7.074十进制数字。如果他认为转换程序是笨拙的并且没有正确地舍入,则结果可以偏离+/- 1位并且N-1是合适的。他们并不笨拙。

或者他认为像一个典型的科学家或(天堂禁止)会计师,并希望计算结果也转换回小数。比如当你平凡地寻找一个7位十进制数时,你的转换来回不会产生相同的数字。是的,这会增加另一个+/- 0.5位错误,总计最多1位错误。

但永远不要犯错,你总是要包含在计算中操纵数字时得到的任何错误。他们中的一些人很快失去了有效数字,尤其是减法是非常危险的。