Two's complement: Difference between revisions
Puppydrum64 (talk | contribs) |
Thundergnat (talk | contribs) m (syntax highlighting fixup automation) |
||
Line 13: | Line 13: | ||
=={{header|6502 Assembly}}== |
=={{header|6502 Assembly}}== |
||
===8-Bit=== |
===8-Bit=== |
||
< |
<syntaxhighlight lang="6502asm">LDA #%01010101 |
||
EOR #255 |
EOR #255 |
||
CLC |
CLC |
||
ADC #1 ;result: #%10101011</ |
ADC #1 ;result: #%10101011</syntaxhighlight> |
||
===16-bit=== |
===16-bit=== |
||
< |
<syntaxhighlight lang="6502asm">myVar equ $20 |
||
LDA #3 |
LDA #3 |
||
Line 39: | Line 39: | ||
LDA myVar+1 |
LDA myVar+1 |
||
ADC #0 |
ADC #0 |
||
STA myVar+1</ |
STA myVar+1</syntaxhighlight> |
||
=={{header|68000 Assembly}}== |
=={{header|68000 Assembly}}== |
||
< |
<syntaxhighlight lang="68000devpac">MOVE.L #3,D0 |
||
NEG.L D0 ;D0 = #$FFFFFFFD</ |
NEG.L D0 ;D0 = #$FFFFFFFD</syntaxhighlight> |
||
=={{header|8086 Assembly}}== |
=={{header|8086 Assembly}}== |
||
< |
<syntaxhighlight lang="asm">mov al,17 |
||
neg al ;8-bit |
neg al ;8-bit |
||
mov bx,4C00h |
mov bx,4C00h |
||
neg bx ;16-bit</ |
neg bx ;16-bit</syntaxhighlight> |
||
=={{header|ALGOL 68}}== |
=={{header|ALGOL 68}}== |
||
Line 55: | Line 55: | ||
<br> |
<br> |
||
Note: BIN a converts a to a BITS (bit-string) value, the NOT operator will flip the bits and the ABS operator will convert back to an integer, so <code>1 + ABS NOT BIN a</code> is a long-winded alternative to <code>-a</code>. Note in Algol 68, the BIN operator cannot be applied to negative integers, so <code>1 + ABS NOT BIN -3</code> won't work. |
Note: BIN a converts a to a BITS (bit-string) value, the NOT operator will flip the bits and the ABS operator will convert back to an integer, so <code>1 + ABS NOT BIN a</code> is a long-winded alternative to <code>-a</code>. Note in Algol 68, the BIN operator cannot be applied to negative integers, so <code>1 + ABS NOT BIN -3</code> won't work. |
||
< |
<syntaxhighlight lang="algol68">BEGIN |
||
INT a := 3; |
INT a := 3; |
||
print( ( -a, " ", 1 + ABS NOT BIN a, newline ) ) |
print( ( -a, " ", 1 + ABS NOT BIN a, newline ) ) |
||
END</ |
END</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 66: | Line 66: | ||
=={{header|ALGOL W}}== |
=={{header|ALGOL W}}== |
||
{{Trans|ALGOL 68}} |
{{Trans|ALGOL 68}} |
||
< |
<syntaxhighlight lang="algolw">begin |
||
integer a; |
integer a; |
||
a := 3; |
a := 3; |
||
write( i_w := 1, s_w := 1, -a, 1 + number( not bitstring( a ) ) ) |
write( i_w := 1, s_w := 1, -a, 1 + number( not bitstring( a ) ) ) |
||
end.</ |
end.</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 77: | Line 77: | ||
=={{header|ARM Assembly}}== |
=={{header|ARM Assembly}}== |
||
< |
<syntaxhighlight lang="arm assembly">MOV R0,#0x0000000F |
||
MOV R1,#1 |
MOV R1,#1 |
||
MVN R0,R0 ;flips the bits of R0, R0 = 0xFFFFFFF0 |
MVN R0,R0 ;flips the bits of R0, R0 = 0xFFFFFFF0 |
||
ADD R0,R0,R1 ;R0 = 0xFFFFFFF1</ |
ADD R0,R0,R1 ;R0 = 0xFFFFFFF1</syntaxhighlight> |
||
=={{header|C}}== |
=={{header|C}}== |
||
< |
<syntaxhighlight lang="c">int a = 3; |
||
a = -a;</ |
a = -a;</syntaxhighlight> |
||
=={{header|FreeBASIC}}== |
=={{header|FreeBASIC}}== |
||
In FreeBASIC as in C, if a number n is any integer type, then -n is the two's complement of n, with type preserved. |
In FreeBASIC as in C, if a number n is any integer type, then -n is the two's complement of n, with type preserved. |
||
< |
<syntaxhighlight lang="freebasic">Dim As Integer d1 = 2147483648, d2 = 2147483646 |
||
Dim As Integer b(1 To ...) = {-d1, -d1+1, -2, -1, 0, 1, 2, d1-2, d1-1} |
Dim As Integer b(1 To ...) = {-d1, -d1+1, -2, -1, 0, 1, 2, d1-2, d1-1} |
||
For i As Integer = 1 To Ubound(b) |
For i As Integer = 1 To Ubound(b) |
||
Print b(i); " -> "; -b(i) |
Print b(i); " -> "; -b(i) |
||
Next i |
Next i |
||
Sleep</ |
Sleep</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>0000000000000011 -> 1111111111111101</pre> |
<pre>0000000000000011 -> 1111111111111101</pre> |
||
=== inline assembly === |
=== inline assembly === |
||
< |
<syntaxhighlight lang="freebasic">Dim As Integer a = &b000011 |
||
Dim As Integer a2c, l |
Dim As Integer a2c, l |
||
#ifdef __FB_64BIT__ |
#ifdef __FB_64BIT__ |
||
Line 117: | Line 117: | ||
Print Bin(a, l); " -> "; Bin(a2c, l) |
Print Bin(a, l); " -> "; Bin(a2c, l) |
||
Sleep</ |
Sleep</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>-2147483648 -> 2147483648 |
<pre>-2147483648 -> 2147483648 |
||
Line 131: | Line 131: | ||
=={{header|J}}== |
=={{header|J}}== |
||
J uses twos complement natively: |
J uses twos complement natively: |
||
< |
<syntaxhighlight lang="j"> -3 |
||
_3</ |
_3</syntaxhighlight> |
||
We can see this by extracting bits representing the number. In this example, we limit ourselves to 8 bits: |
We can see this by extracting bits representing the number. In this example, we limit ourselves to 8 bits: |
||
< |
<syntaxhighlight lang="j"> (8#2)#:3 |
||
0 0 0 0 0 0 1 1 |
0 0 0 0 0 0 1 1 |
||
(8#2)#:-3 |
(8#2)#:-3 |
||
1 1 1 1 1 1 0 1</ |
1 1 1 1 1 1 0 1</syntaxhighlight> |
||
=={{header|Julia}}== |
=={{header|Julia}}== |
||
Line 146: | Line 146: | ||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
=== inline assembly === |
=== inline assembly === |
||
<!--< |
<!--<syntaxhighlight lang="phix">--> |
||
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> |
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> |
||
<span style="color: #004080;">integer</span> <span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0b000011</span><span style="color: #0000FF;">,</span> |
<span style="color: #004080;">integer</span> <span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0b000011</span><span style="color: #0000FF;">,</span> |
||
Line 161: | Line 161: | ||
} |
} |
||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%032b -> %032b\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">a2c</span><span style="color: #0000FF;">})</span> |
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%032b -> %032b\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">a2c</span><span style="color: #0000FF;">})</span> |
||
<!--</ |
<!--</syntaxhighlight>--> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 167: | Line 167: | ||
</pre> |
</pre> |
||
=== normal hll === |
=== normal hll === |
||
<!--< |
<!--<syntaxhighlight lang="phix">(phixonline)--> |
||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
||
<span style="color: #004080;">integer</span> <span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0b000011</span> |
<span style="color: #004080;">integer</span> <span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0b000011</span> |
||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%032b -> %032b\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">a</span><span style="color: #0000FF;">})</span> |
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%032b -> %032b\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">a</span><span style="color: #0000FF;">})</span> |
||
<!--</ |
<!--</syntaxhighlight>--> |
||
Same output (naturally the rhs is twice as long under 64 bit, in both cases) |
Same output (naturally the rhs is twice as long under 64 bit, in both cases) |
||
Line 178: | Line 178: | ||
<br> |
<br> |
||
Even though the original PL/M 8080 compiler only handles unsigned integers, <code>-A</code> two's complements <code>A</code>. |
Even though the original PL/M 8080 compiler only handles unsigned integers, <code>-A</code> two's complements <code>A</code>. |
||
< |
<syntaxhighlight lang="pli">100H: /* TWO'S COMPLEMENT *? |
||
/* CP/M BDOS SYSTEM CALL */ |
/* CP/M BDOS SYSTEM CALL */ |
||
Line 203: | Line 203: | ||
CALL PR$NL; |
CALL PR$NL; |
||
EOF</ |
EOF</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 218: | Line 218: | ||
Here we'll demonstrate twos complement on a 57 bit integer. |
Here we'll demonstrate twos complement on a 57 bit integer. |
||
<lang |
<syntaxhighlight lang="raku" line>use FixedInt; |
||
# Instantiate a new 57(!) bit fixed size integer |
# Instantiate a new 57(!) bit fixed size integer |
||
Line 231: | Line 231: | ||
say fixedint; # Echo the value to the console in decimal format |
say fixedint; # Echo the value to the console in decimal format |
||
say fixedint.bin; # Echo the value to the console in binary format</ |
say fixedint.bin; # Echo the value to the console in binary format</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>144114427045277101 |
<pre>144114427045277101 |
||
Line 242: | Line 242: | ||
This is illustrated by running the following code: |
This is illustrated by running the following code: |
||
< |
<syntaxhighlight lang="ecmascript">var a = 0 |
||
a = -a |
a = -a |
||
System.print(a) // -0</ |
System.print(a) // -0</syntaxhighlight> |
||
which produces 'negative zero' rather than just 'zero'. |
which produces 'negative zero' rather than just 'zero'. |
||
Line 251: | Line 251: | ||
We can therefore emulate how two's complement works on ''signed'' 32 bit integers by using the bitwise complement operator '''~''' to flip the bits as follows: |
We can therefore emulate how two's complement works on ''signed'' 32 bit integers by using the bitwise complement operator '''~''' to flip the bits as follows: |
||
< |
<syntaxhighlight lang="ecmascript">var pow32 = 2.pow(32) |
||
var pow31 = 2.pow(31) |
var pow31 = 2.pow(31) |
||
var bs = [-pow31, -pow31+1, -2, -1, 0, 1, 2, pow31-2, pow31-1] |
var bs = [-pow31, -pow31+1, -2, -1, 0, 1, 2, pow31-2, pow31-1] |
||
Line 258: | Line 258: | ||
if (b2 > pow31) b2 = b2 - pow32 |
if (b2 > pow31) b2 = b2 - pow32 |
||
System.print("%(b) -> %(b2)") |
System.print("%(b) -> %(b2)") |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 274: | Line 274: | ||
=={{header|XPL0}}== |
=={{header|XPL0}}== |
||
< |
<syntaxhighlight lang="xpl0">int I; char C; |
||
[I:= 123; |
[I:= 123; |
||
I:= (~I) + 1; |
I:= (~I) + 1; |
||
Line 281: | Line 281: | ||
C:= ~(C-1); |
C:= ~(C-1); |
||
IntOut(0, C); CrLf(0); |
IntOut(0, C); CrLf(0); |
||
]</ |
]</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 294: | Line 294: | ||
'''Zilog Z80''' |
'''Zilog Z80''' |
||
< |
<syntaxhighlight lang="z80">ld a,%00001111 |
||
neg ;returns %11110001 in a</ |
neg ;returns %11110001 in a</syntaxhighlight> |
||
'''Game Boy''' |
'''Game Boy''' |
||
< |
<syntaxhighlight lang="z80">ld a,%00001111 |
||
cpl ;game boy doesn't have NEG but it has CPL which flips all the bits. |
cpl ;game boy doesn't have NEG but it has CPL which flips all the bits. |
||
inc a ;returns %11110001 in a</ |
inc a ;returns %11110001 in a</syntaxhighlight> |
||
===16 Bit=== |
===16 Bit=== |
||
<code>NEG</code> and <code>CPL</code> only work on the accumulator <code>A</code>. |
<code>NEG</code> and <code>CPL</code> only work on the accumulator <code>A</code>. |
||
The following can be written to work with <code>BC</code>, <code>DE</code>, <code>HL</code>, <code>IX</code>, or <code>IY</code>. |
The following can be written to work with <code>BC</code>, <code>DE</code>, <code>HL</code>, <code>IX</code>, or <code>IY</code>. |
||
< |
<syntaxhighlight lang="z80">xor a ;ld a,0 |
||
sub c |
sub c |
||
ld c,a |
ld c,a |
||
sbc a ;loads &FF into A if "sub c" set the carry (borrow) flag. Otherwise, a remains zero. |
sbc a ;loads &FF into A if "sub c" set the carry (borrow) flag. Otherwise, a remains zero. |
||
sub b |
sub b |
||
ld b,a</ |
ld b,a</syntaxhighlight> |
Revision as of 19:17, 28 August 2022
You are encouraged to solve this task according to the task description, using any language you may know.
Two's complement is an important concept in representing negative numbers. To turn a positive integer negative, flip the bits and add one.
- Task
Show how to calculate the two's complement of an integer. (It doesn't necessarily need to be a 32 bit integer.)
6502 Assembly
8-Bit
LDA #%01010101
EOR #255
CLC
ADC #1 ;result: #%10101011
16-bit
myVar equ $20
LDA #3
STA myVar
LDA #0
STA myVar+1 ;equivalent C: uint16_t myVar = 3;
negate:
LDA myVar+1
EOR #255
STA myVar+1
LDA myVar
EOR #255
STA myVar
CLC
ADC #1
STA myVar
;this handles the case if we started with something where the low byte was zero.
LDA myVar+1
ADC #0
STA myVar+1
68000 Assembly
MOVE.L #3,D0
NEG.L D0 ;D0 = #$FFFFFFFD
8086 Assembly
mov al,17
neg al ;8-bit
mov bx,4C00h
neg bx ;16-bit
ALGOL 68
Algol 68 uses whatever representation the hardware the program is running on uses, which is almost certainly two's complement. So, as in C and most other languages, -a
two's complements a
. Using Algol 68's bit manipulation facilities, we can explicitely two's complement a positive integer, as shown in this example.
Note: BIN a converts a to a BITS (bit-string) value, the NOT operator will flip the bits and the ABS operator will convert back to an integer, so 1 + ABS NOT BIN a
is a long-winded alternative to -a
. Note in Algol 68, the BIN operator cannot be applied to negative integers, so 1 + ABS NOT BIN -3
won't work.
BEGIN
INT a := 3;
print( ( -a, " ", 1 + ABS NOT BIN a, newline ) )
END
- Output:
-3 -3
ALGOL W
begin
integer a;
a := 3;
write( i_w := 1, s_w := 1, -a, 1 + number( not bitstring( a ) ) )
end.
- Output:
-3 -3
ARM Assembly
MOV R0,#0x0000000F
MOV R1,#1
MVN R0,R0 ;flips the bits of R0, R0 = 0xFFFFFFF0
ADD R0,R0,R1 ;R0 = 0xFFFFFFF1
C
int a = 3;
a = -a;
FreeBASIC
In FreeBASIC as in C, if a number n is any integer type, then -n is the two's complement of n, with type preserved.
Dim As Integer d1 = 2147483648, d2 = 2147483646
Dim As Integer b(1 To ...) = {-d1, -d1+1, -2, -1, 0, 1, 2, d1-2, d1-1}
For i As Integer = 1 To Ubound(b)
Print b(i); " -> "; -b(i)
Next i
Sleep
- Output:
0000000000000011 -> 1111111111111101
inline assembly
Dim As Integer a = &b000011
Dim As Integer a2c, l
#ifdef __FB_64BIT__
l = 16
Asm
mov rax, [a]
neg rax
mov [a2c], rax
End Asm
#else
l = 8
Asm
mov eax, [a]
neg eax
mov [a2c], eax
End Asm
#endif
Print Bin(a, l); " -> "; Bin(a2c, l)
Sleep
- Output:
-2147483648 -> 2147483648 -2147483647 -> 2147483647 -2 -> 2 -1 -> 1 0 -> 0 1 -> -1 2 -> -2 2147483646 -> -2147483646 2147483647 -> -2147483647
J
J uses twos complement natively:
-3
_3
We can see this by extracting bits representing the number. In this example, we limit ourselves to 8 bits:
(8#2)#:3
0 0 0 0 0 0 1 1
(8#2)#:-3
1 1 1 1 1 1 0 1
Julia
In Julia as in C, if a number n is any integer type, then -n is the two's complement of n, with type preserved. This is true even if n is unsigned.
Phix
inline assembly
without js integer a = 0b000011, a2c #ilASM{ [32] mov eax,[a] neg eax mov [a2c],eax [64] mov rax,[a] neg rax mov [a2c],rax } printf(1,"%032b -> %032b\n",{a,a2c})
- Output:
00000000000000000000000000000011 -> 11111111111111111111111111111101
normal hll
with javascript_semantics integer a = 0b000011 printf(1,"%032b -> %032b\n",{a,-a})
Same output (naturally the rhs is twice as long under 64 bit, in both cases)
PL/M
... under CP/M (or an emulator)
Even though the original PL/M 8080 compiler only handles unsigned integers, -A
two's complements A
.
100H: /* TWO'S COMPLEMENT *?
/* CP/M BDOS SYSTEM CALL */
BDOS: PROCEDURE( FN, ARG ); DECLARE FN BYTE, ARG ADDRESS; GOTO 5;END;
/* CONSOLE OUTPUT ROUTINES */
PR$CHAR: PROCEDURE( C ); DECLARE C BYTE; CALL BDOS( 2, C ); END;
PR$NL: PROCEDURE; CALL PR$CHAR( 0DH ); CALL PR$CHAR( 0AH ); END;
PR$HEX: PROCEDURE( B ); /* PRINTS B AS A 2 DIGIT HEX NUMBER */
DECLARE B BYTE;
DECLARE D BYTE;
IF ( D := SHR( B, 4 ) ) > 9 THEN CALL PR$CHAR( ( D - 10 ) + 'A' );
ELSE CALL PR$CHAR( D + '0' );
IF ( D := B AND 0FH ) > 9 THEN CALL PR$CHAR( ( D - 10 ) + 'A' );
ELSE CALL PR$CHAR( D + '0' );
END PR$HEX ;
DECLARE A BYTE;
A = 1;
CALL PR$HEX( A );
CALL PR$CHAR( ' ' );
A = -A;
CALL PR$HEX( A );
CALL PR$NL;
EOF
- Output:
01 FF
Raku
By default Rakus integers are arbitrary sized, theoretically of infinite length. You can't really take the twos complement of an infinitely long number; so, we need to specifically use fixed size integers.
There is a module available from the Raku ecosystem that provides fixed size integer support, named (appropriately enough.) FixedInt.
FixedInt supports fixed bit size integers, not only 8 bit, 16 bit, 32 bit or 64 bit, but ANY integer size. 22 bit, 35 bit, 191 bit, whatever.
Here we'll demonstrate twos complement on a 57 bit integer.
use FixedInt;
# Instantiate a new 57(!) bit fixed size integer
my \fixedint = FixedInt.new: :57bits;
fixedint = (2³⁷ / 72 - 5¹⁷); # Set it to a large value
say fixedint; # Echo the value to the console in decimal format
say fixedint.bin; # Echo the value to the console in binary format
fixedint.=C2; # Take the twos complement
say fixedint; # Echo the value to the console in decimal format
say fixedint.bin; # Echo the value to the console in binary format
- Output:
144114427045277101 0b111111111111111110100111011001111000010101110110110101101 761030578771 0b000000000000000001011000100110000111101010001001001010011
Wren
Strictly speaking, Wren doesn't have integers. Instead all numbers are 'IEEE 754' 64 bit floating point values (their underlying C type being double) and negative numbers are therefore represented using the offset binary method rather than two's complement.
This is illustrated by running the following code:
var a = 0
a = -a
System.print(a) // -0
which produces 'negative zero' rather than just 'zero'.
However, when using the bitwise operators, Wren's VM emulates the corresponding operation in C by first converting the operands to unsigned 32 bit values, performing the operation and then converting the result back to a double.
We can therefore emulate how two's complement works on signed 32 bit integers by using the bitwise complement operator ~ to flip the bits as follows:
var pow32 = 2.pow(32)
var pow31 = 2.pow(31)
var bs = [-pow31, -pow31+1, -2, -1, 0, 1, 2, pow31-2, pow31-1]
for (b in bs) {
var b2 = ~b + 1
if (b2 > pow31) b2 = b2 - pow32
System.print("%(b) -> %(b2)")
}
- Output:
-2147483648 -> 2147483648 -2147483647 -> 2147483647 -2 -> 2 -1 -> 1 0 -> 0 1 -> -1 2 -> -2 2147483646 -> -2147483646 2147483647 -> -2147483647
XPL0
int I; char C;
[I:= 123;
I:= (~I) + 1;
IntOut(0, I); CrLf(0);
C:= -123;
C:= ~(C-1);
IntOut(0, C); CrLf(0);
]
- Output:
-123 123
Z80 Assembly
8-Bit
Zilog Z80
ld a,%00001111
neg ;returns %11110001 in a
Game Boy
ld a,%00001111
cpl ;game boy doesn't have NEG but it has CPL which flips all the bits.
inc a ;returns %11110001 in a
16 Bit
NEG
and CPL
only work on the accumulator A
.
The following can be written to work with BC
, DE
, HL
, IX
, or IY
.
xor a ;ld a,0
sub c
ld c,a
sbc a ;loads &FF into A if "sub c" set the carry (borrow) flag. Otherwise, a remains zero.
sub b
ld b,a