为什么计算机不将小数存储为第二个整数?


24

当分母不是2 ^ x的解时,计算机很难存储分数。这是因为小数点后的第一个数字为1/2,第二个为1/4(或1 /(2 ^ 1)和1 /(2 ^ 2))等。

当计算机将数字的小数部分存储为另一个整数(因此是准确的)时,为什么要处理各种舍入错误?

我唯一想到的就是处理重复的小数(以10为基数),但是可能有一个边缘解决方案(就像我们目前使用无穷大)。


8
与浮点/双精度类型相反,您应该查找小数类型的存储方式。
2012年

9
不知道这怎么更准确。小数点后的第一个数字是1/10,第二个是1/100,依此类推。如何更精确地得出舍入问题(如何表示1/3)?唯一的区别是可以精确表示的值。
马丁·约克

17
十进制浮点数(这就是您要引用的两个,只是以一种更尴尬的表示)并不比二进制浮点数更不准确。唯一的区别是哪些值无法表示,并且由于我们习惯了十进制系统,因此不会注意到十进制版本的错误。不,它们都不能代表所有有理数和无理数。

1
归根结底,它归结为效率。计算机是二进制的,使用该二进制表示的电路要复杂得多。今天,其重要性可能有所降低,但是在那时,这非常重要。同样,您选择将数字存储在计算机中的任何表示形式(在有限的空间中)也将具有一组可以表示的有限值,并且所有这些值在使用某些输入时都会出现舍入误差。带有尾数和指数的典型浮点格式提供的范围要大得多,而使用两个整数可能会更大。
Mindor先生2012年

1
我强烈建议您通读对问题“ 什么导致浮点舍入错误”的答案中引用的一些文章我刚刚更新了参考系列中上一篇文章的详细信息。特别要看一看为什么定点无法治愈您的浮点蓝调
Mark Booth

Answers:


35

实际上,有一些数字模式可以做到这一点。

二进制编码的十进制(BCD)算术计算机的基数为10。遇到这种情况的原因很少是因为它浪费空间:数字的每个数字最少要占用四位,而计算机最多可以存储四位。该空间中有16个值。(它也可能比较慢,但是可以使用硬件加速的BCD数学运算就可以了。)实际上,这正是大多数计算器所做的事情,这就是为什么某些类别的舍入问题是您永远不会在5美元的Casio上遇到的,它会在台式计算机上吃午餐。

您可以采用的另一种方法是使用有理数-即以整数形式存储的分子和分母。实际上,几乎所有语言都可以使用它,而且确实可以使用所有语言以本地二进制格式存储所有内容。问题在于,最终,用户可能不想看到463/13之类的分数,甚至不希望看到35和8/13之类的分数。他们希望看到35.615 ...,当您到达那里时,便会遇到所有典型的问题。另外,这种格式占用的空间更大,并且比浮点算术要慢得多,并且默认情况下您不会发现任何计算机使用此格式。

因此:计算机可以执行您想要的操作,但是它速度慢且浪费空间,因此只有在确实需要时才这样做。其余时间,浮点数的速度和空间节省是更好的折衷方案。


您不是在BCD段落中指的是四位(不是字节)吗?

3
另一个选择是定点算法,其中整数代表小数(如果有数字),例如,存储货币值(不包括小数或百分数的计算),其中1代表$ 0.01。
mattnz

1
@mattnz:是的,定点数是理性的一种特殊情况。
乔恩·普迪

太棒了,不知道计算器能做到这一点。
SomeKittens 2012年

3
还有第三种选择。带有十进制指数的浮点,例如C#decimal的实现方式:stackoverflow.com/a/5019178/174335它不是BCD,因为没有单独的十进制数字表示,也不是固定点。
乔伦

38

存储分数的方法有很多,每种方法都有其优点和缺点。

到目前为止,浮点数是最流行的格式。它通过将符号,尾数和带符号的base-2指数编码为整数并将它们打包为一堆位来工作。例如,您可能有一个32位尾数0.5(编码为0x88888888)和一个32位有符号指数+30x00000003),它将解码为4.00.5 * 2 ^ 3)。浮点数是快速的,因为它们是在硬件中实现的,并且它们的精度随绝对大小而定,即,数字越小,绝对精度越好,因此相对舍入误差在绝对大小下保持恒定。对于从连续域中采样的值(例如长度,声压级,光级等),浮点运算非常出色,因此,它们通常用于音频和图像处理以及统计分析和物理模拟。它们的最大缺点是它们不精确,也就是说,它们容易产生舍入误差,并且不能准确表示所有十进制小数。所有主流编程语言都具有某种浮点数。

固定点通过使用足够大的整数并将其一部分位隐式保留为小数部分来工作。例如,一个24.8位定点数为整数部分(包括符号)保留24位,为小数部分保留8位。将该数字右移8位可得到整数部分。当硬件浮点单元不常见或至少比整数浮点数慢时,定点数曾经很流行。虽然定点数在准确性方面较容易处理(如果仅仅是因为它们更易于推论),则它们几乎在其他所有方面都不如浮点数–精度较低,范围较小并且存在额外的误差需要进行运算来更正隐式移位的计算,今天的定点数学通常比浮点数学慢。

小数类型的工作方式与浮点数或定点数非常相似,但是它们采用的是十进制系统,即它们的指数(隐式或显式)编码为10的幂,而不是2的幂。例如,十进制数可以编码尾数为23456,指数为-2,这将扩展为234.56。由于算术不是硬连接到CPU的,因此小数比浮点运算要慢,但是它们对于涉及十进制数并且需要精确数字的任何对象都是理想的,四舍五入发生在明确定义的位置-财务计算,记分板等。某些编程语言内置有十进制类型(例如C#),其他语言则需要库来实现。请注意,虽然小数可以精确地表示非重复的小数,但其精度并不比浮点数更好。选择小数仅表示您可以精确地表示可以在十进制系统中表示的数字(就像浮点数可以精确表示二进制分数一样)。

有理数存储分子和分母,通常使用某种bignum整数类型(这种数字类型可以增长到计算机内存限制所允许的大小)。这是唯一可以准确地对数字(例如1/3或)进行建模3/17以及对其进行运算的数据类型-与其他数据类型不同,有理数将为诸如3 * 1/3。数学非常简单,尽管提出一种有效的分解算法非常具有挑战性。某些编程语言中内置有有理类型(例如Common Lisp)。理性的缺点包括它们运行缓慢(许多操作需要减少分数并分解其成分),并且许多常见的操作难以实施或无法实现,并且大多数实现会在这种情况发生时(例如,当您调用sin()在理性上)。

BCD(二进制编码的十进制)使用“半字节”(4位组)对单个数字进行编码;由于半字节可以保存16个不同的值,而十进制数仅需要10个,因此每个半字节有6个“非法”值。与十进制一样,BCD数字也是十进制精确的,也就是说,对十进制数字进行的计算就像使用笔和纸进行计算一样。BCD的算术规则有些笨拙,但好处是将它们转换为字符串比使用其他某些格式更容易,这对于嵌入式系统等资源匮乏的环境尤其有用。

字符串,是的,普通的旧字符串也可以用来表示小数。从技术上讲,这与BCD非常相似,只是有一个显式的小数点,并且每个十进制数字使用一个完整的字节。这样,该格式很浪费(在256个可能的值中仅使用11个),但是比BCD解析和生成起来更容易。另外,由于所有使用的值都是“不可怀疑的”,无害的,与平台无关的,因此字符串编码的数字可以毫无问题地在网络上传输。直接在字符串上执行算术运算是很罕见的,但是有可能,而且当您这样做时,它们与其他十进制格式(十进制和BCD)一样精确到十进制。


当然,由于定点表示不包含尾数,因此32位定点比32位浮点具有更高的精度。
2012年

4
@han:取决于您要存储的号码的大小。无论数字大小,浮点数都会(大致)为您提供相同的精度,而仅当您要存储的数字完全适合其范围时,固定点才会为您提供全精度。
Leo

@han不一定,两者仍然可以表示2 ^ 32个不同的值。不论显示形式如何,携带的信息量都是相同的。范围和精度是并驾齐驱的,因此在某些方面,定点算法可以更精确。如果您知道可以使用的限制,则可以避免讨厌的随机取整问题。
zxcdw 2012年

@han:它们具有相同的精度(或几乎相同)。区别在于,对于定点数,精度(例如,从一个数字到其后继数字的离散步长)是恒定的,就像整数一样,而对于浮点数,则其精度与绝对值大致呈线性增长-浮点数数字1.0的精度比数字10,000,000.0(大约高一百万倍)更高。
tdammers,2012年

6

浮点数表示很大范围的值,这在您不事先知道值可能是什么时非常有用,但这是一个折衷方案。用第二个整数表示1/10 ^ 100无效。

某些语言(和某些库)具有其他特征。Lisp传统上具有无限精度的整数。Cobol的计算使用定点十进制数字。

您必须选择适合问题域的数字表示形式。


1

听起来您正在描述定点数

请记住,将数字的小数部分存储在一个单独的位置上与创建一个两倍长的单个空间完全相同,并且将整个和小数部分存储在两个独立的半部分中。换句话说,这与将数字存储为整数相同,只是简单地假定固定数量的小数位。

通常,浮点数是使用科学计数法的二进制形式存储的,因为通常重要的是有效数字。但是,还有许多其他方法。定点十进制数字通常用于存储货币值,其中精度对于小数位数一定是至关重要的,但是所需的十进制数字永远不变。


1

那将被称为BCD,我认为如果您确实愿意,您仍然可以使用它。但是,由于:

  1. 您很少会遇到带有64位浮点的舍入错误
  2. 它使算术复杂而低效
  3. 每4位浪费6个值

BCD数学在早期的8位微处理器系统中被大量使用。的确,在一个流行的微处理器(6502)上,BCD的加/减与字节的速度一样快。电子游戏经常使用BCD数学来保持得分。对于1,000,000分的换行没有特殊处理。取而代之的是,在“ 99 99 99”上加1会产生“ 00 00 00”,并带有一个被忽略的进位。与将二进制值转换为可显示格式的成本相比,在BCD上添加分数的额外开销很小。
超级猫

1

简短的答案是浮点设计用于科学计算。它可以存储(最多)指定数量的有效数字,这与大多数科学计算中测量精度的方式非常吻合。

这在很大程度上倾向于由硬件来支持,因为科学计算往往是从硬件支持中受益最大的方法。例如,财务计算通常使用其他格式进行,但财务软件通常无法进行足够的实际计算,即使仅软件支持必需的格式,对于大多数财务软件而言,性能仍然完全合适。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.