File Coverage

GMP.xs
Criterion Covered Total %
statement 168 184 91.3
branch 30 46 65.2
condition n/a
subroutine n/a
pod n/a
total 198 230 86.0


line stmt bran cond sub pod time code
1             #include "EXTERN.h"
2             #include "perl.h"
3             #include "XSUB.h"
4             #include "gmp.h"
5              
6             /*
7             Math::GMP, a Perl module for high-speed arbitrary size integer
8             calculations
9             Copyright (C) 2000 James H. Turner
10              
11             This library is free software; you can redistribute it and/or
12             modify it under the terms of the GNU Library General Public
13             License as published by the Free Software Foundation; either
14             version 2 of the License, or (at your option) any later version.
15              
16             This library is distributed in the hope that it will be useful,
17             but WITHOUT ANY WARRANTY; without even the implied warranty of
18             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19             Library General Public License for more details.
20              
21             You should have received a copy of the GNU Library General Public
22             License along with this library; if not, write to the Free
23             Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24              
25             You can contact the author at chip@redhat.com, chipt@cpan.org, or by mail:
26              
27             Chip Turner
28             Red Hat Inc.
29             2600 Meridian Park Blvd
30             Durham, NC 27713
31             */
32              
33             #define SWAP_GMP if (swap) { mpz_t* t = m; m = n; n = t; }
34              
35             /*
36             * mpz_rootrem() has bug with negative first argument before 5.1.0
37             */
38 6           static int need_rootrem_workaround(mpz_t* m, unsigned long n) {
39             /* workaround only valid for n odd (n even should be an error) */
40 6 100         if ((n & 1) == 0)
41 2           return 0;
42              
43             /* workaround only relevant for m negative */
44 4 100         if (mpz_sgn(*m) >= 0)
45 2           return 0;
46              
47             /* workaround only needed for gmp_version < 5.1.0 */
48 2 50         if ((gmp_version[0] && gmp_version[1] != '.') /* >= 10.0.0 */
    50          
49 2 50         || (gmp_version[0] > '5') /* >= 6.0.0 */
50 0 0         || (gmp_version[0] == '5' && gmp_version[2] != '0') /* >= 5.1.0 */
    0          
51             )
52 2           return 0;
53              
54 0           return 1;
55             }
56              
57             static int
58 0           not_here(char *s)
59             {
60 0           croak("%s not implemented on this architecture", s);
61             return -1;
62             }
63              
64             #if 0
65             static double
66             constant(char *name, int arg)
67             {
68             errno = 0;
69             switch (*name) {
70             }
71             errno = EINVAL;
72             return 0;
73              
74             not_there:
75             errno = ENOENT;
76             return 0;
77             }
78             #endif
79              
80             mpz_t *
81 298           pv2gmp(char* pv)
82             {
83             mpz_t* z;
84             SV* sv;
85              
86 298           z = malloc (sizeof(mpz_t));
87 298           mpz_init_set_str(*z, pv, 0);
88 298           sv = sv_newmortal();
89 298           sv_setref_pv(sv, "Math::GMP", (void*)z);
90 298           return z;
91             }
92              
93             mpz_t *
94 5684           sv2gmp(SV* sv)
95             {
96             char* pv;
97              
98             /* MAYCHANGE in perlguts.pod - bug in perl */
99 5684 50         if (SvGMAGICAL(sv)) mg_get(sv);
100              
101 5684 100         if (SvROK(sv) && sv_derived_from(sv, "Math::GMP")) {
    50          
102 5386 50         IV tmp = SvIV((SV*)SvRV(sv));
103 5386           return (mpz_t *)tmp;
104             }
105              
106 298 100         pv = SvPV_nolen(sv);
107 298           return pv2gmp(pv);
108             }
109              
110              
111             MODULE = Math::GMP PACKAGE = Math::GMP
112             PROTOTYPES: ENABLE
113              
114             mpz_t *
115             new_from_scalar(s)
116             char * s
117              
118             CODE:
119 1628           RETVAL = malloc (sizeof(mpz_t));
120 1628           mpz_init_set_str(*RETVAL, s, 0);
121             OUTPUT:
122             RETVAL
123              
124             mpz_t *
125             new_from_scalar_with_base(s, b)
126             char * s
127             int b
128              
129             CODE:
130 2           RETVAL = malloc (sizeof(mpz_t));
131 2           mpz_init_set_str(*RETVAL, s, b);
132             OUTPUT:
133             RETVAL
134              
135             void
136             destroy(n)
137             mpz_t *n
138              
139             CODE:
140 2860           mpz_clear(*n);
141 2860           free(n);
142              
143             SV *
144             _gmp_build_version()
145             CODE:
146 0           char buf[] = STRINGIFY(__GNU_MP_VERSION)
147             "." STRINGIFY(__GNU_MP_VERSION_MINOR)
148             "." STRINGIFY(__GNU_MP_VERSION_PATCHLEVEL);
149 0           RETVAL = newSV(6);
150 0           scan_vstring(buf, buf + sizeof(buf), RETVAL);
151             OUTPUT:
152             RETVAL
153              
154             SV *
155             _gmp_lib_version()
156             CODE:
157 0           const char* v = gmp_version;
158 0           RETVAL = newSV(6);
159 0           scan_vstring(v, v + strlen(v), RETVAL);
160             OUTPUT:
161             RETVAL
162              
163             SV *
164             stringify(n)
165             mpz_t * n
166              
167             PREINIT:
168             int len;
169              
170             CODE:
171 841           len = mpz_sizeinbase(*n, 10);
172             {
173             char *buf;
174 841           buf = malloc(len + 2);
175 841           mpz_get_str(buf, 10, *n);
176 841           RETVAL = newSVpv(buf, strlen(buf));
177 841           free(buf);
178             }
179             OUTPUT:
180             RETVAL
181              
182              
183             SV *
184             get_str_gmp(n, b)
185             mpz_t * n
186             int b
187              
188             PREINIT:
189             int len;
190              
191             CODE:
192 1           len = mpz_sizeinbase(*n, b);
193             {
194             char *buf;
195 1           buf = malloc(len + 2);
196 1           mpz_get_str(buf, b, *n);
197 1           RETVAL = newSVpv(buf, strlen(buf));
198 1           free(buf);
199             }
200             OUTPUT:
201             RETVAL
202              
203             int
204             sizeinbase_gmp(n, b)
205             mpz_t * n
206             int b
207              
208             CODE:
209 7           RETVAL = mpz_sizeinbase(*n, b);
210             OUTPUT:
211             RETVAL
212              
213             unsigned long
214             uintify(n)
215             mpz_t * n
216              
217             CODE:
218 59           RETVAL = mpz_get_ui(*n);
219             OUTPUT:
220             RETVAL
221              
222             void
223             add_ui_gmp(n, v)
224             mpz_t * n
225             unsigned long v
226              
227             CODE:
228 7           mpz_add_ui(*n, *n, v);
229              
230              
231             long
232             intify(n)
233             mpz_t * n
234              
235             CODE:
236 5           RETVAL = mpz_get_si(*n);
237             OUTPUT:
238             RETVAL
239              
240             mpz_t *
241             mul_2exp_gmp(n, e)
242             mpz_t * n
243             unsigned long e
244              
245             CODE:
246 9           RETVAL = malloc (sizeof(mpz_t));
247 9           mpz_init(*RETVAL);
248 9           mpz_mul_2exp(*RETVAL, *n, e);
249             OUTPUT:
250             RETVAL
251              
252             mpz_t *
253             div_2exp_gmp(n, e)
254             mpz_t * n
255             unsigned long e
256              
257             CODE:
258 5           RETVAL = malloc (sizeof(mpz_t));
259 5           mpz_init(*RETVAL);
260 5           mpz_div_2exp(*RETVAL, *n, e);
261             OUTPUT:
262             RETVAL
263              
264              
265             mpz_t *
266             powm_gmp(n, exp, mod)
267             mpz_t * n
268             mpz_t * exp
269             mpz_t * mod
270              
271             CODE:
272 7           RETVAL = malloc (sizeof(mpz_t));
273 7           mpz_init(*RETVAL);
274 7           mpz_powm(*RETVAL, *n, *exp, *mod);
275             OUTPUT:
276             RETVAL
277              
278              
279             mpz_t *
280             mmod_gmp(a, b)
281             mpz_t * a
282             mpz_t * b
283              
284             CODE:
285 5           RETVAL = malloc (sizeof(mpz_t));
286 5           mpz_init(*RETVAL);
287 5           mpz_mmod(*RETVAL, *a, *b);
288             OUTPUT:
289             RETVAL
290              
291              
292             mpz_t *
293             mod_2exp_gmp(in, cnt)
294             mpz_t * in
295             unsigned long cnt
296              
297             CODE:
298 5           RETVAL = malloc (sizeof(mpz_t));
299 5           mpz_init(*RETVAL);
300 5           mpz_mod_2exp(*RETVAL, *in, cnt);
301             OUTPUT:
302             RETVAL
303              
304              
305             mpz_t *
306             op_add(m,n,swap)
307             mpz_t * m
308             mpz_t * n
309             bool swap
310              
311             CODE:
312 73           RETVAL = malloc (sizeof(mpz_t));
313 73           mpz_init(*RETVAL);
314 73           mpz_add(*RETVAL, *m, *n);
315             OUTPUT:
316             RETVAL
317              
318              
319             mpz_t *
320             op_sub(m,n,swap)
321             mpz_t * m
322             mpz_t * n
323             bool swap
324              
325             CODE:
326 72 100         SWAP_GMP
327 72           RETVAL = malloc (sizeof(mpz_t));
328 72           mpz_init(*RETVAL);
329 72           mpz_sub(*RETVAL, *m, *n);
330             OUTPUT:
331             RETVAL
332              
333              
334             mpz_t *
335             op_mul(m,n,swap)
336             mpz_t * m
337             mpz_t * n
338             bool swap
339              
340             CODE:
341 63           RETVAL = malloc (sizeof(mpz_t));
342 63           mpz_init(*RETVAL);
343 63           mpz_mul(*RETVAL, *m, *n);
344             OUTPUT:
345             RETVAL
346              
347              
348             mpz_t *
349             bmulf(n,d)
350             mpz_t * n
351             double d
352              
353             PREINIT:
354             mpf_t nf, df;
355             mp_bitcnt_t prec;
356             CODE:
357             /*
358             Multiply (mpz_t) n by (double) d returning an (mpz_t) result.
359             Uses GMP floats with maximum needed precision.
360             */
361 46           prec = mpf_get_default_prec();
362 46           mpf_set_default_prec(mpz_sizeinbase(*n, 2) + 8 * sizeof(double));
363              
364 46           RETVAL = malloc (sizeof(mpz_t));
365 46           mpz_init(*RETVAL);
366 46           mpf_init(nf);
367 46           mpf_init(df);
368              
369 46           mpf_set_z(nf, *n);
370 46           mpf_set_d(df, d);
371 46           mpf_mul(nf, nf, df);
372 46           mpz_set_f(*RETVAL, nf);
373 46           mpf_clear(nf);
374 46           mpf_clear(df);
375             /* restore default */
376 46           mpf_set_default_prec(prec);
377             OUTPUT:
378             RETVAL
379              
380              
381             mpz_t *
382             op_div(m,n,swap)
383             mpz_t * m
384             mpz_t * n
385             bool swap
386              
387             CODE:
388 64 100         SWAP_GMP
389 64           RETVAL = malloc (sizeof(mpz_t));
390 64           mpz_init(*RETVAL);
391 64           mpz_div(*RETVAL, *m, *n);
392             OUTPUT:
393             RETVAL
394              
395              
396             void
397             bdiv(m,n)
398             mpz_t * m
399             mpz_t * n
400              
401             PREINIT:
402             mpz_t * quo;
403             mpz_t * rem;
404             PPCODE:
405 129           quo = malloc (sizeof(mpz_t));
406 129           rem = malloc (sizeof(mpz_t));
407 129           mpz_init(*quo);
408 129           mpz_init(*rem);
409 129           mpz_tdiv_qr(*quo, *rem, *m, *n);
410 129 50         EXTEND(SP, 2);
411 129           PUSHs(sv_setref_pv(sv_newmortal(), "Math::GMP", (void*)quo));
412 129           PUSHs(sv_setref_pv(sv_newmortal(), "Math::GMP", (void*)rem));
413              
414              
415              
416             mpz_t *
417             op_mod(m,n,swap)
418             mpz_t * m
419             mpz_t * n
420             bool swap
421              
422             CODE:
423 65 100         SWAP_GMP
424 65           RETVAL = malloc (sizeof(mpz_t));
425 65           mpz_init(*RETVAL);
426 65           mpz_mod(*RETVAL, *m, *n);
427             OUTPUT:
428             RETVAL
429              
430             mpz_t *
431             bmodinv(m,n)
432             mpz_t * m
433             mpz_t * n
434              
435             CODE:
436 11           RETVAL = malloc (sizeof(mpz_t));
437 11           mpz_init(*RETVAL);
438 11           mpz_invert(*RETVAL, *m, *n);
439             OUTPUT:
440             RETVAL
441              
442              
443             int
444             op_spaceship(m,n,swap)
445             mpz_t * m
446             mpz_t * n
447             bool swap
448              
449             PREINIT:
450             int i;
451             CODE:
452 101           i = mpz_cmp(*m, *n);
453 101 100         if (swap) {
454 4           i = -i;
455             }
456 101 100         RETVAL = (i < 0) ? -1 : (i > 0) ? 1 : 0;
457             OUTPUT:
458             RETVAL
459              
460             int
461             op_eq(m,n,swap)
462             mpz_t* m
463             mpz_t* n
464             bool swap
465              
466             PREINIT:
467             int i;
468             CODE:
469 0           i = mpz_cmp(*m, *n);
470 0           RETVAL = (i == 0) ? 1 : 0;
471             OUTPUT:
472             RETVAL
473              
474             int
475             legendre(m, n)
476             mpz_t * m
477             mpz_t * n
478              
479             CODE:
480 1           RETVAL = mpz_legendre(*m, *n);
481             OUTPUT:
482             RETVAL
483              
484             int
485             jacobi(m, n)
486             mpz_t * m
487             mpz_t * n
488              
489             CODE:
490 119           RETVAL = mpz_jacobi(*m, *n);
491             OUTPUT:
492             RETVAL
493              
494             int
495             probab_prime(m, reps)
496             mpz_t * m
497             int reps
498              
499             CODE:
500 25           RETVAL = mpz_probab_prime_p(*m, reps);
501             OUTPUT:
502             RETVAL
503              
504             mpz_t *
505             op_pow(m,n)
506             mpz_t * m
507             long n
508              
509             CODE:
510 2           RETVAL = malloc (sizeof(mpz_t));
511 2           mpz_init(*RETVAL);
512             /* fprintf(stderr, "n is %ld\n", n);*/
513 2           mpz_pow_ui(*RETVAL, *m, n);
514             OUTPUT:
515             RETVAL
516              
517              
518             mpz_t *
519             bgcd(m,n)
520             mpz_t * m
521             mpz_t * n
522              
523             CODE:
524 71           RETVAL = malloc (sizeof(mpz_t));
525 71           mpz_init(*RETVAL);
526 71           mpz_gcd(*RETVAL, *m, *n);
527             OUTPUT:
528             RETVAL
529              
530              
531             mpz_t *
532             blcm(m,n)
533             mpz_t * m
534             mpz_t * n
535              
536             CODE:
537 41           RETVAL = malloc (sizeof(mpz_t));
538 41           mpz_init(*RETVAL);
539 41           mpz_lcm(*RETVAL, *m, *n);
540             OUTPUT:
541             RETVAL
542              
543              
544             mpz_t *
545             fibonacci(n)
546             long n
547              
548             CODE:
549 19           RETVAL = malloc (sizeof(mpz_t));
550 19           mpz_init(*RETVAL);
551 19           mpz_fib_ui(*RETVAL, n);
552             OUTPUT:
553             RETVAL
554              
555              
556             mpz_t *
557             band(m,n, ...)
558             mpz_t * m
559             mpz_t * n
560              
561             CODE:
562 7           RETVAL = malloc (sizeof(mpz_t));
563 7           mpz_init(*RETVAL);
564 7           mpz_and(*RETVAL, *m, *n);
565             OUTPUT:
566             RETVAL
567              
568             mpz_t *
569             bxor(m,n, ...)
570             mpz_t * m
571             mpz_t * n
572              
573             CODE:
574 7           RETVAL = malloc (sizeof(mpz_t));
575 7           mpz_init(*RETVAL);
576 7           mpz_xor(*RETVAL, *m, *n);
577             OUTPUT:
578             RETVAL
579              
580             mpz_t *
581             bior(m,n, ...)
582             mpz_t * m
583             mpz_t * n
584              
585             CODE:
586 7           RETVAL = malloc (sizeof(mpz_t));
587 7           mpz_init(*RETVAL);
588 7           mpz_ior(*RETVAL, *m, *n);
589             OUTPUT:
590             RETVAL
591              
592             mpz_t *
593             blshift(m,n,swap)
594             mpz_t * m
595             mpz_t * n
596             bool swap
597              
598             CODE:
599 9 50         SWAP_GMP
600 9           RETVAL = malloc (sizeof(mpz_t));
601 9           mpz_init(*RETVAL);
602 9           mpz_mul_2exp(*RETVAL, *m, mpz_get_ui(*n));
603             OUTPUT:
604             RETVAL
605              
606             mpz_t *
607             brshift(m,n,swap)
608             mpz_t * m
609             mpz_t * n
610             bool swap
611              
612             CODE:
613 13 50         SWAP_GMP
614 13           RETVAL = malloc (sizeof(mpz_t));
615 13           mpz_init(*RETVAL);
616 13           mpz_div_2exp(*RETVAL, *m, mpz_get_ui(*n));
617             OUTPUT:
618             RETVAL
619              
620             mpz_t *
621             bfac(n)
622             long n
623              
624             CODE:
625 14           RETVAL = malloc (sizeof(mpz_t));
626 14           mpz_init(*RETVAL);
627 14           mpz_fac_ui(*RETVAL, n);
628             OUTPUT:
629             RETVAL
630              
631              
632             mpz_t *
633             bnok(n, k)
634             long n
635             long k
636              
637             CODE:
638 2           RETVAL = malloc (sizeof(mpz_t));
639 2           mpz_init(*RETVAL);
640 2           mpz_bin_uiui(*RETVAL, n, k);
641             OUTPUT:
642             RETVAL
643              
644              
645             mpz_t *
646             gmp_copy(m)
647             mpz_t * m
648              
649             CODE:
650 2           RETVAL = malloc (sizeof(mpz_t));
651 2           mpz_init_set(*RETVAL, *m);
652             OUTPUT:
653             RETVAL
654              
655             int
656             gmp_tstbit(m,n)
657             mpz_t * m
658             long n
659              
660             CODE:
661 10           RETVAL = mpz_tstbit(*m,n);
662             OUTPUT:
663             RETVAL
664              
665             mpz_t *
666             broot(m,n)
667             mpz_t * m
668             unsigned long n
669              
670             CODE:
671 10           RETVAL = malloc (sizeof(mpz_t));
672 10           mpz_init(*RETVAL);
673 10           mpz_root(*RETVAL, *m, n);
674             OUTPUT:
675             RETVAL
676              
677             void
678             brootrem(m,n)
679             mpz_t * m
680             unsigned long n
681              
682             PREINIT:
683             mpz_t * root;
684             mpz_t * remainder;
685             PPCODE:
686 6           root = malloc (sizeof(mpz_t));
687 6           remainder = malloc (sizeof(mpz_t));
688 6           mpz_init(*root);
689 6           mpz_init(*remainder);
690 6 50         if (need_rootrem_workaround(m, n)) {
691             /* Older libgmp have bugs for negative m, but if we need to we can
692             * work on abs(m) then negate the results.
693             */
694 0           mpz_neg(*root, *m);
695 0           mpz_rootrem(*root, *remainder, *root, n);
696 0           mpz_neg(*root, *root);
697 0           mpz_neg(*remainder, *remainder);
698             } else {
699 6           mpz_rootrem(*root, *remainder, *m, n);
700             }
701 6 50         EXTEND(SP, 2);
702 6           PUSHs(sv_setref_pv(sv_newmortal(), "Math::GMP", (void*)root));
703 6           PUSHs(sv_setref_pv(sv_newmortal(), "Math::GMP", (void*)remainder));
704              
705             mpz_t *
706             bsqrt(m)
707             mpz_t * m
708              
709             CODE:
710 13           RETVAL = malloc (sizeof(mpz_t));
711 13           mpz_init(*RETVAL);
712 13           mpz_sqrt(*RETVAL, *m);
713             OUTPUT:
714             RETVAL
715              
716             void
717             bsqrtrem(m)
718             mpz_t * m
719              
720             PREINIT:
721             mpz_t * sqrt;
722             mpz_t * remainder;
723             PPCODE:
724 10           sqrt = malloc (sizeof(mpz_t));
725 10           remainder = malloc (sizeof(mpz_t));
726 10           mpz_init(*sqrt);
727 10           mpz_init(*remainder);
728 10           mpz_sqrtrem(*sqrt, *remainder, *m);
729 10 50         EXTEND(SP, 2);
730 10           PUSHs(sv_setref_pv(sv_newmortal(), "Math::GMP", (void*)sqrt));
731 10           PUSHs(sv_setref_pv(sv_newmortal(), "Math::GMP", (void*)remainder));
732              
733             int
734             is_perfect_power(m)
735             mpz_t * m
736              
737             CODE:
738 12           RETVAL = mpz_perfect_power_p(*m) ? 1 : 0;
739             OUTPUT:
740             RETVAL
741              
742             int
743             is_perfect_square(m)
744             mpz_t * m
745              
746             CODE:
747 12           RETVAL = mpz_perfect_square_p(*m) ? 1 : 0;
748             OUTPUT:
749             RETVAL
750