jdk/src/share/classes/sun/misc/FDBigInt.java
changeset 22809 8f0522f038d3
parent 22808 88bca865e247
parent 18418 ea73f01b9053
child 22810 3a4dae5224c7
equal deleted inserted replaced
22808:88bca865e247 22809:8f0522f038d3
     1 /*
       
     2  * Copyright (c) 1996, 2012, 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 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 }