diff options
| author | Graydon Hoare <[email protected]> | 2010-06-23 21:03:09 -0700 |
|---|---|---|
| committer | Graydon Hoare <[email protected]> | 2010-06-23 21:03:09 -0700 |
| commit | d6b7c96c3eb29b9244ece0c046d3f372ff432d04 (patch) | |
| tree | b425187e232966063ffc2f0d14c04a55d8f004ef /src/rt/bigint/bigint_int.cpp | |
| parent | Initial git commit. (diff) | |
| download | rust-d6b7c96c3eb29b9244ece0c046d3f372ff432d04.tar.xz rust-d6b7c96c3eb29b9244ece0c046d3f372ff432d04.zip | |
Populate tree.
Diffstat (limited to 'src/rt/bigint/bigint_int.cpp')
| -rw-r--r-- | src/rt/bigint/bigint_int.cpp | 1428 |
1 files changed, 1428 insertions, 0 deletions
diff --git a/src/rt/bigint/bigint_int.cpp b/src/rt/bigint/bigint_int.cpp new file mode 100644 index 00000000..194ddcb5 --- /dev/null +++ b/src/rt/bigint/bigint_int.cpp @@ -0,0 +1,1428 @@ +/* bigint - internal portion of large integer package +** +** Copyright � 2000 by Jef Poskanzer <[email protected]>. +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +#include <sys/types.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <time.h> + +#include "bigint.h" + +#define max(a,b) ((a)>(b)?(a):(b)) +#define min(a,b) ((a)<(b)?(a):(b)) + +/* MAXINT and MININT extracted from <values.h>, which gives a warning +** message if included. +*/ +#define BITSPERBYTE 8 +#define BITS(type) (BITSPERBYTE * (int)sizeof(type)) +#define INTBITS BITS(int) +#define MININT (1 << (INTBITS - 1)) +#define MAXINT (~MININT) + + +/* The package represents arbitrary-precision integers as a sign and a sum +** of components multiplied by successive powers of the basic radix, i.e.: +** +** sign * ( comp0 + comp1 * radix + comp2 * radix^2 + comp3 * radix^3 ) +** +** To make good use of the computer's word size, the radix is chosen +** to be a power of two. It could be chosen to be the full word size, +** however this would require a lot of finagling in the middle of the +** algorithms to get the inter-word overflows right. That would slow things +** down. Instead, the radix is chosen to be *half* the actual word size. +** With just a little care, this means the words can hold all intermediate +** values, and the overflows can be handled all at once at the end, in a +** normalization step. This simplifies the coding enormously, and is probably +** somewhat faster to run. The cost is that numbers use twice as much +** storage as they would with the most efficient representation, but storage +** is cheap. +** +** A few more notes on the representation: +** +** - The sign is always 1 or -1, never 0. The number 0 is represented +** with a sign of 1. +** - The components are signed numbers, to allow for negative intermediate +** values. After normalization, all components are >= 0 and the sign is +** updated. +*/ + +/* Type definition for bigints. */ +typedef int64_t comp; /* should be the largest signed int type you have */ +struct _real_bigint { + int refs; + struct _real_bigint* next; + int num_comps, max_comps; + int sign; + comp* comps; + }; +typedef struct _real_bigint* real_bigint; + + +#undef DUMP + + +#define PERMANENT 123456789 + +static comp bi_radix, bi_radix_o2; +static int bi_radix_sqrt, bi_comp_bits; + +static real_bigint active_list, free_list; +static int active_count, free_count; +static int check_level; + + +/* Forwards. */ +static bigint regular_multiply( real_bigint bia, real_bigint bib ); +static bigint multi_divide( bigint binumer, real_bigint bidenom ); +static bigint multi_divide2( bigint binumer, real_bigint bidenom ); +static void more_comps( real_bigint bi, int n ); +static real_bigint alloc( int num_comps ); +static real_bigint clone( real_bigint bi ); +static void normalize( real_bigint bi ); +static void check( real_bigint bi ); +static void double_check( void ); +static void triple_check( void ); +#ifdef DUMP +static void dump( char* str, bigint bi ); +#endif /* DUMP */ +static int csqrt( comp c ); +static int cbits( comp c ); + + +void +bi_initialize( void ) + { + /* Set the radix. This does not actually have to be a power of + ** two, that's just the most efficient value. It does have to + ** be even for bi_half() to work. + */ + bi_radix = 1; + bi_radix <<= BITS(comp) / 2 - 1; + + /* Halve the radix. Only used by bi_half(). */ + bi_radix_o2 = bi_radix >> 1; + + /* Take the square root of the radix. Only used by bi_divide(). */ + bi_radix_sqrt = csqrt( bi_radix ); + + /* Figure out how many bits in a component. Only used by bi_bits(). */ + bi_comp_bits = cbits( bi_radix - 1 ); + + /* Init various globals. */ + active_list = (real_bigint) 0; + active_count = 0; + free_list = (real_bigint) 0; + free_count = 0; + + /* This can be 0 through 3. */ + check_level = 3; + + /* Set up some convenient bigints. */ + bi_0 = int_to_bi( 0 ); bi_permanent( bi_0 ); + bi_1 = int_to_bi( 1 ); bi_permanent( bi_1 ); + bi_2 = int_to_bi( 2 ); bi_permanent( bi_2 ); + bi_10 = int_to_bi( 10 ); bi_permanent( bi_10 ); + bi_m1 = int_to_bi( -1 ); bi_permanent( bi_m1 ); + bi_maxint = int_to_bi( MAXINT ); bi_permanent( bi_maxint ); + bi_minint = int_to_bi( MININT ); bi_permanent( bi_minint ); + } + + +void +bi_terminate( void ) + { + real_bigint p, pn; + + bi_depermanent( bi_0 ); bi_free( bi_0 ); + bi_depermanent( bi_1 ); bi_free( bi_1 ); + bi_depermanent( bi_2 ); bi_free( bi_2 ); + bi_depermanent( bi_10 ); bi_free( bi_10 ); + bi_depermanent( bi_m1 ); bi_free( bi_m1 ); + bi_depermanent( bi_maxint ); bi_free( bi_maxint ); + bi_depermanent( bi_minint ); bi_free( bi_minint ); + + if ( active_count != 0 ) + (void) fprintf( + stderr, "bi_terminate: there were %d un-freed bigints\n", + active_count ); + if ( check_level >= 2 ) + double_check(); + if ( check_level >= 3 ) + { + triple_check(); + for ( p = active_list; p != (bigint) 0; p = pn ) + { + pn = p->next; + free( p->comps ); + free( p ); + } + } + for ( p = free_list; p != (bigint) 0; p = pn ) + { + pn = p->next; + free( p->comps ); + free( p ); + } + } + + +void +bi_no_check( void ) + { + check_level = 0; + } + + +bigint +bi_copy( bigint obi ) + { + real_bigint bi = (real_bigint) obi; + + check( bi ); + if ( bi->refs != PERMANENT ) + ++bi->refs; + return bi; + } + + +void +bi_permanent( bigint obi ) + { + real_bigint bi = (real_bigint) obi; + + check( bi ); + if ( check_level >= 1 && bi->refs != 1 ) + { + (void) fprintf( stderr, "bi_permanent: refs was not 1\n" ); + (void) kill( getpid(), SIGFPE ); + } + bi->refs = PERMANENT; + } + + +void +bi_depermanent( bigint obi ) + { + real_bigint bi = (real_bigint) obi; + + check( bi ); + if ( check_level >= 1 && bi->refs != PERMANENT ) + { + (void) fprintf( stderr, "bi_depermanent: bigint was not permanent\n" ); + (void) kill( getpid(), SIGFPE ); + } + bi->refs = 1; + } + + +void +bi_free( bigint obi ) + { + real_bigint bi = (real_bigint) obi; + + check( bi ); + if ( bi->refs == PERMANENT ) + return; + --bi->refs; + if ( bi->refs > 0 ) + return; + if ( check_level >= 3 ) + { + /* The active list only gets maintained at check levels 3 or higher. */ + real_bigint* nextP; + for ( nextP = &active_list; *nextP != (real_bigint) 0; nextP = &((*nextP)->next) ) + if ( *nextP == bi ) + { + *nextP = bi->next; + break; + } + } + --active_count; + bi->next = free_list; + free_list = bi; + ++free_count; + if ( check_level >= 1 && active_count < 0 ) + { + (void) fprintf( stderr, + "bi_free: active_count went negative - double-freed bigint?\n" ); + (void) kill( getpid(), SIGFPE ); + } + } + + +int +bi_compare( bigint obia, bigint obib ) + { + real_bigint bia = (real_bigint) obia; + real_bigint bib = (real_bigint) obib; + int r, c; + + check( bia ); + check( bib ); + + /* First check for pointer equality. */ + if ( bia == bib ) + r = 0; + else + { + /* Compare signs. */ + if ( bia->sign > bib->sign ) + r = 1; + else if ( bia->sign < bib->sign ) + r = -1; + /* Signs are the same. Check the number of components. */ + else if ( bia->num_comps > bib->num_comps ) + r = bia->sign; + else if ( bia->num_comps < bib->num_comps ) + r = -bia->sign; + else + { + /* Same number of components. Compare starting from the high end + ** and working down. + */ + r = 0; /* if we complete the loop, the numbers are equal */ + for ( c = bia->num_comps - 1; c >= 0; --c ) + { + if ( bia->comps[c] > bib->comps[c] ) + { r = bia->sign; break; } + else if ( bia->comps[c] < bib->comps[c] ) + { r = -bia->sign; break; } + } + } + } + + bi_free( bia ); + bi_free( bib ); + return r; + } + + +bigint +int_to_bi( int i ) + { + real_bigint biR; + + biR = alloc( 1 ); + biR->sign = 1; + biR->comps[0] = i; + normalize( biR ); + check( biR ); + return biR; + } + + +int +bi_to_int( bigint obi ) + { + real_bigint bi = (real_bigint) obi; + comp v, m; + int c, r; + + check( bi ); + if ( bi_compare( bi_copy( bi ), bi_maxint ) > 0 || + bi_compare( bi_copy( bi ), bi_minint ) < 0 ) + { + (void) fprintf( stderr, "bi_to_int: overflow\n" ); + (void) kill( getpid(), SIGFPE ); + } + v = 0; + m = 1; + for ( c = 0; c < bi->num_comps; ++c ) + { + v += bi->comps[c] * m; + m *= bi_radix; + } + r = (int) ( bi->sign * v ); + bi_free( bi ); + return r; + } + + +bigint +bi_int_add( bigint obi, int i ) + { + real_bigint bi = (real_bigint) obi; + real_bigint biR; + + check( bi ); + biR = clone( bi ); + if ( biR->sign == 1 ) + biR->comps[0] += i; + else + biR->comps[0] -= i; + normalize( biR ); + check( biR ); + return biR; + } + + +bigint +bi_int_subtract( bigint obi, int i ) + { + real_bigint bi = (real_bigint) obi; + real_bigint biR; + + check( bi ); + biR = clone( bi ); + if ( biR->sign == 1 ) + biR->comps[0] -= i; + else + biR->comps[0] += i; + normalize( biR ); + check( biR ); + return biR; + } + + +bigint +bi_int_multiply( bigint obi, int i ) + { + real_bigint bi = (real_bigint) obi; + real_bigint biR; + int c; + + check( bi ); + biR = clone( bi ); + if ( i < 0 ) + { + i = -i; + biR->sign = -biR->sign; + } + for ( c = 0; c < biR->num_comps; ++c ) + biR->comps[c] *= i; + normalize( biR ); + check( biR ); + return biR; + } + + +bigint +bi_int_divide( bigint obinumer, int denom ) + { + real_bigint binumer = (real_bigint) obinumer; + real_bigint biR; + int c; + comp r; + + check( binumer ); + if ( denom == 0 ) + { + (void) fprintf( stderr, "bi_int_divide: divide by zero\n" ); + (void) kill( getpid(), SIGFPE ); + } + biR = clone( binumer ); + if ( denom < 0 ) + { + denom = -denom; + biR->sign = -biR->sign; + } + r = 0; + for ( c = biR->num_comps - 1; c >= 0; --c ) + { + r = r * bi_radix + biR->comps[c]; + biR->comps[c] = r / denom; + r = r % denom; + } + normalize( biR ); + check( biR ); + return biR; + } + + +int +bi_int_rem( bigint obi, int m ) + { + real_bigint bi = (real_bigint) obi; + comp rad_r, r; + int c; + + check( bi ); + if ( m == 0 ) + { + (void) fprintf( stderr, "bi_int_rem: divide by zero\n" ); + (void) kill( getpid(), SIGFPE ); + } + if ( m < 0 ) + m = -m; + rad_r = 1; + r = 0; + for ( c = 0; c < bi->num_comps; ++c ) + { + r = ( r + bi->comps[c] * rad_r ) % m; + rad_r = ( rad_r * bi_radix ) % m; + } + if ( bi->sign < 1 ) + r = -r; + bi_free( bi ); + return (int) r; + } + + +bigint +bi_add( bigint obia, bigint obib ) + { + real_bigint bia = (real_bigint) obia; + real_bigint bib = (real_bigint) obib; + real_bigint biR; + int c; + + check( bia ); + check( bib ); + biR = clone( bia ); + more_comps( biR, max( biR->num_comps, bib->num_comps ) ); + for ( c = 0; c < bib->num_comps; ++c ) + if ( biR->sign == bib->sign ) + biR->comps[c] += bib->comps[c]; + else + biR->comps[c] -= bib->comps[c]; + bi_free( bib ); + normalize( biR ); + check( biR ); + return biR; + } + + +bigint +bi_subtract( bigint obia, bigint obib ) + { + real_bigint bia = (real_bigint) obia; + real_bigint bib = (real_bigint) obib; + real_bigint biR; + int c; + + check( bia ); + check( bib ); + biR = clone( bia ); + more_comps( biR, max( biR->num_comps, bib->num_comps ) ); + for ( c = 0; c < bib->num_comps; ++c ) + if ( biR->sign == bib->sign ) + biR->comps[c] -= bib->comps[c]; + else + biR->comps[c] += bib->comps[c]; + bi_free( bib ); + normalize( biR ); + check( biR ); + return biR; + } + + +/* Karatsuba multiplication. This is supposedly O(n^1.59), better than +** regular multiplication for large n. The define below sets the crossover +** point - below that we use regular multiplication, above it we +** use Karatsuba. Note that Karatsuba is a recursive algorithm, so +** all Karatsuba calls involve regular multiplications as the base +** steps. +*/ +#define KARATSUBA_THRESH 12 +bigint +bi_multiply( bigint obia, bigint obib ) + { + real_bigint bia = (real_bigint) obia; + real_bigint bib = (real_bigint) obib; + + check( bia ); + check( bib ); + if ( min( bia->num_comps, bib->num_comps ) < KARATSUBA_THRESH ) + return regular_multiply( bia, bib ); + else + { + /* The factors are large enough that Karatsuba multiplication + ** is a win. The basic idea here is you break each factor up + ** into two parts, like so: + ** i * r^n + j k * r^n + l + ** r is the radix we're representing numbers with, so this + ** breaking up just means shuffling components around, no + ** math required. With regular multiplication the product + ** would be: + ** ik * r^(n*2) + ( il + jk ) * r^n + jl + ** That's four sub-multiplies and one addition, not counting the + ** radix-shifting. With Karatsuba, you instead do: + ** ik * r^(n*2) + ( (i+j)(k+l) - ik - jl ) * r^n + jl + ** This is only three sub-multiplies. The number of adds + ** (and subtracts) increases to four, but those run in linear time + ** so they are cheap. The sub-multiplies are accomplished by + ** recursive calls, eventually reducing to regular multiplication. + */ + int n, c; + real_bigint bi_i, bi_j, bi_k, bi_l; + real_bigint bi_ik, bi_mid, bi_jl; + + n = ( max( bia->num_comps, bib->num_comps ) + 1 ) / 2; + bi_i = alloc( n ); + bi_j = alloc( n ); + bi_k = alloc( n ); + bi_l = alloc( n ); + for ( c = 0; c < n; ++c ) + { + if ( c + n < bia->num_comps ) + bi_i->comps[c] = bia->comps[c + n]; + else + bi_i->comps[c] = 0; + if ( c < bia->num_comps ) + bi_j->comps[c] = bia->comps[c]; + else + bi_j->comps[c] = 0; + if ( c + n < bib->num_comps ) + bi_k->comps[c] = bib->comps[c + n]; + else + bi_k->comps[c] = 0; + if ( c < bib->num_comps ) + bi_l->comps[c] = bib->comps[c]; + else + bi_l->comps[c] = 0; + } + bi_i->sign = bi_j->sign = bi_k->sign = bi_l->sign = 1; + normalize( bi_i ); + normalize( bi_j ); + normalize( bi_k ); + normalize( bi_l ); + bi_ik = bi_multiply( bi_copy( bi_i ), bi_copy( bi_k ) ); + bi_jl = bi_multiply( bi_copy( bi_j ), bi_copy( bi_l ) ); + bi_mid = bi_subtract( + bi_subtract( + bi_multiply( bi_add( bi_i, bi_j ), bi_add( bi_k, bi_l ) ), + bi_copy( bi_ik ) ), + bi_copy( bi_jl ) ); + more_comps( + bi_jl, max( bi_mid->num_comps + n, bi_ik->num_comps + n * 2 ) ); + for ( c = 0; c < bi_mid->num_comps; ++c ) + bi_jl->comps[c + n] += bi_mid->comps[c]; + for ( c = 0; c < bi_ik->num_comps; ++c ) + bi_jl->comps[c + n * 2] += bi_ik->comps[c]; + bi_free( bi_ik ); + bi_free( bi_mid ); + bi_jl->sign = bia->sign * bib->sign; + bi_free( bia ); + bi_free( bib ); + normalize( bi_jl ); + check( bi_jl ); + return bi_jl; + } + } + + +/* Regular O(n^2) multiplication. */ +static bigint +regular_multiply( real_bigint bia, real_bigint bib ) + { + real_bigint biR; + int new_comps, c1, c2; + + check( bia ); + check( bib ); + biR = clone( bi_0 ); + new_comps = bia->num_comps + bib->num_comps; + more_comps( biR, new_comps ); + for ( c1 = 0; c1 < bia->num_comps; ++c1 ) + { + for ( c2 = 0; c2 < bib->num_comps; ++c2 ) + biR->comps[c1 + c2] += bia->comps[c1] * bib->comps[c2]; + /* Normalize after each inner loop to avoid overflowing any + ** components. But be sure to reset biR's components count, + ** in case a previous normalization lowered it. + */ + biR->num_comps = new_comps; + normalize( biR ); + } + check( biR ); + if ( ! bi_is_zero( bi_copy( biR ) ) ) + biR->sign = bia->sign * bib->sign; + bi_free( bia ); + bi_free( bib ); + return biR; + } + + +/* The following three routines implement a multi-precision divide method +** that I haven't seen used anywhere else. It is not quite as fast as +** the standard divide method, but it is a lot simpler. In fact it's +** about as simple as the binary shift-and-subtract method, which goes +** about five times slower than this. +** +** The method assumes you already have multi-precision multiply and subtract +** routines, and also a multi-by-single precision divide routine. The latter +** is used to generate approximations, which are then checked and corrected +** using the former. The result converges to the correct value by about +** 16 bits per loop. +*/ + +/* Public routine to divide two arbitrary numbers. */ +bigint +bi_divide( bigint binumer, bigint obidenom ) + { + real_bigint bidenom = (real_bigint) obidenom; + int sign; + bigint biquotient; + + /* Check signs and trivial cases. */ + sign = 1; + switch ( bi_compare( bi_copy( bidenom ), bi_0 ) ) + { + case 0: + (void) fprintf( stderr, "bi_divide: divide by zero\n" ); + (void) kill( getpid(), SIGFPE ); + case -1: + sign *= -1; + bidenom = bi_negate( bidenom ); + break; + } + switch ( bi_compare( bi_copy( binumer ), bi_0 ) ) + { + case 0: + bi_free( binumer ); + bi_free( bidenom ); + return bi_0; + case -1: + sign *= -1; + binumer = bi_negate( binumer ); + break; + } + switch ( bi_compare( bi_copy( binumer ), bi_copy( bidenom ) ) ) + { + case -1: + bi_free( binumer ); + bi_free( bidenom ); + return bi_0; + case 0: + bi_free( binumer ); + bi_free( bidenom ); + if ( sign == 1 ) + return bi_1; + else + return bi_m1; + } + + /* Is the denominator small enough to do an int divide? */ + if ( bidenom->num_comps == 1 ) + { + /* Win! */ + biquotient = bi_int_divide( binumer, bidenom->comps[0] ); + bi_free( bidenom ); + } + else + { + /* No, we have to do a full multi-by-multi divide. */ + biquotient = multi_divide( binumer, bidenom ); + } + + if ( sign == -1 ) + biquotient = bi_negate( biquotient ); + return biquotient; + } + + +/* Divide two multi-precision positive numbers. */ +static bigint +multi_divide( bigint binumer, real_bigint bidenom ) + { + /* We use a successive approximation method that is kind of like a + ** continued fraction. The basic approximation is to do an int divide + ** by the high-order component of the denominator. Then we correct + ** based on the remainder from that. + ** + ** However, if the high-order component is too small, this doesn't + ** work well. In particular, if the high-order component is 1 it + ** doesn't work at all. Easily fixed, though - if the component + ** is too small, increase it! + */ + if ( bidenom->comps[bidenom->num_comps-1] < bi_radix_sqrt ) + { + /* We use the square root of the radix as the threshhold here + ** because that's the largest value guaranteed to not make the + ** high-order component overflow and become too small again. + ** + ** We increase binumer along with bidenom to keep the end result + ** the same. + */ + binumer = bi_int_multiply( binumer, bi_radix_sqrt ); + bidenom = bi_int_multiply( bidenom, bi_radix_sqrt ); + } + + /* Now start the recursion. */ + return multi_divide2( binumer, bidenom ); + } + + +/* Divide two multi-precision positive conditioned numbers. */ +static bigint +multi_divide2( bigint binumer, real_bigint bidenom ) + { + real_bigint biapprox; + bigint birem, biquotient; + int c, o; + + /* Figure out the approximate quotient. Since we're dividing by only + ** the top component of the denominator, which is less than or equal to + ** the full denominator, the result is guaranteed to be greater than or + ** equal to the correct quotient. + */ + o = bidenom->num_comps - 1; + biapprox = bi_int_divide( bi_copy( binumer ), bidenom->comps[o] ); + /* And downshift the result to get the approximate quotient. */ + for ( c = o; c < biapprox->num_comps; ++c ) + biapprox->comps[c - o] = biapprox->comps[c]; + biapprox->num_comps -= o; + + /* Find the remainder from the approximate quotient. */ + birem = bi_subtract( + bi_multiply( bi_copy( biapprox ), bi_copy( bidenom ) ), binumer ); + + /* If the remainder is negative, zero, or in fact any value less + ** than bidenom, then we have the correct quotient and we're done. + */ + if ( bi_compare( bi_copy( birem ), bi_copy( bidenom ) ) < 0 ) + { + biquotient = biapprox; + bi_free( birem ); + bi_free( bidenom ); + } + else + { + /* The real quotient is now biapprox - birem / bidenom. We still + ** have to do a divide. However, birem is smaller than binumer, + ** so the next divide will go faster. We do the divide by + ** recursion. Since this is tail-recursion or close to it, we + ** could probably re-arrange things and make it a non-recursive + ** loop, but the overhead of recursion is small and the bookkeeping + ** is simpler this way. + ** + ** Note that since the sub-divide uses the same denominator, it + ** doesn't have to adjust the values again - the high-order component + ** will still be good. + */ + biquotient = bi_subtract( biapprox, multi_divide2( birem, bidenom ) ); + } + + return biquotient; + } + + +/* Binary division - about five times slower than the above. */ +bigint +bi_binary_divide( bigint binumer, bigint obidenom ) + { + real_bigint bidenom = (real_bigint) obidenom; + int sign; + bigint biquotient; + + /* Check signs and trivial cases. */ + sign = 1; + switch ( bi_compare( bi_copy( bidenom ), bi_0 ) ) + { + case 0: + (void) fprintf( stderr, "bi_divide: divide by zero\n" ); + (void) kill( getpid(), SIGFPE ); + case -1: + sign *= -1; + bidenom = bi_negate( bidenom ); + break; + } + switch ( bi_compare( bi_copy( binumer ), bi_0 ) ) + { + case 0: + bi_free( binumer ); + bi_free( bidenom ); + return bi_0; + case -1: + sign *= -1; + binumer = bi_negate( binumer ); + break; + } + switch ( bi_compare( bi_copy( binumer ), bi_copy( bidenom ) ) ) + { + case -1: + bi_free( binumer ); + bi_free( bidenom ); + return bi_0; + case 0: + bi_free( binumer ); + bi_free( bidenom ); + if ( sign == 1 ) + return bi_1; + else + return bi_m1; + } + + /* Is the denominator small enough to do an int divide? */ + if ( bidenom->num_comps == 1 ) + { + /* Win! */ + biquotient = bi_int_divide( binumer, bidenom->comps[0] ); + bi_free( bidenom ); + } + else + { + /* No, we have to do a full multi-by-multi divide. */ + int num_bits, den_bits, i; + + num_bits = bi_bits( bi_copy( binumer ) ); + den_bits = bi_bits( bi_copy( bidenom ) ); + bidenom = bi_multiply( bidenom, bi_power( bi_2, int_to_bi( num_bits - den_bits ) ) ); + biquotient = bi_0; + for ( i = den_bits; i <= num_bits; ++i ) + { + biquotient = bi_double( biquotient ); + if ( bi_compare( bi_copy( binumer ), bi_copy( bidenom ) ) >= 0 ) + { + biquotient = bi_int_add( biquotient, 1 ); + binumer = bi_subtract( binumer, bi_copy( bidenom ) ); + } + bidenom = bi_half( bidenom ); + } + bi_free( binumer ); + bi_free( bidenom ); + } + + if ( sign == -1 ) + biquotient = bi_negate( biquotient ); + return biquotient; + } + + +bigint +bi_negate( bigint obi ) + { + real_bigint bi = (real_bigint) obi; + real_bigint biR; + + check( bi ); + biR = clone( bi ); + biR->sign = -biR->sign; + check( biR ); + return biR; + } + + +bigint +bi_abs( bigint obi ) + { + real_bigint bi = (real_bigint) obi; + real_bigint biR; + + check( bi ); + biR = clone( bi ); + biR->sign = 1; + check( biR ); + return biR; + } + + +bigint +bi_half( bigint obi ) + { + real_bigint bi = (real_bigint) obi; + real_bigint biR; + int c; + + check( bi ); + /* This depends on the radix being even. */ + biR = clone( bi ); + for ( c = 0; c < biR->num_comps; ++c ) + { + if ( biR->comps[c] & 1 ) + if ( c > 0 ) + biR->comps[c - 1] += bi_radix_o2; + biR->comps[c] = biR->comps[c] >> 1; + } + /* Avoid normalization. */ + if ( biR->num_comps > 1 && biR->comps[biR->num_comps-1] == 0 ) + --biR->num_comps; + check( biR ); + return biR; + } + + +bigint +bi_double( bigint obi ) + { + real_bigint bi = (real_bigint) obi; + real_bigint biR; + int c; + + check( bi ); + biR = clone( bi ); + for ( c = biR->num_comps - 1; c >= 0; --c ) + { + biR->comps[c] = biR->comps[c] << 1; + if ( biR->comps[c] >= bi_radix ) + { + if ( c + 1 >= biR->num_comps ) + more_comps( biR, biR->num_comps + 1 ); + biR->comps[c] -= bi_radix; + biR->comps[c + 1] += 1; + } + } + check( biR ); + return biR; + } + + +/* Find integer square root by Newton's method. */ +bigint +bi_sqrt( bigint obi ) + { + real_bigint bi = (real_bigint) obi; + bigint biR, biR2, bidiff; + + switch ( bi_compare( bi_copy( bi ), bi_0 ) ) + { + case -1: + (void) fprintf( stderr, "bi_sqrt: imaginary result\n" ); + (void) kill( getpid(), SIGFPE ); + case 0: + return bi; + } + if ( bi_is_one( bi_copy( bi ) ) ) + return bi; + + /* Newton's method converges reasonably fast, but it helps to have + ** a good initial guess. We can make a *very* good initial guess + ** by taking the square root of the top component times the square + ** root of the radix part. Both of those are easy to compute. + */ + biR = bi_int_multiply( + bi_power( int_to_bi( bi_radix_sqrt ), int_to_bi( bi->num_comps - 1 ) ), + csqrt( bi->comps[bi->num_comps - 1] ) ); + + /* Now do the Newton loop until we have the answer. */ + for (;;) + { + biR2 = bi_divide( bi_copy( bi ), bi_copy( biR ) ); + bidiff = bi_subtract( bi_copy( biR ), bi_copy( biR2 ) ); + if ( bi_is_zero( bi_copy( bidiff ) ) || + bi_compare( bi_copy( bidiff ), bi_m1 ) == 0 ) + { + bi_free( bi ); + bi_free( bidiff ); + bi_free( biR2 ); + return biR; + } + if ( bi_is_one( bi_copy( bidiff ) ) ) + { + bi_free( bi ); + bi_free( bidiff ); + bi_free( biR ); + return biR2; + } + bi_free( bidiff ); + biR = bi_half( bi_add( biR, biR2 ) ); + } + } + + +int +bi_is_odd( bigint obi ) + { + real_bigint bi = (real_bigint) obi; + int r; + + check( bi ); + r = bi->comps[0] & 1; + bi_free( bi ); + return r; + } + + +int +bi_is_zero( bigint obi ) + { + real_bigint bi = (real_bigint) obi; + int r; + + check( bi ); + r = ( bi->sign == 1 && bi->num_comps == 1 && bi->comps[0] == 0 ); + bi_free( bi ); + return r; + } + + +int +bi_is_one( bigint obi ) + { + real_bigint bi = (real_bigint) obi; + int r; + + check( bi ); + r = ( bi->sign == 1 && bi->num_comps == 1 && bi->comps[0] == 1 ); + bi_free( bi ); + return r; + } + + +int +bi_is_negative( bigint obi ) + { + real_bigint bi = (real_bigint) obi; + int r; + + check( bi ); + r = ( bi->sign == -1 ); + bi_free( bi ); + return r; + } + + +bigint +bi_random( bigint bi ) + { + real_bigint biR; + int c; + + biR = bi_multiply( bi_copy( bi ), bi_copy( bi ) ); + for ( c = 0; c < biR->num_comps; ++c ) + biR->comps[c] = random(); + normalize( biR ); + biR = bi_mod( biR, bi ); + return biR; + } + + +int +bi_bits( bigint obi ) + { + real_bigint bi = (real_bigint) obi; + int bits; + + bits = + bi_comp_bits * ( bi->num_comps - 1 ) + + cbits( bi->comps[bi->num_comps - 1] ); + bi_free( bi ); + return bits; + } + + +/* Allocate and zero more components. Does not consume bi, of course. */ +static void +more_comps( real_bigint bi, int n ) + { + if ( n > bi->max_comps ) + { + bi->max_comps = max( bi->max_comps * 2, n ); + bi->comps = (comp*) realloc( + (void*) bi->comps, bi->max_comps * sizeof(comp) ); + if ( bi->comps == (comp*) 0 ) + { + (void) fprintf( stderr, "out of memory\n" ); + exit( 1 ); + } + } + for ( ; bi->num_comps < n; ++bi->num_comps ) + bi->comps[bi->num_comps] = 0; + } + + +/* Make a new empty bigint. Fills in everything except sign and the +** components. +*/ +static real_bigint +alloc( int num_comps ) + { + real_bigint biR; + + /* Can we recycle an old bigint? */ + if ( free_list != (real_bigint) 0 ) + { + biR = free_list; + free_list = biR->next; + --free_count; + if ( check_level >= 1 && biR->refs != 0 ) + { + (void) fprintf( stderr, "alloc: refs was not 0\n" ); + (void) kill( getpid(), SIGFPE ); + } + more_comps( biR, num_comps ); + } + else + { + /* No free bigints available - create a new one. */ + biR = (real_bigint) malloc( sizeof(struct _real_bigint) ); + if ( biR == (real_bigint) 0 ) + { + (void) fprintf( stderr, "out of memory\n" ); + exit( 1 ); + } + biR->comps = (comp*) malloc( num_comps * sizeof(comp) ); + if ( biR->comps == (comp*) 0 ) + { + (void) fprintf( stderr, "out of memory\n" ); + exit( 1 ); + } + biR->max_comps = num_comps; + } + biR->num_comps = num_comps; + biR->refs = 1; + if ( check_level >= 3 ) + { + /* The active list only gets maintained at check levels 3 or higher. */ + biR->next = active_list; + active_list = biR; + } + else + biR->next = (real_bigint) 0; + ++active_count; + return biR; + } + + +/* Make a modifiable copy of bi. DOES consume bi. */ +static real_bigint +clone( real_bigint bi ) + { + real_bigint biR; + int c; + + /* Very clever optimization. */ + if ( bi->refs != PERMANENT && bi->refs == 1 ) + return bi; + + biR = alloc( bi->num_comps ); + biR->sign = bi->sign; + for ( c = 0; c < bi->num_comps; ++c ) + biR->comps[c] = bi->comps[c]; + bi_free( bi ); + return biR; + } + + +/* Put bi into normal form. Does not consume bi, of course. +** +** Normal form is: +** - All components >= 0 and < bi_radix. +** - Leading 0 components removed. +** - Sign either 1 or -1. +** - The number zero represented by a single 0 component and a sign of 1. +*/ +static void +normalize( real_bigint bi ) + { + int c; + + /* Borrow for negative components. Got to be careful with the math here: + ** -9 / 10 == 0 -9 % 10 == -9 + ** -10 / 10 == -1 -10 % 10 == 0 + ** -11 / 10 == -1 -11 % 10 == -1 + */ + for ( c = 0; c < bi->num_comps - 1; ++c ) + if ( bi->comps[c] < 0 ) + { + bi->comps[c+1] += bi->comps[c] / bi_radix - 1; + bi->comps[c] = bi->comps[c] % bi_radix; + if ( bi->comps[c] != 0 ) + bi->comps[c] += bi_radix; + else + bi->comps[c+1] += 1; + } + /* Is the top component negative? */ + if ( bi->comps[bi->num_comps - 1] < 0 ) + { + /* Switch the sign of the number, and fix up the components. */ + bi->sign = -bi->sign; + for ( c = 0; c < bi->num_comps - 1; ++c ) + { + bi->comps[c] = bi_radix - bi->comps[c]; + bi->comps[c + 1] += 1; + } + bi->comps[bi->num_comps - 1] = -bi->comps[bi->num_comps - 1]; + } + + /* Carry for components larger than the radix. */ + for ( c = 0; c < bi->num_comps; ++c ) + if ( bi->comps[c] >= bi_radix ) + { + if ( c + 1 >= bi->num_comps ) + more_comps( bi, bi->num_comps + 1 ); + bi->comps[c+1] += bi->comps[c] / bi_radix; + bi->comps[c] = bi->comps[c] % bi_radix; + } + + /* Trim off any leading zero components. */ + for ( ; bi->num_comps > 1 && bi->comps[bi->num_comps-1] == 0; --bi->num_comps ) + ; + + /* Check for -0. */ + if ( bi->num_comps == 1 && bi->comps[0] == 0 && bi->sign == -1 ) + bi->sign = 1; + } + + +static void +check( real_bigint bi ) + { + if ( check_level == 0 ) + return; + if ( bi->refs == 0 ) + { + (void) fprintf( stderr, "check: zero refs in bigint\n" ); + (void) kill( getpid(), SIGFPE ); + } + if ( bi->refs < 0 ) + { + (void) fprintf( stderr, "check: negative refs in bigint\n" ); + (void) kill( getpid(), SIGFPE ); + } + if ( check_level < 3 ) + { + /* At check levels less than 3, active bigints have a zero next. */ + if ( bi->next != (real_bigint) 0 ) + { + (void) fprintf( + stderr, "check: attempt to use a bigint from the free list\n" ); + (void) kill( getpid(), SIGFPE ); + } + } + else + { + /* At check levels 3 or higher, active bigints must be on the active + ** list. + */ + real_bigint p; + + for ( p = active_list; p != (real_bigint) 0; p = p->next ) + if ( p == bi ) + break; + if ( p == (real_bigint) 0 ) + { + (void) fprintf( stderr, + "check: attempt to use a bigint not on the active list\n" ); + (void) kill( getpid(), SIGFPE ); + } + } + if ( check_level >= 2 ) + double_check(); + if ( check_level >= 3 ) + triple_check(); + } + + +static void +double_check( void ) + { + real_bigint p; + int c; + + for ( p = free_list, c = 0; p != (real_bigint) 0; p = p->next, ++c ) + if ( p->refs != 0 ) + { + (void) fprintf( stderr, + "double_check: found a non-zero ref on the free list\n" ); + (void) kill( getpid(), SIGFPE ); + } + if ( c != free_count ) + { + (void) fprintf( stderr, + "double_check: free_count is %d but the free list has %d items\n", + free_count, c ); + (void) kill( getpid(), SIGFPE ); + } + } + + +static void +triple_check( void ) + { + real_bigint p; + int c; + + for ( p = active_list, c = 0; p != (real_bigint) 0; p = p->next, ++c ) + if ( p->refs == 0 ) + { + (void) fprintf( stderr, + "triple_check: found a zero ref on the active list\n" ); + (void) kill( getpid(), SIGFPE ); + } + if ( c != active_count ) + { + (void) fprintf( stderr, + "triple_check: active_count is %d but active_list has %d items\n", + free_count, c ); + (void) kill( getpid(), SIGFPE ); + } + } + + +#ifdef DUMP +/* Debug routine to dump out a complete bigint. Does not consume bi. */ +static void +dump( char* str, bigint obi ) + { + int c; + real_bigint bi = (real_bigint) obi; + + (void) fprintf( stdout, "dump %s at 0x%08x:\n", str, (unsigned int) bi ); + (void) fprintf( stdout, " refs: %d\n", bi->refs ); + (void) fprintf( stdout, " next: 0x%08x\n", (unsigned int) bi->next ); + (void) fprintf( stdout, " num_comps: %d\n", bi->num_comps ); + (void) fprintf( stdout, " max_comps: %d\n", bi->max_comps ); + (void) fprintf( stdout, " sign: %d\n", bi->sign ); + for ( c = bi->num_comps - 1; c >= 0; --c ) + (void) fprintf( stdout, " comps[%d]: %11lld (0x%016llx)\n", c, (long long) bi->comps[c], (long long) bi->comps[c] ); + (void) fprintf( stdout, " print: " ); + bi_print( stdout, bi_copy( bi ) ); + (void) fprintf( stdout, "\n" ); + } +#endif /* DUMP */ + + +/* Trivial square-root routine so that we don't have to link in the math lib. */ +static int +csqrt( comp c ) + { + comp r, r2, diff; + + if ( c < 0 ) + { + (void) fprintf( stderr, "csqrt: imaginary result\n" ); + (void) kill( getpid(), SIGFPE ); + } + + r = c / 2; + for (;;) + { + r2 = c / r; + diff = r - r2; + if ( diff == 0 || diff == -1 ) + return (int) r; + if ( diff == 1 ) + return (int) r2; + r = ( r + r2 ) / 2; + } + } + + +/* Figure out how many bits are in a number. */ +static int +cbits( comp c ) + { + int b; + + for ( b = 0; c != 0; ++b ) + c >>= 1; + return b; + } |