Long multiplication: Difference between revisions
Content added Content deleted
m (→{{header|RPL}}: typos) |
VincentARM (talk | contribs) (add task to arm assembly rapberry pi) |
||
Line 1,103: | Line 1,103: | ||
⎕←longmul⍨input ⍝ calculate 2*128 |
⎕←longmul⍨input ⍝ calculate 2*128 |
||
3 4 0 2 8 2 3 6 6 9 2 0 9 3 8 4 6 3 4 6 3 3 7 4 6 0 7 4 3 1 7 6 8 2 1 1 4 5 6</syntaxhighlight> |
3 4 0 2 8 2 3 6 6 9 2 0 9 3 8 4 6 3 4 6 3 3 7 4 6 0 7 4 3 1 7 6 8 2 1 1 4 5 6</syntaxhighlight> |
||
=={{header|ARM Assembly}}== |
|||
{{works with|as|Raspberry Pi <br> or android 32 bits with application Termux}} |
|||
<syntaxhighlight lang ARM Assembly> |
|||
/* ARM assembly Raspberry PI */ |
|||
/* program longmulti.s */ |
|||
/* REMARK 1 : this program use routines in a include file |
|||
see task Include a file language arm assembly |
|||
for the routine affichageMess conversion10 |
|||
see at end of this program the instruction include */ |
|||
/* REMARK 2 : this program use factors unsigned to 2 power 95 |
|||
and the result is less than 2 power 159 */ |
|||
/* for constantes see task include a file in arm assembly */ |
|||
/************************************/ |
|||
/* Constantes */ |
|||
/************************************/ |
|||
.include "../constantes.inc" |
|||
.equ BUFFERSIZE, 64 |
|||
/***********************************************/ |
|||
/* structures */ |
|||
/**********************************************/ |
|||
/* Définition multi128 */ |
|||
.struct 0 |
|||
multi128_N1: // 31-0 |
|||
.struct multi128_N1 + 4 |
|||
multi128_N2: // 63-32 |
|||
.struct multi128_N2 + 4 |
|||
multi128_N3: // 95-64 |
|||
.struct multi128_N3 + 4 |
|||
multi128_N4: // 127-96 |
|||
.struct multi128_N4 + 4 |
|||
multi128_N5: // 159-128 |
|||
.struct multi128_N5 + 4 |
|||
multi128_end: |
|||
/*********************************/ |
|||
/* Initialized data */ |
|||
/*********************************/ |
|||
.data |
|||
szMessFactor: .asciz "Factor = " |
|||
szMessResult: .asciz "Result = " |
|||
szMessStart: .asciz "Program 32 bits start.\n" |
|||
szCarriageReturn: .asciz "\n" |
|||
i128test1: .int 0,0,1,0,0 // 2 power 64 |
|||
/*********************************/ |
|||
/* UnInitialized data */ |
|||
/*********************************/ |
|||
.bss |
|||
sZoneConv: .skip BUFFERSIZE // conversion buffer |
|||
i128Result1: .skip multi128_end |
|||
/*********************************/ |
|||
/* code section */ |
|||
/*********************************/ |
|||
.text |
|||
.global main |
|||
main: @ entry of program |
|||
ldr r0,iAdrszMessStart |
|||
bl affichageMess |
|||
ldr r0,iAdri128test1 @ origin number |
|||
ldr r1,iAdrsZoneConv |
|||
mov r2,#BUFFERSIZE |
|||
bl convertMultiForString @ convert multi number to string |
|||
mov r2,r0 @ insert conversion in message |
|||
mov r0,#3 @ string number to display |
|||
ldr r1,iAdrszMessFactor |
|||
ldr r3,iAdrszCarriageReturn |
|||
bl displayStrings @ display message |
|||
@ multiplication |
|||
ldr r0,iAdri128test1 @ factor 1 |
|||
ldr r1,iAdri128test1 @ factor 2 |
|||
ldr r2,iAdri128Result1 @ result |
|||
bl multiplierMulti128 |
|||
ldr r0,iAdri128Result1 |
|||
ldr r1,iAdrsZoneConv |
|||
mov r2,#BUFFERSIZE |
|||
bl convertMultiForString @ conversion multi to string |
|||
mov r2,r0 @ insert conversion in message |
|||
mov r0,#3 @ number string to display |
|||
ldr r1,iAdrszMessResult |
|||
ldr r3,iAdrszCarriageReturn |
|||
bl displayStrings @ display message |
|||
100: @ standard end of the program |
|||
mov r0, #0 @ return code |
|||
mov r7, #EXIT @ request to exit program |
|||
svc #0 @ perform the system call |
|||
iAdrszCarriageReturn: .int szCarriageReturn |
|||
iAdrsZoneConv: .int sZoneConv |
|||
iAdri128test1: .int i128test1 |
|||
iAdri128Result1: .int i128Result1 |
|||
iAdrszMessResult: .int szMessResult |
|||
iAdrszMessFactor: .int szMessFactor |
|||
iAdrszMessStart: .int szMessStart |
|||
/***************************************************/ |
|||
/* multiplication multi128 by multi128 */ |
|||
/***************************************************/ |
|||
// r0 contains address multi128 1 |
|||
// r1 contains address multi128 2 |
|||
// r2 contains address result multi128 |
|||
// r0 return address result (= r2) |
|||
multiplierMulti128: |
|||
push {r1-r10,lr} @ save registers |
|||
mov r9,r0 @ factor 1 |
|||
mov r10,r1 @ factor 2 |
|||
mov r7,r2 @ address result |
|||
mov r6,#4 @ multi128 size |
|||
mov r5,#0 |
|||
1: |
|||
str r5,[r7,r6,lsl #2] @ init result |
|||
subs r6,r6,#1 |
|||
bge 1b |
|||
mov r5,#0 @ indice loop 1 |
|||
2: @ loop items factor 1 |
|||
ldr r0,[r9,r5,lsl #2] @ load a item |
|||
mov r4,#0 |
|||
mov r8,#0 |
|||
3: @ loop item factor 2 |
|||
add r6,r4,r5 @ compute result indice |
|||
ldr r1,[r10,r4,lsl #2] @ oad a item factor 2 |
|||
umull r2,r3,r1,r0 @ multiply long 32 bits |
|||
ldr r1,[r7,r6,lsl #2] @ load previous item of result |
|||
adds r1,r1,r2 @ add low part result multiplication |
|||
movcc r2,#0 @ high retain |
|||
movcs r2,#1 |
|||
adds r1,r1,r8 @ add high part precedente |
|||
adc r8,r3,r2 @ new high part with retenue |
|||
str r1,[r7,r6,lsl #2] @ store the sum in result |
|||
add r4,r4,#1 |
|||
cmp r4,#3 |
|||
blt 3b @ and loop 2 |
|||
cmp r8,#0 @ high part ? |
|||
beq 4f |
|||
add r6,r6,#1 |
|||
cmp r6,#4 @ on last item ? |
|||
strle r8,[r7,r6,lsl #2] @ no store high part in next item |
|||
ble 4f |
|||
adr r0,szMessErrOverflow @ yes -> overflow |
|||
bl affichageMess |
|||
mov r0,#0 @ return 0 |
|||
b 100f |
|||
4: |
|||
add r5,r5,#1 |
|||
cmp r5,#3 |
|||
blt 2b @ and loop 1 |
|||
mov r0,r7 |
|||
100: |
|||
pop {r1-r10,pc} @ restaur registers |
|||
szMessErrOverflow: .asciz "\033[31mOverflow !!\033[0m \n" |
|||
.align 4 |
|||
/***************************************************/ |
|||
/* display multi strings */ |
|||
/***************************************************/ |
|||
/* r0 contains number strings address */ |
|||
/* r1 address string1 */ |
|||
/* r2 address string2 */ |
|||
/* r3 address string3 */ |
|||
/* other address on the stack */ |
|||
/* thinck to add number other address * 4 to add to the stack */ |
|||
displayStrings: @ INFO: displayStrings |
|||
push {r1-r4,fp,lr} @ save des registres |
|||
add fp,sp,#24 @ save paraméters address (6 registers saved * 4 bytes) |
|||
mov r4,r0 @ save strings number |
|||
cmp r4,#0 @ 0 string -> end |
|||
ble 100f |
|||
mov r0,r1 @ string 1 |
|||
bl affichageMess |
|||
cmp r4,#1 @ number > 1 |
|||
ble 100f |
|||
mov r0,r2 |
|||
bl affichageMess |
|||
cmp r4,#2 |
|||
ble 100f |
|||
mov r0,r3 |
|||
bl affichageMess |
|||
cmp r4,#3 |
|||
ble 100f |
|||
mov r3,#3 |
|||
sub r2,r4,#4 |
|||
1: @ loop extract address string on stack |
|||
ldr r0,[fp,r2,lsl #2] |
|||
bl affichageMess |
|||
subs r2,#1 |
|||
bge 1b |
|||
100: |
|||
pop {r1-r4,fp,pc} |
|||
/***************************************************/ |
|||
/* conversion multi128 unsigned to string */ |
|||
/***************************************************/ |
|||
// r0 contains address multi128 |
|||
// r1 contains address buffer |
|||
// r2 contains buffer length |
|||
convertMultiForString: |
|||
push {r1-r5,fp,lr} @ save des registres |
|||
sub sp,sp,#multi128_end @ reserve place to stack |
|||
mov fp,sp @ init address to quotient |
|||
mov r5,r1 @ save address buffer |
|||
mov r3,#0 @ init indice |
|||
1: |
|||
ldr r4,[r0,r3,lsl #2] @ load one part of number |
|||
str r4,[fp,r3,lsl #2] @ copy part on stack |
|||
add r3,#1 |
|||
cmp r3,#5 |
|||
blt 1b |
|||
2: |
|||
mov r0,#0 |
|||
strb r0,[r5,r2] @ store final 0 in buffer |
|||
sub r4,r2,#1 @ end number storage |
|||
3: |
|||
mov r0,fp |
|||
mov r1,#10 |
|||
bl calculerModuloMultiEntier @ compute modulo 10 |
|||
add r0,r0,#0x30 @ convert result to character |
|||
strb r0,[r5,r4] @ store character on buffer |
|||
subs r4,r4,#1 @ |
|||
blt 99f @ buffer too low |
|||
ldr r0,[fp,#multi128_N1] @ test if quotient = zero |
|||
cmp r0,#0 |
|||
bne 3b |
|||
ldr r0,[fp,#multi128_N2] |
|||
cmp r0,#0 |
|||
bne 3b |
|||
ldr r0,[fp,#multi128_N3] |
|||
cmp r0,#0 |
|||
bne 3b |
|||
ldr r0,[fp,#multi128_N4] |
|||
cmp r0,#0 |
|||
bne 3b |
|||
ldr r0,[fp,#multi128_N5] |
|||
cmp r0,#0 |
|||
bne 3b |
|||
add r0,r5,r4 @ return begin number in buffer |
|||
add r0,r0,#1 |
|||
b 100f |
|||
99: @ display error if buffer est toop low |
|||
adr r0,szMessErrBuffer |
|||
bl affichageMess |
|||
mov r0,#-1 |
|||
100: |
|||
add sp,sp,#multi128_end @ stack alignement |
|||
pop {r1-r5,fp,pc} @ restaur registers |
|||
szMessErrBuffer: .asciz "\033[31mBuffer de conversion trop petit !!\033[0m \n" |
|||
.align 4 |
|||
/***************************************************/ |
|||
/* modulo compute unsigned */ |
|||
/***************************************************/ |
|||
// r0 contains address multi128 |
|||
// r1 contains modulo (positive) |
|||
// r0 return modulo |
|||
// ATTENTION : le multientier origine est modifié et contient le quotient |
|||
calculerModuloMultiEntier: @ INFO: calculerModuloMultiEntier |
|||
push {r1-r5,lr} @ save des registres |
|||
cmp r1,#0 |
|||
ble 99f |
|||
mov r4,r1 @ save modulo |
|||
mov r3,#4 |
|||
mov r5,r0 @ multi128 address |
|||
ldr r0,[r5,r3,lsl #2] @ load last part of number in low part of 64 bits |
|||
mov r1,#0 @ init higt part 64 bits |
|||
1: |
|||
cmp r3,#0 @ end part ? |
|||
ble 2f |
|||
mov r2,r4 @ modulo |
|||
bl division32R @ divide r0,r1 by r2 in r0,r1 and remainder in r2 |
|||
str r0,[r5,r3,lsl #2] @ store result part low |
|||
sub r3,r3,#1 @ other part ? |
|||
ldr r0,[r5,r3,lsl #2] @ load prev part |
|||
mov r1,r2 @ store remainder un high part of 64 bits |
|||
b 1b |
|||
2: |
|||
mov r2,r4 @ modulo |
|||
bl division32R |
|||
str r0,[r5] @ stockage dans le 1er chunk |
|||
mov r0,r2 @ return remainder |
|||
b 100f |
|||
99: |
|||
adr r0,szMessNegatif |
|||
bl affichageMess |
|||
mov r0,#-1 |
|||
100: @ fin standard de la fonction |
|||
pop {r1-r5,pc} @ restaur des registres |
|||
szMessNegatif: .asciz "\033[31mLe diviseur doit être positif !\033[0m\n" |
|||
.align 4 |
|||
/***************************************************/ |
|||
/* division 64 bits number in 2 registers by 32 bits number */ |
|||
/***************************************************/ |
|||
/* r0 contains dividende low part */ |
|||
/* r1 contains dividende high part */ |
|||
/* r2 contains divisor */ |
|||
/* r0 return quotient low part */ |
|||
/* r1 return quotient high part */ |
|||
/* r2 return remainder */ |
|||
division32R: |
|||
push {r3-r7,lr} @ save registers |
|||
mov r6,#0 @ init high high part of remainder !! |
|||
@ r1 = high part of number in high part of remainder |
|||
mov r7,r0 @ low part of number in low part of remainder |
|||
mov r3,#0 @ init high part quotient |
|||
mov r4,#0 @ init low part quotient |
|||
mov r5,#32 |
|||
1: @ begin loop |
|||
lsl r6,#1 @ left shift high high part of remainder |
|||
lsls r1,#1 @ left shift high part of remainder |
|||
orrcs r6,#1 @ add left bit high part on high high part |
|||
lsls r7,#1 @ left shift low part of remainder |
|||
orrcs r1,#1 @ add left bit low part on high part |
|||
lsls r4,#1 @ left shift low part quotient |
|||
lsl r3,#1 @ left shift high part quotient |
|||
orrcs r3,#1 @ add left bit low part on high part |
|||
@ sub divisor to high part remainder |
|||
subs r1,r2 |
|||
sbcs r6,#0 @ sub restraint (retenue in french) |
|||
bmi 2f @ result negative ? |
|||
@ positive or equal |
|||
orr r4,#1 @ right bit quotient to 1 |
|||
b 3f |
|||
2: @ negative |
|||
orr r4,#0 @ right bit quotient to 0 |
|||
adds r1,r2 @ and restaure the remainder to precedent value |
|||
adc r6,#0 @ and restraint |
|||
3: |
|||
subs r5,#1 @ decrement indice |
|||
bgt 1b @ and loop |
|||
mov r0,r4 @ low part quotient |
|||
mov r2,r1 @ remainder |
|||
mov r1,r3 @ high part quotient |
|||
100: @ |
|||
pop {r3-r7,pc} @ restaur registers |
|||
/***************************************************/ |
|||
/* ROUTINES INCLUDE */ |
|||
/***************************************************/ |
|||
.include "../affichage.inc" |
|||
</syntaxhighlight> |
|||
{{Out}} |
|||
<pre> |
|||
Program 32 bits start. |
|||
Factor = 18446744073709551616 |
|||
Result = 340282366920938463463374607431768211456 |
|||
</pre> |
|||
=={{header|Arturo}}== |
=={{header|Arturo}}== |