Tonelli-Shanks algorithm: Difference between revisions
Content added Content deleted
m (Phix/mpfr) |
(add task to aarch64 assembly raspberry pi) |
||
Line 69: | Line 69: | ||
* [[Cipolla's algorithm]] |
* [[Cipolla's algorithm]] |
||
<br><br> |
<br><br> |
||
=={{header|AArch64 Assembly}}== |
|||
{{works with|as|Raspberry Pi 3B version Buster 64 bits <br> or android 64 bits with application Termux }} |
|||
<lang AArch64 Assembly> |
|||
/* ARM assembly AARCH64 Raspberry PI 3B or android 64 bits */ |
|||
/* program tonshan64.s */ |
|||
/*******************************************/ |
|||
/* Constantes file */ |
|||
/*******************************************/ |
|||
/* for this file see task include a file in language AArch64 assembly*/ |
|||
.include "../includeConstantesARM64.inc" |
|||
/*******************************************/ |
|||
/* Initialized data */ |
|||
/*******************************************/ |
|||
.data |
|||
szMessStartPgm: .asciz "Program 64 bits start \n" |
|||
szMessEndPgm: .asciz "Program normal end.\n" |
|||
szMessError: .asciz "\033[31mError !!!\n" |
|||
szMessErrGen: .asciz "Error end program.\n" |
|||
szMessOverflow: .asciz "Overflow function modulo.\n" |
|||
szMessNoSolution: .asciz "No solution.\n" |
|||
szCarriageReturn: .asciz "\n" |
|||
/* datas message display */ |
|||
szMessEntry: .asciz "Number : @ modulo : @ ==> " |
|||
szMessResult: .asciz "Racine 1 : @ Racine 2 : @ \n" |
|||
qNumberN: .quad 44402 |
|||
qNumberP: .quad 100049 |
|||
/*******************************************/ |
|||
/* UnInitialized data */ |
|||
/*******************************************/ |
|||
.bss |
|||
.align 4 |
|||
sZoneConv: .skip 24 |
|||
/*******************************************/ |
|||
/* code section */ |
|||
/*******************************************/ |
|||
.text |
|||
.global main |
|||
main: // program start |
|||
ldr x0,qAdrszMessStartPgm // display start message |
|||
bl affichageMess |
|||
mov x0,10 |
|||
mov x1,13 |
|||
bl displayEntry |
|||
bl computeTonSha |
|||
bl displayResult |
|||
mov x0,56 |
|||
mov x1,101 |
|||
bl displayEntry |
|||
bl computeTonSha |
|||
bl displayResult |
|||
mov x0,1030 |
|||
mov x1,10009 |
|||
bl displayEntry |
|||
bl computeTonSha |
|||
bl displayResult |
|||
mov x0,1032 |
|||
mov x1,10009 |
|||
bl displayEntry |
|||
bl computeTonSha |
|||
bcs 1f |
|||
bl displayResult |
|||
1: |
|||
ldr x4,qAdrqNumberN |
|||
ldr x0,[x4] |
|||
ldr x4,qAdrqNumberP |
|||
ldr x1,[x4] |
|||
bl displayEntry |
|||
bl computeTonSha |
|||
bl displayResult |
|||
ldr x0,qAdrszMessEndPgm // display end message |
|||
bl affichageMess |
|||
b 100f |
|||
99: // display error message |
|||
ldr x0,qAdrszMessError |
|||
bl affichageMess |
|||
100: // standard end of the program |
|||
mov x0, #0 // return code |
|||
mov x8, #EXIT // request to exit program |
|||
svc 0 // perform system call |
|||
qAdrszMessStartPgm: .quad szMessStartPgm |
|||
qAdrszMessEndPgm: .quad szMessEndPgm |
|||
qAdrszMessError: .quad szMessError |
|||
qAdrszMessNoSolution: .quad szMessNoSolution |
|||
qAdrszCarriageReturn: .quad szCarriageReturn |
|||
qAdrqNumberN: .quad qNumberN |
|||
qAdrqNumberP: .quad qNumberP |
|||
qAdrszMessResult: .quad szMessResult |
|||
qAdrsZoneConv: .quad sZoneConv |
|||
/******************************************************************/ |
|||
/* algorithm Tonelli–Shanks */ |
|||
/******************************************************************/ |
|||
/* x0 contains number */ |
|||
/* x1 contains modulus */ |
|||
/* x0 return root 1 */ |
|||
/* x1 return root 2 */ |
|||
computeTonSha: |
|||
stp x10,lr,[sp,-16]! // save registres |
|||
stp x2,x3,[sp,-16]! // save registres |
|||
stp x4,x5,[sp,-16]! // save registres |
|||
stp x6,x7,[sp,-16]! // save registres |
|||
stp x8,x9,[sp,-16]! // save registres |
|||
stp x11,x12,[sp,-16]! // save registres |
|||
mov x9,x0 // save number |
|||
mov x10,x1 // save modulo p |
|||
mov x2,x10 |
|||
sub x1,x2,1 |
|||
lsr x1,x1,1 |
|||
bl moduloPuR64 |
|||
bcs 100f // error ? |
|||
cmp x0,#1 |
|||
bne 20f |
|||
sub x5,x10,1 |
|||
mov x6,#1 // s |
|||
1: |
|||
lsr x5,x5,#1 // div by 2 |
|||
tst x5,1 // even ? |
|||
cinc x6,x6,eq // yes count |
|||
beq 1b // and loop |
|||
// x5 = q |
|||
cmp x6,#1 // s = 1 ? |
|||
bne 3f |
|||
add x1,x10,1 // compute root 1 |
|||
lsr x1,x1,#2 // p + 1 / 4 |
|||
mov x0,x9 // n |
|||
mov x2,x10 // p |
|||
bl moduloPuR64 |
|||
bcs 100f // error ? |
|||
neg x1,x0 // compute root 2 = - root 1 |
|||
b 100f // and end |
|||
3: |
|||
mov x7,#3 // z |
|||
4: |
|||
mov x0,x7 |
|||
mov x2,x10 // p |
|||
sub x1,x2,1 |
|||
lsr x1,x1,1 // power = p - 1 / 2 |
|||
bl moduloPuR64 |
|||
bcs 100f // error ? |
|||
cmp x0,#1 |
|||
cinc x7,x7,eq // si égal à 1 |
|||
cinc x7,x7,eq |
|||
beq 4b |
|||
cmp x0,0 |
|||
cinc x7,x7,eq // si egal à 0 |
|||
cinc x7,x7,eq |
|||
beq 4b |
|||
mov x0,x7 // z |
|||
mov x1,x5 // q |
|||
mov x2,x10 // p |
|||
bl moduloPuR64 |
|||
bcs 100f // error ? |
|||
mov x12,x0 // c = z pow q mod p |
|||
add x1,x5,1 // = q +1 |
|||
lsr x1,x1,1 // div 2 |
|||
mov x0,x9 // n |
|||
mov x2,x10 // p |
|||
bl moduloPuR64 |
|||
mov x4,x0 // r = n puis (q+1)/2 mod p |
|||
mov x0,x9 // n |
|||
mov x1,x5 // = q |
|||
mov x2,x10 // p |
|||
bl moduloPuR64 |
|||
bcs 100f // error ? |
|||
mov x5,x0 // reuse r5 = t = n pow q mod p |
|||
8: // begin loop |
|||
cmp x5,1 |
|||
beq 10f |
|||
mov x0,x5 // t |
|||
mov x1,x6 // m |
|||
mov x2,x10 // p |
|||
bl searchI // search i for t puis 2 puis i = 1 mod p |
|||
cmp x0,-1 // not find -> no solution |
|||
beq 20f |
|||
mov x9,x0 // i |
|||
sub x8,x6,x0 // compute b |
|||
sub x8,x8,1 // m - i - 1 |
|||
mov x1,1 |
|||
lsl x1,x1,x8 |
|||
mov x0,x12 |
|||
mov x2,x10 // p |
|||
bl moduloPuR64 |
|||
bcs 100f // error ? |
|||
mov x7,x0 // b = c puis 2 puis 2 puis m-i-1 à verifier |
|||
mul x0,x7,x4 // r = r * b mod p |
|||
umulh x1,x7,x4 |
|||
mov x2,x10 |
|||
bl divisionReg128U |
|||
mov x4,x3 // r mod p |
|||
mul x0,x7,x7 |
|||
umulh x1,x7,x7 |
|||
mov x2,x10 |
|||
bl divisionReg128U |
|||
mov x12,x3 // c mod p |
|||
mul x0,x5,x12 |
|||
umulh x1,x5,x12 |
|||
mov x2,x10 |
|||
bl divisionReg128U |
|||
mov x5,x3 // t mod p |
|||
mov x6,x9 // m = i |
|||
b 8b |
|||
9: |
|||
10: |
|||
mov x0,x4 // x0 return root 1 |
|||
sub x1,x10,x0 // x1 return root 2 |
|||
cmn x0,0 // carry à zero roots ok |
|||
b 100f |
|||
20: |
|||
ldr x0,qAdrszMessNoSolution |
|||
bl affichageMess |
|||
mov x0,0 |
|||
mov x1,0 |
|||
cmp x0,0 // carry to 1 No solution |
|||
100: |
|||
ldp x11,x12,[sp],16 |
|||
ldp x8,x9,[sp],16 |
|||
ldp x6,x7,[sp],16 |
|||
ldp x4,x5,[sp],16 |
|||
ldp x2,x3,[sp],16 |
|||
ldp x10,lr,[sp],16 // restaur des 2 registres |
|||
ret // retour adresse lr x30 |
|||
/******************************************************************/ |
|||
/* search i */ |
|||
/******************************************************************/ |
|||
// x0 contains t |
|||
// x1 contains maxi |
|||
// x2 contains modulo |
|||
searchI: |
|||
stp x1,lr,[sp,-16]! // save registres |
|||
stp x2,x3,[sp,-16]! // save registres |
|||
stp x4,x5,[sp,-16]! // save registres |
|||
stp x6,x7,[sp,-16]! // save registres |
|||
mov x4,x0 // t |
|||
mov x6,x1 // m |
|||
mov x3,1 // i |
|||
1: |
|||
mov x5,1 |
|||
lsl x5,x5,x3 // compute 2 power i |
|||
mov x0,x4 |
|||
mov x1,x5 |
|||
bl moduloPuR64 // compute t pow 2 pow i mod p |
|||
cmp x0,1 // = 1 ? |
|||
beq 3f // yes it is ok |
|||
add x3,x3,1 // next i |
|||
cmp x3,x6 |
|||
blt 1b // loop |
|||
mov x0,-1 // not find |
|||
b 100f |
|||
3: |
|||
mov x0,x3 // return i |
|||
100: |
|||
ldp x6,x7,[sp],16 |
|||
ldp x4,x5,[sp],16 |
|||
ldp x2,x3,[sp],16 |
|||
ldp x1,lr,[sp],16 // restaur des 2 registres |
|||
ret // retour adresse lr x30 |
|||
/******************************************************************/ |
|||
/* display numbers */ |
|||
/******************************************************************/ |
|||
/* x0 contains number */ |
|||
/* x1 contains modulo */ |
|||
displayEntry: |
|||
stp x0,lr,[sp,-16]! // save registres |
|||
stp x1,x2,[sp,-16]! // save registres |
|||
mov x2,x1 // root 2 |
|||
ldr x1,qAdrsZoneConv // convert root 1 in r0 |
|||
bl conversion10S // convert ascii string |
|||
ldr x0,qAdrszMessEntry |
|||
ldr x1,qAdrsZoneConv |
|||
bl strInsertAtCharInc // and put in message |
|||
mov x3,x0 |
|||
mov x0,x2 // racine 2 |
|||
ldr x1,qAdrsZoneConv |
|||
bl conversion10S // convert ascii string |
|||
mov x0,x3 |
|||
ldr x1,qAdrsZoneConv |
|||
bl strInsertAtCharInc // and put in message |
|||
bl affichageMess |
|||
100: |
|||
ldp x1,x2,[sp],16 |
|||
ldp x0,lr,[sp],16 // restaur des 2 registres |
|||
ret // retour adresse lr x30 |
|||
qAdrszMessEntry: .quad szMessEntry |
|||
/******************************************************************/ |
|||
/* display roots */ |
|||
/******************************************************************/ |
|||
/* x0 contains root 1 */ |
|||
/* x1 contains root 2 */ |
|||
displayResult: |
|||
stp x1,lr,[sp,-16]! // save registres |
|||
stp x2,x3,[sp,-16]! // save registres |
|||
mov x2,x1 // root 2 |
|||
ldr x1,qAdrsZoneConv // convert root 1 in r0 |
|||
bl conversion10S // convert ascii string |
|||
ldr x0,qAdrszMessResult |
|||
ldr x1,qAdrsZoneConv |
|||
bl strInsertAtCharInc // and put in message |
|||
mov x3,x0 |
|||
mov x0,x2 // racine 2 |
|||
ldr x1,qAdrsZoneConv |
|||
bl conversion10S // convert ascii string |
|||
mov x0,x3 |
|||
ldr x1,qAdrsZoneConv |
|||
bl strInsertAtCharInc // and put in message |
|||
bl affichageMess |
|||
100: |
|||
ldp x2,x3,[sp],16 |
|||
ldp x1,lr,[sp],16 // restaur des 2 registres |
|||
ret // retour adresse lr x30 |
|||
/**************************************************************/ |
|||
/********************************************************/ |
|||
/* Calcul modulo de b puissance e modulo m */ |
|||
/* Exemple 4 puissance 13 modulo 497 = 445 */ |
|||
/********************************************************/ |
|||
/* x0 nombre */ |
|||
/* x1 exposant */ |
|||
/* x2 modulo */ |
|||
moduloPuR64: |
|||
stp x1,lr,[sp,-16]! // save registres |
|||
stp x3,x4,[sp,-16]! // save registres |
|||
stp x5,x6,[sp,-16]! // save registres |
|||
stp x7,x8,[sp,-16]! // save registres |
|||
stp x9,x10,[sp,-16]! // save registres |
|||
cbz x0,100f |
|||
cbz x1,100f |
|||
mov x8,x0 |
|||
mov x7,x1 |
|||
mov x6,1 // resultat |
|||
udiv x4,x8,x2 |
|||
msub x9,x4,x2,x8 // contient le reste |
|||
1: |
|||
tst x7,1 |
|||
beq 2f |
|||
mul x4,x9,x6 |
|||
umulh x5,x9,x6 |
|||
mov x6,x4 |
|||
mov x0,x6 |
|||
mov x1,x5 |
|||
bl divisionReg128U |
|||
cbnz x1,99f // overflow |
|||
mov x6,x3 |
|||
2: |
|||
mul x8,x9,x9 |
|||
umulh x5,x9,x9 |
|||
mov x0,x8 |
|||
mov x1,x5 |
|||
bl divisionReg128U |
|||
cbnz x1,99f // overflow |
|||
mov x9,x3 |
|||
lsr x7,x7,1 |
|||
cbnz x7,1b |
|||
cmn x0,0 // carry à zero pas d'erreur |
|||
mov x0,x6 // result |
|||
b 100f |
|||
99: |
|||
ldr x0,qAdrszMessOverflow |
|||
bl affichageMess |
|||
cmp x0,0 // carry à un car erreur |
|||
mov x0,-1 // code erreur |
|||
100: |
|||
ldp x9,x10,[sp],16 // restaur des 2 registres |
|||
ldp x7,x8,[sp],16 // restaur des 2 registres |
|||
ldp x5,x6,[sp],16 // restaur des 2 registres |
|||
ldp x3,x4,[sp],16 // restaur des 2 registres |
|||
ldp x1,lr,[sp],16 // restaur des 2 registres |
|||
ret // retour adresse lr x30 |
|||
qAdrszMessOverflow: .quad szMessOverflow |
|||
/***************************************************/ |
|||
/* division d un nombre de 128 bits par un nombre de 64 bits */ |
|||
/***************************************************/ |
|||
/* x0 contient partie basse dividende */ |
|||
/* x1 contient partie haute dividente */ |
|||
/* x2 contient le diviseur */ |
|||
/* x0 retourne partie basse quotient */ |
|||
/* x1 retourne partie haute quotient */ |
|||
/* x3 retourne le reste */ |
|||
divisionReg128U: |
|||
stp x6,lr,[sp,-16]! // save registres |
|||
stp x4,x5,[sp,-16]! // save registres |
|||
mov x5,#0 // raz du reste R |
|||
mov x3,#128 // compteur de boucle |
|||
mov x4,#0 // dernier bit |
|||
1: |
|||
lsl x5,x5,#1 // on decale le reste de 1 |
|||
tst x1,1<<63 // test du bit le plus à gauche |
|||
lsl x1,x1,#1 // on decale la partie haute du quotient de 1 |
|||
beq 2f |
|||
orr x5,x5,#1 // et on le pousse dans le reste R |
|||
2: |
|||
tst x0,1<<63 |
|||
lsl x0,x0,#1 // puis on decale la partie basse |
|||
beq 3f |
|||
orr x1,x1,#1 // et on pousse le bit de gauche dans la partie haute |
|||
3: |
|||
orr x0,x0,x4 // position du dernier bit du quotient |
|||
mov x4,#0 // raz du bit |
|||
cmp x5,x2 |
|||
blt 4f |
|||
sub x5,x5,x2 // on enleve le diviseur du reste |
|||
mov x4,#1 // dernier bit à 1 |
|||
4: |
|||
// et boucle |
|||
subs x3,x3,#1 |
|||
bgt 1b |
|||
lsl x1,x1,#1 // on decale le quotient de 1 |
|||
tst x0,1<<63 |
|||
lsl x0,x0,#1 // puis on decale la partie basse |
|||
beq 5f |
|||
orr x1,x1,#1 |
|||
5: |
|||
orr x0,x0,x4 // position du dernier bit du quotient |
|||
mov x3,x5 |
|||
100: |
|||
ldp x4,x5,[sp],16 // restaur des 2 registres |
|||
ldp x6,lr,[sp],16 // restaur des 2 registres |
|||
ret // retour adresse lr x30 |
|||
/********************************************************/ |
|||
/* File Include fonctions */ |
|||
/********************************************************/ |
|||
/* for this file see task include a file in language AArch64 assembly */ |
|||
.include "../includeARM64.inc" |
|||
</lang> |
|||
{{Output}} |
|||
<pre> |
|||
Program 64 bits start |
|||
Number : +10 modulo : +13 ==> Racine 1 : +7 Racine 2 : +6 |
|||
Number : +56 modulo : +101 ==> Racine 1 : +37 Racine 2 : +64 |
|||
Number : +1030 modulo : +10009 ==> Racine 1 : +1632 Racine 2 : +8377 |
|||
Number : +1032 modulo : +10009 ==> No solution. |
|||
Number : +44402 modulo : +100049 ==> Racine 1 : +30468 Racine 2 : +69581 |
|||
Program normal end. |
|||
</pre> |
|||
=={{header|C}}== |
=={{header|C}}== |