5 /* for Perl prior to v5.7.1 */
7 # define SvUOK(sv) SvIOK_UV(sv)
11 double XS_BASE_LEN = 0;
13 MODULE = Math::BigInt::FastCalc PACKAGE = Math::BigInt::FastCalc
17 #############################################################################
18 # 2002-08-12 0.03 Tels unreleased
19 # * is_zero/is_one/is_odd/is_even/len work now (pass v1.61 tests)
20 # 2002-08-13 0.04 Tels unreleased
21 # * returns no/yes for is_foo() methods to be faster
22 # 2002-08-18 0.06alpha
23 # * added _num(), _inc() and _dec()
24 # 2002-08-25 0.06 Tels
25 # * added __strip_zeros(), _copy()
26 # 2004-08-13 0.07 Tels
27 # * added _is_two(), _is_ten(), _ten()
28 # 2007-04-02 0.08 Tels
29 # * plug leaks by creating mortals
30 # 2007-05-27 0.09 Tels
33 #define RETURN_MORTAL_INT(value) \
34 ST(0) = sv_2mortal(newSViv(value)); \
40 croak("Usage: Math::BigInt::FastCalc::BOOT(package, version, base_len, base)");
41 XS_BASE_LEN = SvIV(ST(2));
42 XS_BASE = SvNV(ST(3));
45 ##############################################################################
58 if (SvUOK(x) && SvUV(x) < XS_BASE)
60 /* shortcut for integer arguments */
61 av_push (av, newSVuv( SvUV(x) ));
65 /* split the input (as string) into XS_BASE_LEN long parts */
67 [ reverse(unpack("a" . ($il % $BASE_LEN+1)
68 . ("a$BASE_LEN" x ($il / $BASE_LEN)), $_[1])) ];
70 cur = SvPV(x, len); /* convert to string & store length */
71 cur += len; /* doing "cur = SvEND(x)" does not work! */
72 # process the string from the back
75 /* use either BASE_LEN or the amount of remaining digits */
76 part_len = (STRLEN) XS_BASE_LEN;
81 /* processed so many digits */
84 /* printf ("part '%s' (part_len: %i, len: %i, BASE_LEN: %i)\n", cur, part_len, len, XS_BASE_LEN); */
87 av_push (av, newSVpvn(cur, part_len) );
91 RETVAL = newRV_noinc((SV *)av);
95 ##############################################################################
107 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
108 elems = av_len(a); /* number of elems in array */
109 a2 = (AV*)sv_2mortal((SV*)newAV());
110 av_extend (a2, elems); /* pre-padd */
113 /* av_store( a2, elems, newSVsv( (SV*)*av_fetch(a, elems, 0) ) ); */
115 /* looking and trying to preserve IV is actually slower when copying */
116 /* temp = (SV*)*av_fetch(a, elems, 0);
119 av_store( a2, elems, newSViv( SvIV( (SV*)*av_fetch(a, elems, 0) )));
123 av_store( a2, elems, newSVnv( SvNV( (SV*)*av_fetch(a, elems, 0) )));
126 av_store( a2, elems, newSVnv( SvNV( (SV*)*av_fetch(a, elems, 0) )));
129 ST(0) = sv_2mortal( newRV_inc((SV*) a2) );
131 ##############################################################################
132 # __strip_zeros (also check for empty arrays from div)
144 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
145 elems = av_len(a); /* number of elems in array */
146 ST(0) = x; /* we return x */
149 av_push (a, newSViv(0)); /* correct empty arrays */
154 XSRETURN(1); /* nothing to do since only one elem */
159 temp = *av_fetch(a, index, 0); /* fetch ptr to current element */
168 index = elems - index;
176 ##############################################################################
177 # decrement (subtract one)
190 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
191 elems = av_len(a); /* number of elems in array */
192 ST(0) = x; /* we return x */
196 while (index <= elems)
198 temp = *av_fetch(a, index, 0); /* fetch ptr to current element */
199 sv_setnv (temp, SvNV(temp)-1); /* decrement */
202 break; /* early out */
204 sv_setnv (temp, MAX); /* overflow, so set this to $MAX */
207 /* do have more than one element? */
208 /* (more than one because [0] should be kept as single-element) */
211 temp = *av_fetch(a, elems, 0); /* fetch last element */
212 if (SvIV(temp) == 0) /* did last elem overflow? */
214 av_pop(a); /* yes, so shrink array */
215 /* aka remove leading zeros */
218 XSRETURN(1); /* return x */
220 ##############################################################################
221 # increment (add one)
234 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
235 elems = av_len(a); /* number of elems in array */
236 ST(0) = x; /* we return x */
240 while (index <= elems)
242 temp = *av_fetch(a, index, 0); /* fetch ptr to current element */
243 sv_setnv (temp, SvNV(temp)+1);
244 if (SvNV(temp) < BASE)
246 XSRETURN(1); /* return (early out) */
248 sv_setiv (temp, 0); /* overflow, so set this elem to 0 */
251 temp = *av_fetch(a, elems, 0); /* fetch last element */
252 if (SvIV(temp) == 0) /* did last elem overflow? */
254 av_push(a, newSViv(1)); /* yes, so extend array by 1 */
256 XSRETURN(1); /* return x */
258 ##############################################################################
259 # Make a number (scalar int/float) from a BigInt object
274 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
275 elems = av_len(a); /* number of elems in array */
277 if (elems == 0) /* only one element? */
279 ST(0) = *av_fetch(a, 0, 0); /* fetch first (only) element */
280 XSRETURN(1); /* return it */
282 fac = 1.0; /* factor */
286 while (index <= elems)
288 temp = *av_fetch(a, index, 0); /* fetch current element */
289 num += fac * SvNV(temp);
293 ST(0) = newSVnv(num);
295 ##############################################################################
306 av_push (av, newSViv( ix ));
307 RETVAL = newRV_noinc((SV *)av);
311 ##############################################################################
323 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
324 temp = *av_fetch(a, 0, 0); /* fetch first element */
325 ST(0) = sv_2mortal(boolSV((SvIV(temp) & 1) == ix));
327 ##############################################################################
340 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
343 ST(0) = &PL_sv_no; /* len != 1, can't be '0' */
347 SV *const temp = *av_fetch(a, 0, 0); /* fetch first element */
348 ST(0) = boolSV(SvIV(temp) == ix);
352 ##############################################################################
364 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
365 elems = av_len(a); /* number of elems in array */
366 temp = *av_fetch(a, elems, 0); /* fetch last element */
367 SvPV(temp, len); /* convert to string & store length */
368 len += (IV) XS_BASE_LEN * elems;
369 ST(0) = sv_2mortal(newSViv(len));
371 ##############################################################################
374 _acmp(class, cx, cy);
380 I32 elemsx, elemsy, diff;
389 array_x = (AV*)SvRV(cx); /* ref to aray, don't check ref */
390 array_y = (AV*)SvRV(cy); /* ref to aray, don't check ref */
391 elemsx = av_len(array_x);
392 elemsy = av_len(array_y);
393 diff = elemsx - elemsy; /* difference */
397 RETURN_MORTAL_INT(1); /* len differs: X > Y */
401 RETURN_MORTAL_INT(-1); /* len differs: X < Y */
403 /* both have same number of elements, so check length of last element
404 and see if it differes */
405 tempx = *av_fetch(array_x, elemsx, 0); /* fetch last element */
406 tempy = *av_fetch(array_y, elemsx, 0); /* fetch last element */
407 SvPV(tempx, lenx); /* convert to string & store length */
408 SvPV(tempy, leny); /* convert to string & store length */
409 diff_str = (I32)lenx - (I32)leny;
412 RETURN_MORTAL_INT(1); /* same len, but first elems differs in len */
416 RETURN_MORTAL_INT(-1); /* same len, but first elems differs in len */
418 /* same number of digits, so need to make a full compare */
422 tempx = *av_fetch(array_x, elemsx, 0); /* fetch curr x element */
423 tempy = *av_fetch(array_y, elemsx, 0); /* fetch curr y element */
424 diff_nv = SvNV(tempx) - SvNV(tempy);
433 RETURN_MORTAL_INT(1);
437 RETURN_MORTAL_INT(-1);
439 ST(0) = sv_2mortal(newSViv(0)); /* X and Y are equal */