6 double XS_BASE_LEN = 0;
8 MODULE = Math::BigInt::FastCalc PACKAGE = Math::BigInt::FastCalc
10 #############################################################################
11 # 2002-08-12 0.03 Tels unreleased
12 # * is_zero/is_one/is_odd/is_even/len work now (pass v1.61 tests)
13 # 2002-08-13 0.04 Tels unreleased
14 # * returns no/yes for is_foo() methods to be faster
15 # 2002-08-18 0.06alpha
16 # * added _num(), _inc() and _dec()
17 # 2002-08-25 0.06 Tels
18 # * added __strip_zeros(), _copy()
19 # 2004-08-13 0.07 Tels
20 # * added _is_two(), _is_ten(), _ten()
21 # 2007-04-02 0.08 Tels
22 # * plug leaks by creating mortals
23 # 2007-05-27 0.09 Tels
26 #define RETURN_MORTAL_INT(value) \
27 ST(0) = sv_2mortal(newSViv(value)); \
30 #define RETURN_MORTAL_BOOL(temp, comp) \
31 ST(0) = sv_2mortal(boolSV( SvIV(temp) == comp));
33 #define CONSTANT_OBJ(int) \
35 sv_2mortal((SV*)RETVAL); \
36 av_push (RETVAL, newSViv( int ));
39 _set_XS_BASE(BASE, BASE_LEN)
45 XS_BASE_LEN = SvIV(BASE_LEN);
47 ##############################################################################
59 /* create the array */
61 sv_2mortal((SV*)RETVAL);
62 /* cur = SvPV(x, len); printf ("input '%s'\n", cur); */
63 if (SvIOK(x) && SvIV(x) < XS_BASE)
65 /* shortcut for integer arguments */
66 av_push (RETVAL, newSViv( SvIV(x) ));
70 /* split the input (as string) into XS_BASE_LEN long parts */
72 [ reverse(unpack("a" . ($il % $BASE_LEN+1)
73 . ("a$BASE_LEN" x ($il / $BASE_LEN)), $_[1])) ];
75 cur = SvPV(x, len); /* convert to string & store length */
76 cur += len; /* doing "cur = SvEND(x)" does not work! */
77 # process the string from the back
80 /* use either BASE_LEN or the amount of remaining digits */
81 part_len = XS_BASE_LEN;
86 /* processed so many digits */
89 /* printf ("part '%s' (part_len: %i, len: %i, BASE_LEN: %i)\n", cur, part_len, len, XS_BASE_LEN); */
92 av_push (RETVAL, newSVpvn(cur, part_len) );
99 ##############################################################################
111 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
112 elems = av_len(a); /* number of elems in array */
113 a2 = (AV*)sv_2mortal((SV*)newAV());
114 av_extend (a2, elems); /* prepadd */
117 /* av_store( a2, elems, newSVsv( (SV*)*av_fetch(a, elems, 0) ) ); */
119 /* looking and trying to preserve IV is actually slower when copying */
120 /* temp = (SV*)*av_fetch(a, elems, 0);
123 av_store( a2, elems, newSViv( SvIV( (SV*)*av_fetch(a, elems, 0) )));
127 av_store( a2, elems, newSVnv( SvNV( (SV*)*av_fetch(a, elems, 0) )));
130 av_store( a2, elems, newSVnv( SvNV( (SV*)*av_fetch(a, elems, 0) )));
133 ST(0) = sv_2mortal( newRV_inc((SV*) a2) );
135 ##############################################################################
136 # __strip_zeros (also check for empty arrays from div)
148 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
149 elems = av_len(a); /* number of elems in array */
150 ST(0) = x; /* we return x */
153 av_push (a, newSViv(0)); /* correct empty arrays */
158 XSRETURN(1); /* nothing to do since only one elem */
163 temp = *av_fetch(a, index, 0); /* fetch ptr to current element */
172 index = elems - index;
180 ##############################################################################
181 # decrement (subtract one)
194 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
195 elems = av_len(a); /* number of elems in array */
196 ST(0) = x; /* we return x */
200 while (index <= elems)
202 temp = *av_fetch(a, index, 0); /* fetch ptr to current element */
203 sv_setnv (temp, SvNV(temp)-1);
206 break; /* early out */
208 sv_setnv (temp, MAX); /* overflow, so set this to $MAX */
211 /* do have more than one element? */
212 /* (more than one because [0] should be kept as single-element) */
215 temp = *av_fetch(a, elems, 0); /* fetch last element */
216 if (SvIV(temp) == 0) /* did last elem overflow? */
218 av_pop(a); /* yes, so shrink array */
219 /* aka remove leading zeros */
222 XSRETURN(1); /* return x */
224 ##############################################################################
225 # increment (add one)
238 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
239 elems = av_len(a); /* number of elems in array */
240 ST(0) = x; /* we return x */
244 while (index <= elems)
246 temp = *av_fetch(a, index, 0); /* fetch ptr to current element */
247 sv_setnv (temp, SvNV(temp)+1);
248 if (SvNV(temp) < BASE)
250 XSRETURN(1); /* return (early out) */
252 sv_setiv (temp, 0); /* overflow, so set this elem to 0 */
255 temp = *av_fetch(a, elems, 0); /* fetch last element */
256 if (SvIV(temp) == 0) /* did last elem overflow? */
258 av_push(a, newSViv(1)); /* yes, so extend array by 1 */
260 XSRETURN(1); /* return x */
262 ##############################################################################
263 # Make a number (scalar int/float) from a BigInt object
278 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
279 elems = av_len(a); /* number of elems in array */
281 if (elems == 0) /* only one element? */
283 ST(0) = *av_fetch(a, 0, 0); /* fetch first (only) element */
284 XSRETURN(1); /* return it */
286 fac = 1.0; /* factor */
290 while (index <= elems)
292 temp = *av_fetch(a, index, 0); /* fetch current element */
293 num += fac * SvNV(temp);
297 ST(0) = newSVnv(num);
299 ##############################################################################
308 ##############################################################################
317 ##############################################################################
326 ##############################################################################
335 ##############################################################################
345 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
346 temp = *av_fetch(a, 0, 0); /* fetch first element */
347 ST(0) = sv_2mortal(boolSV((SvIV(temp) & 1) == 0));
349 ##############################################################################
359 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
360 temp = *av_fetch(a, 0, 0); /* fetch first element */
361 ST(0) = sv_2mortal(boolSV((SvIV(temp) & 1) != 0));
363 ##############################################################################
373 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
377 XSRETURN(1); /* len != 1, can't be '1' */
379 temp = *av_fetch(a, 0, 0); /* fetch first element */
380 RETURN_MORTAL_BOOL(temp, 1);
382 ##############################################################################
392 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
396 XSRETURN(1); /* len != 1, can't be '2' */
398 temp = *av_fetch(a, 0, 0); /* fetch first element */
399 RETURN_MORTAL_BOOL(temp, 2);
401 ##############################################################################
411 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
415 XSRETURN(1); /* len != 1, can't be '10' */
417 temp = *av_fetch(a, 0, 0); /* fetch first element */
418 RETURN_MORTAL_BOOL(temp, 10);
420 ##############################################################################
430 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
434 XSRETURN(1); /* len != 1, can't be '0' */
436 temp = *av_fetch(a, 0, 0); /* fetch first element */
437 RETURN_MORTAL_BOOL(temp, 0);
439 ##############################################################################
451 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
452 elems = av_len(a); /* number of elems in array */
453 temp = *av_fetch(a, elems, 0); /* fetch last element */
454 SvPV(temp, len); /* convert to string & store length */
455 len += (IV) XS_BASE_LEN * elems;
456 ST(0) = sv_2mortal(newSViv(len));
458 ##############################################################################
461 _acmp(class, cx, cy);
467 I32 elemsx, elemsy, diff;
476 array_x = (AV*)SvRV(cx); /* ref to aray, don't check ref */
477 array_y = (AV*)SvRV(cy); /* ref to aray, don't check ref */
478 elemsx = av_len(array_x);
479 elemsy = av_len(array_y);
480 diff = elemsx - elemsy; /* difference */
484 RETURN_MORTAL_INT(1); /* len differs: X > Y */
488 RETURN_MORTAL_INT(-1); /* len differs: X < Y */
490 /* both have same number of elements, so check length of last element
491 and see if it differes */
492 tempx = *av_fetch(array_x, elemsx, 0); /* fetch last element */
493 tempy = *av_fetch(array_y, elemsx, 0); /* fetch last element */
494 SvPV(tempx, lenx); /* convert to string & store length */
495 SvPV(tempy, leny); /* convert to string & store length */
496 diff_str = (I32)lenx - (I32)leny;
499 RETURN_MORTAL_INT(1); /* same len, but first elems differs in len */
503 RETURN_MORTAL_INT(-1); /* same len, but first elems differs in len */
505 /* same number of digits, so need to make a full compare */
509 tempx = *av_fetch(array_x, elemsx, 0); /* fetch curr x element */
510 tempy = *av_fetch(array_y, elemsx, 0); /* fetch curr y element */
511 diff_nv = SvNV(tempx) - SvNV(tempy);
520 RETURN_MORTAL_INT(1);
524 RETURN_MORTAL_INT(-1);
526 ST(0) = sv_2mortal(newSViv(0)); /* X and Y are equal */