Home | History | Annotate | Download | only in misc
      1 /*
      2  * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 package sun.misc;
     27 
     28 /*
     29  * A really, really simple bigint package
     30  * tailored to the needs of floating base conversion.
     31  */
     32 public class FDBigInt {
     33     int nWords; // number of words used
     34     int data[]; // value: data[0] is least significant
     35 
     36 
     37     public FDBigInt( int v ){
     38         nWords = 1;
     39         data = new int[1];
     40         data[0] = v;
     41     }
     42 
     43     public FDBigInt( long v ){
     44         data = new int[2];
     45         data[0] = (int)v;
     46         data[1] = (int)(v>>>32);
     47         nWords = (data[1]==0) ? 1 : 2;
     48     }
     49 
     50     public FDBigInt( FDBigInt other ){
     51         data = new int[nWords = other.nWords];
     52         System.arraycopy( other.data, 0, data, 0, nWords );
     53     }
     54 
     55     private FDBigInt( int [] d, int n ){
     56         data = d;
     57         nWords = n;
     58     }
     59 
     60     public FDBigInt( long seed, char digit[], int nd0, int nd ){
     61         int n= (nd+8)/9;        // estimate size needed.
     62         if ( n < 2 ) n = 2;
     63         data = new int[n];      // allocate enough space
     64         data[0] = (int)seed;    // starting value
     65         data[1] = (int)(seed>>>32);
     66         nWords = (data[1]==0) ? 1 : 2;
     67         int i = nd0;
     68         int limit = nd-5;       // slurp digits 5 at a time.
     69         int v;
     70         while ( i < limit ){
     71             int ilim = i+5;
     72             v = (int)digit[i++]-(int)'0';
     73             while( i <ilim ){
     74                 v = 10*v + (int)digit[i++]-(int)'0';
     75             }
     76             multaddMe( 100000, v); // ... where 100000 is 10^5.
     77         }
     78         int factor = 1;
     79         v = 0;
     80         while ( i < nd ){
     81             v = 10*v + (int)digit[i++]-(int)'0';
     82             factor *= 10;
     83         }
     84         if ( factor != 1 ){
     85             multaddMe( factor, v );
     86         }
     87     }
     88 
     89     /*
     90      * Left shift by c bits.
     91      * Shifts this in place.
     92      */
     93     public void
     94     lshiftMe( int c )throws IllegalArgumentException {
     95         if ( c <= 0 ){
     96             if ( c == 0 )
     97                 return; // silly.
     98             else
     99                 throw new IllegalArgumentException("negative shift count");
    100         }
    101         int wordcount = c>>5;
    102         int bitcount  = c & 0x1f;
    103         int anticount = 32-bitcount;
    104         int t[] = data;
    105         int s[] = data;
    106         if ( nWords+wordcount+1 > t.length ){
    107             // reallocate.
    108             t = new int[ nWords+wordcount+1 ];
    109         }
    110         int target = nWords+wordcount;
    111         int src    = nWords-1;
    112         if ( bitcount == 0 ){
    113             // special hack, since an anticount of 32 won't go!
    114             System.arraycopy( s, 0, t, wordcount, nWords );
    115             target = wordcount-1;
    116         } else {
    117             t[target--] = s[src]>>>anticount;
    118             while ( src >= 1 ){
    119                 t[target--] = (s[src]<<bitcount) | (s[--src]>>>anticount);
    120             }
    121             t[target--] = s[src]<<bitcount;
    122         }
    123         while( target >= 0 ){
    124             t[target--] = 0;
    125         }
    126         data = t;
    127         nWords += wordcount + 1;
    128         // may have constructed high-order word of 0.
    129         // if so, trim it
    130         while ( nWords > 1 && data[nWords-1] == 0 )
    131             nWords--;
    132     }
    133 
    134     /*
    135      * normalize this number by shifting until
    136      * the MSB of the number is at 0x08000000.
    137      * This is in preparation for quoRemIteration, below.
    138      * The idea is that, to make division easier, we want the
    139      * divisor to be "normalized" -- usually this means shifting
    140      * the MSB into the high words sign bit. But because we know that
    141      * the quotient will be 0 < q < 10, we would like to arrange that
    142      * the dividend not span up into another word of precision.
    143      * (This needs to be explained more clearly!)
    144      */
    145     public int
    146     normalizeMe() throws IllegalArgumentException {
    147         int src;
    148         int wordcount = 0;
    149         int bitcount  = 0;
    150         int v = 0;
    151         for ( src= nWords-1 ; src >= 0 && (v=data[src]) == 0 ; src--){
    152             wordcount += 1;
    153         }
    154         if ( src < 0 ){
    155             // oops. Value is zero. Cannot normalize it!
    156             throw new IllegalArgumentException("zero value");
    157         }
    158         /*
    159          * In most cases, we assume that wordcount is zero. This only
    160          * makes sense, as we try not to maintain any high-order
    161          * words full of zeros. In fact, if there are zeros, we will
    162          * simply SHORTEN our number at this point. Watch closely...
    163          */
    164         nWords -= wordcount;
    165         /*
    166          * Compute how far left we have to shift v s.t. its highest-
    167          * order bit is in the right place. Then call lshiftMe to
    168          * do the work.
    169          */
    170         if ( (v & 0xf0000000) != 0 ){
    171             // will have to shift up into the next word.
    172             // too bad.
    173             for( bitcount = 32 ; (v & 0xf0000000) != 0 ; bitcount-- )
    174                 v >>>= 1;
    175         } else {
    176             while ( v <= 0x000fffff ){
    177                 // hack: byte-at-a-time shifting
    178                 v <<= 8;
    179                 bitcount += 8;
    180             }
    181             while ( v <= 0x07ffffff ){
    182                 v <<= 1;
    183                 bitcount += 1;
    184             }
    185         }
    186         if ( bitcount != 0 )
    187             lshiftMe( bitcount );
    188         return bitcount;
    189     }
    190 
    191     /*
    192      * Multiply a FDBigInt by an int.
    193      * Result is a new FDBigInt.
    194      */
    195     public FDBigInt
    196     mult( int iv ) {
    197         long v = iv;
    198         int r[];
    199         long p;
    200 
    201         // guess adequate size of r.
    202         r = new int[ ( v * ((long)data[nWords-1]&0xffffffffL) > 0xfffffffL ) ? nWords+1 : nWords ];
    203         p = 0L;
    204         for( int i=0; i < nWords; i++ ) {
    205             p += v * ((long)data[i]&0xffffffffL);
    206             r[i] = (int)p;
    207             p >>>= 32;
    208         }
    209         if ( p == 0L){
    210             return new FDBigInt( r, nWords );
    211         } else {
    212             r[nWords] = (int)p;
    213             return new FDBigInt( r, nWords+1 );
    214         }
    215     }
    216 
    217     /*
    218      * Multiply a FDBigInt by an int and add another int.
    219      * Result is computed in place.
    220      * Hope it fits!
    221      */
    222     public void
    223     multaddMe( int iv, int addend ) {
    224         long v = iv;
    225         long p;
    226 
    227         // unroll 0th iteration, doing addition.
    228         p = v * ((long)data[0]&0xffffffffL) + ((long)addend&0xffffffffL);
    229         data[0] = (int)p;
    230         p >>>= 32;
    231         for( int i=1; i < nWords; i++ ) {
    232             p += v * ((long)data[i]&0xffffffffL);
    233             data[i] = (int)p;
    234             p >>>= 32;
    235         }
    236         if ( p != 0L){
    237             data[nWords] = (int)p; // will fail noisily if illegal!
    238             nWords++;
    239         }
    240     }
    241 
    242     /*
    243      * Multiply a FDBigInt by another FDBigInt.
    244      * Result is a new FDBigInt.
    245      */
    246     public FDBigInt
    247     mult( FDBigInt other ){
    248         // crudely guess adequate size for r
    249         int r[] = new int[ nWords + other.nWords ];
    250         int i;
    251         // I think I am promised zeros...
    252 
    253         for( i = 0; i < this.nWords; i++ ){
    254             long v = (long)this.data[i] & 0xffffffffL; // UNSIGNED CONVERSION
    255             long p = 0L;
    256             int j;
    257             for( j = 0; j < other.nWords; j++ ){
    258                 p += ((long)r[i+j]&0xffffffffL) + v*((long)other.data[j]&0xffffffffL); // UNSIGNED CONVERSIONS ALL 'ROUND.
    259                 r[i+j] = (int)p;
    260                 p >>>= 32;
    261             }
    262             r[i+j] = (int)p;
    263         }
    264         // compute how much of r we actually needed for all that.
    265         for ( i = r.length-1; i> 0; i--)
    266             if ( r[i] != 0 )
    267                 break;
    268         return new FDBigInt( r, i+1 );
    269     }
    270 
    271     /*
    272      * Add one FDBigInt to another. Return a FDBigInt
    273      */
    274     public FDBigInt
    275     add( FDBigInt other ){
    276         int i;
    277         int a[], b[];
    278         int n, m;
    279         long c = 0L;
    280         // arrange such that a.nWords >= b.nWords;
    281         // n = a.nWords, m = b.nWords
    282         if ( this.nWords >= other.nWords ){
    283             a = this.data;
    284             n = this.nWords;
    285             b = other.data;
    286             m = other.nWords;
    287         } else {
    288             a = other.data;
    289             n = other.nWords;
    290             b = this.data;
    291             m = this.nWords;
    292         }
    293         int r[] = new int[ n ];
    294         for ( i = 0; i < n; i++ ){
    295             c += (long)a[i] & 0xffffffffL;
    296             if ( i < m ){
    297                 c += (long)b[i] & 0xffffffffL;
    298             }
    299             r[i] = (int) c;
    300             c >>= 32; // signed shift.
    301         }
    302         if ( c != 0L ){
    303             // oops -- carry out -- need longer result.
    304             int s[] = new int[ r.length+1 ];
    305             System.arraycopy( r, 0, s, 0, r.length );
    306             s[i++] = (int)c;
    307             return new FDBigInt( s, i );
    308         }
    309         return new FDBigInt( r, i );
    310     }
    311 
    312     /*
    313      * Subtract one FDBigInt from another. Return a FDBigInt
    314      * Assert that the result is positive.
    315      */
    316     public FDBigInt
    317     sub( FDBigInt other ){
    318         int r[] = new int[ this.nWords ];
    319         int i;
    320         int n = this.nWords;
    321         int m = other.nWords;
    322         int nzeros = 0;
    323         long c = 0L;
    324         for ( i = 0; i < n; i++ ){
    325             c += (long)this.data[i] & 0xffffffffL;
    326             if ( i < m ){
    327                 c -= (long)other.data[i] & 0xffffffffL;
    328             }
    329             if ( ( r[i] = (int) c ) == 0 )
    330                 nzeros++;
    331             else
    332                 nzeros = 0;
    333             c >>= 32; // signed shift
    334         }
    335         assert c == 0L : c; // borrow out of subtract
    336         assert dataInRangeIsZero(i, m, other); // negative result of subtract
    337         return new FDBigInt( r, n-nzeros );
    338     }
    339 
    340     private static boolean dataInRangeIsZero(int i, int m, FDBigInt other) {
    341         while ( i < m )
    342             if (other.data[i++] != 0)
    343                 return false;
    344         return true;
    345     }
    346 
    347     /*
    348      * Compare FDBigInt with another FDBigInt. Return an integer
    349      * >0: this > other
    350      *  0: this == other
    351      * <0: this < other
    352      */
    353     public int
    354     cmp( FDBigInt other ){
    355         int i;
    356         if ( this.nWords > other.nWords ){
    357             // if any of my high-order words is non-zero,
    358             // then the answer is evident
    359             int j = other.nWords-1;
    360             for ( i = this.nWords-1; i > j ; i-- )
    361                 if ( this.data[i] != 0 ) return 1;
    362         }else if ( this.nWords < other.nWords ){
    363             // if any of other's high-order words is non-zero,
    364             // then the answer is evident
    365             int j = this.nWords-1;
    366             for ( i = other.nWords-1; i > j ; i-- )
    367                 if ( other.data[i] != 0 ) return -1;
    368         } else{
    369             i = this.nWords-1;
    370         }
    371         for ( ; i > 0 ; i-- )
    372             if ( this.data[i] != other.data[i] )
    373                 break;
    374         // careful! want unsigned compare!
    375         // use brute force here.
    376         int a = this.data[i];
    377         int b = other.data[i];
    378         if ( a < 0 ){
    379             // a is really big, unsigned
    380             if ( b < 0 ){
    381                 return a-b; // both big, negative
    382             } else {
    383                 return 1; // b not big, answer is obvious;
    384             }
    385         } else {
    386             // a is not really big
    387             if ( b < 0 ) {
    388                 // but b is really big
    389                 return -1;
    390             } else {
    391                 return a - b;
    392             }
    393         }
    394     }
    395 
    396     /*
    397      * Compute
    398      * q = (int)( this / S )
    399      * this = 10 * ( this mod S )
    400      * Return q.
    401      * This is the iteration step of digit development for output.
    402      * We assume that S has been normalized, as above, and that
    403      * "this" has been lshift'ed accordingly.
    404      * Also assume, of course, that the result, q, can be expressed
    405      * as an integer, 0 <= q < 10.
    406      */
    407     public int
    408     quoRemIteration( FDBigInt S )throws IllegalArgumentException {
    409         // ensure that this and S have the same number of
    410         // digits. If S is properly normalized and q < 10 then
    411         // this must be so.
    412         if ( nWords != S.nWords ){
    413             throw new IllegalArgumentException("disparate values");
    414         }
    415         // estimate q the obvious way. We will usually be
    416         // right. If not, then we're only off by a little and
    417         // will re-add.
    418         int n = nWords-1;
    419         long q = ((long)data[n]&0xffffffffL) / (long)S.data[n];
    420         long diff = 0L;
    421         for ( int i = 0; i <= n ; i++ ){
    422             diff += ((long)data[i]&0xffffffffL) -  q*((long)S.data[i]&0xffffffffL);
    423             data[i] = (int)diff;
    424             diff >>= 32; // N.B. SIGNED shift.
    425         }
    426         if ( diff != 0L ) {
    427             // damn, damn, damn. q is too big.
    428             // add S back in until this turns +. This should
    429             // not be very many times!
    430             long sum = 0L;
    431             while ( sum ==  0L ){
    432                 sum = 0L;
    433                 for ( int i = 0; i <= n; i++ ){
    434                     sum += ((long)data[i]&0xffffffffL) +  ((long)S.data[i]&0xffffffffL);
    435                     data[i] = (int) sum;
    436                     sum >>= 32; // Signed or unsigned, answer is 0 or 1
    437                 }
    438                 /*
    439                  * Originally the following line read
    440                  * "if ( sum !=0 && sum != -1 )"
    441                  * but that would be wrong, because of the
    442                  * treatment of the two values as entirely unsigned,
    443                  * it would be impossible for a carry-out to be interpreted
    444                  * as -1 -- it would have to be a single-bit carry-out, or
    445                  * +1.
    446                  */
    447                 assert sum == 0 || sum == 1 : sum; // carry out of division correction
    448                 q -= 1;
    449             }
    450         }
    451         // finally, we can multiply this by 10.
    452         // it cannot overflow, right, as the high-order word has
    453         // at least 4 high-order zeros!
    454         long p = 0L;
    455         for ( int i = 0; i <= n; i++ ){
    456             p += 10*((long)data[i]&0xffffffffL);
    457             data[i] = (int)p;
    458             p >>= 32; // SIGNED shift.
    459         }
    460         assert p == 0L : p; // Carry out of *10
    461         return (int)q;
    462     }
    463 
    464     public long
    465     longValue(){
    466         // if this can be represented as a long, return the value
    467         assert this.nWords > 0 : this.nWords; // longValue confused
    468 
    469         if (this.nWords == 1)
    470             return ((long)data[0]&0xffffffffL);
    471 
    472         assert dataInRangeIsZero(2, this.nWords, this); // value too big
    473         assert data[1] >= 0;  // value too big
    474         return ((long)(data[1]) << 32) | ((long)data[0]&0xffffffffL);
    475     }
    476 
    477     public String
    478     toString() {
    479         StringBuffer r = new StringBuffer(30);
    480         r.append('[');
    481         int i = Math.min( nWords-1, data.length-1) ;
    482         if ( nWords > data.length ){
    483             r.append( "("+data.length+"<"+nWords+"!)" );
    484         }
    485         for( ; i> 0 ; i-- ){
    486             r.append( Integer.toHexString( data[i] ) );
    487             r.append(' ');
    488         }
    489         r.append( Integer.toHexString( data[0] ) );
    490         r.append(']');
    491         return new String( r );
    492     }
    493 }
    494