1*b8851fccSafresh1 #define PERL_NO_GET_CONTEXT 2*b8851fccSafresh1 3*b8851fccSafresh1 #include "EXTERN.h" 4*b8851fccSafresh1 #include "perl.h" 5*b8851fccSafresh1 #include "XSUB.h" 6*b8851fccSafresh1 7*b8851fccSafresh1 /* for Perl prior to v5.7.1 */ 8*b8851fccSafresh1 #ifndef SvUOK 9*b8851fccSafresh1 # define SvUOK(sv) SvIOK_UV(sv) 10*b8851fccSafresh1 #endif 11*b8851fccSafresh1 12*b8851fccSafresh1 /* for Perl v5.6 (RT #63859) */ 13*b8851fccSafresh1 #ifndef croak_xs_usage 14*b8851fccSafresh1 # define croak_xs_usage croak 15*b8851fccSafresh1 #endif 16*b8851fccSafresh1 17*b8851fccSafresh1 static double XS_BASE = 0; 18*b8851fccSafresh1 static double XS_BASE_LEN = 0; 19*b8851fccSafresh1 20*b8851fccSafresh1 MODULE = Math::BigInt::FastCalc PACKAGE = Math::BigInt::FastCalc 21*b8851fccSafresh1 22*b8851fccSafresh1 PROTOTYPES: DISABLE 23*b8851fccSafresh1 24*b8851fccSafresh1 ############################################################################# 25*b8851fccSafresh1 # 2002-08-12 0.03 Tels unreleased 26*b8851fccSafresh1 # * is_zero/is_one/is_odd/is_even/len work now (pass v1.61 tests) 27*b8851fccSafresh1 # 2002-08-13 0.04 Tels unreleased 28*b8851fccSafresh1 # * returns no/yes for is_foo() methods to be faster 29*b8851fccSafresh1 # 2002-08-18 0.06alpha 30*b8851fccSafresh1 # * added _num(), _inc() and _dec() 31*b8851fccSafresh1 # 2002-08-25 0.06 Tels 32*b8851fccSafresh1 # * added __strip_zeros(), _copy() 33*b8851fccSafresh1 # 2004-08-13 0.07 Tels 34*b8851fccSafresh1 # * added _is_two(), _is_ten(), _ten() 35*b8851fccSafresh1 # 2007-04-02 0.08 Tels 36*b8851fccSafresh1 # * plug leaks by creating mortals 37*b8851fccSafresh1 # 2007-05-27 0.09 Tels 38*b8851fccSafresh1 # * add _new() 39*b8851fccSafresh1 40*b8851fccSafresh1 #define RETURN_MORTAL_INT(value) \ 41*b8851fccSafresh1 ST(0) = sv_2mortal(newSViv(value)); \ 42*b8851fccSafresh1 XSRETURN(1); 43*b8851fccSafresh1 44*b8851fccSafresh1 BOOT: 45*b8851fccSafresh1 { 46*b8851fccSafresh1 if (items < 4) 47*b8851fccSafresh1 croak("Usage: Math::BigInt::FastCalc::BOOT(package, version, base_len, base)"); 48*b8851fccSafresh1 XS_BASE_LEN = SvIV(ST(2)); 49*b8851fccSafresh1 XS_BASE = SvNV(ST(3)); 50*b8851fccSafresh1 } 51*b8851fccSafresh1 52*b8851fccSafresh1 ############################################################################## 53*b8851fccSafresh1 # _new 54*b8851fccSafresh1 55*b8851fccSafresh1 SV * 56*b8851fccSafresh1 _new(class, x) 57*b8851fccSafresh1 SV* x 58*b8851fccSafresh1 INIT: 59*b8851fccSafresh1 STRLEN len; 60*b8851fccSafresh1 char* cur; 61*b8851fccSafresh1 STRLEN part_len; 62*b8851fccSafresh1 AV *av = newAV(); 63*b8851fccSafresh1 64*b8851fccSafresh1 CODE: 65*b8851fccSafresh1 if (SvUOK(x) && SvUV(x) < XS_BASE) 66*b8851fccSafresh1 { 67*b8851fccSafresh1 /* shortcut for integer arguments */ 68*b8851fccSafresh1 av_push (av, newSVuv( SvUV(x) )); 69*b8851fccSafresh1 } 70*b8851fccSafresh1 else 71*b8851fccSafresh1 { 72*b8851fccSafresh1 /* split the input (as string) into XS_BASE_LEN long parts */ 73*b8851fccSafresh1 /* in perl: 74*b8851fccSafresh1 [ reverse(unpack("a" . ($il % $BASE_LEN+1) 75*b8851fccSafresh1 . ("a$BASE_LEN" x ($il / $BASE_LEN)), $_[1])) ]; 76*b8851fccSafresh1 */ 77*b8851fccSafresh1 cur = SvPV(x, len); /* convert to string & store length */ 78*b8851fccSafresh1 cur += len; /* doing "cur = SvEND(x)" does not work! */ 79*b8851fccSafresh1 # process the string from the back 80*b8851fccSafresh1 while (len > 0) 81*b8851fccSafresh1 { 82*b8851fccSafresh1 /* use either BASE_LEN or the amount of remaining digits */ 83*b8851fccSafresh1 part_len = (STRLEN) XS_BASE_LEN; 84*b8851fccSafresh1 if (part_len > len) 85*b8851fccSafresh1 { 86*b8851fccSafresh1 part_len = len; 87*b8851fccSafresh1 } 88*b8851fccSafresh1 /* processed so many digits */ 89*b8851fccSafresh1 cur -= part_len; 90*b8851fccSafresh1 len -= part_len; 91*b8851fccSafresh1 /* printf ("part '%s' (part_len: %i, len: %i, BASE_LEN: %i)\n", cur, part_len, len, XS_BASE_LEN); */ 92*b8851fccSafresh1 if (part_len > 0) 93*b8851fccSafresh1 { 94*b8851fccSafresh1 av_push (av, newSVpvn(cur, part_len) ); 95*b8851fccSafresh1 } 96*b8851fccSafresh1 } 97*b8851fccSafresh1 } 98*b8851fccSafresh1 RETVAL = newRV_noinc((SV *)av); 99*b8851fccSafresh1 OUTPUT: 100*b8851fccSafresh1 RETVAL 101*b8851fccSafresh1 102*b8851fccSafresh1 ############################################################################## 103*b8851fccSafresh1 # _copy 104*b8851fccSafresh1 105*b8851fccSafresh1 void 106*b8851fccSafresh1 _copy(class, x) 107*b8851fccSafresh1 SV* x 108*b8851fccSafresh1 INIT: 109*b8851fccSafresh1 AV* a; 110*b8851fccSafresh1 AV* a2; 111*b8851fccSafresh1 SSize_t elems; 112*b8851fccSafresh1 113*b8851fccSafresh1 CODE: 114*b8851fccSafresh1 a = (AV*)SvRV(x); /* ref to aray, don't check ref */ 115*b8851fccSafresh1 elems = av_len(a); /* number of elems in array */ 116*b8851fccSafresh1 a2 = (AV*)sv_2mortal((SV*)newAV()); 117*b8851fccSafresh1 av_extend (a2, elems); /* pre-padd */ 118*b8851fccSafresh1 while (elems >= 0) 119*b8851fccSafresh1 { 120*b8851fccSafresh1 /* av_store( a2, elems, newSVsv( (SV*)*av_fetch(a, elems, 0) ) ); */ 121*b8851fccSafresh1 122*b8851fccSafresh1 /* looking and trying to preserve IV is actually slower when copying */ 123*b8851fccSafresh1 /* temp = (SV*)*av_fetch(a, elems, 0); 124*b8851fccSafresh1 if (SvIOK(temp)) 125*b8851fccSafresh1 { 126*b8851fccSafresh1 av_store( a2, elems, newSViv( SvIV( (SV*)*av_fetch(a, elems, 0) ))); 127*b8851fccSafresh1 } 128*b8851fccSafresh1 else 129*b8851fccSafresh1 { 130*b8851fccSafresh1 av_store( a2, elems, newSVnv( SvNV( (SV*)*av_fetch(a, elems, 0) ))); 131*b8851fccSafresh1 } 132*b8851fccSafresh1 */ 133*b8851fccSafresh1 av_store( a2, elems, newSVnv( SvNV( (SV*)*av_fetch(a, elems, 0) ))); 134*b8851fccSafresh1 elems--; 135*b8851fccSafresh1 } 136*b8851fccSafresh1 ST(0) = sv_2mortal( newRV_inc((SV*) a2) ); 137*b8851fccSafresh1 138*b8851fccSafresh1 ############################################################################## 139*b8851fccSafresh1 # __strip_zeros (also check for empty arrays from div) 140*b8851fccSafresh1 141*b8851fccSafresh1 void 142*b8851fccSafresh1 __strip_zeros(x) 143*b8851fccSafresh1 SV* x 144*b8851fccSafresh1 INIT: 145*b8851fccSafresh1 AV* a; 146*b8851fccSafresh1 SV* temp; 147*b8851fccSafresh1 SSize_t elems; 148*b8851fccSafresh1 SSize_t index; 149*b8851fccSafresh1 150*b8851fccSafresh1 CODE: 151*b8851fccSafresh1 a = (AV*)SvRV(x); /* ref to aray, don't check ref */ 152*b8851fccSafresh1 elems = av_len(a); /* number of elems in array */ 153*b8851fccSafresh1 ST(0) = x; /* we return x */ 154*b8851fccSafresh1 if (elems == -1) 155*b8851fccSafresh1 { 156*b8851fccSafresh1 av_push (a, newSViv(0)); /* correct empty arrays */ 157*b8851fccSafresh1 XSRETURN(1); 158*b8851fccSafresh1 } 159*b8851fccSafresh1 if (elems == 0) 160*b8851fccSafresh1 { 161*b8851fccSafresh1 XSRETURN(1); /* nothing to do since only one elem */ 162*b8851fccSafresh1 } 163*b8851fccSafresh1 index = elems; 164*b8851fccSafresh1 while (index > 0) 165*b8851fccSafresh1 { 166*b8851fccSafresh1 temp = *av_fetch(a, index, 0); /* fetch ptr to current element */ 167*b8851fccSafresh1 if (SvNV(temp) != 0) 168*b8851fccSafresh1 { 169*b8851fccSafresh1 break; 170*b8851fccSafresh1 } 171*b8851fccSafresh1 index--; 172*b8851fccSafresh1 } 173*b8851fccSafresh1 if (index < elems) 174*b8851fccSafresh1 { 175*b8851fccSafresh1 index = elems - index; 176*b8851fccSafresh1 while (index-- > 0) 177*b8851fccSafresh1 { 178*b8851fccSafresh1 av_pop (a); 179*b8851fccSafresh1 } 180*b8851fccSafresh1 } 181*b8851fccSafresh1 XSRETURN(1); 182*b8851fccSafresh1 183*b8851fccSafresh1 ############################################################################## 184*b8851fccSafresh1 # decrement (subtract one) 185*b8851fccSafresh1 186*b8851fccSafresh1 void 187*b8851fccSafresh1 _dec(class,x) 188*b8851fccSafresh1 SV* x 189*b8851fccSafresh1 INIT: 190*b8851fccSafresh1 AV* a; 191*b8851fccSafresh1 SV* temp; 192*b8851fccSafresh1 SSize_t elems; 193*b8851fccSafresh1 SSize_t index; 194*b8851fccSafresh1 NV MAX; 195*b8851fccSafresh1 196*b8851fccSafresh1 CODE: 197*b8851fccSafresh1 a = (AV*)SvRV(x); /* ref to aray, don't check ref */ 198*b8851fccSafresh1 elems = av_len(a); /* number of elems in array */ 199*b8851fccSafresh1 ST(0) = x; /* we return x */ 200*b8851fccSafresh1 201*b8851fccSafresh1 MAX = XS_BASE - 1; 202*b8851fccSafresh1 index = 0; 203*b8851fccSafresh1 while (index <= elems) 204*b8851fccSafresh1 { 205*b8851fccSafresh1 temp = *av_fetch(a, index, 0); /* fetch ptr to current element */ 206*b8851fccSafresh1 sv_setnv (temp, SvNV(temp)-1); /* decrement */ 207*b8851fccSafresh1 if (SvNV(temp) >= 0) 208*b8851fccSafresh1 { 209*b8851fccSafresh1 break; /* early out */ 210*b8851fccSafresh1 } 211*b8851fccSafresh1 sv_setnv (temp, MAX); /* overflow, so set this to $MAX */ 212*b8851fccSafresh1 index++; 213*b8851fccSafresh1 } 214*b8851fccSafresh1 /* do have more than one element? */ 215*b8851fccSafresh1 /* (more than one because [0] should be kept as single-element) */ 216*b8851fccSafresh1 if (elems > 0) 217*b8851fccSafresh1 { 218*b8851fccSafresh1 temp = *av_fetch(a, elems, 0); /* fetch last element */ 219*b8851fccSafresh1 if (SvIV(temp) == 0) /* did last elem overflow? */ 220*b8851fccSafresh1 { 221*b8851fccSafresh1 av_pop(a); /* yes, so shrink array */ 222*b8851fccSafresh1 /* aka remove leading zeros */ 223*b8851fccSafresh1 } 224*b8851fccSafresh1 } 225*b8851fccSafresh1 XSRETURN(1); /* return x */ 226*b8851fccSafresh1 227*b8851fccSafresh1 ############################################################################## 228*b8851fccSafresh1 # increment (add one) 229*b8851fccSafresh1 230*b8851fccSafresh1 void 231*b8851fccSafresh1 _inc(class,x) 232*b8851fccSafresh1 SV* x 233*b8851fccSafresh1 INIT: 234*b8851fccSafresh1 AV* a; 235*b8851fccSafresh1 SV* temp; 236*b8851fccSafresh1 SSize_t elems; 237*b8851fccSafresh1 SSize_t index; 238*b8851fccSafresh1 NV BASE; 239*b8851fccSafresh1 240*b8851fccSafresh1 CODE: 241*b8851fccSafresh1 a = (AV*)SvRV(x); /* ref to aray, don't check ref */ 242*b8851fccSafresh1 elems = av_len(a); /* number of elems in array */ 243*b8851fccSafresh1 ST(0) = x; /* we return x */ 244*b8851fccSafresh1 245*b8851fccSafresh1 BASE = XS_BASE; 246*b8851fccSafresh1 index = 0; 247*b8851fccSafresh1 while (index <= elems) 248*b8851fccSafresh1 { 249*b8851fccSafresh1 temp = *av_fetch(a, index, 0); /* fetch ptr to current element */ 250*b8851fccSafresh1 sv_setnv (temp, SvNV(temp)+1); 251*b8851fccSafresh1 if (SvNV(temp) < BASE) 252*b8851fccSafresh1 { 253*b8851fccSafresh1 XSRETURN(1); /* return (early out) */ 254*b8851fccSafresh1 } 255*b8851fccSafresh1 sv_setiv (temp, 0); /* overflow, so set this elem to 0 */ 256*b8851fccSafresh1 index++; 257*b8851fccSafresh1 } 258*b8851fccSafresh1 temp = *av_fetch(a, elems, 0); /* fetch last element */ 259*b8851fccSafresh1 if (SvIV(temp) == 0) /* did last elem overflow? */ 260*b8851fccSafresh1 { 261*b8851fccSafresh1 av_push(a, newSViv(1)); /* yes, so extend array by 1 */ 262*b8851fccSafresh1 } 263*b8851fccSafresh1 XSRETURN(1); /* return x */ 264*b8851fccSafresh1 265*b8851fccSafresh1 ############################################################################## 266*b8851fccSafresh1 267*b8851fccSafresh1 SV * 268*b8851fccSafresh1 _zero(class) 269*b8851fccSafresh1 ALIAS: 270*b8851fccSafresh1 _one = 1 271*b8851fccSafresh1 _two = 2 272*b8851fccSafresh1 _ten = 10 273*b8851fccSafresh1 PREINIT: 274*b8851fccSafresh1 AV *av = newAV(); 275*b8851fccSafresh1 CODE: 276*b8851fccSafresh1 av_push (av, newSViv( ix )); 277*b8851fccSafresh1 RETVAL = newRV_noinc((SV *)av); 278*b8851fccSafresh1 OUTPUT: 279*b8851fccSafresh1 RETVAL 280*b8851fccSafresh1 281*b8851fccSafresh1 ############################################################################## 282*b8851fccSafresh1 283*b8851fccSafresh1 void 284*b8851fccSafresh1 _is_even(class, x) 285*b8851fccSafresh1 SV* x 286*b8851fccSafresh1 ALIAS: 287*b8851fccSafresh1 _is_odd = 1 288*b8851fccSafresh1 INIT: 289*b8851fccSafresh1 AV* a; 290*b8851fccSafresh1 SV* temp; 291*b8851fccSafresh1 292*b8851fccSafresh1 CODE: 293*b8851fccSafresh1 a = (AV*)SvRV(x); /* ref to aray, don't check ref */ 294*b8851fccSafresh1 temp = *av_fetch(a, 0, 0); /* fetch first element */ 295*b8851fccSafresh1 ST(0) = sv_2mortal(boolSV((SvIV(temp) & 1) == ix)); 296*b8851fccSafresh1 297*b8851fccSafresh1 ############################################################################## 298*b8851fccSafresh1 299*b8851fccSafresh1 void 300*b8851fccSafresh1 _is_zero(class, x) 301*b8851fccSafresh1 SV* x 302*b8851fccSafresh1 ALIAS: 303*b8851fccSafresh1 _is_one = 1 304*b8851fccSafresh1 _is_two = 2 305*b8851fccSafresh1 _is_ten = 10 306*b8851fccSafresh1 INIT: 307*b8851fccSafresh1 AV* a; 308*b8851fccSafresh1 309*b8851fccSafresh1 CODE: 310*b8851fccSafresh1 a = (AV*)SvRV(x); /* ref to aray, don't check ref */ 311*b8851fccSafresh1 if ( av_len(a) != 0) 312*b8851fccSafresh1 { 313*b8851fccSafresh1 ST(0) = &PL_sv_no; /* len != 1, can't be '0' */ 314*b8851fccSafresh1 } 315*b8851fccSafresh1 else 316*b8851fccSafresh1 { 317*b8851fccSafresh1 SV *const temp = *av_fetch(a, 0, 0); /* fetch first element */ 318*b8851fccSafresh1 ST(0) = boolSV(SvIV(temp) == ix); 319*b8851fccSafresh1 } 320*b8851fccSafresh1 XSRETURN(1); 321*b8851fccSafresh1 322*b8851fccSafresh1 ############################################################################## 323*b8851fccSafresh1 324*b8851fccSafresh1 void 325*b8851fccSafresh1 _len(class,x) 326*b8851fccSafresh1 SV* x 327*b8851fccSafresh1 INIT: 328*b8851fccSafresh1 AV* a; 329*b8851fccSafresh1 SV* temp; 330*b8851fccSafresh1 IV elems; 331*b8851fccSafresh1 STRLEN len; 332*b8851fccSafresh1 333*b8851fccSafresh1 CODE: 334*b8851fccSafresh1 a = (AV*)SvRV(x); /* ref to aray, don't check ref */ 335*b8851fccSafresh1 elems = av_len(a); /* number of elems in array */ 336*b8851fccSafresh1 temp = *av_fetch(a, elems, 0); /* fetch last element */ 337*b8851fccSafresh1 SvPV(temp, len); /* convert to string & store length */ 338*b8851fccSafresh1 len += (IV) XS_BASE_LEN * elems; 339*b8851fccSafresh1 ST(0) = sv_2mortal(newSViv(len)); 340*b8851fccSafresh1 341*b8851fccSafresh1 ############################################################################## 342*b8851fccSafresh1 343*b8851fccSafresh1 void 344*b8851fccSafresh1 _acmp(class, cx, cy); 345*b8851fccSafresh1 SV* cx 346*b8851fccSafresh1 SV* cy 347*b8851fccSafresh1 INIT: 348*b8851fccSafresh1 AV* array_x; 349*b8851fccSafresh1 AV* array_y; 350*b8851fccSafresh1 SSize_t elemsx, elemsy, diff; 351*b8851fccSafresh1 SV* tempx; 352*b8851fccSafresh1 SV* tempy; 353*b8851fccSafresh1 STRLEN lenx; 354*b8851fccSafresh1 STRLEN leny; 355*b8851fccSafresh1 NV diff_nv; 356*b8851fccSafresh1 SSize_t diff_str; 357*b8851fccSafresh1 358*b8851fccSafresh1 CODE: 359*b8851fccSafresh1 array_x = (AV*)SvRV(cx); /* ref to aray, don't check ref */ 360*b8851fccSafresh1 array_y = (AV*)SvRV(cy); /* ref to aray, don't check ref */ 361*b8851fccSafresh1 elemsx = av_len(array_x); 362*b8851fccSafresh1 elemsy = av_len(array_y); 363*b8851fccSafresh1 diff = elemsx - elemsy; /* difference */ 364*b8851fccSafresh1 365*b8851fccSafresh1 if (diff > 0) 366*b8851fccSafresh1 { 367*b8851fccSafresh1 RETURN_MORTAL_INT(1); /* len differs: X > Y */ 368*b8851fccSafresh1 } 369*b8851fccSafresh1 else if (diff < 0) 370*b8851fccSafresh1 { 371*b8851fccSafresh1 RETURN_MORTAL_INT(-1); /* len differs: X < Y */ 372*b8851fccSafresh1 } 373*b8851fccSafresh1 /* both have same number of elements, so check length of last element 374*b8851fccSafresh1 and see if it differs */ 375*b8851fccSafresh1 tempx = *av_fetch(array_x, elemsx, 0); /* fetch last element */ 376*b8851fccSafresh1 tempy = *av_fetch(array_y, elemsx, 0); /* fetch last element */ 377*b8851fccSafresh1 SvPV(tempx, lenx); /* convert to string & store length */ 378*b8851fccSafresh1 SvPV(tempy, leny); /* convert to string & store length */ 379*b8851fccSafresh1 diff_str = (SSize_t)lenx - (SSize_t)leny; 380*b8851fccSafresh1 if (diff_str > 0) 381*b8851fccSafresh1 { 382*b8851fccSafresh1 RETURN_MORTAL_INT(1); /* same len, but first elems differs in len */ 383*b8851fccSafresh1 } 384*b8851fccSafresh1 if (diff_str < 0) 385*b8851fccSafresh1 { 386*b8851fccSafresh1 RETURN_MORTAL_INT(-1); /* same len, but first elems differs in len */ 387*b8851fccSafresh1 } 388*b8851fccSafresh1 /* same number of digits, so need to make a full compare */ 389*b8851fccSafresh1 diff_nv = 0; 390*b8851fccSafresh1 while (elemsx >= 0) 391*b8851fccSafresh1 { 392*b8851fccSafresh1 tempx = *av_fetch(array_x, elemsx, 0); /* fetch curr x element */ 393*b8851fccSafresh1 tempy = *av_fetch(array_y, elemsx, 0); /* fetch curr y element */ 394*b8851fccSafresh1 diff_nv = SvNV(tempx) - SvNV(tempy); 395*b8851fccSafresh1 if (diff_nv != 0) 396*b8851fccSafresh1 { 397*b8851fccSafresh1 break; 398*b8851fccSafresh1 } 399*b8851fccSafresh1 elemsx--; 400*b8851fccSafresh1 } 401*b8851fccSafresh1 if (diff_nv > 0) 402*b8851fccSafresh1 { 403*b8851fccSafresh1 RETURN_MORTAL_INT(1); 404*b8851fccSafresh1 } 405*b8851fccSafresh1 if (diff_nv < 0) 406*b8851fccSafresh1 { 407*b8851fccSafresh1 RETURN_MORTAL_INT(-1); 408*b8851fccSafresh1 } 409*b8851fccSafresh1 ST(0) = sv_2mortal(newSViv(0)); /* X and Y are equal */ 410