当分母不是2 ^ x的解时,计算机很难存储分数。这是因为小数点后的第一个数字为1/2,第二个为1/4(或1 /(2 ^ 1)和1 /(2 ^ 2))等。
当计算机将数字的小数部分存储为另一个整数(因此是准确的)时,为什么要处理各种舍入错误?
我唯一想到的就是处理重复的小数(以10为基数),但是可能有一个边缘解决方案(就像我们目前使用无穷大)。
当分母不是2 ^ x的解时,计算机很难存储分数。这是因为小数点后的第一个数字为1/2,第二个为1/4(或1 /(2 ^ 1)和1 /(2 ^ 2))等。
当计算机将数字的小数部分存储为另一个整数(因此是准确的)时,为什么要处理各种舍入错误?
我唯一想到的就是处理重复的小数(以10为基数),但是可能有一个边缘解决方案(就像我们目前使用无穷大)。
Answers:
实际上,有一些数字模式可以做到这一点。
二进制编码的十进制(BCD)算术计算机的基数为10。遇到这种情况的原因很少是因为它浪费空间:数字的每个数字最少要占用四位,而计算机最多可以存储四位。该空间中有16个值。(它也可能比较慢,但是可以使用硬件加速的BCD数学运算就可以了。)实际上,这正是大多数计算器所做的事情,这就是为什么某些类别的舍入问题是您永远不会在5美元的Casio上遇到的,它会在台式计算机上吃午餐。
您可以采用的另一种方法是使用有理数-即以整数形式存储的分子和分母。实际上,几乎所有语言都可以使用它,而且确实可以使用所有语言以本地二进制格式存储所有内容。问题在于,最终,用户可能不想看到463/13之类的分数,甚至不希望看到35和8/13之类的分数。他们希望看到35.615 ...,当您到达那里时,便会遇到所有典型的问题。另外,这种格式占用的空间更大,并且比浮点算术要慢得多,并且默认情况下您不会发现任何计算机使用此格式。
因此:计算机可以执行您想要的操作,但是它速度慢且浪费空间,因此只有在确实需要时才这样做。其余时间,浮点数的速度和空间节省是更好的折衷方案。
decimal
的实现方式:stackoverflow.com/a/5019178/174335它不是BCD,因为没有单独的十进制数字表示,也不是固定点。
存储分数的方法有很多,每种方法都有其优点和缺点。
到目前为止,浮点数是最流行的格式。它通过将符号,尾数和带符号的base-2指数编码为整数并将它们打包为一堆位来工作。例如,您可能有一个32位尾数0.5
(编码为0x88888888
)和一个32位有符号指数+3
(0x00000003
),它将解码为4.0
(0.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)一样精确到十进制。