Binary coded decimal: Difference between revisions

Content added Content deleted
m (syntax highlighting fixup automation)
m (Automated syntax highlighting fixup (second round - minor fixes))
Line 18: Line 18:
The 6502 is a bit different in that it has a special operating mode where all addition and subtraction is handled as binary-coded decimal. Like the 68000, this must be invoked ahead of time, rather than using the Intel method of doing the math normally and then correcting it after the fact. (This special operating mode won't work on the aforementioned Ricoh 2A03, which performs math in "normal" mode even if the decimal flag is set.)
The 6502 is a bit different in that it has a special operating mode where all addition and subtraction is handled as binary-coded decimal. Like the 68000, this must be invoked ahead of time, rather than using the Intel method of doing the math normally and then correcting it after the fact. (This special operating mode won't work on the aforementioned Ricoh 2A03, which performs math in "normal" mode even if the decimal flag is set.)


<syntaxhighlight lang=6502asm>sed ;set decimal flag; now all math is BCD
<syntaxhighlight lang="6502asm">sed ;set decimal flag; now all math is BCD
lda #$19
lda #$19
clc
clc
Line 53: Line 53:
=={{header|68000 Assembly}}==
=={{header|68000 Assembly}}==
The 68000 has special mathematics commands for binary-coded decimal. However, they only work at byte length, and cannot use immediate operands. Even adding by 1 this way requires you to load 1 into a register first.
The 68000 has special mathematics commands for binary-coded decimal. However, they only work at byte length, and cannot use immediate operands. Even adding by 1 this way requires you to load 1 into a register first.
<syntaxhighlight lang=68000devpac> MOVEQ #$19,D0
<syntaxhighlight lang="68000devpac"> MOVEQ #$19,D0
MOVEQ #1,D1
MOVEQ #1,D1
MOVEQ #0,D2
MOVEQ #0,D2
Line 84: Line 84:
=={{header|ALGOL 68}}==
=={{header|ALGOL 68}}==
Algol 68 does not have BCD as standard. This sample implements 2-digit unsigned packed decimal numbers, similar to the [[#PL/M|PL/M]] sample. The 2-digit numbers are then used to provide addition/subtraction of larger numbers.
Algol 68 does not have BCD as standard. This sample implements 2-digit unsigned packed decimal numbers, similar to the [[#PL/M|PL/M]] sample. The 2-digit numbers are then used to provide addition/subtraction of larger numbers.
<syntaxhighlight lang=algol68>BEGIN # implements packed BCD arithmetic #
<syntaxhighlight lang="algol68">BEGIN # implements packed BCD arithmetic #
INT x99 = ( 9 * 16 ) + 9; # maximum unsigned 2-digit BCD value #
INT x99 = ( 9 * 16 ) + 9; # maximum unsigned 2-digit BCD value #
# structure to hold BCD values #
# structure to hold BCD values #
Line 232: Line 232:
023456790012 - 011111111111 = 012345678901
023456790012 - 011111111111 = 012345678901
</pre>
</pre>

=={{header|ALGOL W}}==
=={{header|ALGOL W}}==
{{Trans|ALGOL 68}}
{{Trans|ALGOL 68}}
<syntaxhighlight lang=pascal>begin % implements packed BCD arithmetic %
<syntaxhighlight lang="pascal">begin % implements packed BCD arithmetic %
integer X99; % maximum unsigned 2-digit BCD value %
integer X99; % maximum unsigned 2-digit BCD value %
% structure to hold BCD values %
% structure to hold BCD values %
Line 398: Line 397:
023456790012 - 011111111111 = 012345678901
023456790012 - 011111111111 = 012345678901
</pre>
</pre>

=={{header|Forth}}==
=={{header|Forth}}==
This code implements direct BCD arithmetic using notes from Douglas Jones from the University of Iowa: https://homepage.cs.uiowa.edu/~jones/bcd/bcd.html#packed
This code implements direct BCD arithmetic using notes from Douglas Jones from the University of Iowa: https://homepage.cs.uiowa.edu/~jones/bcd/bcd.html#packed
<syntaxhighlight lang=Forth>
<syntaxhighlight lang="forth">
\ add two 15 digit bcd numbers
\ add two 15 digit bcd numbers
\
\
Line 430: Line 428:
99 1 bcd+ . 100 ok
99 1 bcd+ . 100 ok
</pre>
</pre>

=={{header|J}}==
=={{header|J}}==


Here, we represent hexadecimal numbers using J's constant notation, and to demonstrate bcd we generate results in that representation:
Here, we represent hexadecimal numbers using J's constant notation, and to demonstrate bcd we generate results in that representation:


<syntaxhighlight lang=J> bcd=: &.((10 #. 16 #.inv ". ::]) :. ('16b',16 hfd@#. 10 #.inv ]))
<syntaxhighlight lang="j"> bcd=: &.((10 #. 16 #.inv ". ::]) :. ('16b',16 hfd@#. 10 #.inv ]))
16b19 +bcd 1
16b19 +bcd 1
16b20
16b20
Line 449: Line 446:
For reference, here are decimal and binary representations of the above numbers:
For reference, here are decimal and binary representations of the above numbers:


<syntaxhighlight lang=J> (":,_16{.' '-.~'2b',":@#:) 16b19
<syntaxhighlight lang="j"> (":,_16{.' '-.~'2b',":@#:) 16b19
25 2b11001
25 2b11001
(":,_16{.' '-.~'2b',":@#:) 16b20
(":,_16{.' '-.~'2b',":@#:) 16b20
Line 464: Line 461:
25
25
NB. ...</syntaxhighlight>
NB. ...</syntaxhighlight>

=={{header|Julia}}==
=={{header|Julia}}==
Handles negative and floating point numbers (but avoid BigFloats due to very long decimal places from binary to decimal conversion).
Handles negative and floating point numbers (but avoid BigFloats due to very long decimal places from binary to decimal conversion).
<syntaxhighlight lang=ruby>const nibs = [0b0, 0b1, 0b10, 0b11, 0b100, 0b101, 0b110, 0b111, 0b1000, 0b1001]
<syntaxhighlight lang="ruby">const nibs = [0b0, 0b1, 0b10, 0b11, 0b100, 0b101, 0b110, 0b111, 0b1000, 0b1001]


"""
"""
Line 577: Line 573:
BCD 99 (UInt8[0x99]) + BCD 1 ((UInt8[0x01], 1)[1]) = BCD 100 ((UInt8[0x01, 0x00], 1))
BCD 99 (UInt8[0x99]) + BCD 1 ((UInt8[0x01], 1)[1]) = BCD 100 ((UInt8[0x01, 0x00], 1))
</pre>
</pre>

=={{header|Pascal}}==
=={{header|Pascal}}==
==={{header|Free Pascal}}===
==={{header|Free Pascal}}===
There exist a special unit for BCD, even with fractions.Obvious for Delphi compatibility.
There exist a special unit for BCD, even with fractions.Obvious for Delphi compatibility.
<syntaxhighlight lang=pascal>program CheckBCD;
<syntaxhighlight lang="pascal">program CheckBCD;
// See https://wiki.freepascal.org/BcdUnit
// See https://wiki.freepascal.org/BcdUnit
{$IFDEF FPC} {$MODE objFPC}{$ELSE} {$APPTYPE CONSOLE} {$ENDIF}
{$IFDEF FPC} {$MODE objFPC}{$ELSE} {$APPTYPE CONSOLE} {$ENDIF}
Line 618: Line 613:
99*99 =9801
99*99 =9801
</pre>
</pre>

=={{header|Phix}}==
=={{header|Phix}}==
=== using fbld and fbstp ===
=== using fbld and fbstp ===
The FPU maths is all as normal (decimal), it is only the load and store that convert from/to BCD.<br>
The FPU maths is all as normal (decimal), it is only the load and store that convert from/to BCD.<br>
While I supply everything in decimal, you could easily return and pass around the likes of acc and res.
While I supply everything in decimal, you could easily return and pass around the likes of acc and res.
<!--<syntaxhighlight lang=Phix>-->
<!--<syntaxhighlight lang="phix">-->
<span style="color: #008080;">without</span> <span style="color: #008080;">javascript_semantics</span> <span style="color: #000080;font-style:italic;">-- (not a chance!)</span>
<span style="color: #008080;">without</span> <span style="color: #008080;">javascript_semantics</span> <span style="color: #000080;font-style:italic;">-- (not a chance!)</span>
<span style="color: #7060A8;">requires</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"1.0.2"</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- #ilASM{fbld, fbstp} added</span>
<span style="color: #7060A8;">requires</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"1.0.2"</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- #ilASM{fbld, fbstp} added</span>
Line 678: Line 672:
The aaa, aas, aam, and aad instructions are also available.
The aaa, aas, aam, and aad instructions are also available.
Same output as above, of course
Same output as above, of course
<!--<syntaxhighlight lang=Phix>-->
<!--<syntaxhighlight lang="phix">-->
<span style="color: #008080;">without</span> <span style="color: #008080;">javascript_semantics</span> <span style="color: #000080;font-style:italic;">-- (not a chance!)</span>
<span style="color: #008080;">without</span> <span style="color: #008080;">javascript_semantics</span> <span style="color: #000080;font-style:italic;">-- (not a chance!)</span>
<span style="color: #7060A8;">requires</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"1.0.2"</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- #ilASM{aaa, etc} added</span>
<span style="color: #7060A8;">requires</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"1.0.2"</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- #ilASM{aaa, etc} added</span>
Line 710: Line 704:
With routines to convert between decimal and bcd, same output as above, of course.
With routines to convert between decimal and bcd, same output as above, of course.
No attempt has been made to support fractions or negative numbers...
No attempt has been made to support fractions or negative numbers...
<!--<syntaxhighlight lang=Phix>(phixonline)-->
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> <span style="color: #000080;font-style:italic;">-- (no requires() needed here)</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> <span style="color: #000080;font-style:italic;">-- (no requires() needed here)</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">bcd_decode</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">bcd</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">bcd_decode</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">bcd</span><span style="color: #0000FF;">)</span>
Line 767: Line 761:
<span style="color: #000000;">test3</span><span style="color: #0000FF;">(</span><span style="color: #000000;">99</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'+'</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">test3</span><span style="color: #0000FF;">(</span><span style="color: #000000;">99</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'+'</span><span style="color: #0000FF;">)</span>
<!--</syntaxhighlight>-->
<!--</syntaxhighlight>-->

=={{header|PL/M}}==
=={{header|PL/M}}==
{{works with|8080 PL/M Compiler}} ... under CP/M (or an emulator)
{{works with|8080 PL/M Compiler}} ... under CP/M (or an emulator)
The 8080 PL/M compiler supports packed BCD by wrapping the 8080/Z80 DAA instruction with the DEC built in function, demonstrated here. Unfortunately, I couldn't get the first use of DEC to yeild the correct result without first doing a shift operation. Not sure if this is a bug in the program, the compiler or the 8080 emulator or that I'm misunderstanding something...
The 8080 PL/M compiler supports packed BCD by wrapping the 8080/Z80 DAA instruction with the DEC built in function, demonstrated here. Unfortunately, I couldn't get the first use of DEC to yeild the correct result without first doing a shift operation. Not sure if this is a bug in the program, the compiler or the 8080 emulator or that I'm misunderstanding something...
This is basically {{Trans|Z80 Assembly}}
This is basically {{Trans|Z80 Assembly}}
<syntaxhighlight lang=pli>100H: /* DEMONSTRATE PL/M'S BCD HANDLING */
<syntaxhighlight lang="pli">100H: /* DEMONSTRATE PL/M'S BCD HANDLING */


BDOS: PROCEDURE( FN, ARG ); /* CP/M BDOS SYSTEM CALL */
BDOS: PROCEDURE( FN, ARG ); /* CP/M BDOS SYSTEM CALL */
Line 813: Line 806:


A more complex example, showing how the DEC function can be used to perform unsigned BCD addition and subtraction on arbitrary length BCD numbers.
A more complex example, showing how the DEC function can be used to perform unsigned BCD addition and subtraction on arbitrary length BCD numbers.
<syntaxhighlight lang=pli>100H: /* DEMONSTRATE PL/M'S BCD HANDLING */
<syntaxhighlight lang="pli">100H: /* DEMONSTRATE PL/M'S BCD HANDLING */


BDOS: PROCEDURE( FN, ARG ); /* CP/M BDOS SYSTEM CALL */
BDOS: PROCEDURE( FN, ARG ); /* CP/M BDOS SYSTEM CALL */
Line 912: Line 905:
023456790012 - 011111111111 = 012345678901
023456790012 - 011111111111 = 012345678901
</pre>
</pre>

=={{header|Rust}}==
=={{header|Rust}}==
Based on the Forth implementation re: how to implement BCD arithmetic in software. Uses operator overloading for new BCD type.
Based on the Forth implementation re: how to implement BCD arithmetic in software. Uses operator overloading for new BCD type.
<syntaxhighlight lang=Rust>
<syntaxhighlight lang="rust">
#[derive(Copy, Clone)]
#[derive(Copy, Clone)]
pub struct Bcd64 {
pub struct Bcd64 {
Line 970: Line 962:
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
</pre>
</pre>

=={{header|Wren}}==
=={{header|Wren}}==
{{libheader|Wren-check}}
{{libheader|Wren-check}}
Line 983: Line 974:


In what follows, the hex prefix '0x' is simply a way of representing BCD literals and has nothing to do with hexadecimal as such.
In what follows, the hex prefix '0x' is simply a way of representing BCD literals and has nothing to do with hexadecimal as such.
<syntaxhighlight lang=ecmascript>import "./check" for Check
<syntaxhighlight lang="ecmascript">import "./check" for Check
import "./math" for Int
import "./math" for Int
import "./str" for Str
import "./str" for Str
Line 1,073: Line 1,064:
0x99 + 1 = 0x100 or, in unpacked BCD, 100100001001 + 1 = 10000000000000000
0x99 + 1 = 0x100 or, in unpacked BCD, 100100001001 + 1 = 10000000000000000
</pre>
</pre>

=={{header|Z80 Assembly}}==
=={{header|Z80 Assembly}}==
The <code>DAA</code> function will convert an 8-bit hexadecimal value to BCD after an addition or subtraction is performed. The algorithm used is actually quite complex, but the Z80's dedicated hardware for it makes it all happen in 4 clock cycles, tied with the fastest instructions the CPU can perform.
The <code>DAA</code> function will convert an 8-bit hexadecimal value to BCD after an addition or subtraction is performed. The algorithm used is actually quite complex, but the Z80's dedicated hardware for it makes it all happen in 4 clock cycles, tied with the fastest instructions the CPU can perform.


<syntaxhighlight lang=z80>
<syntaxhighlight lang="z80">
PrintChar equ &BB5A ;Amstrad CPC kernel's print routine
PrintChar equ &BB5A ;Amstrad CPC kernel's print routine
org &1000
org &1000