diff --git a/10334.cpp b/10334.cpp new file mode 100644 index 0000000..fe2e9d7 --- /dev/null +++ b/10334.cpp @@ -0,0 +1,317 @@ +/* bignum.c + Implementation of large integer arithmetic: addition, subtraction, + multiplication, and division. + + begun: February 7, 2002 + by: Steven Skiena +*/ + +/* +Copyright 2003 by Steven S. Skiena; all rights reserved. + +Permission is granted for use in non-commerical applications +provided this copyright notice remains intact and unchanged. + +This program appears in my book: + +"Programming Challenges: The Programming Contest Training Manual" +by Steven Skiena and Miguel Revilla, Springer-Verlag, New York 2003. + +See our website www.programming-challenges.com for additional information. + +This book can be ordered from Amazon.com at + +http://www.amazon.com/exec/obidos/ASIN/0387001638/thealgorithmrepo/ + +*/ + + +#include +#include +#include +using namespace std; + +#define MAXDIGITS 10000 /* maximum length bignum */ + +#define PLUS 1 /* positive sign bit */ +#define MINUS -1 /* negative sign bit */ + +typedef struct { + char digits[MAXDIGITS]; /* represent the number */ + int signbit; /* 1 if positive, -1 if negative */ + int lastdigit; /* index of high-order digit */ +} bignum; + + +void print_bignum(bignum*); +void string_to_bignum(string, bignum*); +void int_to_bignum(int, bignum*); +void initialize_bignum(bignum*); +int max(int, int); +void add_bignum(bignum*, bignum*, bignum*); +void subtract_bignum(bignum*, bignum*, bignum*); +int compare_bignum(bignum*, bignum*); +void zero_justify(bignum*); +void digit_shift(bignum*, int); +void multiply_bignum(bignum*, bignum*, bignum*); +void divide_bignum(bignum*, bignum*, bignum*); + + +void print_bignum(bignum *n) +{ + int i; + + if (n->signbit == MINUS) printf("- "); + for (i=n->lastdigit; i>=0; i--) + printf("%c",'0'+ n->digits[i]); + + printf("\n"); +} + +void string_to_bignum (string s, bignum* n) { + n->signbit = PLUS; // TODO: currently no negative numbers + + for (int i = 0; i < MAXDIGITS; i++) n->digits[i] = (char) 0; + + n->lastdigit = -1; + + for (int i = s.size() - 1; i >= 0; i--) { + n->lastdigit++; + n->digits[n->lastdigit] = s[i] - 48; + } + + if (s == "0") n->lastdigit = 0; +} + +void int_to_bignum(int s, bignum *n) +{ + int i; /* counter */ + int t; /* int to work with */ + + if (s >= 0) n->signbit = PLUS; + else n->signbit = MINUS; + + for (i=0; idigits[i] = (char) 0; + + n->lastdigit = -1; + + t = abs(s); + + while (t > 0) { + n->lastdigit ++; + n->digits[ n->lastdigit ] = (t % 10); + t = t / 10; + } + + if (s == 0) n->lastdigit = 0; +} + +void initialize_bignum(bignum *n) +{ + int_to_bignum(0,n); +} + + +int max(int a, int b) +{ + if (a > b) return(a); else return(b); +} + +/* c = a +-/* b; */ + +void add_bignum(bignum *a, bignum *b, bignum *c) +{ + int carry; /* carry digit */ + int i; /* counter */ + + initialize_bignum(c); + + if (a->signbit == b->signbit) c->signbit = a->signbit; + else { + if (a->signbit == MINUS) { + a->signbit = PLUS; + subtract_bignum(b,a,c); + a->signbit = MINUS; + } else { + b->signbit = PLUS; + subtract_bignum(a,b,c); + b->signbit = MINUS; + } + return; + } + + c->lastdigit = max(a->lastdigit,b->lastdigit)+1; + carry = 0; + + for (i=0; i<=(c->lastdigit); i++) { + c->digits[i] = (char) (carry+a->digits[i]+b->digits[i]) % 10; + carry = (carry + a->digits[i] + b->digits[i]) / 10; + } + + zero_justify(c); +} + + +void subtract_bignum(bignum *a, bignum *b, bignum *c) +{ + int borrow; /* has anything been borrowed? */ + int v; /* placeholder digit */ + int i; /* counter */ + + initialize_bignum(c); + + if ((a->signbit == MINUS) || (b->signbit == MINUS)) { + b->signbit = -1 * b->signbit; + add_bignum(a,b,c); + b->signbit = -1 * b->signbit; + return; + } + + if (compare_bignum(a,b) == PLUS) { + subtract_bignum(b,a,c); + c->signbit = MINUS; + return; + } + + c->lastdigit = max(a->lastdigit,b->lastdigit); + borrow = 0; + + for (i=0; i<=(c->lastdigit); i++) { + v = (a->digits[i] - borrow - b->digits[i]); + if (a->digits[i] > 0) + borrow = 0; + if (v < 0) { + v = v + 10; + borrow = 1; + } + + c->digits[i] = (char) v % 10; + } + + zero_justify(c); +} + +int compare_bignum(bignum *a, bignum *b) +{ + int i; /* counter */ + + if ((a->signbit == MINUS) && (b->signbit == PLUS)) return(PLUS); + if ((a->signbit == PLUS) && (b->signbit == MINUS)) return(MINUS); + + if (b->lastdigit > a->lastdigit) return (PLUS * a->signbit); + if (a->lastdigit > b->lastdigit) return (MINUS * a->signbit); + + for (i = a->lastdigit; i>=0; i--) { + if (a->digits[i] > b->digits[i]) return(MINUS * a->signbit); + if (b->digits[i] > a->digits[i]) return(PLUS * a->signbit); + } + + return(0); +} + +void zero_justify(bignum *n) +{ + while ((n->lastdigit > 0) && (n->digits[ n->lastdigit ] == 0)) + n->lastdigit --; + + if ((n->lastdigit == 0) && (n->digits[0] == 0)) + n->signbit = PLUS; /* hack to avoid -0 */ +} + + +void digit_shift(bignum *n, int d) /* multiply n by 10^d */ +{ + int i; /* counter */ + + if ((n->lastdigit == 0) && (n->digits[0] == 0)) return; + + for (i=n->lastdigit; i>=0; i--) + n->digits[i+d] = n->digits[i]; + + for (i=0; idigits[i] = 0; + + n->lastdigit = n->lastdigit + d; +} + + + +void multiply_bignum(bignum *a, bignum *b, bignum *c) +{ + bignum row; /* represent shifted row */ + bignum tmp; /* placeholder bignum */ + int i,j; /* counters */ + + initialize_bignum(c); + + row = *a; + + for (i=0; i<=b->lastdigit; i++) { + for (j=1; j<=b->digits[i]; j++) { + add_bignum(c,&row,&tmp); + *c = tmp; + } + digit_shift(&row,1); + } + + c->signbit = a->signbit * b->signbit; + + zero_justify(c); +} + + +void divide_bignum(bignum *a, bignum *b, bignum *c) +{ + bignum row; /* represent shifted row */ + bignum tmp; /* placeholder bignum */ + int asign, bsign; /* temporary signs */ + int i,j; /* counters */ + + initialize_bignum(c); + + c->signbit = a->signbit * b->signbit; + + asign = a->signbit; + bsign = b->signbit; + + a->signbit = PLUS; + b->signbit = PLUS; + + initialize_bignum(&row); + initialize_bignum(&tmp); + + c->lastdigit = a->lastdigit; + + for (i=a->lastdigit; i>=0; i--) { + digit_shift(&row,1); + row.digits[0] = a->digits[i]; + c->digits[i] = 0; + while (compare_bignum(&row,b) != PLUS) { + c->digits[i] ++; + subtract_bignum(&row,b,&tmp); + row = tmp; + } + } + + zero_justify(c); + + a->signbit = asign; + b->signbit = bsign; +} + +int main (void) { + int n; + bignum *f = new bignum[5001]; + + int_to_bignum (1, &f[0]); + int_to_bignum (2, &f[1]); + + for (int i = 2; i < 1001; i++) { + add_bignum (&f[i-2], &f[i-1], &f[i]); + } + + while (cin >> n) { + print_bignum(&f[n]); + } + + delete f; +}