efficient way to divide a very large number stored in 2 registers by a constant

情到浓时终转凉″ 提交于 2019-12-31 02:49:12

问题


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 Q and the rest R
  • 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 iR and 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!