汇编语言:为什么BCD存在?

12

我知道如果你不懂二进制,BCD 类型可能更加直观。 但我不知道为什么要使用这种编码方式,因为当表示大于 9 时,它会浪费 4 比特的空间。

此外,我认为 x86 只直接支持加减运算(可以通过 FPU 进行转换)。

这可能是来自旧机器或其他体系结构的限制吗?

10个回答

12

BCD算术对于精确的十进制计算非常有用,通常在金融应用、会计等方面是必需的。它还使得乘以/除以10的幂等操作更容易。但现在有更好的替代方案。

有一篇很好的维基百科文章讨论了其利弊。


1
"更好的替代方案"? 如果您使用硬件的BCD,我可以在C++中构建一个BigDecimal类型 - 这样肯定会很快。我不确定有什么比使用硬件数据类型更好的选择。 - S.Lott
5
我怀疑现代的x86 CPU并没有优化的BCD实现 - 它们可能是通过微码实现的,重点是兼容性而不是性能。 - Michael
1
IBM的POWER 6 CPU具有对DECFLOAT的硬件支持。 - Paul R

11

BCD在电子技术领域的极低端非常有用,当寄存器中的数值由某个输出设备显示时,它就能派上用场。例如,假设你有一台计算器,它有多个七段显示器用于显示数字。如果每个显示器都由单独的位控制那就很方便了。

虽然现代的x86处理器被用于这种类型的显示设备似乎不太可能,但x86已经存在了很长时间,并且ISA保持了很高的向后兼容性。


1
这是最好的答案。在7段显示器或类似的显示屏上显示非BCD数字是一个逻辑噩梦。 - Miloš Rašić

7

BCD自从原始的8086处理器就存在于现代x86 CPU中,所有的x86 CPU都兼容8086。在x86中,BCD运算用于支持早期的商业应用程序。现在,处理器本身中的BCD支持已不再实际使用。

请注意,BCD是十进制数的精确表示,而浮点数不是,硬件实现BCD比实现浮点数简单得多。这些问题在处理器只有不到一百万个晶体管且运行速度只有几兆赫时更加重要。


@Michael:我不记得BCD的x86指令了。你能提醒我一下吗? - John Saunders
@John,我能想到的是DAA,DAS(十进制调整[后]加法/减法)。可能还有其他一些,我已经有一段时间没玩了;-) - mjv
@mjv:谢谢。我完全忘记了那些东西。我几乎不记得曾经看到过使用它们的示例 - 那不是一个真实世界的例子。 - John Saunders

6

BCD虽然在空间上浪费,但它有一个优点,那就是它是一种"定长"格式,这使得在特定数字中找到第n个数字变得容易。

另一个优点是它允许对任意大小的数字进行精确算术计算。此外,使用上述提到的"定长"特性,这样的算术运算可以轻松地分成多个线程(并行处理)。


使用普通的二进制数字,也可以轻松地对任意大小的数字进行精确算术计算。 - Nubok
2
使用BCD,可以读入任意大小的十进制格式值,在其上执行计算,并以十进制格式写出,每个数字的时间恒定。如果任意大小数码格式使用二的幂次基来存储内容,则转换为/从十进制格式所需的每位时间将随着N的增大而增加。 - supercat
@nubok:如果你只是处理整数,那么这是正确的。但是如果你要处理实数,二进制表示就不太好用了,这就是所谓的浮点数。 - karatedog
如果使用基于二进制的大整数来表示一个大的十进制类型,你很快就会发现舍入是非常缓慢的——你必须除以10的某个大的幂次。所以,最终发生的是一个加法可能很快,但它仍然需要向下舍入到所需的精度,这意味着你的加法实际上是一个小的加法和一个大的除法。相当慢。BCD不存在这个问题。 - Eric Lagergren
多线程的论点并不令人信服,除非你指的是需要访问数字的十进制位数(这对于扩展精度的二进制BigInts来说非常慢)。如果您可以多线程执行BCD加法或乘法或其他操作,那么您也可以在二进制大整数的32位或64位块上进行多线程操作。(但通常您无法进行多线程或甚至SIMD,因为在加法时需要进行进位传播。) - Peter Cordes

5
我认为BCD在许多事情上都很有用,原因如上所述。一个似乎被忽视的显而易见的事情是提供一条从二进制到BCD和相反方向的指令。这在将ASCII数字转换为二进制进行算术运算时非常有用。
其中一位海报关于数字通常以ASCII存储的说法是错误的,实际上很多二进制数字存储是因为它更有效率。而将ASCII转换为二进制有点复杂。BCD是ASCII和二进制之间的一种过渡方式,如果有bsdtoint和inttobcd指令,将使得这样的转换变得非常容易。所有ASCII值必须转换为二进制进行算术运算。因此,BCD在ASCII到二进制转换中实际上是有用的。

4
现在,将数字以二进制格式存储并将其转换为十进制格式以显示是很常见的,但转换需要一些时间。如果数字的主要目的是显示或添加到将要显示的数字中,那么执行十进制格式的计算可能比执行二进制并转换为十进制更实用。许多具有数字读数器的设备和许多视频游戏都使用打包的BCD格式存储数字,每个字节存储两个数字。这就是为什么许多得分计数器在100万分之后会溢出,而不是某个2的幂值。如果硬件不支持打包BCD算术,则替代方案不是使用二进制,而是使用未打包的十进制。在显示时将打包的BCD转换为未打包的十进制可以轻松地逐位进行。相比之下,将二进制转换为十进制要慢得多,并且需要对整个数量进行操作。
顺便说一句,8086指令集是我见过的唯一一个具有“ASCII调整除法”和“ASCII调整乘法”的指令集,其中一个将一个字节乘以十,而另一个将其除以十。有趣的是,“0A”值是机器指令的一部分,替换不同的数字将导致这些指令乘以或除以其他数量,但这些指令未被记录为通用乘除常数指令。我想知道为什么这个功能没有被记录下来,因为它可能是有用的?
还有一点有趣的是,处理器用于添加或减去打包BCD的方法各不相同。许多执行二进制加法但使用标志位来跟踪在加法期间是否从第3位到第4位发生了进位;然后他们可能期望代码清理结果(例如PIC),提供一个操作码来清理加法但不是减法,提供一个操作码来清理加法和另一个来减法(例如x86),或者使用标志位来跟踪上一个操作是加法还是减法,并使用相同的操作码来清理两个操作(例如Z80)。一些使用单独的操作码进行BCD算术运算(例如68000),而一些使用标志位来指示加/减操作应该使用二进制还是BCD(例如6502派生物)。有趣的是,最初的6502以与二进制数学相同的速度执行BCD数学运算,但其CMOS衍生物需要为BCD运算额外的周期。

在x87中,还有FBLDFLSTP用于加载和存储BCD数字。一些现代架构具有十进制浮点数的硬件支持,例如Power6和IBM z10。 - phuclv

2
我确信之前链接的维基文章会提供更详细的信息,但我在IBM主机编程(使用PL/I)中使用了BCD。BCD不仅保证您可以查看字节的特定区域以找到单个数字 - 这有时很有用 - 而且还允许硬件应用简单的规则来计算所需的精度和比例,例如将两个数字相加或相乘。
据我回忆,在主机上,对BCD的支持是通过硬件实现的,那时它是表示浮点数的唯一选择。(我们说的是18年前的事情!)

一些适用于6502的浮点格式是基于十进制的。MOS技术的KIMath软件(以印刷形式出版)使用未打包的十进制尾数和二进制指数进行计算,并使用打包的十进制进行存储。 - supercat
当时我使用BCD将PC和大型机系统集成。 - olivecoder

1

当我在30多年前上大学时,我被告知BCD(COBOL中的COMP-3)是一个好的格式的原因。

现代硬件已经不再需要这些理由。我们有快速的二进制定点算术。我们不再需要通过为每个BCD数字添加偏移量来将BCD转换为可显示格式。我们很少将数字存储为每个数字8位,因此BCD每个数字只占用4位并不是非常有趣。

BCD是一个过时的遗物,应该留在过去。


0

现代计算强调编码捕捉设计逻辑,而非优化一点点CPU周期。省下的时间和/或内存的价值往往不值得写特殊的位级程序。

话虽如此,BCD仍然偶尔有用。

我能想到的一个例子是当你拥有一个巨大的数据库、平面文件或其他类似的大数据,它们以CSV等ASCII格式呈现。如果你只是在查找某些限制之间的值,BCD将非常有用。 如果在扫描所有这些数据时转换所有值将大大增加处理时间。


-1

很少有人能够理解十六进制表示的数值大小,因此在金融或会计领域中,显示或至少允许查看十进制的中间结果非常有用。


1
请记住,这个问题是关于汇编语言的“数据类型”的。在低级别上使用BCD并没有太多意义,这就是我的问题的核心所在。今天,大多数软件开发都是使用高级语言完成的,这些语言将以人类可读的形式显示信息。 - llazzaro
我认为这更像是固件的问题。你不能坐在机器前等待超过3秒钟的答案。最终真正重要的是最终用户得到的响应。 - user3237507
现代计算机只需要几十纳秒就能将二进制整数转换为ASCII十进制数字串。以二进制形式存储数字并不会限制您向用户显示它的方式。(BCD使得将其转换为十进制ASCII非常便宜,但对于除最小整数外的所有整数,在具有非常快速的二进制加/减/乘/除的现代计算机上进行计算会变得更加昂贵。) - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接