Two's complement
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
AArch64 Assembly
/* ARM assembly AARCH64 Raspberry PI 3B */
/* program bincompl64.s */
/*******************************************/
/* Constantes file */
/*******************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc"
/*********************************/
/* Initialized data */
/*********************************/
.data
szMessDebutPgm: .asciz "Program 64 bits start. \n"
szMessFinOK: .asciz "Program normal end. \n"
szMessError: .asciz "Error detected !!!!. \n"
szMessNumber: .asciz "Start number : "
szMessResUns: .asciz "Result unsigned : "
szMessResS: .asciz "Result signed : "
szMessResMvn: .asciz "Result with mvn instruction : "
szCarriageReturn: .asciz "\n"
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
.align 4
sZoneConv: .skip 24
/*********************************/
/* code section */
/*********************************/
.text
.global main
main:
ldr x0,qAdrszMessDebutPgm
bl affichageMess // start message
mov x4,12345 // number
mov x0,x4
ldr x1,qAdrsZoneConv
bl conversion10 // decimal conversion
mov x0,3
ldr x1,qAdrszMessNumber
ldr x2,qAdrsZoneConv
ldr x3,qAdrszCarriageReturn
bl displayStrings
mov x0,x4
neg x0,x0
ldr x1,qAdrsZoneConv
bl conversion10 // decimal conversion unsigned
mov x0,3
ldr x1,qAdrszMessResUns
ldr x2,qAdrsZoneConv
ldr x3,qAdrszCarriageReturn
bl displayStrings
mov x0,x4
neg x0,x0
ldr x1,qAdrsZoneConv
bl conversion10S // decimal conversion signed
mov x0,3
ldr x1,qAdrszMessResS
ldr x2,qAdrsZoneConv
ldr x3,qAdrszCarriageReturn
bl displayStrings
mov x0,x4
mvn x0,x0 // use mvn instruction
ldr x1,qAdrsZoneConv
bl conversion10S // decimal conversion signed
mov x0,3
ldr x1,qAdrszMessResMvn
ldr x2,qAdrsZoneConv
ldr x3,qAdrszCarriageReturn
bl displayStrings
ldr x0,qAdrszMessFinOK
bl affichageMess
100: // standard end of the program
mov x0,0 // return code
mov x8,EXIT // request to exit program
svc 0 // perform the system call
qAdrszMessDebutPgm: .quad szMessDebutPgm
qAdrszMessFinOK: .quad szMessFinOK
qAdrszMessError: .quad szMessError
qAdrszCarriageReturn: .quad szCarriageReturn
qAdrsZoneConv: .quad sZoneConv
qAdrszMessNumber: .quad szMessNumber
qAdrszMessResUns: .quad szMessResUns
qAdrszMessResS: .quad szMessResS
qAdrszMessResMvn: .quad szMessResMvn
/***************************************************/
/* display multi strings */
/* new version 24/05/2023 */
/***************************************************/
/* x0 contains number strings address */
/* x1 address string1 */
/* x2 address string2 */
/* x3 address string3 */
/* x4 address string4 */
/* x5 address string5 */
/* x6 address string6 */
displayStrings: // INFO: displayStrings
stp x7,lr,[sp,-16]! // save registers
stp x2,fp,[sp,-16]! // save registers
add fp,sp,#32 // save paraméters address (4 registers saved * 8 bytes)
mov x7,x0 // save strings number
cmp x7,#0 // 0 string -> end
ble 100f
mov x0,x1 // string 1
bl affichageMess
cmp x7,#1 // number > 1
ble 100f
mov x0,x2
bl affichageMess
cmp x7,#2
ble 100f
mov x0,x3
bl affichageMess
cmp x7,#3
ble 100f
mov x0,x4
bl affichageMess
cmp x7,#4
ble 100f
mov x0,x5
bl affichageMess
cmp x7,#5
ble 100f
mov x0,x6
bl affichageMess
100:
ldp x2,fp,[sp],16 // restaur registers
ldp x7,lr,[sp],16 // restaur registers
ret
/********************************************************/
/* File Include fonctions */
/********************************************************/
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"
- Output:
Program 64 bits start. Start number : 12345 Result unsigned : 18446744073709539271 Result signed : -12345 Result with mvn instruction : -12346 Program normal end.
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
Asymptote
int d = 1234567;
int b[] = {-d,-d + 1,-2,-1,0,1,2,d -2,d -1};
for(int i = 0; i < b.length; ++i) {
write(string(b[i]) + " -> " + string(-b[i]));
}
BASIC
Applesoft BASIC
The GW-BASIC solution works without any changes.
BASIC256
d = 1234567
dim b = {-d, -d+1, -2, -1, 0, 1, 2, d-2, d-1}
for i = 0 to b[?]-1
print b[i]; " -> "; -b[i]
next i
- Output:
Similar as Craft Basic entry.
Chipmunk Basic
10 d = 1234567
20 dim b(8)
30 b(0) = -d
40 b(1) = -d+1
50 b(2) = -2
60 b(3) = -1
70 b(4) = 0
80 b(5) = 1
90 b(6) = 2
100 b(7) = d-2
110 b(8) = d-1
120 for i = 0 to ubound(b)
130 print b(i);"-> ";-b(i)
140 next i
- Output:
Similar as Craft Basic entry.
Craft Basic
let d = 1234567
dim b[d * -1, d * -1 + 1, -2, -1, 0, 1, 2, d - 2, d - 1]
arraysize s, b
for i = 0 to s - 1
print b[i], " : ", b[i] * -1
next i
end
- Output:
-1234567 : 1234567 -1234566 : 1234566 -2 : 2 -1 : 1 0 : 0 1 : -1 2 : -2 1234565 : -1234565 1234566 : -1234566
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
Gambas
Public d As Integer = 1234567
Public b As Integer[] = [-d, -d + 1, -2, -1, 0, 1, 2, d - 2, d - 1]
Public Sub Main()
For i As Integer = 0 To b.Count - 1
Print b[i]; " -> "; -b[i] ' * -1
Next
End
- Output:
Same as Craft Basic entry.
GW-BASIC
10 LET D = 1234567
20 DIM B(8)
30 LET B(0) = -D
40 LET B(1) = -D + 1
50 LET B(2) = -2
60 LET B(3) = -1
70 LET B(4) = 0
80 LET B(5) = 1
90 LET B(6) = 2
100 LET B(7) = D - 2
110 LET B(8) = D - 1
120 FOR I = 0 TO 8
130 PRINT B(I); "-> "; -B(I)
140 NEXT I
150 END
- Output:
-1234567 -> 1234567 -1234566 -> 1234566 -2 -> 2 -1 -> 1 0 -> 0 1 -> -1 2 -> -2 1234565 -> -1234565 1234566 -> -1234566
Minimal BASIC
The GW-BASIC solution works without any changes.
MSX Basic
The GW-BASIC solution works without any changes.
PureBasic
Define d.l
d = 1234567
Dim b.l(8)
b(0) = -d
b(1) = -d + 1
b(2) = -2
b(3) = -1
b(4) = 0
b(5) = 1
b(6) = 2
b(7) = d - 2
b(8) = d - 1
OpenConsole()
For i = 0 To ArraySize(b()) - 1
PrintN(Str(b(i)) + " -> " + Str(-b(i)))
Next i
Input()
CloseConsole()
- Output:
Similar as Craft Basic entry.
QBasic
The QB64 solution works without any changes.
QB64
Dim d As Long
d = 1234567
Dim b(8) As Long
b(0) = -d
b(1) = -d + 1
b(2) = -2
b(3) = -1
b(4) = 0
b(5) = 1
b(6) = 2
b(7) = d - 2
b(8) = d - 1
For i = 0 To UBound(b)
Print b(i); " -> "; -b(i) ' * -1
Next i
- Output:
Similar as Craft Basic entry.
Just BASIC
d = 1234567
dim b(8)
b(0) = d * -1
b(1) = d * -1 + 1
b(2) = -2
b(3) = -1
b(4) = 0
b(5) = 1
b(6) = 2
b(7) = d - 2
b(8) = d - 1
for i = 0 to 8
print b(i); " -> "; b(i) * -1
next i
- Output:
Similar as Craft Basic entry.
XBasic
PROGRAM "Two's complement"
VERSION "0.0000"
DECLARE FUNCTION Entry ()
FUNCTION Entry ()
d = 1234567
DIM b[8]
b[0] = -d
b[1] = -d+1
b[2] = -2
b[3] = -1
b[4] = 0
b[5] = 1
b[6] = 2
b[7] = d-2
b[8] = d-1
FOR i = 0 TO UBOUND(b[])
PRINT b[i]; " -> "; -b[i]
NEXT i
END FUNCTION
END PROGRAM
- Output:
Similar as Craft Basic entry.
Yabasic
d = 1234567
dim b(8)
b(0) = -d
b(1) = -d+1
b(2) = -2
b(3) = -1
b(4) = 0
b(5) = 1
b(6) = 2
b(7) = d-2
b(8) = d-1
for i = 0 to arraysize(b(), 1)
print b(i), " -> ", -b(i)
next i
- Output:
Similar as Craft Basic entry.
C
int a = 3;
a = -a;
C++
In C++ the two's complement of an integer 'n' is its arithmetic negation '-n'.
The two's complement of an integer 'n' can also be calculated by adding 1 to its bitwise complement '~n'.
#include <cstdint>
#include <iostream>
#include <iomanip>
#include <vector>
#include <bitset>
std::string to_hex(const int32_t number) {
std::stringstream stream;
stream << std::setfill('0') << std::setw(8) << std::hex << number;
return stream.str();
}
std::string to_binary(const int32_t number) {
std::stringstream stream;
stream << std::bitset<16>(number);
return stream.str();
}
int32_t twos_complement(const int32_t number) {
return ~number + 1;
}
std::string to_upper_case(std::string str) {
for ( char& ch : str ) {
ch = toupper(ch);
}
return str;
}
int main() {
std::vector<int32_t> examples = { 0, 1, -1, 42 };
std::cout << std::setw(9) << "decimal" << std::setw(12) << "hex"
<< std::setw(17) << "binary" << std::setw(25) << "two's complement" << std::endl;
std::cout << std::setw(6) << "-----------" << std::setw(12) << "--------"
<< std::setw(20) << "----------------" << std::setw(20) << "----------------" << std::endl;
for ( const int32_t& example : examples ) {
std::cout << std::setw(6) << example << std::setw(17) << to_upper_case(to_hex(example))
<< std::setw(20) << to_binary(example) << std::setw(13) << twos_complement(example) << std::endl;
}
}
- Output:
decimal hex binary two's complement ----------- -------- ---------------- ---------------- 0 00000000 0000000000000000 0 1 00000001 0000000000000001 -1 -1 FFFFFFFF 1111111111111111 1 42 0000002A 0000000000101010 -42
COBOL
IDENTIFICATION DIVISION.
PROGRAM-ID. Twos_complement.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 d PIC S9(7) COMP-5 VALUE 1234567.
01 neg-d PIC S9(7) COMP-5.
01 neg-d1 PIC S9(7) COMP-5.
01 neg-b PIC S9(7) COMP-5.
01 d2 PIC S9(7) COMP-5.
01 d1 PIC S9(7) COMP-5.
01 b OCCURS 9 TIMES PIC S9(7) COMP-5.
01 i PIC 9(2) VALUE 1.
PROCEDURE DIVISION.
COMPUTE neg-d = -d
COMPUTE neg-d1 = -d + 1
COMPUTE d2 = d - 2
COMPUTE d1 = d - 1
MOVE neg-d TO b(1)
MOVE neg-d1 TO b(2)
MOVE -2 TO b(3)
MOVE -1 TO b(4)
MOVE 0 TO b(5)
MOVE 1 TO b(6)
MOVE 2 TO b(7)
MOVE d2 TO b(8)
MOVE d1 TO b(9)
PERFORM VARYING i FROM 1 BY 1 UNTIL i > 9
COMPUTE neg-b = -b(i)
DISPLAY b(i) " -> " neg-b
END-PERFORM
STOP RUN.
Delphi
procedure TwosCompliment(Memo: TMemo);
var N: integer;
begin
N:=123456789;
Memo.Lines.Add(Format('N=%10d $%0.8x',[N,N]));
Memo.Lines.Add('');
Memo.Lines.Add('N:=(N xor $FFFFFFFF)+1');
N:=(N xor $FFFFFFFF)+1;
Memo.Lines.Add('');
Memo.Lines.Add(Format('N=%10d $%0.8x',[N,N]));
end;
- Output:
N= 123456789 $075BCD15 N:=(N xor $FFFFFFFF)+1 N=-123456789 $F8A432EB Elapsed Time: 5.206 ms.
Forth
Forth uses two's complement internally. One can use the 'base' variable to switch from one base to another.
: 2s'complement base @ swap dup negate swap 2 base ! u. u. base ! ;
25 2s'complement
- Output:
11001 1111111111111111111111111111111111111111111111111111111111100111 ok
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
Java
In Java the two's complement of an integer 'n' is its arithmetic negation '-n'.
The two's complement of an integer 'n' can also be calculated by adding 1 to its bitwise complement '~n'.
import java.util.List;
public final class TwosComplement {
public static void main(String[] args) {
List<Integer> examples = List.of( 0, 1, -1, 42 );
System.out.println(String.format("%9s%12s%24s%34s", "decimal", "hex", "binary", "two's complement"));
System.out.println(
String.format("%6s%12s%24s%32s", "-----------", "--------", "----------", "----------------"));
for ( int example : examples ) {
System.out.println(String.format("%5d%18s%36s%13d",
example, toHex(example), toBinary(example), twosComplement(example)));
}
}
private static String toHex(int number) {
return String.format("%8s", Integer.toHexString(number).toUpperCase()).replace(" ", "0");
}
private static String toBinary(int number) {
return String.format("%32s", Integer.toBinaryString(number)).replace(" ", "0");
}
private static int twosComplement(int number) {
return ~number + 1;
}
}
- Output:
decimal hex binary two's complement ----------- -------- ---------- ---------------- 0 00000000 00000000000000000000000000000000 0 1 00000001 00000000000000000000000000000001 -1 -1 FFFFFFFF 11111111111111111111111111111111 1 42 0000002A 00000000000000000000000000101010 -42
Jakt
fn main() {
let n = 0xabcdeabcdeu64
println("{:064b}", n)
println("{:064b}", ~n + 1)
println("{:064b}", -n) // Same result
}
- Output:
0000000000000000000000001010101111001101111010101011110011011110 1111111111111111111111110101010000110010000101010100001100100010 1111111111111111111111110101010000110010000101010100001100100010
jq
Works with jq, the C implementation of jq
Works with gojq, the Go implementation of jq
In this entry, a function for emitting the binary array (an array of 0s and 1s) corresponding to the twos-complement of a non-negative integer is defined. See the comments below for details.
The second illustration is in accordance with the Jakt entry.
The jq "bitwise" module is used.
include "bitwise" {search: "."}; # see above
# Arithmetically add 1 to the non-negative integer represented by the
# bit stream `stream`, in which the least significant bit is first.
def plusplus(stream):
foreach (stream, null) as $bit ({carry: 1};
if $bit == null
then if .carry == 1 then .emit = 1 else empty end
elif .carry == 0 then .emit = $bit
## .carry is now 1:
elif $bit == 0 then {carry: 0, emit: 1 }
else .emit = 0
end )
| .emit;
# input: a non-negative integer
# output: the bit array (with most-significant bit first and with length $width)
# corresponding to the twos-complement of the input integer, it being understood
# that all but the ($width-1) least significant bits of the binary representation of . are dropped.
def twosComplement($width):
def rpad($width): ($width - length) as $l | . + [range(0; $l) | 0];
if . < 0 then "input of twosComplement should be non-negative" | error
else [flipbits( [limit($width; bitwise)] | rpad($width) | .[] )]
| [limit($width; plusplus(.[]))]
| reverse
end;
def illustrate($width):
"decimal: \(.)",
"binary: \([bitwise] | reverse | join(""))",
"twos-complement(\($width)): \(twosComplement($width) | join(""))",
"";
( 3
| illustrate(8)),
(737894120670 # 0xABCDEABCDE9
| illustrate(64))
- Output:
decimal: 3 binary: 11 twos-complement(8): 11111101 decimal: 737894120670 binary: 1010101111001101111010101011110011011110 twos-complement(64): 1111111111111111111111110101010000110010000101010100001100100010
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.
M2000 Interpreter
Module Complement2{
// we use binary.and to get a number in range of byte 0 to 255
byte k, v
v=random(1, 255) ' there is no two's complement for zero
z=binary.and(binary.not(v)+1, 0xFF)
print v
print z
print z=255-v+1 // z is type of byte always positive
print sint(z+0xFFFFFF00)=-v // using 4bytes, we add unsinged 0xFFFFFF00
}
Complement2
Complement2
- Output:
2 254 True True 208 48 True True
Nim
We define a function to compute the two’s complement by taking the logical complement and adding one. As Nim uses the native complement of the computer, which is two’s complement, the result should be equal to the arithmetic negation.
import std/[strformat, strutils]
func twosComplement[T: SomeSignedInt](n: T): T =
## Compute the two's complement of "n".
not n + 1
echo &"""{"n":^15}{"2's complement":^15}{"-n":^15}"""
for n in [0i32, 1i32, -1i32]:
echo &"{n.toHex:^15}{twosComplement(n).toHex:^15}{(-n).toHex:^15}"
for n in [-50i8, 50i8]:
echo &"{n.toHex:^15}{twosComplement(n).toHex:^15}{(-n).toHex:^15}"
- Output:
n 2's complement -n ──────── ────────────── ──────── 00000000 00000000 00000000 00000001 FFFFFFFF FFFFFFFF FFFFFFFF 00000001 00000001 CE 32 32 32 CE CE
PascalABC.NET
begin
var x := 56;
x := not x + 1;
Print(x);
end.
- Output:
-56
Perl
use strict;
use warnings;
for ( -2**31, -2**31+1, -2, -1, 0, 1, 2, 2**31-2, 2**31-1 ) {
printf "$_ -> %d\n", $_ == 0 ? 0 : ~$_+1
}
Output is the same as the Wren entry.
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
Prolog
d(1234567).
b([-D, -D + 1, -2, -1, 0, 1, 2, D - 2, D - 1]) :-
d(D).
print_array([]).
print_array([H|T]) :-
NegH is -H,
format('~d -> ~d~n', [H, NegH]),
print_array(T).
main :-
b(B),
print_array(B).
Python
-n
or
~n+1
Quackery
Ways of calculating the two's complement of an integer in Quackery include negate
, ~ 1+
, -1 *
, and 0 swap -
.
These are demonstrated as a dialogue in the Quackery shell.
/O> 37 negate ... Stack: -37 /O> negate ... Stack: 37 /O> ~ 1+ ... Stack: -37 /O> ~ 1+ ... Stack: 37 /O> -1 * ... Stack: -37 /O> -1 * ... Stack: 37 /O> 0 swap - ... Stack: -37 /O> 0 swap - ... Stack: 37 /O>
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
RPL
RPL can handle integers whose size can be set from 1 to 64 bits. For this task, a 8-bit size is selected with STWS
.
RPL considers 'true' integers (i.e. declared by the prefix #
) to be positive, so the two's complement can not be done by the NEG
instruction.
8 STWS BIN #3d NOT 1 +
- Output:
1: #11111101b
Ruby
Ruby integers have a built-in 'one-complement'method: ~, which flips all bits. Adding 1 leads to a negative integer:
~42 + 1 # => -42
Rust
fn main() {
let i = 1;
println!("i = {:#?}, -(i) = {:#?}, !(i) + 1 = {:#?}", i, -i, !i + 1);
return (); // i = 1, -(i) = -1, !(i) + 1 = -1
}
Verilog
module main;
integer d;
integer b[0:8];
integer i;
initial begin
d = 1234567;
b[0] = -d;
b[1] = -d + 1;
b[2] = -2;
b[3] = -1;
b[4] = 0;
b[5] = 1;
b[6] = 2;
b[7] = d - 2;
b[8] = d - 1;
for (i = 0; i <= 8; i = i + 1) begin
$display("%0d -> %0d", b[i], -b[i]);
end
end
endmodule
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
x86-64 Assembly
The NEG instruction negates a number. It's the same thing as flipping the bits and adding one.
mov rax, 1968 ; 1968 in rax
neg rax ; -1968 should be in rax
;------------------
not rax
inc rax ; 1968 should be in rax again.
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
- Programming Tasks
- Basic language learning
- Simple
- 6502 Assembly
- 68000 Assembly
- 8086 Assembly
- AArch64 Assembly
- ALGOL 68
- ALGOL W
- ARM Assembly
- Asymptote
- BASIC
- Applesoft BASIC
- BASIC256
- Chipmunk Basic
- Craft Basic
- FreeBASIC
- Gambas
- GW-BASIC
- Minimal BASIC
- MSX Basic
- PureBasic
- QBasic
- QB64
- Just BASIC
- XBasic
- Yabasic
- C
- C++
- COBOL
- Delphi
- SysUtils,StdCtrls
- Forth
- J
- Java
- Jakt
- Jq
- Julia
- M2000 Interpreter
- Nim
- PascalABC.NET
- Perl
- Phix
- PL/M
- Prolog
- Python
- Quackery
- Raku
- RPL
- Ruby
- Rust
- Verilog
- Wren
- X86-64 Assembly
- XPL0
- Z80 Assembly