Ho implementato un numero intero a 256 bit utilizzando un array di unsigned long long
e un assembly x64 usato per implementare l'add con carry. Ecco il chiamante C++:
#include "stdafx.h"
extern "C" void add256(unsigned long long *a, unsigned long long * b, unsigned long long *c);
int _tmain(int argc, _TCHAR* argv[])
{
unsigned long long a[4] = {0x8000000000000001, 2, 3, 4};
unsigned long long b[4] = {0x8000000000000005, 6, 7, 8};
unsigned long long c[4] = {0, 0, 0, 0};
add256(a, b, c); // c[] == {6, 9, 10, 12};
return 0;
}
Il add256
è implementato in assemblea:
; void add256(unsigned long long *a, unsigned long long * b, unsigned long long *c)
.CODE
PUBLIC add256
add256 PROC
mov qword ptr [rsp+18h],r8
mov qword ptr [rsp+10h],rdx
mov qword ptr [rsp+8],rcx
push rdi
; c[0] = a[0] + b[0];
mov rax,qword ptr 16[rsp]
mov rax,qword ptr [rax]
mov rcx,qword ptr 24[rsp]
add rax,qword ptr [rcx]
mov rcx,qword ptr 32[rsp]
mov qword ptr [rcx],rax
; c[1] = a[1] + b[1] + CARRY;
mov rax,qword ptr 16[rsp]
mov rax,qword ptr [rax+8]
mov rcx,qword ptr 24[rsp]
adc rax,qword ptr [rcx+8]
mov rcx,qword ptr 32[rsp]
mov qword ptr [rcx+8],rax
; c[2] = a[2] + b[2] + CARRY;
mov rax,qword ptr 16[rsp]
mov rax,qword ptr [rax+10h]
mov rcx,qword ptr 24[rsp]
adc rax,qword ptr [rcx+10h]
mov rcx,qword ptr 32[rsp]
mov qword ptr [rcx+10h],rax
; c[3] = a[3] + b[3] + CARRY;
mov rax,qword ptr 16[rsp]
mov rax,qword ptr [rax+18h]
mov rcx,qword ptr 24[rsp]
adc rax,qword ptr [rcx+18h]
mov rcx,qword ptr 32[rsp]
mov qword ptr [rcx+18h],rax
; }
pop rdi
ret
add256 endp
end
So che indica che non volevi un emulato aggiungere con la soluzione di trasporto, e volevamo una soluzione ad alte prestazioni, ma , ancora, si può considerare unica soluzione il seguente C++ che ha un bel modo di simulare 256 numeri di bit:
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
unsigned long long a[4] = {0x8000000000000001, 2, 3, 4};
unsigned long long b[4] = {0x8000000000000005, 6, 7, 8};
unsigned long long c[4] = {0, 0, 0, 0};
c[0] = a[0] + b[0]; // 6
c[1] = a[1] + b[1] + (c[0] < a[0]); // 9
c[2] = a[2] + b[2] + (c[1] < a[1]); // 10
c[3] = a[3] + b[3] + (c[2] < a[2]); // 12
return 0;
}
Dicci di più su questo "256 megabit add". È abbastanza probabile che fare più aggiunte contemporaneamente utilizzando SIMD sarà considerevolmente più veloce, anche considerando che le transazioni devono essere gestite come un ulteriore passaggio. –
Ho già fatto un po 'di ricerca. Vedi http://stackoverflow.com/questions/8866973/can-long-integer-routines-benefit-from-sse. – jnm2
@ jnm2 - Il modo x64 sembra scrivere codice assembly separato e chiamarlo dalla funzione C++. L'assemblatore fa già parte del pacchetto. –