Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
317 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <stdio.h> | ||
#include <iostream> | ||
#include <cstdlib> | ||
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; i<MAXDIGITS; i++) n->digits[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; i<d; i++) n->digits[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; | ||
} |