ChatGPT解决这个技术问题 Extra ChatGPT

为什么十进制数不能用二进制精确表示?

已经向 SO 发布了几个关于浮点表示的问题。例如,十进制数 0.1 没有精确的二进制表示,因此使用 == 运算符将其与另一个浮点数进行比较是很危险的。我了解浮点表示背后的原理。

我不明白的是,从数学的角度来看,为什么小数点右边的数字比左边的数字更“特殊”?

例如,数字 61.0 具有精确的二进制表示,因为任何数字的整数部分总是精确的。但数字 6.10 并不准确。我所做的只是将小数点移动一位,然后我突然从 Exactopia 转到了 Inexactville。从数学上讲,这两个数字之间应该没有本质的区别——它们只是数字。

相比之下,如果我将小数点向另一个方向移动一位以产生数字 610,我仍然在 Exactopia。我可以继续朝那个方向前进(6100、610000000、610000000000000),它们仍然是准确的、准确的、准确的。但一旦小数点超过某个阈值,数字就不再准确。

这是怎么回事?

编辑:澄清一下,我想远离有关行业标准表示的讨论,例如 IEEE,并坚持我认为是数学上“纯”的方式。以 10 为底,位置值为:

... 1000  100   10    1   1/10  1/100 ...

在二进制中,它们将是:

... 8    4    2    1    1/2  1/4  1/8 ...

这些数字也没有任意限制。位置向左和向右无限增加。

您可能会发现这有助于准确了解浮点数中发生的情况:Anatomy of a floating point number
在二进制中,数字 3 表示为 2¹+2°=2+1。好,易于。现在,看看1/3。使用 2 的负幂,你会如何表示它?稍微试验一下,你会发现 1/3 等于无限序列 2^-2 + 2^-4 + 2^-6 + 2^-8 + ... 的总和,即。用二进制精确表示并不容易。
Jon Skeet 很好地回答了你身体里的问题。缺少的一件事是您实际上提出了两个不同的问题。标题问题是“为什么十进制数不能用二进制精确表示?”答案是,他们可以。在您的标题和正文之间,您将“二进制”的概念和“浮点表示”的概念混为一谈。浮点是一种以固定数量的二进制数字表示十进制数字的方法,但会以精度为代价。二进制只是一种不同的计数基数,可以表示任何十进制数,给定无限位数。
有几个系统具有精确的十进制表示。它的工作原理与您描述的非常相似。 SQL 十进制类型就是一个例子。 LISP 语言内置了它。有几个商业和开源库用于使用精确的十进制计算。只是没有对此的硬件支持,而且大多数语言和硬件都实现了 IEEE 标准,以 32 或 64 位表示无限数量的数字。
这个问题似乎离题了,因为它是关于数学的(即使它是与编程相关的数学)并且在 Mathematics 上会更好

C
Community

如果您有足够的空间,小数可以精确表示 - 只是不能用浮点 二进制 点数表示。如果您使用浮点 decimal 点类型(例如 .NET 中的 System.Decimal),则可以准确表示大量无法准确表示为二进制浮点的值。

让我们以另一种方式看待它 - 在您可能习惯的以 10 为底的情况下,您无法准确表达 1/3。它是 0.3333333...(重复出现)。您不能将 0.1 表示为二进制浮点数的原因完全相同。您可以精确地表示 3、9 和 27 - 但不能表示 1/3、1/9 或 1/27。

问题是 3 是一个质数,它不是 10 的因数。当您想将一个数字乘以 3 时,这不是问题:您始终可以乘以一个整数而不会遇到问题。但是当你除以一个素数并且不是你的基数时,你可能会遇到麻烦(如果你试图将 1 除以那个数字,就会遇到麻烦)。

虽然 0.1 通常用作无法用二进制浮点精确表示的精确十进制数的最简单示例,但可以说 0.2 是一个更简单的示例,因为它是 1/5 - 而 5 是导致十进制和二进制之间问题的质数.

处理有限表示问题的旁注:

某些浮点小数点类型具有固定大小,例如 System.Decimal 其他类似 java.math.BigDecimal 的大小“任意大” - 但它们会在某个时候达到限制,无论是系统内存还是数组的理论最大大小。但是,这与该答案的主要内容完全不同。即使您有真正任意大量的位可供使用,您仍然无法以浮点二进制点表示精确地表示十进制 0.1。将其与相反的方式进行比较:给定任意数量的十进制数字,您可以精确地表示任何可以精确地表示为浮点二进制点的数字。


先生,这是一个很好的例子!
...希望我能两次投票。我被问过太多次了。这几乎就像人们不能在十进制之外思考。呵呵
是的,世界上有 10 种人——懂二进制的和不懂二进制的。
@JonSkeet:Ctrl+Alt+Delete 只用两根手指就会显得很尴尬。
@muusbolla:不。十进制表示1和十进制表示0.9...(在小数点后无限重复9)表示的数字是相等的。也许最简单的方法是:让 x = 0.9...。请注意10x = 9.9....。因此 9x = 10x - x = 9.9... - 0.9... = 9 使得 9x = 9x = 1。还有其他方法可以看到这一点,但我相信这是最简单的。
A
AakashM

例如,数字 61.0 具有精确的二进制表示,因为任何数字的整数部分总是精确的。但数字 6.10 并不准确。我所做的只是将小数点移动一位,然后我突然从 Exactopia 转到了 Inexactville。从数学上讲,这两个数字之间应该没有本质的区别——它们只是数字。

让我们暂时远离基数 10 和 2 的细节。让我们问一下 - 在基数 b 中,哪些数字具有终止表示,哪些数字没有?片刻的想法告诉我们,一个数 x 有一个终止的 b 表示当且仅当存在一个整数 n 使得 x b^n 是一个整数。

因此,例如,x = 11/500 有一个终止的 10 表示,因为我们可以选择 n = 3,然后选择 x b^n = 22,一个整数。但是 x = 1/3 没有,因为无论我们选择什么 n,我们都无法摆脱 3。

第二个例子提示我们考虑因子,我们可以看到对于任何 有理 x = p/q(假设是最低限度的),我们可以通过比较 {2 的素因子分解来回答这个问题} 和 q。如果 q 有任何不在 b 的素因子分解中的素因子,我们将永远无法找到合适的 n 来消除这些因子。

因此,对于以 10 为底的 任何 p/q,其中 q 的质因数不是 2 或 5 将没有终止表示。

所以现在回到基数 10 和 2,我们看到任何具有终止 10 表示的有理数都将是 p/q 的形式,恰好当 q 在其素因数分解中只有 25 时;并且恰好当 q 在其素数分解中只有 2 时,相同的数字将具有终止的 2 表示。

但是其中一种情况是另一种情况的子集!每当

在其素因数分解中只有 2s

显然也是如此

在其素因数分解中只有 2s 和 5s

或者,换一种说法,只要 p/q 有一个终止 2 表示,p/q 就有一个终止 10 表示。然而,相反的情况 成立 - 每当 q 在其素数分解中具有 5 时,它将具有终止 10-表示,但 不是 终止 2-表示。这是其他答案提到的 0.1 示例。

所以我们有你问题的答案 - 因为 2 的质因数是 10 的质因数的子集,所以所有以 2 结尾的数字都是以 10 结尾的数字,但反之则不然。不是 61 对 6.1,而是 10 对 2。

作为结束语,如果某些怪癖的人使用(例如)以 17 为底,但我们的计算机使用以 5 为底,那么您的直觉永远不会因此而误入歧途 - 不会有(非零,非整数)数字终止在这两种情况下!


那么为什么“alert(0.15*0.15)”会显示“0.0225”呢?
@MichaelGeiser 简短回答:在显示点四舍五入。您认为 0.15 实际上是(当存储为 IEEE 双精度时)`0.149999999999999994448884876874`。请参阅jsfiddle
很清楚点代码示例!我希望我能给你一个赞成票!我必须使用一些函数来探索向上截断发生的位置。我仍然很惊讶我们实际上必须处理这些垃圾。因为人们几乎 100% 的时间都在以 10 为基数工作,而且我们在很多时候都使用非整数,所以你会认为浮点数学的默认实现会处理这种废话。
@MichaelGeiser 使用 base 2 的电路比使用 base 10 的电路更小、更快、更节能。今天我们可能能够证明开销是合理的,但在 1970 年代制定标准时,这是一个大不了。在没有处理器电路直接支持的情况下尝试这样做会更糟,预计速度会出现数量级差异。
这个答案比 Jon Skeet 自己解释得更好!
T
TM.

根本(数学)原因是,当您处理整数时,它们是可数无限的。

这意味着,即使它们的数量是无限的,我们也可以“数出”序列中的所有项目,而不会跳过任何项目。这意味着如果我们想要获得列表中第 610000000000000 位的项目,我们可以通过公式计算出来。

然而,实数是不可数无限的。您不能说“给我位置 610000000000000 的实数”并得到答案。原因是,即使在 01 之间,当您考虑浮点值时,也有无限数量的值。这同样适用于任何两个浮点数。

更多信息:

http://en.wikipedia.org/wiki/Countable_set

http://en.wikipedia.org/wiki/Uncountable_set

更新:抱歉,我似乎误解了这个问题。我的回答是关于为什么我们不能代表每一个真正的价值,我没有意识到浮点被自动归类为理性。


实际上,有理数是可数无限的。但并不是每个实数都是有理数。我当然可以生成一系列精确的十进制数字,这些数字最终会达到你想要给我的任何精确的十进制数字。如果您还需要处理无理数,您就会进入不可数的无限集合。
没错,我应该说“真实”,而不是“浮点”。会澄清。
在这一点上,逻辑变得不那么适用了,IMO——因为我们不仅不能使用二进制浮点处理所有实数,而且我们甚至不能处理所有有理数(例如 0.1)。换句话说,我认为这根本与可数性无关:)
@jonskeet 我知道不同意 Jon Skeet 会违反基本的自然法则,所以我当然不会这样做 :) 但是,我确实认为可以将数字的内部表示视为 a 的索引一组要在外部表示的值。通过这种思路,您可以看到,无论您的索引列表有多大(即使您说过无限位精度),您仍然无法表示所有实数。
@TM:但是 OP 并没有试图代表所有的实数。他试图表示所有精确的十进制数,这是有理数的一个子集,因此只能是可数无限的。如果他使用一组无限位作为十进制浮点类型,那么他会没事的。它将这些位用作二进制浮点类型,这会导致十进制数出现问题。
n
ntownsend

重复我在对斯基特先生的评论中所说的话:我们可以用十进制表示法表示 1/3、1/9、1/27 或任何有理数。我们通过添加一个额外的符号来做到这一点。例如,在数字的十进制扩展中重复的数字上方的一行。我们需要将十进制数表示为二进制数序列是 1) 二进制数序列,2) 小数点,以及 3) 一些其他符号来指示序列的重复部分。

Hehner 的引用符号 是这样做的一种方式。他使用引号符号来表示序列的重复部分。文章:http://www.cs.toronto.edu/~hehner/ratno.pdf 和 Wikipedia 条目:http://en.wikipedia.org/wiki/Quote_notation

没有什么说我们不能在我们的表示系统中添加一个符号,所以我们可以使用二进制引号表示法精确地表示十进制有理数,反之亦然。


如果我们知道循环在哪里开始和结束,那么这个符号系统就可以工作。人类非常擅长检测周期。但是,一般来说,计算机不是。为了能够有效地使用重复符号,计算机必须能够在计算后找出循环的位置。例如,对于数字 1/3,循环立即开始。但是对于数字 1/97,在您找到至少 96 位数字的答案之前,循环不会显示出来。 (实际上,您需要 96*2+1 = 193 位才能确定。)
实际上,计算机检测周期并不难。如果您阅读 Hehner 的论文,他描述了如何检测各种算术运算的周期。例如,在使用重复减法的除法算法中,当您看到以前看到的差异时,您就知道循环从哪里开始。
此外,问题是关于准确地表示数字。有时精确的表示意味着很多位。引用符号的美妙之处在于,Hehner 证明,与标准的 32 位固定长度表示相比,表示的大小平均节省了 31%。
A
Alan

BCD - Binary-coded Decimal - 表示是准确的。它们不是很节省空间,但在这种情况下,您必须为准确性做出权衡。


BCD 并不比任何其他基础更精确。示例:如何在 BCD 中准确表示 1/3?你不能。
BCD 是 DECIMAL 的精确表示,因此是其名称的“十进制”部分。 1/3 也没有精确的十进制表示。
T
ThibThib

这是一个很好的问题。

你所有的问题都是基于“我们如何表示一个数字?”

所有数字都可以用十进制表示或二进制(2 的补码)表示。他们全部 !!

但是有些(大多数)需要无限数量的元素(二进制位置为“0”或“1”,十进制表示为“0”、“1”到“9”)。

就像十进制表示中的 1/3(1/3 = 0.3333333...<- 有无限个“3”)

就像二进制中的 0.1( 0.1 = 0.00011001100110011.... <- 具有无限数量的“0011”)

一切都在这个概念中。由于您的计算机只能考虑有限的数字集(十进制或二进制),因此您的计算机中只能精确表示一些数字......

正如乔恩所说,3 是一个素数,它不是 10 的因数,所以 1/3 不能用以 10 为底的有限数量的元素来表示。

即使使用任意精度的算术,以 2 为底的编号位置系统也不能完全描述 6.1,尽管它可以表示 61。

对于 6.1,我们必须使用另一种表示法(如十进制表示法,或 IEEE 854,它允许以 2 或 10 为基数来表示浮点值)


您可以将 1/3 表示为分数本身。您不需要无限数量的位来表示它。您只需将其表示为分数 1/3,而不是取 1 并将其除以 3 的结果。有几个系统以这种方式工作。然后,您需要一种方法来使用标准 / * + - 和类似的运算符来处理分数的表示,但这很容易 - 您可以用笔和纸来完成这些操作,教计算机去做这没什么大不了的.
我说的是“二进制(2 的补码)表示”。因为,当然,使用其他表示可以帮助您用有限数量的元素来表示一些数字(对于其他一些,您将需要无限数量的元素)
D
Dan Lew

如果你用浮点数做一个足够大的数字(因为它可以做指数),那么你最终也会在小数点前出现不精确。所以我不认为你的问题是完全有效的,因为前提是错误的;移位 10 并不总是会产生更高的精度,因为在某些时候浮点数将不得不使用指数来表示数字的大小,并且也会因此而失去一些精度。


J
James

这与您不能以 10 为基数精确表示 1/3 的原因相同,您需要说 0.33333(3)。在二进制中,它是同一类型的问题,但只发生在不同的数字集上。


B
Boojum

(注意:我将在此处附加“b”以表示二进制数。所有其他数字均以十进制给出)

思考事物的一种方法是使用科学记数法。我们习惯于看到以科学计数法表示的数字,例如 6.022141 * 10^23。浮点数在内部使用类似的格式存储 - 尾数和指数,但使用 2 的幂而不是 10。

您的 61.0 可以用尾数和指数重写为 1.90625 * 2^5 或 1.11101b * 2^101b。将其乘以十并(移动小数点),我们可以这样做:

(1.90625 * 2^5) * (1.25 * 2^3) = (2.3828125 * 2^8) = (1.19140625 * 2^9)

或使用二进制尾数和指数:

(1.11101b * 2^101b) * (1.01b * 2^11b) = (10.0110001b * 2^1000b) = (1.00110001b * 2^1001b)

注意我们在那里做了什么来乘以数字。我们将尾数相乘并添加指数。然后,由于尾数大于 2,我们通过增加指数来标准化结果。就像我们对十进制科学计数法的数字进行运算后调整指数一样。在每种情况下,我们使用的值都具有二进制的有限表示,因此基本乘法和加法运算输出的值也产生了具有有限表示的值。

现在,考虑我们如何将 61 除以 10。我们首先将尾数 1.90625 和 1.25 相除。在十进制中,这给出了 1.525,一个不错的短数字。但是,如果我们将其转换为二进制,这是什么?我们将按照通常的方式进行 - 尽可能减去 2 的最大幂,就像将整数小数转换为二进制一样,但我们将使用 2 的负幂:

1.525         - 1*2^0   --> 1
0.525         - 1*2^-1  --> 1
0.025         - 0*2^-2  --> 0
0.025         - 0*2^-3  --> 0
0.025         - 0*2^-4  --> 0
0.025         - 0*2^-5  --> 0
0.025         - 1*2^-6  --> 1
0.009375      - 1*2^-7  --> 1
0.0015625     - 0*2^-8  --> 0
0.0015625     - 0*2^-9  --> 0
0.0015625     - 1*2^-10 --> 1
0.0005859375  - 1*2^-11 --> 1
0.00009765625...

哦哦。现在我们遇到了麻烦。事实证明,1.90625 / 1.25 = 1.525,当以二进制表示时是一个重复分数: 1.11101b / 1.01b = 1.10000110011...b 我们的机器只有这么多位来保存尾数,所以它们只会对分数进行四舍五入并假设超过某个点为零。将 61 除以 10 时看到的错误是:

1.100001100110011001100110011001100110011...b * 2^10b 比如说:1.100001100110011001100110b * 2^10b

正是尾数的这种舍入导致我们与浮点值相关联的精度损失。即使尾数可以精确表示(例如,当仅添加两个数字时),如果在标准化指数后尾数需要太多数字来适应,我们仍然会丢失数字。

当我们将十进制数字四舍五入到可管理的大小并只给出它的前几位时,我们实际上一直在做这种事情。因为我们用十进制表示结果,所以感觉很自然。但是,如果我们将小数四舍五入,然后将其转换为不同的基数,那么它看起来就像我们通过浮点四舍五入得到的小数一样难看。


N
Nick

我很惊讶没有人这么说:使用 continued fractions。任何有理数都可以用这种方式有限地表示为二进制。

一些例子:

1/3 (0.3333...)

0; 3

5/9 (0.5555...)

0; 1, 1, 4

10/43 (0.232558139534883720930...)

0; 4, 3, 3

9093/18478 (0.49209871198181621387596060179673...)

0; 2, 31, 7, 8, 5

从这里开始,有多种已知方法可以将整数序列存储在内存中。

除了以完美的准确性存储您的数字之外,连分数还有其他一些好处,例如最佳有理逼近。如果您决定提前终止连分数中的数字序列,则剩余的数字(当重新组合为分数时)将为您提供可能的最佳分数。这是如何找到 pi 的近似值:

Pi 的连分数:

3; 7, 15, 1, 292 ...

在 1 处终止序列,得到分数:

355/113

这是一个极好的有理近似。


但是你会如何用二进制表示呢?例如,15 需要 4 位来表示,但 292 需要 9。硬件(甚至软件)如何知道每个位之间的位边界在哪里?这是效率与准确性的权衡。
r
rachit_verma

在等式中

2^x = y ;  
x = log(y) / log(2)

因此,我只是想知道我们是否可以有一个二进制的对数基系统,例如,

 2^1, 2^0, 2^(log(1/2) / log(2)), 2^(log(1/4) / log(2)), 2^(log(1/8) / log(2)),2^(log(1/16) / log(2)) ........

这也许可以解决问题,所以如果你想用二进制写 32.41 之类的东西,那就是

2^5 + 2^(log(0.4) / log(2)) + 2^(log(0.01) / log(2))

或者

2^5 + 2^(log(0.41) / log(2))

D
Dima

问题是您并不真正知道该数字实际上是否正好是 61.0 。考虑一下:


float a = 60;
float b = 0.1;
float c = a + b * 10;

c的值是多少?它不完全是 61,因为 b 不是真正的 .1,因为 .1 没有精确的二进制表示。


J
John Calsbeek

数字 61.0 确实具有精确的浮点运算——但并非所有整数都如此。如果你编写了一个循环,将一个双精度浮点数和一个 64 位整数加一,最终你会达到一个 64 位整数完美地表示一个数字的点,但浮点不会——因为没有足够的有效位。

到达小数点右侧的近似点要容易得多。如果您开始以二进制浮点数写出所有数字,那会更有意义。

另一种思考方式是,当您注意到 61.0 可以完美地以 10 为底表示,并且移动小数点并不会改变这一点时,您正在执行乘以 10 的幂 (10^1, 10^-1 )。在浮点数中,乘以 2 的幂不会影响数字的精度。尝试将 61.0 反复除以 3,以说明完美精确的数字如何失去其精确表示。


M
Mark Ransom

有一个阈值,因为数字的含义已经从整数变为非整数。要表示 61,您有 6*10^1 + 1*10^0; 10^1 和 10^0 都是整数。 6.1是6*10^0 + 1*10^-1,但是10^-1是1/10,绝对不是整数。这就是你最终进入 Inexactville 的方式。


m
mP.

平行可以由分数和整数组成。如果没有很多小数,某些分数(例如 1/7)就不能以十进制形式表示。因为浮点是基于二进制的,所以特殊情况会发生变化,但会出现同样的精度问题。


z
zpasternack

有无限数量的有理数和有限数量的比特来表示它们。请参阅http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems


但即使有无限位数,如果你使用浮点二进制,你仍然不能准确地表示 0.1,就像你不能用十进制表示 1/3 一样,即使有无限位数。
@Jon那是不正确的:有无限个小数,例如,我可以准确地表达“三分之一”。现实世界的问题是物理上不可能有“无限数量”的小数或位。
对于那些刚刚加入的人,请参阅 Wikipedia article on 0.9999999999...
y
yan bellavance

你知道整数吗?每个位代表 2^n

2^4=16 2^3=8 2^2=4 2^1=2 2^0=1

浮点数相同(有一些区别),但位代表 2^-n 2^-1=1/2=0.5 2^-2=1/(2*2)=0.25 2^-3=0.125 2^-4=0.0625

浮点二进制表示:

符号指数分数(我认为不可见的 1 附加到分数) B11 B10 B9 B8 B7 B6 B5 B4 B3 B2 B1 B0


o
old_timer

上面的高分答案确定了它。

首先,您在问题中混合了基数 2 和基数 10,然后当您在右侧放置一个不可整除的数字时,您会遇到问题。就像十进制的 1/3,因为 3 不等于 10 的幂,或者二进制的 1/5 不等于 2 的幂。

另一个评论虽然永远不要使用等于浮点数,句号。即使它是一个精确的表示,在一些浮点系统中也有一些数字可以用不止一种方式准确表示(IEEE 对此很不好,这是一个可怕的浮点规范,所以会让人头疼)。这里没有什么不同,1/3 不等于计算器上的数字 0.3333333,无论小数点右侧有多少个 3。它是或可以足够接近但不相等。所以你会期望像 2*1/3 这样的东西不等于 2/3,具体取决于四舍五入。永远不要使用等于浮点数。


J
Joe

正如我们一直在讨论的,在浮点运算中,十进制 0.1 不能完美地用二进制表示。

浮点和整数表示为表示的数字提供网格或格子。算术完成后,结果会脱离网格,必须通过四舍五入将其放回网格上。示例是二进制网格上的 1/10。

如果我们像一位绅士建议的那样使用二进制编码的十进制表示,我们能否将数字保留在网格上?


十进制数字,当然。但这只是定义。你不能用十进制表示 1/3,就像你不能用二进制表示 0.1 一样。对于无限大的数字集,任何量化方案都会失败。
l
logbasex

一个简单的答案:计算机没有无限的内存来存储分数(在将十进制数表示为科学记数法形式之后)。根据双精度浮点数的 IEEE 754 标准,我们只有 53 位的限制来存储小数。欲了解更多信息:http://mathcenter.oxford.emory.edu/site/cs170/ieee754/


A
AMDG

其他20个答案已经总结的内容我就不重复了,简单回答一下:

您的内容中的答案:

为什么不能以两个数字为基数准确表示某些比率?

出于同样的原因,小数不足以表示某些比率,即分母包含除 2 或 5 以外的素因数的不可约分数,至少在其小数展开的尾数中总是有一个不定串。

为什么十进制数不能用二进制精确表示?

从表面上看,这个问题是基于对价值观本身的误解。任何数字系统都不足以以事物本身告诉您它既是数量的方式来表示任何数量或比率,同时也提供了关于表示的内在价值的解释。因此,所有定量表示和一般模型都是象征性的,只能在事后理解,即在教一个人如何阅读和解释这些数字之后。

由于模型是反映现实的真实的主观事物,因此我们不需要将二进制字符串严格解释为两个负幂和正幂的总和。相反,人们可能会观察到我们可以创建任意一组符号,这些符号使用以 2 为底或任何其他底数来精确地表示任何数字或比率。试想一下,我们可以用一个词甚至一个符号来指代所有的无限,而无需“显示无限”本身。

例如,我正在为混合数字设计二进制编码,以便我可以比 IEEE 754 浮点数具有更高的精度和准确度。在写这篇文章的时候,想法是有一个符号位,一个倒数位,一个标量的一定数量的位来确定要“放大”小数部分的多少,然后将剩余的位在混合数的整数部分,后者是定点数,如果设置了倒数位,则应将其解释为除以该数。这样做的好处是允许我通过使用具有终止小数扩展的倒数来表示具有无限小数扩展的数字,或者根据我的需要,直接作为分数,可能作为近似值。


S
Steve Summit

你不能用二进制精确地表示 0.1,因为你不能用传统的英制尺子测量 0.1 英寸。

英语标尺,就像二进制分数一样,都是一半。您可以测量半英寸,或四分之一英寸(当然是二分之一),八分之一,或十六分之一等。

但是,如果您想测量十分之一英寸,那么您就不走运了。它不到八分之一英寸,但超过十六分之一。如果您尝试更精确,您会发现它比 3/32 多一点,但比 7/64 少一点。我从来没有见过真正的尺子的等级比 64 更精细,但如果你算一算,你会发现 1/10 小于 13/128,大于 25/256,大于 51 /512。你可以继续做得越来越精细,达到 1024 和 2048 以及 4096 和 8192,但你永远找不到精确的标记,即使在无限精细的以 2 为底的尺子上,它也恰好对应于 1/10 或 0.1。

不过,你会发现一些有趣的东西。让我们看看我列出的所有近似值,对于每一个,明确记录 0.1 是更小还是更大:

小数小数 0.1 是... 0/1 1/2 0.5 小于 0 1/4 0.25 小于 0 1/8 0.125 小于 0 1/16 0.0625 大于 1 3/32 0.09375 大于 1 7/64 0.109375 小于 0 13/128 0.1015625 less 0 25/256 0.09765625 greater 1 51/512 0.099609375 greater 1 103/1024 0.1005859375 less 0 205/2048 0.10009765625 less 0 409/4096 0.099853515625 greater 1 819/8192 0.0999755859375 greater 1

现在,如果您阅读最后一列,您会得到 0001100110011。 1/10 的无限重复二进制分数是 0.0001100110011 并非巧合...


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅