问题
Let's say I want to calculate the following:
A/Z
Where A is of length 128 bit and Z is 64 bit long. A is stored in 2 64 bit registers since the registers of the system can store up to 64 bits. What would be an efficient way to calculate the result?
P.S: I've solved similar multiplication problems by using CSD representations. However, this would require calculating 1/Z first.
回答1:
The right way to solve such a problem, is by returning to the basics:
- divide the most significant register by the denominator
- calculate the quotient
Qand the restR - define a new temporary register preferrably with the same length as the other 2
- the rest should occupy the most significant bits in the temporary register
- shift the lesser significant register to the right by the same amount of bits contained i
Rand add to the result to the temporary register. - go back to step 1
after the division, the resulting rest must be casted to double, divided by the denominator then added to the quotient.
回答2:
I assume you want integer division so here is the math:
A = { a0 + (a1<<64) }
D = { d0 + (d1<<64) } ... division result
Z = { z0 }
D = A/Z
D = (a0 + (a1<<64))/z0
D = (a0/z0) + ((a1<<64)/z0)
D = (a0/z0) + ((a1/z0)<<64) + (((a1%z0)<<64)/z0)
d0 = (a0/z0) + (((a1%z0)<<64)/z0)
d1 = a1/z1 + d0>>64
d0&=0xFFFFFFFFFFFFFFFF
and some 'C++' code:
ALU32 alu;
DWORD a1=0x12345678,a0=0x9ABCDEF0,d0,d1,z0=0x23,i;
// D = 0085270A C297AE99 R = 5
if (z0>=2)
{
d1=a1/z0; d0=a0/z0;
a1=a1%z0; a0=a0%z0;
if (a1)
{
i= (0xFFFFFFFF/z0) *a1;
alu.add(d0,d0,i); // addition with carry
alu.adc(d1,d1,0);
i=((0xFFFFFFFF%z0)+1)*a1;
a0+=i; i=a0/z0; a0%=z0;
alu.add(d0,d0,i); // addition with carry
alu.adc(d1,d1,0);
}
}
Notes:
This is only 32 bit. To convert it to 64 bit just change 0xFFFFFFFF to 0xFFFFFFFFFFFFFFFF and DWORDs to your data type.
ALU32 is just my class for basic 32bit operations with carry. I assume you are doing it in asm so you use CPU carry instead.
Division result is in d0, d1.
Remainder result is in a0.
Code does not handle negative values and division by 0, 1. Add ifs to handle it.
来源:https://stackoverflow.com/questions/19356690/efficient-way-to-divide-a-very-large-number-stored-in-2-registers-by-a-constant