Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

Changeset 3884

Show
Ignore:
Timestamp:
08/18/08 03:09:56 (4 months ago)
Author:
Don Clugston
Message:

* multibyteShl() now returns the msb.
* bugfix in Karatsuba multiply for an asymmetric case exactly at the Karatsuba threshold.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/tango/math/internal/BignumNoAsm.d

    r3831 r3884  
    156156 *  numbits must be in the range 1..31 
    157157 */ 
    158 void multibyteShl(uint [] dest, uint [] src, uint numbits) 
     158uint multibyteShl(uint [] dest, uint [] src, uint numbits) 
    159159{ 
    160160    ulong c = 0; 
     
    164164        c >>>= 32; 
    165165   } 
     166   return cast(uint)c; 
    166167} 
    167168 
  • trunk/tango/math/internal/BignumX86.d

    r3877 r3884  
    298298/** dest[#] = src[#] << numbits 
    299299 *  numbits must be in the range 1..31 
    300  */ 
    301 void multibyteShl(uint [] dest, uint [] src, uint numbits) 
     300 *  Returns the overflow 
     301 */ 
     302uint multibyteShl(uint [] dest, uint [] src, uint numbits) 
    302303{ 
    303304    // Timing: Optimal for P6 family. 
     
    333334        jg L_even; 
    334335L_last: 
    335         shl EAX, CL; 
     336        mov EDX, 0; 
     337        shld EAX, EDX, CL; 
    336338        mov [EDI], EAX; 
    337  
     339        mov EAX, EDX; 
    338340        pop EBX; 
    339341        pop EDI; 
  • trunk/tango/math/internal/BiguintCore.d

    r3877 r3884  
    1919} 
    2020 
     21private: 
     22uint [1] BIGINTZERO = [0]; 
    2123public: 
    22 // Converts a big uint to a hexadecimal string. 
    23 // 
    24 // Optionally, a separator character (eg, an underscore) may be added between 
    25 // every 8 digits. 
    26 // buff.length must be data.length*8 if separator is zero, 
    27 // or data.length*9 if separator is non-zero. It will be completely filled. 
    28 char [] biguintToHex(char [] buff, uint [] data, char separator=0) 
    29 
    30     int x=0; 
    31     for (int i=data.length - 1; i>=0; --i) { 
    32         toHexZeroPadded(buff[x..x+8], data[i]); 
    33         x+=8; 
    34         if (separator) { 
    35             if (i>0) buff[x]='_'; 
    36             ++x; 
    37         } 
    38     } 
    39     return buff; 
    40 
    41  
    42 /** Convert a big uint into a decimal string. 
    43  * 
    44  * Params: 
    45  *  data    The biguint to be converted. Will be destroyed. 
    46  *  buff    The destination buffer for the decimal string. Must be 
    47  *          large enough to store the result, including leading zeros. 
    48  *          Will be filled starting from the end. 
    49  * 
    50  * Ie, buff.length must be (data.length*32)/log2(10) = 9.63296 * data.length. 
    51  * Returns: 
    52  *    the lowest index of buff which was used. 
    53  */ 
    54 int biguintToDecimal(char [] buff, uint [] data){ 
    55     int sofar = buff.length; 
    56     // Might be better to divide by (10^38/2^32) since that gives 38 digits for 
    57     // the price of 3 divisions and a shr; this version only gives 27 digits 
    58     // for 3 divisions. 
    59     while(data.length>1) { 
    60         uint rem = multibyteDivAssign(data, 10_0000_0000, 0); 
    61         itoaZeroPadded(buff[sofar-9 .. sofar], rem); 
    62         sofar -= 9; 
    63         if (data[$-1]==0 && data.length>1) { 
    64             data.length = data.length - 1; 
    65         } 
    66     } 
    67     itoaZeroPadded(buff[sofar-10 .. sofar], data[0]); 
    68     sofar-=10; 
    69     // and strip off the leading zeros 
    70     while(sofar!= buff.length-1 && buff[sofar] == '0') sofar++;     
    71     return sofar; 
    72 
    73  
    74 /** Convert a decimal string into a big uint. 
    75  * 
    76  * Params: 
    77  *  data    The biguint to be receive the result. Must be large enough to  
    78  *          store the result. 
    79  *  s       The decimal string. May contain 0..9, or _. Will be preserved. 
    80  * 
    81  * The required length for the destination buffer is slightly less than 
    82  *  1 + s.length/log2(10) = 1 + s.length/3.3219. 
    83  * 
    84  * Returns: 
    85  *    the highest index of data which was used. 
    86  */ 
    87 int biguintFromDecimal(uint [] data, char [] s) { 
    88     // Convert to base 1e19 = 10_000_000_000_000_000_000. 
    89     // (this is the largest power of 10 that will fit into a long). 
    90     // The length will be less than 1 + s.length/log2(10) = 1 + s.length/3.3219. 
    91     // 485 bits will only just fit into 146 decimal digits. 
    92     uint lo = 0; 
    93     uint x = 0; 
    94     ulong y = 0; 
    95     uint hi = 0; 
    96     data[0] = 0; // initially number is 0. 
    97     
    98     for (int i= (s[0]=='-' || s[0]=='+')? 1 : 0; i<s.length; ++i) {             
    99         if (s[i] == '_') continue; 
    100         x *= 10; 
    101         x += s[i] - '0'; 
    102         ++lo; 
    103         if (lo==9) { 
    104             y = x; 
    105             x = 0; 
    106         } 
    107         if (lo==18) { 
    108             y *= 10_0000_0000; 
    109             y += x; 
    110             x = 0; 
    111         } 
    112         if (lo==19) { 
    113             y *= 10; 
    114             y += x; 
    115             x = 0; 
    116             // Multiply existing number by 10^19, then add y1. 
    117             if (hi>0) { 
    118                 data[hi] = multibyteMul(data[0..hi], data[0..hi], 1220703125*2, 0); // 5^13*2 = 0x9184_E72A 
    119                 ++hi; 
    120                 data[hi] = multibyteMul(data[0..hi], data[0..hi], 15625*262144, 0); // 5^6*2^18 = 0xF424_0000 
    121                 ++hi; 
    122             } else hi = 2; 
    123             uint c = multibyteIncrementAssign!('+')(data[0..hi], cast(uint)(y&0xFFFF_FFFF)); 
    124             c += multibyteIncrementAssign!('+')(data[1..hi], cast(uint)(y>>32)); 
    125             if (c!=0) { data[hi]=c; ++hi; } 
    126             y = 0; 
    127             lo = 0; 
    128         } 
    129     } 
    130     // Now set y = all remaining digits. 
    131     if (lo>=18) {         
    132     } else if (lo>=9) { 
    133         for (int k=9; k<lo; ++k) y*=10; 
    134         y+=x; 
     24 
     25// return 1 if x>y, -1 if x<y, 0 if equal 
     26int biguintCompare(uint [] x, uint []y) 
     27
     28    uint k = lastDifferentDigit(x, y); 
     29    if (x[k] == y[k]) return 0; 
     30    return x[k] > y[k] ? 1 : -1; 
     31
     32 
     33// return x >> y 
     34uint [] biguintShr(uint[] x, ulong y) 
     35
     36    assert(y>0); 
     37    uint bits = cast(uint)y & 31; 
     38    if ((y>>5) >= x.length) return BIGINTZERO; 
     39    uint words = cast(uint)(y >> 5); 
     40    if (bits==0) { 
     41        return x[words..$]; 
    13542    } else { 
    136         for (int k=0; k<lo; ++k) y*=10; 
    137         y+=x; 
    138     } 
    139     if (y!=0) { 
    140         if (hi==0)  { *cast(ulong *)(&data[hi]) = y; hi=2; } 
    141         else { 
    142  
    143         while (lo>0) { 
    144             uint c = multibyteMul(data[0..hi], data[0..hi], 10, 0); 
    145             if (c!=0) { data[hi]=c; ++hi; }                 
    146             --lo; 
    147         } 
    148             uint c = multibyteIncrementAssign!('+')(data[0..hi], cast(uint)(y&0xFFFF_FFFF)); 
    149             if (y>0xFFFF_FFFFL) { 
    150                 c += multibyteIncrementAssign!('+')(data[1..hi], cast(uint)(y>>32)); 
    151             } 
    152             if (c!=0) { data[hi]=c; ++hi; } 
    153             hi+=2; 
    154         } 
    155     }     
    156     return hi; 
    157 
    158  
    159 public: 
     43        uint [] result = new uint[x.length - words]; 
     44        multibyteShr(result, x[words..$], bits); 
     45        if (result.length>1 && result[$-1]==0) return result[0..$-1]; 
     46        else return result; 
     47    } 
     48
     49 
     50// return x << y 
     51uint [] biguintShl(uint[] x, ulong y) 
     52
     53    assert(y>0); 
     54    if (x.length==1 && x[0]==0) return x; 
     55    uint bits = cast(uint)y & 31; 
     56    assert ((y>>5) < cast(ulong)(uint.max)); 
     57    uint words = cast(uint)(y >> 5); 
     58    uint [] result = new uint[x.length + words+1]; 
     59    result[0..words] = 0; 
     60    if (bits==0) { 
     61        result[words..words+x.length] = x[]; 
     62        return result[0..words+x.length]; 
     63    } else { 
     64        uint c = multibyteShl(result[words..words+x.length], x, bits); 
     65        if (c==0) return result[0..words+x.length]; 
     66        result[$-1] = c; 
     67        return result; 
     68    } 
     69
     70 
    16071 
    16172/** General unsigned subtraction routine for bigints. 
     
    198109} 
    199110 
    200 // return a+
     111// return a +
    201112uint [] biguintAdd(uint[] a, uint [] b) { 
    202113    uint [] x, y; 
     
    399310} 
    400311 
     312public: 
     313// Converts a big uint to a hexadecimal string. 
     314// 
     315// Optionally, a separator character (eg, an underscore) may be added between 
     316// every 8 digits. 
     317// buff.length must be data.length*8 if separator is zero, 
     318// or data.length*9 if separator is non-zero. It will be completely filled. 
     319char [] biguintToHex(char [] buff, uint [] data, char separator=0) 
     320{ 
     321    int x=0; 
     322    for (int i=data.length - 1; i>=0; --i) { 
     323        toHexZeroPadded(buff[x..x+8], data[i]); 
     324        x+=8; 
     325        if (separator) { 
     326            if (i>0) buff[x]='_'; 
     327            ++x; 
     328        } 
     329    } 
     330    return buff; 
     331} 
     332 
     333/** Convert a big uint into a decimal string. 
     334 * 
     335 * Params: 
     336 *  data    The biguint to be converted. Will be destroyed. 
     337 *  buff    The destination buffer for the decimal string. Must be 
     338 *          large enough to store the result, including leading zeros. 
     339 *          Will be filled starting from the end. 
     340 * 
     341 * Ie, buff.length must be (data.length*32)/log2(10) = 9.63296 * data.length. 
     342 * Returns: 
     343 *    the lowest index of buff which was used. 
     344 */ 
     345int biguintToDecimal(char [] buff, uint [] data){ 
     346    int sofar = buff.length; 
     347    // Might be better to divide by (10^38/2^32) since that gives 38 digits for 
     348    // the price of 3 divisions and a shr; this version only gives 27 digits 
     349    // for 3 divisions. 
     350    while(data.length>1) { 
     351        uint rem = multibyteDivAssign(data, 10_0000_0000, 0); 
     352        itoaZeroPadded(buff[sofar-9 .. sofar], rem); 
     353        sofar -= 9; 
     354        if (data[$-1]==0 && data.length>1) { 
     355            data.length = data.length - 1; 
     356        } 
     357    } 
     358    itoaZeroPadded(buff[sofar-10 .. sofar], data[0]); 
     359    sofar-=10; 
     360    // and strip off the leading zeros 
     361    while(sofar!= buff.length-1 && buff[sofar] == '0') sofar++;     
     362    return sofar; 
     363} 
     364 
     365/** Convert a decimal string into a big uint. 
     366 * 
     367 * Params: 
     368 *  data    The biguint to be receive the result. Must be large enough to  
     369 *          store the result. 
     370 *  s       The decimal string. May contain 0..9, or _. Will be preserved. 
     371 * 
     372 * The required length for the destination buffer is slightly less than 
     373 *  1 + s.length/log2(10) = 1 + s.length/3.3219. 
     374 * 
     375 * Returns: 
     376 *    the highest index of data which was used. 
     377 */ 
     378int biguintFromDecimal(uint [] data, char [] s) { 
     379    // Convert to base 1e19 = 10_000_000_000_000_000_000. 
     380    // (this is the largest power of 10 that will fit into a long). 
     381    // The length will be less than 1 + s.length/log2(10) = 1 + s.length/3.3219. 
     382    // 485 bits will only just fit into 146 decimal digits. 
     383    uint lo = 0; 
     384    uint x = 0; 
     385    ulong y = 0; 
     386    uint hi = 0; 
     387    data[0] = 0; // initially number is 0. 
     388    
     389    for (int i= (s[0]=='-' || s[0]=='+')? 1 : 0; i<s.length; ++i) {             
     390        if (s[i] == '_') continue; 
     391        x *= 10; 
     392        x += s[i] - '0'; 
     393        ++lo; 
     394        if (lo==9) { 
     395            y = x; 
     396            x = 0; 
     397        } 
     398        if (lo==18) { 
     399            y *= 10_0000_0000; 
     400            y += x; 
     401            x = 0; 
     402        } 
     403        if (lo==19) { 
     404            y *= 10; 
     405            y += x; 
     406            x = 0; 
     407            // Multiply existing number by 10^19, then add y1. 
     408            if (hi>0) { 
     409                data[hi] = multibyteMul(data[0..hi], data[0..hi], 1220703125*2, 0); // 5^13*2 = 0x9184_E72A 
     410                ++hi; 
     411                data[hi] = multibyteMul(data[0..hi], data[0..hi], 15625*262144, 0); // 5^6*2^18 = 0xF424_0000 
     412                ++hi; 
     413            } else hi = 2; 
     414            uint c = multibyteIncrementAssign!('+')(data[0..hi], cast(uint)(y&0xFFFF_FFFF)); 
     415            c += multibyteIncrementAssign!('+')(data[1..hi], cast(uint)(y>>32)); 
     416            if (c!=0) { data[hi]=c; ++hi; } 
     417            y = 0; 
     418            lo = 0; 
     419        } 
     420    } 
     421    // Now set y = all remaining digits. 
     422    if (lo>=18) {         
     423    } else if (lo>=9) { 
     424        for (int k=9; k<lo; ++k) y*=10; 
     425        y+=x; 
     426    } else { 
     427        for (int k=0; k<lo; ++k) y*=10; 
     428        y+=x; 
     429    } 
     430    if (y!=0) { 
     431        if (hi==0)  { *cast(ulong *)(&data[hi]) = y; hi=2; } 
     432        else { 
     433 
     434        while (lo>0) { 
     435            uint c = multibyteMul(data[0..hi], data[0..hi], 10, 0); 
     436            if (c!=0) { data[hi]=c; ++hi; }                 
     437            --lo; 
     438        } 
     439            uint c = multibyteIncrementAssign!('+')(data[0..hi], cast(uint)(y&0xFFFF_FFFF)); 
     440            if (y>0xFFFF_FFFFL) { 
     441                c += multibyteIncrementAssign!('+')(data[1..hi], cast(uint)(y>>32)); 
     442            } 
     443            if (c!=0) { data[hi]=c; ++hi; } 
     444            hi+=2; 
     445        } 
     446    }     
     447    return hi; 
     448} 
     449 
    401450 
    402451private: 
     
    465514void simpleAddAssign(uint [] result, uint [] right) 
    466515{ 
    467    assert(result.length > right.length); 
     516   assert(result.length >= right.length); 
    468517   uint c = multibyteAddSub!('+')(result[0..right.length], result[0..right.length], right, 0); 
    469518   if (c) { 
     519   assert(result.length > right.length); 
    470520       c = multibyteIncrementAssign!('+')(result[right.length .. $], c); 
    471521       assert(c==0); 
     
    496546    assert(result.length == x.length + y.length); 
    497547    assert(x.length >= y.length); 
    498     if (x.length <= KARATSUBALIMIT) { 
     548    if (y.length <= KARATSUBALIMIT) { 
    499549        return mulSimple(result, x, y); 
    500550    } 
    501551    // Must be almost square. 
    502     assert(2 * y.length * y.length >= x.length * x.length, "Asymmetric Karatsuba"); 
     552    assert(2 * y.length * y.length > (x.length-1) * (x.length-1), "Asymmetric Karatsuba"); 
    503553         
    504554    // Karatsuba multiply uses the following result: 
     
    528578    // (Nx1 + x0)*(Ny1 + y0) = (N*N) x1y1 + x0y0 - N * mid 
    529579    // where mid = (x0-x1)*(y0-y1) - x1y1 - x0y0 
    530     // since then the lengths cannot exceed length N. 
     580    // since then mid.length cannot exceed length N. 
    531581    uint carry_x = addSimple(xsum, x0, x1); 
    532582    uint carry_y = addSimple(ysum, y0, y1); 
     
    536586    if (carry_x)  simpleAddAssign(mid[half..$], ysum); 
    537587    if (carry_y)  simpleAddAssign(mid[half..$], xsum); 
    538          
    539588    // Low half of result gets x0 * y0. High half gets x1 * y1 
    540589    
     
    555604                ysmaller?y1:x1[0..quarter], newscratchbuff); 
    556605            // Save the part which will be overwritten. 
     606            bool ysmaller2 = ((x1.length -quarter) >= y1.length); 
    557607            newscratchbuff[0..y1.length] = resultHigh[quarter..quarter+y1.length]; 
    558             mulKaratsuba(resultHigh[quarter..$], ysmaller?x1[quarter..$]: y1,  
    559                 ysmaller?y1:x1[quarter..$], newscratchbuff[y1.length..$]); 
     608            mulKaratsuba(resultHigh[quarter..$], ysmaller2?x1[quarter..$]: y1,  
     609                ysmaller2?y1:x1[quarter..$], newscratchbuff[y1.length..$]); 
     610 
    560611            resultHigh[quarter..$].simpleAddAssign(newscratchbuff[0..y1.length]);                 
    561612        } 
    562613    } else mulKaratsuba(resultHigh, x1, y1, newscratchbuff); 
    563      
     614         
    564615    mid.simpleSubAssign(resultHigh); 
    565          
     616 
    566617    // result += MID 
    567618    result[half..$].simpleAddAssign(mid); 
    568619} 
     620 
    569621 
    570622private: