Wan*_*ool 21 floating-point binary decimal significant-digits floating-point-precision
我遇到了两种不同的浮点数精度公式.
⌊(N-1)log 10(2)⌋= 6位小数(单精度)
和
N log 10(2)≈7.225十进制数字(单精度)
其中N = 24个有效位(单精度)
第一个公式位于由W. Kahan教授撰写的" IEEE标准754二进制浮点运算 " 第4页的顶部.
第二个公式可以在维基百科文章" 单精度浮点格式 "的IEEE 754单精度二进制浮点格式:binary32下找到.
对于第一个公式,W.Kahan教授说
如果十进制字符串最多为6 sig.(分解). 转换为Single,然后转换回相同数量的sig.dec.,那么最后的字符串应该与原始字符串匹配.
对于第二个公式,维基百科说
...总精度为24位(相当于log 10(2 24)≈7.225十进制数字).
两个公式(6和7.225十进制数字)的结果是不同的,我希望它们是相同的,因为我假设它们都是为了表示最有效的十进制数字,可以转换为浮点二进制,然后转换回来十进制,其开头的有效十进制数字相同.
为什么这两个数字不同,什么是最重要的十进制数字精度可以转换为二进制并返回到十进制而不会失去重要性?
Jer*_*fin 14
这些是谈论两个略有不同的事情.
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;
}
}
Run Code Online (Sandbox Code Playgroud)
这会生成如下表:
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
Run Code Online (Sandbox Code Playgroud)
如果我们仔细观察,我们可以看到前六个有效数字始终精确地遵循模式(即,每个结果正好比其前一个结果大0.01).正如我们在原来的看到double,该值实际上是98x.xx456 -但是当我们转换的单精度浮点十进制,我们可以看到,7 个数字经常会不正确地读回-由于后续数字大于5,它应该向上舍入到98x.xx46,但是某些值不会(例如,第一列中的倒数第二个项目988.154541,它将向下舍入而不是向上,所以我们' d最终得到98x.xx45而不是46.所以,即使值(存储的)精确到7位数(加上一点点),当我们通过转换为十进制和返回值往返时,我们可以不再依赖于第七个数字的精确匹配(即使有足够的精度,它往往会更多).
1.这基本上意味着7位,8 个数字会稍微比没有更准确,但不是一大堆-例如,如果我们从双转换1.2345678时,.225精度数字意味着最后一个数字将从那里开始的大约+/- .775(而没有.225精确的数字,它将基本上+/- 1开始那里).
\n\n\n可以在不损失重要性的情况下转换为二进制并返回十进制的最高有效十进制数字精度是多少?
\n
可以转换为二进制并返回十进制而不丢失重要性(对于单精度浮点数或 24 位)的最高有效十进制数字精度是 6 位十进制数字。
\n\n\n\n\n为什么这两个数字不同...
\n
数字 6 和 7.225 不同,因为它们定义了两个不同的事物。6 是可往返的最多小数位。7.225 是 24 位二进制整数的近似十进制位数精度,因为 24 位二进制整数根据其具体值可以有 7 或 8 位十进制位数。
\n\n使用特定的二进制整数公式得出 7.225。
\n\n\n\n\ndspec = b·log 10 ( 2) (dspec \ n = 特定的十进制数字,b = 位)
\n
然而,您通常需要知道的是 b 位整数的最小和最大十进制数字。以下公式用于查找特定二进制整数的最小和最大十进制数字(24 位分别为 7 和 8)。
\n\n\n\n\nd min = \xe2\x8c\x88(b-1)·log 10 (2)\xe2\x8c\x89 (d min \n = 最小十进制位数,b = 位,\xe2\x8c\x88x\xe2\x8c \x89 = 最小整数 ≥ x)
\n\nd max = \xe2\x8c\x88b·log 10 (2)\xe2\x8c\x89 (d max \n = 最大十进制位数,b = 位,\xe2\x8c\x88x\xe2\x8c\x89 = 最小整数≥x)
\n
要了解有关如何推导这些公式的更多信息,请阅读Rick Regan 撰写的《二进制整数中的十进制位数》 。
\n\n这一切都很好,但您可能会问,如果您说 24 位数字的十进制数字范围是 7 到 8,为什么 6 是往返转换中最多的十进制数字?
\n\n答案是 \xe2\x80\x94 因为上面的公式只适用于整数,不适用于浮点数!
\n\n每个十进制整数都有一个精确的二进制值。然而,对于每个十进制浮点数来说,情况并非如此。举.1个例子。.1二进制中的数字0.000110011001100...是重复或循环的二进制。这可能会产生舍入误差。
此外,表示十进制浮点数比表示同等意义的十进制整数多需要一位。这是因为浮点数越接近 0 精度越高,而距离 0 越远精度越低。因此,许多浮点数接近最小值和最大值范围(e min = -126 和对于单精度, e max = +127)由于舍入误差而损失 1 位精度。要直观地看到这一点,请参阅Josh Haberman 撰写的《每个计算机程序员应该了解的浮点知识,第 1 部分》。
\n\n此外,至少有784,757正七位十进制数在往返转换后无法保留其原始值。此类无法在往返过程中幸存下来的数字的一个示例是8.589973e9。这是不保留其原始值的最小正数。
以下是您应该用于浮点数精度的公式,该公式将为您提供 6 个小数位用于往返转换。
\n\n\n\n\nd max = \xe2\x8c\x8a(b-1)\xc2\xb7log 10 (2)\xe2\x8c\x8b (d max \n = 最大十进制位数,b = 位,\xe2\x8c\x8ax\xe2 \x8c\x8b = 最大整数 ≤ x)
\n
要了解有关如何推导此公式的更多信息,请阅读往返转换所需的位数,也由 Rick Regan 撰写。里克(Rick)出色地展示了公式推导并引用了严格的证明。
\n\n因此,您可以建设性地利用上述公式;如果您了解它们的工作原理,则可以将它们应用于任何使用浮点数据类型的编程语言。您所需要知道的只是浮点数据类型具有的有效位数,并且您可以找到它们各自的小数位数,您可以指望这些位数在往返转换后不会丢失有效位数。
\n\n2017 年 6 月 18 日更新:我想添加 Rick Regan 的新文章的链接,该文章更详细,在我看来,它比此处提供的任何答案都更好地回答了这个问题。他的文章是“二进制浮点数的十进制精度”,可以在他的网站www.exploringbinary.com上找到。
\n