【问题标题】:Why can't decimal numbers be represented exactly in binary?为什么十进制数不能用二进制精确表示?
【发布时间】:2010-11-08 12:13:20
【问题描述】:

已经向 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上会更好

标签: math floating-point


【解决方案1】:

如果你有足够的空间,可以精确地表示十进制数字 - 只是不能用浮点 二进制 点数字。如果您使用浮点 十进制 点类型(例如 .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 进制之外思考。呵呵
  • 是的,世界上有10种人——懂二进制的和不懂二进制的。
  • @JonSkeet:Ctrl+Alt+Delete 用两根手指会显得很别扭。
  • @muusbolla:不。十进制表示 1 和十进制表示 0.9... 表示的数字(在小数点后无限重复 9s)是相等的。也许最简单的方法是:让 x = 0.9...。请注意10x = 9.9....。因此9x = 10x - x = 9.9... - 0.9... = 99x = 9x = 1。还有其他方法可以看到这个,但我相信这是最简单的。
【解决方案2】:

例如,数字 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(假设是最低限度的),我们可以通过比较素因子分解来回答这个问题bq。如果q 有任何质因数不在b 的质因式分解中,我们将永远无法找到合适的n 来消除这些因数。

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

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

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

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

显然是真的

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

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

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

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

【讨论】:

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

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

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

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

更多信息:

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

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

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

【讨论】:

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

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

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

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

【讨论】:

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

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

【讨论】:

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

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

【讨论】:

    【解决方案7】:

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

    【讨论】:

      【解决方案8】:

      (注意:这里我会附加'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

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

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

      【讨论】:

        【解决方案9】:

        这是个好问题。

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

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

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

        类似于十进制表示的 1/3(1/3 = 0.3333333...

        就像二进制中的 0.1(0.1 = 0.00011001100110011....

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

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

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

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

        【讨论】:

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

        我很惊讶还没有人这么说:使用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。硬件(甚至软件)如何知道每个位之间的位边界在哪里?这是效率与准确性的权衡。
        【解决方案11】:

        在等式中

        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))
        

        【讨论】:

          【解决方案12】:

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

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

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

          【讨论】:

            【解决方案13】:

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

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

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

            【讨论】:

              【解决方案14】:

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

              【讨论】:

                【解决方案15】:

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

                【讨论】:

                  【解决方案16】:

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

                  【讨论】:

                  • 但是即使有无限位数,如果你使用浮动 binary 点,你仍然不能准确地表示 0.1,就像你不能一样即使有无限位数,也可以精确地用十进制表示 1/3。
                  • @Jon 这是不正确的:使用 无限 个小数,我 可以 例如表达“三分之一”完全。现实世界的问题是在物理上不可能拥有“无限数量”的小数或位。
                  • 对于那些刚刚加入的人,请参阅Wikipedia article on 0.9999999999...
                  【解决方案17】:

                  你知道整数吗?每个位代表 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

                  【讨论】:

                    【解决方案18】:

                    上面的高分答案成功了。

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

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

                    【讨论】:

                      【解决方案19】:

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

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

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

                      【讨论】:

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

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

                      【讨论】:

                        【解决方案21】:

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

                        您的内容中的答案:

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

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

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

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

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

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

                        【讨论】:

                          【解决方案22】:

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

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

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

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

                          fraction decimal 0.1 is... as 0/1
                          1/2 0.5 less 0
                          1/4 0.25 less 0
                          1/8 0.125 less 0
                          1/16 0.0625 greater 1
                          3/32 0.09375 greater 1
                          7/64 0.109375 less 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 并非巧合...

                          【讨论】:

                            猜你喜欢
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2021-10-26
                            • 1970-01-01
                            • 1970-01-01
                            • 2018-06-09
                            • 2014-08-14
                            • 2013-11-07
                            相关资源
                            最近更新 更多