Silence a couple of VC++ compiler warnings
[p5sagit/p5-mst-13.2.git] / ext / Math / BigInt / FastCalc / FastCalc.xs
CommitLineData
062a4e99 1#include "EXTERN.h"
2#include "perl.h"
3#include "XSUB.h"
4
5double XS_BASE = 0;
6double XS_BASE_LEN = 0;
7
8MODULE = Math::BigInt::FastCalc PACKAGE = Math::BigInt::FastCalc
9
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()
7d193e39 21 # 2007-04-02 0.08 Tels
22 # * plug leaks by creating mortals
5ed38b1a 23 # 2007-05-27 0.09 Tels
24 # * add _new()
7d193e39 25
26#define RETURN_MORTAL_INT(value) \
27 ST(0) = sv_2mortal(newSViv(value)); \
28 XSRETURN(1);
29
30#define RETURN_MORTAL_BOOL(temp, comp) \
31 ST(0) = sv_2mortal(boolSV( SvIV(temp) == comp));
32
33#define CONSTANT_OBJ(int) \
34 RETVAL = newAV(); \
35 sv_2mortal((SV*)RETVAL); \
36 av_push (RETVAL, newSViv( int ));
062a4e99 37
38void
39_set_XS_BASE(BASE, BASE_LEN)
40 SV* BASE
41 SV* BASE_LEN
42
43 CODE:
44 XS_BASE = SvNV(BASE);
45 XS_BASE_LEN = SvIV(BASE_LEN);
46
47##############################################################################
5ed38b1a 48# _new
49
50AV *
51_new(class, x)
52 SV* x
53 INIT:
54 STRLEN len;
55 char* cur;
a436f3ee 56 STRLEN part_len;
5ed38b1a 57
58 CODE:
59 /* create the array */
60 RETVAL = newAV();
61 sv_2mortal((SV*)RETVAL);
62 /* cur = SvPV(x, len); printf ("input '%s'\n", cur); */
63 if (SvIOK(x) && SvIV(x) < XS_BASE)
64 {
65 /* shortcut for integer arguments */
66 av_push (RETVAL, newSViv( SvIV(x) ));
67 }
68 else
69 {
70 /* split the input (as string) into XS_BASE_LEN long parts */
71 /* in perl:
72 [ reverse(unpack("a" . ($il % $BASE_LEN+1)
73 . ("a$BASE_LEN" x ($il / $BASE_LEN)), $_[1])) ];
74 */
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
78 while (len > 0)
79 {
80 /* use either BASE_LEN or the amount of remaining digits */
a436f3ee 81 part_len = (STRLEN) XS_BASE_LEN;
5ed38b1a 82 if (part_len > len)
83 {
84 part_len = len;
85 }
86 /* processed so many digits */
87 cur -= part_len;
88 len -= part_len;
89 /* printf ("part '%s' (part_len: %i, len: %i, BASE_LEN: %i)\n", cur, part_len, len, XS_BASE_LEN); */
90 if (part_len > 0)
91 {
92 av_push (RETVAL, newSVpvn(cur, part_len) );
93 }
94 }
95 }
96 OUTPUT:
97 RETVAL
98
99##############################################################################
062a4e99 100# _copy
101
102void
103_copy(class, x)
104 SV* x
105 INIT:
106 AV* a;
107 AV* a2;
108 I32 elems;
109
110 CODE:
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 */
115 while (elems >= 0)
116 {
117 /* av_store( a2, elems, newSVsv( (SV*)*av_fetch(a, elems, 0) ) ); */
118
119 /* looking and trying to preserve IV is actually slower when copying */
120 /* temp = (SV*)*av_fetch(a, elems, 0);
121 if (SvIOK(temp))
122 {
123 av_store( a2, elems, newSViv( SvIV( (SV*)*av_fetch(a, elems, 0) )));
124 }
125 else
126 {
127 av_store( a2, elems, newSVnv( SvNV( (SV*)*av_fetch(a, elems, 0) )));
128 }
129 */
130 av_store( a2, elems, newSVnv( SvNV( (SV*)*av_fetch(a, elems, 0) )));
131 elems--;
132 }
133 ST(0) = sv_2mortal( newRV_inc((SV*) a2) );
134
135##############################################################################
136# __strip_zeros (also check for empty arrays from div)
137
138void
139__strip_zeros(x)
140 SV* x
141 INIT:
142 AV* a;
143 SV* temp;
144 I32 elems;
145 I32 index;
146
147 CODE:
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 */
151 if (elems == -1)
152 {
153 av_push (a, newSViv(0)); /* correct empty arrays */
154 XSRETURN(1);
155 }
156 if (elems == 0)
157 {
158 XSRETURN(1); /* nothing to do since only one elem */
159 }
160 index = elems;
161 while (index > 0)
162 {
163 temp = *av_fetch(a, index, 0); /* fetch ptr to current element */
164 if (SvNV(temp) != 0)
165 {
166 break;
167 }
168 index--;
169 }
170 if (index < elems)
171 {
172 index = elems - index;
173 while (index-- > 0)
174 {
175 av_pop (a);
176 }
177 }
178 XSRETURN(1);
179
180##############################################################################
181# decrement (subtract one)
182
183void
184_dec(class,x)
185 SV* x
186 INIT:
187 AV* a;
188 SV* temp;
189 I32 elems;
190 I32 index;
191 NV MAX;
192
193 CODE:
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 */
197
198 MAX = XS_BASE - 1;
199 index = 0;
200 while (index <= elems)
201 {
202 temp = *av_fetch(a, index, 0); /* fetch ptr to current element */
203 sv_setnv (temp, SvNV(temp)-1);
204 if (SvNV(temp) >= 0)
205 {
206 break; /* early out */
207 }
208 sv_setnv (temp, MAX); /* overflow, so set this to $MAX */
209 index++;
210 }
211 /* do have more than one element? */
212 /* (more than one because [0] should be kept as single-element) */
213 if (elems > 0)
214 {
215 temp = *av_fetch(a, elems, 0); /* fetch last element */
216 if (SvIV(temp) == 0) /* did last elem overflow? */
217 {
218 av_pop(a); /* yes, so shrink array */
219 /* aka remove leading zeros */
220 }
221 }
222 XSRETURN(1); /* return x */
223
224##############################################################################
225# increment (add one)
226
227void
228_inc(class,x)
229 SV* x
230 INIT:
231 AV* a;
232 SV* temp;
233 I32 elems;
234 I32 index;
235 NV BASE;
236
237 CODE:
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 */
241
242 BASE = XS_BASE;
243 index = 0;
244 while (index <= elems)
245 {
246 temp = *av_fetch(a, index, 0); /* fetch ptr to current element */
247 sv_setnv (temp, SvNV(temp)+1);
248 if (SvNV(temp) < BASE)
249 {
250 XSRETURN(1); /* return (early out) */
251 }
252 sv_setiv (temp, 0); /* overflow, so set this elem to 0 */
253 index++;
254 }
255 temp = *av_fetch(a, elems, 0); /* fetch last element */
256 if (SvIV(temp) == 0) /* did last elem overflow? */
257 {
258 av_push(a, newSViv(1)); /* yes, so extend array by 1 */
259 }
260 XSRETURN(1); /* return x */
261
262##############################################################################
263# Make a number (scalar int/float) from a BigInt object
264
265void
266_num(class,x)
267 SV* x
268 INIT:
269 AV* a;
270 NV fac;
271 SV* temp;
272 NV num;
273 I32 elems;
274 I32 index;
275 NV BASE;
276
277 CODE:
278 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
279 elems = av_len(a); /* number of elems in array */
280
281 if (elems == 0) /* only one element? */
282 {
283 ST(0) = *av_fetch(a, 0, 0); /* fetch first (only) element */
284 XSRETURN(1); /* return it */
285 }
286 fac = 1.0; /* factor */
287 index = 0;
288 num = 0.0;
289 BASE = XS_BASE;
290 while (index <= elems)
291 {
292 temp = *av_fetch(a, index, 0); /* fetch current element */
293 num += fac * SvNV(temp);
294 fac *= BASE;
295 index++;
296 }
297 ST(0) = newSVnv(num);
298
299##############################################################################
300
caa64001 301AV *
302_zero(class)
062a4e99 303 CODE:
caa64001 304 CONSTANT_OBJ(0)
305 OUTPUT:
306 RETVAL
062a4e99 307
308##############################################################################
309
caa64001 310AV *
062a4e99 311_one(class)
062a4e99 312 CODE:
caa64001 313 CONSTANT_OBJ(1)
314 OUTPUT:
315 RETVAL
062a4e99 316
317##############################################################################
318
caa64001 319AV *
062a4e99 320_two(class)
062a4e99 321 CODE:
caa64001 322 CONSTANT_OBJ(2)
323 OUTPUT:
324 RETVAL
062a4e99 325
326##############################################################################
327
caa64001 328AV *
062a4e99 329_ten(class)
062a4e99 330 CODE:
caa64001 331 CONSTANT_OBJ(10)
332 OUTPUT:
333 RETVAL
062a4e99 334
335##############################################################################
336
337void
338_is_even(class, x)
339 SV* x
340 INIT:
341 AV* a;
342 SV* temp;
343
344 CODE:
345 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
346 temp = *av_fetch(a, 0, 0); /* fetch first element */
7d193e39 347 ST(0) = sv_2mortal(boolSV((SvIV(temp) & 1) == 0));
062a4e99 348
349##############################################################################
350
351void
352_is_odd(class, x)
353 SV* x
354 INIT:
355 AV* a;
356 SV* temp;
357
358 CODE:
359 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
360 temp = *av_fetch(a, 0, 0); /* fetch first element */
7d193e39 361 ST(0) = sv_2mortal(boolSV((SvIV(temp) & 1) != 0));
062a4e99 362
363##############################################################################
364
365void
366_is_one(class, x)
367 SV* x
368 INIT:
369 AV* a;
370 SV* temp;
371
372 CODE:
373 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
374 if ( av_len(a) != 0)
375 {
376 ST(0) = &PL_sv_no;
377 XSRETURN(1); /* len != 1, can't be '1' */
378 }
379 temp = *av_fetch(a, 0, 0); /* fetch first element */
7d193e39 380 RETURN_MORTAL_BOOL(temp, 1);
062a4e99 381
382##############################################################################
383
384void
385_is_two(class, x)
386 SV* x
387 INIT:
388 AV* a;
389 SV* temp;
390
391 CODE:
392 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
393 if ( av_len(a) != 0)
394 {
395 ST(0) = &PL_sv_no;
396 XSRETURN(1); /* len != 1, can't be '2' */
397 }
398 temp = *av_fetch(a, 0, 0); /* fetch first element */
7d193e39 399 RETURN_MORTAL_BOOL(temp, 2);
062a4e99 400
401##############################################################################
402
403void
404_is_ten(class, x)
405 SV* x
406 INIT:
407 AV* a;
408 SV* temp;
409
410 CODE:
411 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
412 if ( av_len(a) != 0)
413 {
414 ST(0) = &PL_sv_no;
415 XSRETURN(1); /* len != 1, can't be '10' */
416 }
417 temp = *av_fetch(a, 0, 0); /* fetch first element */
7d193e39 418 RETURN_MORTAL_BOOL(temp, 10);
062a4e99 419
420##############################################################################
421
422void
423_is_zero(class, x)
424 SV* x
425 INIT:
426 AV* a;
427 SV* temp;
428
429 CODE:
430 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
431 if ( av_len(a) != 0)
432 {
433 ST(0) = &PL_sv_no;
434 XSRETURN(1); /* len != 1, can't be '0' */
435 }
436 temp = *av_fetch(a, 0, 0); /* fetch first element */
7d193e39 437 RETURN_MORTAL_BOOL(temp, 0);
062a4e99 438
439##############################################################################
440
441void
442_len(class,x)
443 SV* x
444 INIT:
445 AV* a;
446 SV* temp;
6c0b8e73 447 IV elems;
062a4e99 448 STRLEN len;
449
450 CODE:
451 a = (AV*)SvRV(x); /* ref to aray, don't check ref */
6c0b8e73 452 elems = av_len(a); /* number of elems in array */
062a4e99 453 temp = *av_fetch(a, elems, 0); /* fetch last element */
454 SvPV(temp, len); /* convert to string & store length */
6c0b8e73 455 len += (IV) XS_BASE_LEN * elems;
7d193e39 456 ST(0) = sv_2mortal(newSViv(len));
062a4e99 457
458##############################################################################
459
460void
461_acmp(class, cx, cy);
462 SV* cx
463 SV* cy
464 INIT:
465 AV* array_x;
466 AV* array_y;
467 I32 elemsx, elemsy, diff;
468 SV* tempx;
469 SV* tempy;
470 STRLEN lenx;
471 STRLEN leny;
472 NV diff_nv;
473 I32 diff_str;
474
475 CODE:
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 */
481
482 if (diff > 0)
483 {
7d193e39 484 RETURN_MORTAL_INT(1); /* len differs: X > Y */
062a4e99 485 }
7d193e39 486 else if (diff < 0)
062a4e99 487 {
7d193e39 488 RETURN_MORTAL_INT(-1); /* len differs: X < Y */
062a4e99 489 }
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;
497 if (diff_str > 0)
498 {
7d193e39 499 RETURN_MORTAL_INT(1); /* same len, but first elems differs in len */
062a4e99 500 }
501 if (diff_str < 0)
502 {
7d193e39 503 RETURN_MORTAL_INT(-1); /* same len, but first elems differs in len */
062a4e99 504 }
505 /* same number of digits, so need to make a full compare */
506 diff_nv = 0;
507 while (elemsx >= 0)
508 {
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);
512 if (diff_nv != 0)
513 {
514 break;
515 }
516 elemsx--;
517 }
518 if (diff_nv > 0)
519 {
7d193e39 520 RETURN_MORTAL_INT(1);
062a4e99 521 }
522 if (diff_nv < 0)
523 {
7d193e39 524 RETURN_MORTAL_INT(-1);
062a4e99 525 }
7d193e39 526 ST(0) = sv_2mortal(newSViv(0)); /* X and Y are equal */
062a4e99 527