2010-05-23 23:31:22 +00:00
|
|
|
/* Based on Steven Skiena source code. licensed as LGPL
|
|
|
|
* http://www.cs.sunysb.edu/~skiena/392/programs/bignum.c
|
|
|
|
* --pancake
|
|
|
|
*/
|
|
|
|
|
2010-05-24 10:07:54 +00:00
|
|
|
/* XXX : seems broken for big numbers */
|
2010-05-23 23:31:22 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <r_util.h>
|
|
|
|
|
2010-05-24 00:27:05 +00:00
|
|
|
static inline void r_big_zero(RNumBig *n) {
|
2010-05-24 01:24:57 +00:00
|
|
|
while ((n->last>0) && !n->dgts[n->last])
|
|
|
|
n->last--;
|
2010-05-24 00:27:05 +00:00
|
|
|
if (!n->last && !*n->dgts)
|
|
|
|
n->sign = 1; /* hack to avoid -0 */
|
|
|
|
}
|
2010-05-23 23:31:22 +00:00
|
|
|
|
|
|
|
R_API void r_big_print(RNumBig *n) {
|
|
|
|
int i;
|
|
|
|
if (n->last>=0) {
|
|
|
|
if (n->sign<0)
|
|
|
|
printf ("-");
|
|
|
|
for (i=n->last; i>=0; i--)
|
2010-05-24 00:27:05 +00:00
|
|
|
printf ("%c", '0'+n->dgts[i]);
|
2010-05-23 23:31:22 +00:00
|
|
|
printf ("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-24 00:27:05 +00:00
|
|
|
R_API void r_big_set_str(RNumBig *n, const char *str) {
|
|
|
|
int i, len;
|
|
|
|
if (*str=='-') {
|
|
|
|
n->sign = -1;
|
|
|
|
str++;
|
2010-05-24 01:24:57 +00:00
|
|
|
} else n->sign = 1;
|
|
|
|
for (i=len=strlen (str)-1; *str; i--, str++)
|
2010-05-24 00:27:05 +00:00
|
|
|
n->dgts[i] = *str-'0';
|
2010-05-24 01:24:57 +00:00
|
|
|
n->last = len;
|
2010-05-24 00:27:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
R_API RNumBig *r_big_new(RNumBig *b) {
|
|
|
|
RNumBig *n = R_NEW (RNumBig);
|
2010-06-02 17:17:47 +00:00
|
|
|
if (n) {
|
|
|
|
if (b) memcpy (n, b, sizeof (RNumBig));
|
2010-07-16 21:13:34 +00:00
|
|
|
else r_big_set_st (n, 0);
|
2010-06-02 17:17:47 +00:00
|
|
|
}
|
2010-05-24 09:15:32 +00:00
|
|
|
return n;
|
2010-05-24 00:27:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_big_free(RNumBig *b) {
|
|
|
|
free (b);
|
2010-05-23 23:31:22 +00:00
|
|
|
}
|
|
|
|
|
2010-05-24 16:35:08 +00:00
|
|
|
R_API void r_big_set(RNumBig *a, RNumBig *b) {
|
|
|
|
memcpy (a, b, sizeof (RNumBig));
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_big_set_st(RNumBig *n, int v) {
|
2010-05-24 00:27:05 +00:00
|
|
|
int t;
|
2010-05-24 01:24:57 +00:00
|
|
|
n->last = 0;
|
2010-05-23 23:31:22 +00:00
|
|
|
n->sign = (v>=0)?1:-1;
|
|
|
|
memset (n->dgts, 0, R_BIG_SIZE);
|
2010-05-24 01:24:57 +00:00
|
|
|
for (n->last=0, t=R_ABS (v); t>0; t/=10, n->last++)
|
2010-05-23 23:31:22 +00:00
|
|
|
n->dgts[n->last] = (t % 10);
|
|
|
|
if (!v) n->last = 0;
|
|
|
|
}
|
|
|
|
|
2010-05-24 16:35:08 +00:00
|
|
|
R_API void r_big_set_st64(RNumBig *n, st64 v) {
|
2010-05-24 00:27:05 +00:00
|
|
|
st64 t;
|
2010-05-23 23:31:22 +00:00
|
|
|
n->sign = (v<0)?-1:1;
|
|
|
|
memset (n->dgts, 0, R_BIG_SIZE);
|
2010-05-24 01:24:57 +00:00
|
|
|
n->last = 0;//-1;
|
2010-05-23 23:31:22 +00:00
|
|
|
for (t=R_ABS(v); t>0; t/=10) {
|
2010-05-24 00:27:05 +00:00
|
|
|
n->last++;
|
|
|
|
n->dgts[n->last] = t%10;
|
2010-05-23 23:31:22 +00:00
|
|
|
}
|
|
|
|
if (!v) n->last = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* c = a [+*-/] b; */
|
|
|
|
R_API void r_big_add (RNumBig *c, RNumBig *a, RNumBig *b) {
|
|
|
|
int i, carry;
|
2010-05-24 00:27:05 +00:00
|
|
|
RNumBig t;
|
2010-05-24 16:35:08 +00:00
|
|
|
r_big_set_st (&t, 0);
|
2010-05-23 23:31:22 +00:00
|
|
|
if (a->sign != b->sign) {
|
|
|
|
a->sign = 1;
|
|
|
|
if (a->sign == -1)
|
2010-05-24 00:27:05 +00:00
|
|
|
r_big_sub (&t, b, a);
|
|
|
|
else r_big_sub (&t, a, b);
|
2010-05-23 23:31:22 +00:00
|
|
|
a->sign = -1;
|
2010-05-24 10:07:54 +00:00
|
|
|
*c = t;
|
2010-05-23 23:31:22 +00:00
|
|
|
return;
|
2010-05-24 00:27:05 +00:00
|
|
|
} else t.sign = a->sign;
|
2010-05-23 23:31:22 +00:00
|
|
|
|
2010-05-24 00:27:05 +00:00
|
|
|
t.last = R_MAX (a->last, b->last)+1;
|
2010-05-23 23:31:22 +00:00
|
|
|
|
2010-05-24 01:24:57 +00:00
|
|
|
for (carry=i=0; i<=t.last && i<R_BIG_SIZE; i++) {
|
2010-05-24 00:27:05 +00:00
|
|
|
t.dgts[i] = (char) (carry+a->dgts[i]+b->dgts[i]) % 10;
|
2010-05-23 23:31:22 +00:00
|
|
|
carry = (carry + a->dgts[i] + b->dgts[i]) / 10;
|
|
|
|
}
|
2010-05-24 00:27:05 +00:00
|
|
|
*c = t;
|
2010-05-23 23:31:22 +00:00
|
|
|
r_big_zero (c);
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_big_sub(RNumBig *c, RNumBig *a, RNumBig *b) {
|
2010-05-24 00:27:05 +00:00
|
|
|
RNumBig t;
|
2010-05-23 23:31:22 +00:00
|
|
|
int i, v, borrow;
|
|
|
|
|
2010-05-24 16:35:08 +00:00
|
|
|
r_big_set_st (&t, 0);
|
2010-05-23 23:31:22 +00:00
|
|
|
|
|
|
|
if ((a->sign == -1) || (b->sign == -1)) {
|
|
|
|
b->sign *= -1;
|
2010-05-24 00:27:05 +00:00
|
|
|
r_big_add (&t, a, b);
|
2010-05-23 23:31:22 +00:00
|
|
|
b->sign *= -1;
|
2010-05-24 01:24:57 +00:00
|
|
|
*c = t;
|
2010-05-23 23:31:22 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r_big_cmp (a, b) == 1) {
|
2010-05-24 00:27:05 +00:00
|
|
|
r_big_sub (&t, b, a);
|
|
|
|
t.sign = -1;
|
2010-05-24 01:24:57 +00:00
|
|
|
*c = t;
|
2010-05-23 23:31:22 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-05-24 00:27:05 +00:00
|
|
|
t.last = R_MAX (a->last, b->last);
|
2010-05-24 01:24:57 +00:00
|
|
|
for (borrow=i=0; i<=(t.last) &&i<R_BIG_SIZE; i++) {
|
2010-05-23 23:31:22 +00:00
|
|
|
v = (a->dgts[i] - borrow - b->dgts[i]);
|
|
|
|
if (v < 0) {
|
|
|
|
v += 10;
|
|
|
|
borrow = 1;
|
|
|
|
} else
|
|
|
|
if (a->dgts[i] > 0)
|
|
|
|
borrow = 0;
|
2010-05-24 00:27:05 +00:00
|
|
|
t.dgts[i] = (char) v % 10;
|
2010-05-23 23:31:22 +00:00
|
|
|
}
|
2010-05-24 00:27:05 +00:00
|
|
|
*c = t;
|
2010-05-23 23:31:22 +00:00
|
|
|
r_big_zero (c);
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API int r_big_cmp(RNumBig *a, RNumBig *b) {
|
|
|
|
int i;
|
|
|
|
if ((a->sign == -1) && (b->sign == 1)) return 1;
|
|
|
|
if ((a->sign == 1) && (b->sign == -1)) return -1;
|
|
|
|
if (b->last > a->last) return a->sign;
|
|
|
|
if (a->last > b->last) return a->sign*-1;
|
|
|
|
for (i = a->last; i>=0; i--) {
|
|
|
|
if (a->dgts[i] > b->dgts[i]) return a->sign*-1;
|
|
|
|
if (b->dgts[i] > a->dgts[i]) return a->sign;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-05-24 16:35:08 +00:00
|
|
|
R_API int r_big_cmp_st(RNumBig *n, int v) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-05-23 23:31:22 +00:00
|
|
|
/* multiply n by 10^d */
|
|
|
|
R_API void r_big_shift(RNumBig *n, int d) {
|
|
|
|
int i;
|
|
|
|
if (!n->last && !*n->dgts)
|
|
|
|
return;
|
|
|
|
for (i=n->last; i>=0; i--)
|
|
|
|
n->dgts[i+d] = n->dgts[i];
|
|
|
|
memset (n->dgts, 0, d);
|
|
|
|
n->last += d;
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_big_mul (RNumBig *c, RNumBig *a, RNumBig *b) {
|
2010-05-24 00:27:05 +00:00
|
|
|
RNumBig t, tmp, row;
|
2010-05-23 23:31:22 +00:00
|
|
|
int i,j;
|
2010-05-24 16:35:08 +00:00
|
|
|
r_big_set_st (&t, 0);
|
|
|
|
r_big_set_st (&tmp, 0);
|
2010-05-23 23:31:22 +00:00
|
|
|
row = *a;
|
2010-05-24 01:24:57 +00:00
|
|
|
for (i=0; i<=b->last && i<R_BIG_SIZE; i++) {
|
2010-05-23 23:31:22 +00:00
|
|
|
for (j=1; j<=b->dgts[i]; j++) {
|
2010-05-24 01:24:57 +00:00
|
|
|
r_big_add (&tmp, &t, &row);
|
2010-05-24 00:27:05 +00:00
|
|
|
t = tmp;
|
2010-05-23 23:31:22 +00:00
|
|
|
}
|
|
|
|
r_big_shift (&row, 1);
|
|
|
|
}
|
2010-05-24 00:27:05 +00:00
|
|
|
*c = t;
|
2010-05-23 23:31:22 +00:00
|
|
|
c->sign = a->sign * b->sign;
|
|
|
|
r_big_zero (c);
|
|
|
|
}
|
|
|
|
|
2010-05-24 16:35:08 +00:00
|
|
|
R_API void r_big_mul_ut (RNumBig *c, RNumBig *a, ut32 b) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-05-23 23:31:22 +00:00
|
|
|
R_API void r_big_div(RNumBig *c, RNumBig *a, RNumBig *b) {
|
2010-05-24 09:15:32 +00:00
|
|
|
RNumBig t, tmp, row;
|
2010-05-24 00:27:05 +00:00
|
|
|
int i, asign, bsign;
|
2010-05-23 23:31:22 +00:00
|
|
|
|
2010-05-24 16:35:08 +00:00
|
|
|
r_big_set_st (&t, 0);
|
2010-05-24 00:27:05 +00:00
|
|
|
t.sign = a->sign * b->sign;
|
2010-05-23 23:31:22 +00:00
|
|
|
asign = a->sign;
|
|
|
|
bsign = b->sign;
|
|
|
|
a->sign = b->sign = 1;
|
2010-05-24 16:35:08 +00:00
|
|
|
r_big_set_st (&row, 0);
|
|
|
|
r_big_set_st (&tmp, 0);
|
2010-05-24 00:27:05 +00:00
|
|
|
t.last = a->last;
|
2010-05-23 23:31:22 +00:00
|
|
|
|
|
|
|
for (i=a->last; i>=0; i--) {
|
|
|
|
r_big_shift (&row, 1);
|
|
|
|
*row.dgts = a->dgts[i];
|
|
|
|
c->dgts[i] = 0;
|
|
|
|
while (r_big_cmp (&row, b) != 1) {
|
2010-05-24 00:27:05 +00:00
|
|
|
t.dgts[i]++;
|
2010-05-23 23:31:22 +00:00
|
|
|
r_big_sub (&tmp, &row, b);
|
|
|
|
row = tmp;
|
|
|
|
}
|
|
|
|
}
|
2010-05-24 00:27:05 +00:00
|
|
|
*c = t;
|
2010-05-23 23:31:22 +00:00
|
|
|
r_big_zero (c);
|
|
|
|
a->sign = asign;
|
|
|
|
b->sign = bsign;
|
|
|
|
}
|
|
|
|
|
2010-05-24 16:35:08 +00:00
|
|
|
R_API void r_big_div_ut(RNumBig *c, RNumBig *a, ut32 b) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API int r_big_divisible_ut(RNumBig *n, ut32 v) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-05-24 00:27:05 +00:00
|
|
|
R_API void r_big_mod(RNumBig *c, RNumBig *a, RNumBig *b) {
|
|
|
|
RNumBig t; // a%b = a-((a/b)*b)
|
|
|
|
r_big_div (c, a, b); // c=a/b
|
|
|
|
r_big_mul (&t, c, b); // t=c*b
|
|
|
|
r_big_sub (c, a, &t); // c=a-t
|
2010-05-23 23:31:22 +00:00
|
|
|
}
|