File Coverage

XS.xs
Criterion Covered Total %
statement 1595 1842 86.5
branch 1788 3018 59.2
condition n/a
subroutine n/a
pod n/a
total 3383 4860 69.6


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT 1 /* Define at top for more efficiency. */
2              
3             #include "EXTERN.h"
4             #include "perl.h"
5             #include "XSUB.h"
6             #include "multicall.h" /* only works in 5.6 and newer */
7             #include /* For fileno and stdout */
8              
9             #define NEED_newCONSTSUB
10             #define NEED_newRV_noinc
11             #define NEED_sv_2pv_flags
12             #define NEED_HvNAME_get
13             #include "ppport.h"
14              
15             #define FUNC_gcd_ui 1
16             #define FUNC_isqrt 1
17             #define FUNC_ipow 1
18             #define FUNC_popcnt 1
19             #include "ptypes.h"
20             #include "cache.h"
21             #include "sieve.h"
22             #include "sieve_cluster.h"
23             #include "util.h"
24             #include "primality.h"
25             #include "factor.h"
26             #include "lehmer.h"
27             #include "lmo.h"
28             #include "aks.h"
29             #include "constants.h"
30             #include "mulmod.h"
31             #include "entropy.h"
32             #include "csprng.h"
33             #include "random_prime.h"
34             #include "ramanujan_primes.h"
35             #include "semi_primes.h"
36             #include "prime_nth_count.h"
37              
38             #ifdef FACTORING_HARNESSES
39             #include
40             static double my_difftime (struct timeval * start, struct timeval * end) {
41             double secs, usecs;
42             if (start->tv_sec == end->tv_sec) {
43             secs = 0;
44             usecs = end->tv_usec - start->tv_usec;
45             } else {
46             usecs = 1000000 - start->tv_usec;
47             secs = end->tv_sec - (start->tv_sec + 1);
48             usecs += end->tv_usec;
49             if (usecs >= 1000000) {
50             usecs -= 1000000;
51             secs += 1;
52             }
53             }
54             return secs + usecs / 1000000.;
55             }
56             #endif
57              
58             #if BITS_PER_WORD == 64
59             #if defined(_MSC_VER)
60             #include
61             #define strtoull _strtoui64
62             #define strtoll _strtoi64
63             #endif
64             #define PSTRTOULL(str, end, base) strtoull (str, end, base)
65             #define PSTRTOLL(str, end, base) strtoll (str, end, base)
66             #else
67             #define PSTRTOULL(str, end, base) strtoul (str, end, base)
68             #define PSTRTOLL(str, end, base) strtol (str, end, base)
69             #endif
70             #if defined(_MSC_VER) && !defined(strtold)
71             #define strtold strtod
72             #endif
73              
74             #if PERL_REVISION <= 5 && PERL_VERSION <= 6 && BITS_PER_WORD == 64
75             /* Workaround perl 5.6 UVs and bigints */
76             #define my_svuv(sv) PSTRTOULL(SvPV_nolen(sv), NULL, 10)
77             #define my_sviv(sv) PSTRTOLL(SvPV_nolen(sv), NULL, 10)
78             #elif PERL_REVISION <= 5 && PERL_VERSION < 14 && BITS_PER_WORD == 64
79             /* Workaround RT 49569 in Math::BigInt::FastCalc (pre 5.14.0) */
80             /* TODO: Math::BigInt::Pari has the same problem with negs pre-5.18.0 */
81             #define my_svuv(sv) ( (!SvROK(sv)) ? SvUV(sv) : PSTRTOULL(SvPV_nolen(sv),NULL,10) )
82             #define my_sviv(sv) ( (!SvROK(sv)) ? SvIV(sv) : PSTRTOLL(SvPV_nolen(sv),NULL,10) )
83             #else
84             #define my_svuv(sv) SvUV(sv)
85             #define my_sviv(sv) SvIV(sv)
86             #endif
87              
88             #if PERL_REVISION >=5 && PERL_VERSION >= 9 && PERL_SUBVERSION >= 4
89             #define SVf_MAGTEST SVf_ROK
90             #else
91             #define SVf_MAGTEST SVf_AMAGIC
92             #endif
93              
94             #define SVNUMTEST(n) \
95             ((SvFLAGS(n) & (SVf_IOK | SVf_MAGTEST | SVs_GMG )) == SVf_IOK)
96              
97             /* multicall compatibility stuff */
98             #if (PERL_REVISION <= 5 && PERL_VERSION < 7) || !defined(dMULTICALL)
99             # define USE_MULTICALL 0 /* Too much trouble to work around it */
100             #else
101             # define USE_MULTICALL 1
102             #endif
103             #if PERL_VERSION < 13 || (PERL_VERSION == 13 && PERL_SUBVERSION < 9)
104             # define FIX_MULTICALL_REFCOUNT \
105             if (CvDEPTH(multicall_cv) > 1) SvREFCNT_inc(multicall_cv);
106             #else
107             # define FIX_MULTICALL_REFCOUNT
108             #endif
109              
110             #ifndef CvISXSUB
111             # define CvISXSUB(cv) CvXSUB(cv)
112             #endif
113              
114             /* Not right, but close */
115             #if !defined cxinc && ( (PERL_VERSION == 8 && PERL_SUBVERSION >= 1) || (PERL_VERSION == 10 && PERL_SUBVERSION <= 1) )
116             # define cxinc() Perl_cxinc(aTHX)
117             #endif
118              
119             #if PERL_VERSION < 17 || (PERL_VERSION == 17 && PERL_SUBVERSION < 7)
120             # define SvREFCNT_dec_NN(sv) SvREFCNT_dec(sv)
121             #endif
122              
123             #if BITS_PER_WORD == 32
124             static const unsigned int uvmax_maxlen = 10;
125             static const unsigned int ivmax_maxlen = 10;
126             static const char uvmax_str[] = "4294967295";
127             static const char ivmax_str[] = "2147483648";
128             #else
129             static const unsigned int uvmax_maxlen = 20;
130             static const unsigned int ivmax_maxlen = 19;
131             static const char uvmax_str[] = "18446744073709551615";
132             static const char ivmax_str[] = "9223372036854775808";
133             #endif
134              
135             #define MY_CXT_KEY "Math::Prime::Util::API_guts"
136             #define CINTS 100
137             typedef struct {
138             HV* MPUroot;
139             HV* MPUGMP;
140             HV* MPUPP;
141             SV* const_int[CINTS+1]; /* -1, 0, 1, ..., 99 */
142             void* randcxt; /* per-thread csprng context */
143             uint16_t forcount;
144             char forexit;
145             } my_cxt_t;
146              
147             START_MY_CXT
148              
149 41184           static int _is_sv_bigint(pTHX_ SV* n)
150             {
151 41184 100         if (sv_isobject(n)) {
152 41171 50         const char *hvname = HvNAME_get(SvSTASH(SvRV(n)));
    50          
    50          
    0          
    50          
    50          
153 41171 50         if (hvname != 0) {
154 41171 100         if (strEQ(hvname, "Math::BigInt") || strEQ(hvname, "Math::BigFloat") ||
    50          
    0          
155 0 0         strEQ(hvname, "Math::GMPz") || strEQ(hvname, "Math::GMP") ||
    0          
156 0 0         strEQ(hvname, "Math::GMPq") || strEQ(hvname, "Math::AnyNum") ||
    0          
157 0 0         strEQ(hvname, "Math::Pari") || strEQ(hvname, "Math::BigInt::Lite"))
158 41171           return 1;
159             }
160             }
161 13           return 0;
162             }
163              
164             /* Is this a pedantically valid integer?
165             * Croaks if undefined or invalid.
166             * Returns 0 if it is an object or a string too large for a UV.
167             * Returns 1 if it is good to process by XS.
168             */
169 1069779           static int _validate_int(pTHX_ SV* n, int negok)
170             {
171             const char* maxstr;
172             char* ptr;
173             STRLEN i, len, maxlen;
174 1069779           int ret, isbignum = 0, isneg = 0;
175              
176             /* TODO: magic, grok_number, etc. */
177 1069779 100         if (SVNUMTEST(n)) { /* If defined as number, use it */
178 1020871 100         if (SvIsUV(n) || SvIVX(n) >= 0) return 1; /* The normal case */
    100          
179 26806 100         if (negok) return -1;
180 11           else croak("Parameter '%" SVf "' must be a positive integer", n);
181             }
182 48908 100         if (sv_isobject(n)) {
183 41171           isbignum = _is_sv_bigint(aTHX_ n);
184 41171 50         if (!isbignum) return 0;
185             }
186             /* Without being very careful, don't process magic variables here */
187 48908 100         if (SvGAMAGIC(n) && !isbignum) return 0;
    100          
    50          
    50          
    100          
188 48907 100         if (!SvOK(n)) croak("Parameter must be defined");
    50          
    50          
189 48887 100         ptr = SvPV_nomg(n, len); /* Includes stringifying bigints */
190 48887 100         if (len == 0 || ptr == 0) croak("Parameter must be a positive integer");
    50          
191 48886 100         if (ptr[0] == '-' && negok) {
    100          
192 1449           isneg = 1; ptr++; len--; /* Read negative sign */
193 47437 100         } else if (ptr[0] == '+') {
194 5           ptr++; len--; /* Allow a single plus sign */
195             }
196 48886 100         if (len == 0 || !isDIGIT(ptr[0]))
    100          
197 25           croak("Parameter '%" SVf "' must be a positive integer", n);
198 49100 100         while (len > 0 && *ptr == '0') /* Strip all leading zeros */
    100          
199 239           { ptr++; len--; }
200 48861 100         if (len > uvmax_maxlen) /* Huge number, don't even look at it */
201 36855           return 0;
202 86270 100         for (i = 0; i < len; i++) /* Ensure all characters are digits */
203 74275 100         if (!isDIGIT(ptr[i]))
204 11           croak("Parameter '%" SVf "' must be a positive integer", n);
205 11995 100         if (isneg == 1) /* Negative number (ignore overflow) */
206 1027           return -1;
207 10968 50         ret = isneg ? -1 : 1;
208 10968 50         maxlen = isneg ? ivmax_maxlen : uvmax_maxlen;
209 10968 50         maxstr = isneg ? ivmax_str : uvmax_str;
210 10968 100         if (len < maxlen) /* Valid small integer */
211 10644           return ret;
212 1134 100         for (i = 0; i < maxlen; i++) { /* Check if in range */
213 1129 100         if (ptr[i] < maxstr[i]) return ret;
214 1046 100         if (ptr[i] > maxstr[i]) return 0;
215             }
216 1069711           return ret; /* value = UV_MAX/UV_MIN. That's ok */
217             }
218              
219             #define VCALL_ROOT 0x0
220             #define VCALL_PP 0x1
221             #define VCALL_GMP 0x2
222             /* Call a Perl sub to handle work for us. */
223 38571           static int _vcallsubn(pTHX_ I32 flags, I32 stashflags, const char* name, int nargs, int minversion)
224             {
225 38571           GV* gv = NULL;
226             dMY_CXT;
227 38571           Size_t namelen = strlen(name);
228             /* If given a GMP function, and GMP enabled, and function exists, use it. */
229 38571 100         int use_gmp = stashflags & VCALL_GMP && _XS_get_callgmp() && _XS_get_callgmp() >= minversion;
    50          
    0          
230             assert(!(stashflags & ~(VCALL_PP|VCALL_GMP)));
231 38571 50         if (use_gmp && hv_exists(MY_CXT.MPUGMP,name,namelen)) {
    0          
232 0           GV ** gvp = (GV**)hv_fetch(MY_CXT.MPUGMP,name,namelen,0);
233 0 0         if (gvp) gv = *gvp;
234             }
235 38571 50         if (!gv && (stashflags & VCALL_PP))
    100          
236 31070           perl_require_pv("Math/Prime/Util/PP.pm");
237 38571 50         if (!gv) {
238 38571 100         GV ** gvp = (GV**)hv_fetch(stashflags & VCALL_PP? MY_CXT.MPUPP : MY_CXT.MPUroot, name,namelen,0);
239 38571 50         if (gvp) gv = *gvp;
240             }
241             /* use PL_stack_sp in PUSHMARK macro directly it will be read after
242             the possible mark stack extend */
243 38571 50         PUSHMARK(PL_stack_sp-nargs);
244             /* no PUTBACK bc we didn't move global SP */
245 38571           return call_sv((SV*)gv, flags);
246             }
247             #define _vcallsub(func) (void)_vcallsubn(aTHX_ G_SCALAR, VCALL_ROOT, func, items,0)
248             #define _vcallsub_with_gmp(ver,func) (void)_vcallsubn(aTHX_ G_SCALAR, VCALL_GMP|VCALL_PP, func, items,(int)(100*(ver)))
249             #define _vcallsub_with_pp(func) (void)_vcallsubn(aTHX_ G_SCALAR, VCALL_PP, func, items,0)
250             #define _vcallsub_with_gmpobj(ver,func) (void)_vcallsubn(aTHX_ G_SCALAR, (PERL_REVISION >= 5 && PERL_VERSION > 8) ? VCALL_GMP|VCALL_PP : VCALL_PP, func, items,(int)(100*(ver)))
251              
252             #if 0
253             static int _vcallgmpsubn(pTHX_ I32 flags, const char* name, int nargs, int minversion)
254             {
255             Size_t namelen = strlen(name);
256             int gmpver = _XS_get_callgmp();
257             dMY_CXT;
258             if (gmpver && gmpver >= minversion && hv_exists(MY_CXT.MPUGMP,name,namelen)) {
259             GV ** gvp = (GV**)hv_fetch(MY_CXT.MPUGMP,name,namelen,0);
260             if (gvp) {
261             GV* gv = *gvp;
262             PUSHMARK(PL_stack_sp-nargs);
263             return call_sv((SV*)gv, flags);
264             }
265             }
266             return 0;
267             }
268             #endif
269              
270             /* In my testing, this constant return works fine with threads, but to be
271             * correct (see perlxs) one has to make a context, store separate copies in
272             * each one, then retrieve them from a struct using a hash index. This
273             * defeats the purpose if only done once. */
274             #define RETURN_NPARITY(ret) \
275             do { int r_ = ret; \
276             dMY_CXT; \
277             if (r_ >= -1 && r_
278             else { XSRETURN_IV(r_); } \
279             } while (0)
280             #define PUSH_NPARITY(ret) \
281             do { int r_ = ret; \
282             if (r_ >= -1 && r_
283             else { PUSHs(sv_2mortal(newSViv(r_))); } \
284             } while (0)
285              
286             #define OBJECTIFY_RESULT(input, output) \
287             if (!sv_isobject(output) && PERL_REVISION >= 5 && PERL_VERSION > 8) { \
288             SV* resptr = output; \
289             const char *iname = (input && sv_isobject(input)) \
290             ? HvNAME_get(SvSTASH(SvRV(input))) : 0; \
291             if (iname == 0 || strEQ(iname, "Math::BigInt")) { \
292             (void)_vcallsubn(aTHX_ G_SCALAR, VCALL_ROOT, "_to_bigint", 1, 0); \
293             } else if (iname == 0 || strEQ(iname, "Math::GMPz")) { \
294             (void)_vcallsubn(aTHX_ G_SCALAR, VCALL_ROOT, "_to_gmpz", 1, 0); \
295             } else if (iname == 0 || strEQ(iname, "Math::GMP")) { \
296             (void)_vcallsubn(aTHX_ G_SCALAR, VCALL_ROOT, "_to_gmp", 1, 0); \
297             } else { /* Return it as: ref(input)->new(result) */ \
298             dSP; (void)POPs; ENTER; PUSHMARK(SP); \
299             XPUSHs(sv_2mortal(newSVpv(iname, 0))); XPUSHs(resptr); \
300             PUTBACK; call_method("new", G_SCALAR); LEAVE; \
301             } \
302             }
303              
304 1           static SV* sv_to_bigint(pTHX_ SV* r) {
305 1 50         dSP; ENTER; PUSHMARK(SP);
306 1 50         XPUSHs(r);
307 1           PUTBACK;
308 1           call_pv("Math::Prime::Util::_to_bigint", G_SCALAR);
309 1           SPAGAIN;
310 1           r = POPs;
311 1           PUTBACK; LEAVE;
312 1           return r;
313             }
314              
315             #define RETURN_128(hi,lo) \
316             do { char str[40]; \
317             int slen = to_string_128(str, hi, lo); \
318             XPUSHs( sv_to_bigint( aTHX_ sv_2mortal(newSVpv(str,slen)) ) ); \
319             XSRETURN(1); } while(0)
320              
321 13           static int arrayref_to_int_array(pTHX_ UV** ret, AV* av, int base)
322             {
323             int len, i;
324 13           UV *r, carry = 0;
325 13 50         if (SvTYPE((SV*)av) != SVt_PVAV)
326 0           croak("fromdigits first argument must be a string or array reference");
327 13           len = 1 + av_len(av);
328 13 50         New(0, r, len, UV);
329 76 100         for (i = len-1; i >= 0; i--) {
330 63           SV** psvd = av_fetch(av, i, 0);
331 63 50         if (_validate_int(aTHX_ *psvd, 1) != 1) break;
332 63 50         r[i] = my_svuv(*psvd) + carry;
333 63 100         if (r[i] >= (UV)base && i > 0) {
    100          
334 11           carry = r[i] / base;
335 11           r[i] -= carry * base;
336             } else {
337 52           carry = 0;
338             }
339             }
340 13 50         if (i >= 0) {
341 0           Safefree(r);
342 0           return -1;
343             }
344             /* printf("array is ["); for(i=0;i
345 13           *ret = r;
346 13           return len;
347             }
348              
349 122           static UV negmod(IV a, UV n) {
350 122           UV negamod = ((UV)(-a)) % n;
351 122 50         return (negamod == 0) ? 0 : n-negamod;
352             }
353              
354 72           static void csprng_init_seed(void* ctx) {
355             unsigned char* data;
356 72           New(0, data, 64, unsigned char);
357 72           get_entropy_bytes(64, data);
358 72           csprng_seed(ctx, 64, data);
359 72           Safefree(data);
360 72           }
361              
362 27           static void _comb_init(UV* cm, UV k, int derangement) {
363             UV i;
364 27           cm[0] = UV_MAX;
365 107 100         for (i = 0; i < k; i++)
366 80           cm[i] = k-i;
367 27 100         if (derangement && k >= 2) { /* Make derangements start deranged */
    100          
368 23 100         for (i = 0; i < k; i++)
369 19 100         cm[k-i-1] = (i&1) ? i : i+2;
370 4 100         if (k & 1) {
371 3           cm[0] = k-2;
372 3           cm[1] = k;
373             }
374             }
375 27           }
376              
377 22484           static int _comb_iterate(UV* cm, UV k, UV n, int ix) {
378             UV i, j, m;
379 22484 100         if (ix == 0) {
380 15534 100         if (cm[0]++ < n) return 0; /* Increment last value */
381 38790 100         for (i = 1; i < k && cm[i] >= n-i; i++) ; /* Find next index to incr */
    100          
382 11647 100         if (i >= k) return 1; /* Done! */
383 11634           cm[i]++; /* Increment this one */
384 50387 100         while (i-- > 0) cm[i] = cm[i+1] + 1; /* Set the rest */
385 6950 100         } else if (ix == 1) {
386 8736 100         for (j = 1; j < k && cm[j] > cm[j-1]; j++) ; /* Find last decrease */
    100          
387 5086 100         if (j >= k) return 1; /* Done! */
388 6898 100         for (m = 0; cm[j] > cm[m]; m++) ; /* Find next greater */
389 5080           { UV t = cm[j]; cm[j] = cm[m]; cm[m] = t; } /* Swap */
390 7833 100         for (i = j-1, m = 0; m < i; i--, m++) /* Reverse the end */
391 2753           { UV t = cm[i]; cm[i] = cm[m]; cm[m] = t; }
392             } else {
393             REDERANGE:
394 5005 100         for (j = 1; j < k && cm[j] > cm[j-1]; j++) ; /* Find last decrease */
    100          
395 2737 100         if (j >= k) return 1; /* Done! */
396 3866 100         for (m = 0; cm[j] > cm[m]; m++) ; /* Find next greater */
397 2732           { UV t = cm[j]; cm[j] = cm[m]; cm[m] = t; } /* Swap */
398 2732 100         if (cm[j] == k-j) goto REDERANGE; /* Skip? */
399 3567 100         for (i = j-1, m = 0; m < i; i--, m++) /* Reverse the end */
400 1371           { UV t = cm[i]; cm[i] = cm[m]; cm[m] = t; }
401 17120 100         for (i = 0; i < k; i++) /* Check deranged */
402 15261 100         if (cm[k-i-1]-1 == i)
403 337           break;
404 2196 100         if (i != k) goto REDERANGE;
405             }
406 18573           return 0;
407             }
408              
409              
410              
411             MODULE = Math::Prime::Util PACKAGE = Math::Prime::Util
412              
413             PROTOTYPES: ENABLE
414              
415             BOOT:
416             {
417             int i;
418 72           SV * sv = newSViv(BITS_PER_WORD);
419 72           HV * stash = gv_stashpv("Math::Prime::Util", TRUE);
420 72           newCONSTSUB(stash, "_XS_prime_maxbits", sv);
421              
422             {
423             MY_CXT_INIT;
424 72           MY_CXT.MPUroot = stash;
425 72           MY_CXT.MPUGMP = gv_stashpv("Math::Prime::Util::GMP", TRUE);
426 72           MY_CXT.MPUPP = gv_stashpv("Math::Prime::Util::PP", TRUE);
427 7344 100         for (i = 0; i <= CINTS; i++) {
428 7272           MY_CXT.const_int[i] = newSViv(i-1);
429 7272           SvREADONLY_on(MY_CXT.const_int[i]);
430             }
431 72           New(0, MY_CXT.randcxt, csprng_context_size(), char);
432 72           csprng_init_seed(MY_CXT.randcxt);
433 72           MY_CXT.forcount = 0;
434 72           MY_CXT.forexit = 0;
435             }
436             }
437              
438             #if defined(USE_ITHREADS) && defined(MY_CXT_KEY)
439              
440             void
441             CLONE(...)
442             PREINIT:
443             int i;
444             PPCODE:
445             {
446             MY_CXT_CLONE; /* possible declaration */
447             MY_CXT.MPUroot = gv_stashpv("Math::Prime::Util", TRUE);
448             MY_CXT.MPUGMP = gv_stashpv("Math::Prime::Util::GMP", TRUE);
449             MY_CXT.MPUPP = gv_stashpv("Math::Prime::Util::PP", TRUE);
450             /* These should be shared between threads, but that's dodgy. */
451             for (i = 0; i <= CINTS; i++) {
452             MY_CXT.const_int[i] = newSViv(i-1);
453             SvREADONLY_on(MY_CXT.const_int[i]);
454             }
455             /* Make a new CSPRNG context for this thread */
456             New(0, MY_CXT.randcxt, csprng_context_size(), char);
457             csprng_init_seed(MY_CXT.randcxt);
458             /* NOTE: There is no thread destroy, so these never get freed... */
459             MY_CXT.forcount = 0;
460             MY_CXT.forexit = 0;
461             }
462             return; /* skip implicit PUTBACK, returning @_ to caller, more efficient*/
463              
464             #endif
465              
466             void
467             END(...)
468             PREINIT:
469             dMY_CXT;
470             int i;
471             PPCODE:
472 72           _prime_memfreeall();
473 72           MY_CXT.MPUroot = NULL;
474 72           MY_CXT.MPUGMP = NULL;
475 72           MY_CXT.MPUPP = NULL;
476 7344 100         for (i = 0; i <= CINTS; i++) {
477 7272           SV * const sv = MY_CXT.const_int[i];
478 7272           MY_CXT.const_int[i] = NULL;
479 7272           SvREFCNT_dec_NN(sv);
480             } /* stashes are owned by stash tree, no refcount on them in MY_CXT */
481 72           Safefree(MY_CXT.randcxt); MY_CXT.randcxt = 0;
482 72           return; /* skip implicit PUTBACK, returning @_ to caller, more efficient*/
483              
484              
485             void csrand(IN SV* seed = 0)
486             PREINIT:
487             unsigned char* data;
488             STRLEN size;
489             dMY_CXT;
490             PPCODE:
491 6 50         if (items == 0) {
492 0           csprng_init_seed(MY_CXT.randcxt);
493 6 50         } else if (_XS_get_secure()) {
494 0           croak("secure option set, manual seeding disabled");
495             } else {
496 6 50         data = (unsigned char*) SvPV(seed, size);
497 6           csprng_seed(MY_CXT.randcxt, size, data);
498             }
499 6 50         if (_XS_get_callgmp() >= 42) _vcallsub("_csrand_p");
500 6           return;
501              
502             UV srand(IN UV seedval = 0)
503             PREINIT:
504             dMY_CXT;
505             CODE:
506 5 50         if (_XS_get_secure())
507 0           croak("secure option set, manual seeding disabled");
508 5 100         if (items == 0)
509 1           get_entropy_bytes(sizeof(UV), (unsigned char*) &seedval);
510 5           csprng_srand(MY_CXT.randcxt, seedval);
511 5 50         if (_XS_get_callgmp() >= 42) _vcallsub("_srand_p");
512 5           RETVAL = seedval;
513             OUTPUT:
514             RETVAL
515              
516             UV irand()
517             ALIAS:
518             irand64 = 1
519             PREINIT:
520             dMY_CXT;
521             CODE:
522 100012 100         if (ix == 0)
523 100005           RETVAL = irand32(MY_CXT.randcxt);
524             else
525             #if BITS_PER_WORD >= 64
526 7           RETVAL = irand64(MY_CXT.randcxt);
527             #else /* TODO: should irand64 on 32-bit perl (1) croak, (2) return 32-bits */
528             RETVAL = irand32(MY_CXT.randcxt);
529             #endif
530             OUTPUT:
531             RETVAL
532              
533             NV drand(NV m = 0.0)
534             ALIAS:
535             rand = 1
536             PREINIT:
537             dMY_CXT;
538             CODE:
539             PERL_UNUSED_VAR(ix);
540 6037           RETVAL = drand64(MY_CXT.randcxt);
541 6037 100         if (m != 0) RETVAL *= m;
542             OUTPUT:
543             RETVAL
544              
545             SV* random_bytes(IN UV n)
546             PREINIT:
547             char* sptr;
548             dMY_CXT;
549             CODE:
550 56 100         RETVAL = newSV(n == 0 ? 1 : n);
551 56           SvPOK_only(RETVAL);
552 56           SvCUR_set(RETVAL, n);
553 56           sptr = SvPVX(RETVAL);
554 56           csprng_rand_bytes(MY_CXT.randcxt, n, (unsigned char*)sptr);
555 56           sptr[n] = '\0';
556             OUTPUT:
557             RETVAL
558              
559             SV* entropy_bytes(IN UV n)
560             PREINIT:
561             char* sptr;
562             CODE:
563 2 50         RETVAL = newSV(n == 0 ? 1 : n);
564 2           SvPOK_only(RETVAL);
565 2           SvCUR_set(RETVAL, n);
566 2           sptr = SvPVX(RETVAL);
567 2           get_entropy_bytes(n, (unsigned char*)sptr);
568 2           sptr[n] = '\0';
569             OUTPUT:
570             RETVAL
571              
572             UV _is_csprng_well_seeded()
573             ALIAS:
574             _XS_get_verbose = 1
575             _XS_get_callgmp = 2
576             _XS_get_secure = 3
577             _XS_set_secure = 4
578             _get_forexit = 5
579             _start_for_loop = 6
580             _get_prime_cache_size = 7
581             CODE:
582 2457           switch (ix) {
583 1           case 0: { dMY_CXT; RETVAL = is_csprng_well_seeded(MY_CXT.randcxt); } break;
584 0           case 1: RETVAL = _XS_get_verbose(); break;
585 0           case 2: RETVAL = _XS_get_callgmp(); break;
586 0           case 3: RETVAL = _XS_get_secure(); break;
587 0           case 4: _XS_set_secure(); RETVAL = 1; break;
588 177           case 5: { dMY_CXT; RETVAL = MY_CXT.forexit; } break;
589 12           case 6: { dMY_CXT; MY_CXT.forcount++; RETVAL = MY_CXT.forexit; MY_CXT.forexit = 0; } break;
590             case 7:
591 2267           default: RETVAL = get_prime_cache(0,0); break;
592             }
593             OUTPUT:
594             RETVAL
595              
596             void prime_memfree()
597             PREINIT:
598             dMY_CXT;
599             PPCODE:
600 10           prime_memfree();
601             /* (void) _vcallgmpsubn(aTHX_ G_VOID|G_DISCARD, "_GMP_memfree", 0, 49); */
602 10 50         if (MY_CXT.MPUPP != NULL) _vcallsub_with_pp("prime_memfree");
603 10           return;
604              
605             void
606             prime_precalc(IN UV n)
607             ALIAS:
608             _XS_set_verbose = 1
609             _XS_set_callgmp = 2
610             _end_for_loop = 3
611             PPCODE:
612 172           PUTBACK; /* SP is never used again, the 3 next func calls are tailcall
613             friendly since this XSUB has nothing to do after the 3 calls return */
614 172           switch (ix) {
615 79           case 0: prime_precalc(n); break;
616 8           case 1: _XS_set_verbose(n); break;
617 73           case 2: _XS_set_callgmp(n); break;
618             case 3:
619 12           default: { dMY_CXT; MY_CXT.forcount--; MY_CXT.forexit = n; } break;
620             }
621 172           return; /* skip implicit PUTBACK */
622              
623             void
624             prime_count(IN SV* svlo, ...)
625             ALIAS:
626             semiprime_count = 1
627             twin_prime_count = 2
628             ramanujan_prime_count = 3
629             ramanujan_prime_count_approx = 4
630             sum_primes = 5
631             print_primes = 6
632             PREINIT:
633             int lostatus, histatus;
634             UV lo, hi;
635             PPCODE:
636 1194           lostatus = _validate_int(aTHX_ svlo, 0);
637 1194 100         histatus = (items == 1 || _validate_int(aTHX_ ST(1), 0));
    100          
638 1194 100         if (lostatus == 1 && histatus == 1) {
    50          
639 1193           UV count = 0;
640 1193 100         if (items == 1) {
641 1161           lo = 2;
642 1161 50         hi = my_svuv(svlo);
643             } else {
644 32 50         lo = my_svuv(svlo);
645 32 50         hi = my_svuv(ST(1));
646             }
647 1193 100         if (lo <= hi) {
648 1183 100         if (ix == 0) { count = prime_count(lo, hi); }
649 1042 100         else if (ix == 1) { count = semiprime_count(lo, hi); }
650 1026 100         else if (ix == 2) { count = twin_prime_count(lo, hi); }
651 1015 100         else if (ix == 3) { count = ramanujan_prime_count(lo, hi); }
652 1005 100         else if (ix == 4) { count = ramanujan_prime_count_approx(hi);
653 2 50         if (lo > 2)
654 2           count -= ramanujan_prime_count_approx(lo-1); }
655 1003 50         else if (ix == 5) {
656             #if BITS_PER_WORD == 64 && HAVE_UINT128
657 1003 50         if (hi >= 29505444491UL && hi-lo > hi/50) {
    0          
658             UV hicount, lo_hic, lo_loc;
659 0           lostatus = sum_primes128(hi, &hicount, &count);
660 0 0         if (lostatus == 1 && lo > 2) {
    0          
661 0           lostatus = sum_primes128(lo-1, &lo_hic, &lo_loc);
662 0           hicount -= lo_hic;
663 0 0         if (count < lo_loc) hicount--;
664 0           count -= lo_loc;
665             }
666 0 0         if (lostatus == 1 && hicount > 0)
    0          
667 0 0         RETURN_128(hicount, count);
668             }
669             #endif
670 1003           lostatus = sum_primes(lo, hi, &count);
671 0 0         } else if (ix == 6) {
672 0 0         int fd = (items < 3) ? fileno(stdout) : my_sviv(ST(2));
    0          
673 0           print_primes(lo, hi, fd);
674 0           XSRETURN_EMPTY;
675             }
676             }
677 1193 50         if (lostatus == 1) XSRETURN_UV(count);
678             }
679 1           switch (ix) {
680 1 50         case 0: _vcallsubn(aTHX_ GIMME_V, VCALL_ROOT, "_generic_prime_count", items, 0); break;
681 0           case 1: _vcallsub_with_pp("semiprime_count"); break;
682 0           case 2: _vcallsub_with_pp("twin_prime_count"); break;
683 0           case 3: _vcallsub_with_pp("ramanujan_prime_count"); break;
684 0           case 4: _vcallsub_with_pp("ramanujan_prime_count_approx"); break;
685 0           case 5: _vcallsub_with_pp("sum_primes"); break;
686             case 6:
687 0           default:_vcallsub_with_pp("print_primes"); break;
688             }
689 1           return; /* skip implicit PUTBACK */
690              
691             void random_prime(IN SV* svlo, IN SV* svhi = 0)
692             PREINIT:
693             int lostatus, histatus;
694             UV lo, hi, ret;
695             dMY_CXT;
696             PPCODE:
697 22031           lostatus = _validate_int(aTHX_ svlo, 0);
698 22024 100         histatus = (items == 1 || _validate_int(aTHX_ svhi, 0));
    100          
699 22018 100         if (lostatus == 1 && histatus == 1) {
    50          
700 22017 100         if (items == 1) {
701 12000           lo = 2;
702 12000 50         hi = my_svuv(svlo);
703             } else {
704 10017 50         lo = my_svuv(svlo);
705 10017 50         hi = my_svuv(svhi);
706             }
707 22017           ret = random_prime(MY_CXT.randcxt,lo,hi);
708 22017 100         if (ret) XSRETURN_UV(ret);
709 6           else XSRETURN_UNDEF;
710             }
711 1           _vcallsub_with_gmpobj(0.44,"random_prime");
712 1 50         OBJECTIFY_RESULT(ST(0), ST(0));
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
713 1           XSRETURN(1);
714              
715             UV
716             _LMO_pi(IN UV n)
717             ALIAS:
718             _legendre_pi = 1
719             _meissel_pi = 2
720             _lehmer_pi = 3
721             _LMOS_pi = 4
722             _segment_pi = 5
723             PREINIT:
724             UV ret;
725             CODE:
726 2           switch (ix) {
727 1           case 0: ret = LMO_prime_count(n); break;
728 0           case 1: ret = legendre_prime_count(n); break;
729 0           case 2: ret = meissel_prime_count(n); break;
730 0           case 3: ret = lehmer_prime_count(n); break;
731 0           case 4: ret = LMOS_prime_count(n); break;
732 1           default:ret = segment_prime_count(2,n); break;
733             }
734 2           RETVAL = ret;
735             OUTPUT:
736             RETVAL
737              
738             void
739             sieve_primes(IN UV low, IN UV high)
740             ALIAS:
741             trial_primes = 1
742             erat_primes = 2
743             segment_primes = 3
744             segment_twin_primes = 4
745             semi_prime_sieve = 5
746             _ramanujan_primes = 6
747             _n_ramanujan_primes = 7
748             PREINIT:
749             AV* av;
750             PPCODE:
751 1228           av = newAV();
752             {
753 1228           SV * retsv = sv_2mortal(newRV_noinc( (SV*) av ));
754 1228           PUSHs(retsv);
755 1228           PUTBACK;
756 1228           SP = NULL; /* never use SP again, poison */
757             }
758 1228 100         if (ix == 4) { /* twin primes */
759 17 100         if ((low <= 3) && (high >= 3)) av_push(av, newSVuv( 3 ));
    50          
760 17 100         if ((low <= 5) && (high >= 5)) av_push(av, newSVuv( 5 ));
    50          
761 1211 100         } else if (ix == 5) { /* semiprimes */
762 17 100         if ((low <= 4) && (high >= 4)) av_push(av, newSVuv( 4 ));
    50          
763 17 100         if ((low <= 6) && (high >= 6)) av_push(av, newSVuv( 6 ));
    50          
764 1194 100         } else if (ix == 6) { /* ramanujan primes */
765 15 100         if ((low <= 2) && (high >= 2)) av_push(av, newSVuv( 2 ));
    50          
766             } else {
767 1179 100         if ((low <= 2) && (high >= 2)) av_push(av, newSVuv( 2 ));
    100          
768 1179 100         if ((low <= 3) && (high >= 3)) av_push(av, newSVuv( 3 ));
    100          
769 1179 100         if ((low <= 5) && (high >= 5)) av_push(av, newSVuv( 5 ));
    100          
770             }
771 1228 100         if (low < 7) low = 7;
772 1228 100         if (low <= high) {
773 1185 100         if (ix == 4) high += 2;
774 1185 100         if (ix == 0) { /* Sieve with primary cache */
775 1261678 50         START_DO_FOR_EACH_PRIME(low, high) {
    50          
    0          
    0          
    100          
    100          
    100          
    100          
    50          
    100          
776 1239900           av_push(av,newSVuv(p));
777 1240998           } END_DO_FOR_EACH_PRIME
778 87 100         } else if (ix == 1) { /* Trial */
779 558 100         for (low = next_prime(low-1);
780 547 50         low <= high && low != 0;
781 547           low = next_prime(low) ) {
782 547           av_push(av,newSVuv(low));
783             }
784 76 100         } else if (ix == 2) { /* Erat with private memory */
785 9           unsigned char* sieve = sieve_erat30(high);
786 665 50         START_DO_FOR_EACH_SIEVE_PRIME( sieve, 0, low, high ) {
    100          
    100          
    100          
    100          
787 538           av_push(av,newSVuv(p));
788 26           } END_DO_FOR_EACH_SIEVE_PRIME
789 9           Safefree(sieve);
790 102 100         } else if (ix == 3 || ix == 4) { /* Segment */
    100          
791             unsigned char* segment;
792 35           UV seg_base, seg_low, seg_high, lastp = 0;
793 35           void* ctx = start_segment_primes(low, high, &segment);
794 74 100         while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) {
795 417241 50         START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_base, seg_low, seg_high )
    100          
    100          
    100          
    100          
796 394202 100         if (ix == 3) av_push(av,newSVuv( p ));
797 86052 100         else if (lastp+2 == p) av_push(av,newSVuv( lastp ));
798 394202           lastp = p;
799 22962           END_DO_FOR_EACH_SIEVE_PRIME
800             }
801 35           end_segment_primes(ctx);
802 32 100         } else if (ix == 5) { /* Semiprimes */
803             UV i, count, *semi;
804 17           count = range_semiprime_sieve(&semi, low, high);
805 79 100         for (i = 0; i < count; i++)
806 62           av_push(av, newSVuv(semi[i]));
807 17           Safefree(semi);
808 15 50         } else if (ix == 6) { /* Ramanujan primes */
809             UV i, beg, end, *L;
810 15           L = ramanujan_primes(&beg, &end, low, high);
811 15 50         if (L && end >= beg)
    100          
812 108 100         for (i = beg; i <= end; i++)
813 94           av_push(av,newSVuv(L[i]));
814 15           Safefree(L);
815 0 0         } else if (ix == 7) { /* Ramanujan primes */
816             UV i, *L;
817 0           L = n_range_ramanujan_primes(low, high);
818 0 0         if (L && high >= low)
    0          
819 0 0         for (i = 0; i <= (high-low); i++)
820 0           av_push(av,newSVuv(L[i]));
821 0           Safefree(L);
822             }
823             }
824 1228           return; /* skip implicit PUTBACK */
825              
826             void
827             sieve_range(IN SV* svn, IN UV width, IN UV depth)
828             PREINIT:
829             int status;
830             PPCODE:
831 10           status = _validate_int(aTHX_ svn, 0);
832 10 50         if (status == 1) {
833             /* TODO: actually sieve */
834 10 50         UV factors[MPU_MAX_FACTORS+1], i, n = my_svuv(svn);
835 10 50         if (depth == 0) depth = 1; /* Trial factor takes 0 to means sqrt(n) */
836 10 50         if ( (n + width) < n) { /* Overflow */
837 0           status = 0;
838 10 50         } else if (depth <= 100) { /* trial division for each value */
839 1620 100         for (i = (n<2)?2-n:0; i < width; i++)
    100          
840 1610 100         if (trial_factor(n+i, factors, 2, depth) < 2)
841 316 50         XPUSHs(sv_2mortal(newSVuv( i )));
842             } else { /* small trial + factor for each value */
843 10 0         for (i = (n<2)?2-n:0; i < width; i++)
    0          
844 0 0         if (factor_one(n+i, factors, 1, 1) < 2 || factors[0] > depth)
    0          
845 0 0         XPUSHs(sv_2mortal(newSVuv( i )));
846             }
847             }
848 10 50         if (status != 1) {
849 0 0         _vcallsubn(aTHX_ GIMME_V, VCALL_GMP|VCALL_PP, "sieve_range", items, 36);
850 0           return;
851             }
852              
853             void
854             sieve_prime_cluster(IN SV* svlo, IN SV* svhi, ...)
855             PREINIT:
856             uint32_t nc, cl[100];
857             UV i, cval, nprimes, *list;
858             int lostatus, histatus, done;
859             PPCODE:
860 41           nc = items-1;
861 41 50         if (items > 100) croak("sieve_prime_cluster: too many entries");
862 41           cl[0] = 0;
863 256 100         for (i = 1; i < nc; i++) {
864 215 50         if (!_validate_int(aTHX_ ST(1+i), 0)) croak("sieve_prime_cluster: cluster values must be standard integers");
865 215 50         cval = my_svuv(ST(1+i));
866 215 50         if (cval & 1) croak("sieve_prime_cluster: values must be even");
867 215 50         if (cval > 2147483647UL) croak("sieve_prime_cluster: values must be 31-bit");
868 215 50         if (cval <= cl[i-1]) croak("sieve_prime_cluster: values must be increasing");
869 215           cl[i] = cval;
870             }
871 41           lostatus = _validate_int(aTHX_ svlo, 1);
872 41           histatus = _validate_int(aTHX_ svhi, 1);
873 41           done = 0;
874 41 100         if (lostatus == 1 && histatus == 1) {
    50          
875 32 50         UV low = my_svuv(svlo);
876 32 50         UV high = my_svuv(svhi);
877 32           list = sieve_cluster(low, high, nc, cl, &nprimes);
878 32 50         if (list != 0) {
879 32           done = 1;
880 32 50         EXTEND(SP, (IV)nprimes);
    100          
881 12308 100         for (i = 0; i < nprimes; i++)
882 12276           PUSHs(sv_2mortal(newSVuv( list[i] )));
883 32           Safefree(list);
884             }
885             }
886 41 100         if (!done) {
887 9 50         _vcallsubn(aTHX_ GIMME_V, VCALL_GMP|VCALL_PP, "sieve_prime_cluster", items, 34);
888 9           return;
889             }
890              
891             void
892             trial_factor(IN UV n, ...)
893             ALIAS:
894             fermat_factor = 1
895             holf_factor = 2
896             squfof_factor = 3
897             lehman_factor = 4
898             prho_factor = 5
899             pplus1_factor = 6
900             pbrent_factor = 7
901             pminus1_factor = 8
902             ecm_factor = 9
903             PREINIT:
904             UV arg1, arg2;
905             static const UV default_arg1[] =
906             {0, 64000000, 8000000, 4000000, 0, 4000000, 200, 4000000, 1000000};
907             /* Trial, Fermat, Holf, SQUFOF, Lmn, PRHO, P+1, Brent, P-1 */
908             PPCODE:
909 83 50         if (n == 0) XSRETURN_UV(0);
910 83 50         if (ix == 9) { /* We don't have an ecm_factor, call PP. */
911 0 0         _vcallsubn(aTHX_ GIMME_V, VCALL_PP, "ecm_factor", 1, 0);
912 0           return;
913             }
914             /* Must read arguments before pushing anything */
915 83 100         arg1 = (items >= 2) ? my_svuv(ST(1)) : default_arg1[ix];
    50          
916 83 50         arg2 = (items >= 3) ? my_svuv(ST(2)) : 0;
    0          
917             /* Small factors */
918 131 50         while ( (n% 2) == 0 ) { n /= 2; XPUSHs(sv_2mortal(newSVuv( 2 ))); }
    100          
919 131 50         while ( (n% 3) == 0 ) { n /= 3; XPUSHs(sv_2mortal(newSVuv( 3 ))); }
    100          
920 147 50         while ( (n% 5) == 0 ) { n /= 5; XPUSHs(sv_2mortal(newSVuv( 5 ))); }
    100          
921 83 100         if (n == 1) { /* done */ }
922 43 100         else if (is_prime(n)) { XPUSHs(sv_2mortal(newSVuv( n ))); }
    50          
923             else {
924             UV factors[MPU_MAX_FACTORS+1];
925 19           int i, nfactors = 0;
926 19           switch (ix) {
927 5           case 0: nfactors = trial_factor (n, factors, 2, arg1); break;
928 2           case 1: nfactors = fermat_factor (n, factors, arg1); break;
929 2           case 2: nfactors = holf_factor (n, factors, arg1); break;
930 2           case 3: nfactors = squfof_factor (n, factors, arg1); break;
931 0           case 4: nfactors = lehman_factor (n, factors, arg1); break;
932 2           case 5: nfactors = prho_factor (n, factors, arg1); break;
933 2           case 6: nfactors = pplus1_factor (n, factors, arg1); break;
934 2 50         case 7: if (items < 3) arg2 = 1;
935 2           nfactors = pbrent_factor (n, factors, arg1, arg2); break;
936             case 8:
937 2 50         default: if (items < 3) arg2 = 10*arg1;
938 2           nfactors = pminus1_factor(n, factors, arg1, arg2); break;
939             }
940 19 50         EXTEND(SP, nfactors);
    50          
941 58 100         for (i = 0; i < nfactors; i++)
942 39           PUSHs(sv_2mortal(newSVuv( factors[i] )));
943             }
944              
945             void
946             is_strong_pseudoprime(IN SV* svn, ...)
947             ALIAS:
948             is_pseudoprime = 1
949             is_euler_pseudoprime = 2
950             PREINIT:
951 55133           int c, status = 1;
952             PPCODE:
953 55133 100         if (items < 2)
954 1           croak("No bases given to is_strong_pseudoprime");
955             /* Check all arguments */
956 215147 100         for (c = 0; c < items && status == 1; c++)
    100          
957 160015 100         if (_validate_int(aTHX_ ST(c), 0) != 1)
958 294           status = 0;
959 55132 100         if (status == 1) {
960 54838 50         UV n = my_svuv(svn);
961 54838           int b, ret = 1;
962 54838 100         if (n < 4) { /* 0,1 composite; 2,3 prime */
963 8           ret = (n >= 2);
964 54830 100         } else if (ix == 1) { /* Fermat test */
965 168 100         for (c = 1; c < items && ret == 1; c++)
    50          
966 86 50         ret = is_pseudoprime(n, my_svuv(ST(c)));
967 54748 100         } else if (ix == 2) { /* Euler test */
968 218 100         for (c = 1; c < items && ret == 1; c++)
    50          
969 109 50         ret = is_euler_pseudoprime(n, my_svuv(ST(c)));
970 54639 100         } else if ((n % 2) == 0) { /* evens composite */
971 27032           ret = 0;
972             } else {
973             UV bases[32];
974 55212 100         for (c = 1; c < items && ret == 1; ) {
    50          
975 80237 50         for (b = 0; b < 32 && c < items; c++)
    100          
976 52630 50         bases[b++] = my_svuv(ST(c));
977 27607           ret = miller_rabin(n, bases, b);
978             }
979             }
980 54836 50         RETURN_NPARITY(ret);
    50          
981             }
982 294           switch (ix) {
983 294           case 0: _vcallsub_with_gmp(0.00,"is_strong_pseudoprime"); break;
984 0           case 1: _vcallsub_with_gmp(0.20,"is_pseudoprime"); break;
985             case 2:
986 0           default:_vcallsub_with_gmp(0.00,"is_euler_pseudoprime"); break;
987             }
988 294           return; /* skip implicit PUTBACK */
989              
990             void
991             gcd(...)
992             PROTOTYPE: @
993             ALIAS:
994             lcm = 1
995             vecmin = 2
996             vecmax = 3
997             vecsum = 4
998             vecprod = 5
999             PREINIT:
1000 20561           int i, status = 1;
1001             UV ret, nullv, n;
1002             PPCODE:
1003 20563 100         if (ix == 2 || ix == 3) {
    100          
1004 29           UV retindex = 0;
1005 29           int sign, minmax = (ix == 2);
1006 29 100         if (items == 0) XSRETURN_UNDEF;
1007 27 100         if (items == 1) XSRETURN(1);
1008 21           status = _validate_int(aTHX_ ST(0), 2);
1009 21 100         if (status != 0 && items > 1) {
    50          
1010 19           sign = status;
1011 19 50         ret = my_svuv(ST(0));
1012 98 100         for (i = 1; i < items; i++) {
1013 79           status = _validate_int(aTHX_ ST(i), 2);
1014 79 50         if (status == 0) break;
1015 79 50         n = my_svuv(ST(i));
1016 129 100         if (( (sign == -1 && status == 1) ||
    100          
    100          
    100          
1017 50 100         (n >= ret && sign == status)
1018             ) ? !minmax : minmax ) {
1019 31           sign = status;
1020 31           ret = n;
1021 31           retindex = i;
1022             }
1023             }
1024             }
1025 21 100         if (status != 0) {
1026 19           ST(0) = ST(retindex);
1027 19           XSRETURN(1);
1028             }
1029 20532 100         } else if (ix == 4) {
1030 2739           UV lo = 0;
1031 2739           IV hi = 0;
1032 120832 100         for (ret = i = 0; i < items; i++) {
1033 118616           status = _validate_int(aTHX_ ST(i), 2);
1034 118616 100         if (status == 0) break;
1035 118213 100         n = my_svuv(ST(i));
1036 118213 100         if (status == 1) {
1037 117260           hi += (n > (UV_MAX - lo));
1038             } else {
1039 953 100         if (UV_MAX-n == (UV)IV_MAX) { status = 0; break; } /* IV Overflow */
1040 833           hi -= ((UV_MAX-n) >= lo);
1041             }
1042 118093           lo += n;
1043             }
1044 2739 100         if (status != 0 && hi != 0) {
    100          
1045 5 100         if (hi == -1 && lo > IV_MAX) XSRETURN_IV((IV)lo);
    50          
1046 1 50         else RETURN_128(hi, lo);
1047             }
1048 2734           ret = lo;
1049 17793 100         } else if (ix == 5) {
1050 15822           int sign = 1;
1051 15822           ret = 1;
1052 21575 100         for (i = 0; i < items; i++) {
1053 19785           status = _validate_int(aTHX_ ST(i), 2);
1054 19785 100         if (status == 0) break;
1055 6422 100         n = (status == 1) ? my_svuv(ST(i)) : (UV)-my_sviv(ST(i));
    50          
    50          
1056 6422 100         if (ret > 0 && n > UV_MAX/ret) { status = 0; break; }
    100          
1057 5753           sign *= status;
1058 5753           ret *= n;
1059             }
1060 15822 100         if (sign == -1 && status != 0) {
    50          
1061 5 50         if (ret <= (UV)IV_MAX) XSRETURN_IV(-(IV)ret);
1062 15817           else status = 0;
1063             }
1064             } else {
1065             /* For each arg, while valid input, validate+gcd/lcm. Shortcut stop. */
1066 1971 100         if (ix == 0) { ret = 0; nullv = 1; }
1067 25           else { ret = (items == 0) ? 0 : 1; nullv = 0; }
1068 5916 100         for (i = 0; i < items && ret != nullv && status != 0; i++) {
    100          
    100          
1069 3952           status = _validate_int(aTHX_ ST(i), 2);
1070 3952 100         if (status == 0)
1071 7           break;
1072 3945 100         n = status * my_svuv(ST(i)); /* n = abs(arg) */
1073 3945 100         if (i == 0) {
1074 1965           ret = n;
1075             } else {
1076 1980           UV gcd = gcd_ui(ret, n);
1077 1980 100         if (ix == 0) {
1078 1950           ret = gcd;
1079             } else {
1080 30           n /= gcd;
1081 30 100         if (n <= (UV_MAX / ret) ) ret *= n;
1082 2           else status = 0; /* Overflow */
1083             }
1084             }
1085             }
1086             }
1087 20524 100         if (status != 0)
1088 5958           XSRETURN_UV(ret);
1089             /* For min/max, use string compare if not an object */
1090 14566 100         if ((ix == 2 || ix == 3) && !sv_isobject(ST(0))) {
    100          
    50          
1091 2           int retindex = 0;
1092 2           int minmax = (ix == 2);
1093             STRLEN alen, blen;
1094             char *aptr, *bptr;
1095 2 50         aptr = SvPV(ST(0), alen);
1096 2           (void) strnum_minmax(minmax, 0, 0, aptr, alen);
1097 4 100         for (i = 1; i < items; i++) {
1098 2 50         bptr = SvPV(ST(i), blen);
1099 2 50         if (strnum_minmax(minmax, aptr, alen, bptr, blen)) {
1100 2           aptr = bptr;
1101 2           alen = blen;
1102 2           retindex = i;
1103             }
1104             }
1105 2           ST(0) = ST(retindex);
1106 2           XSRETURN(1);
1107             }
1108 14564           switch (ix) {
1109 6           case 0: _vcallsub_with_gmp(0.17,"gcd"); break;
1110 3           case 1: _vcallsub_with_gmp(0.17,"lcm"); break;
1111 0           case 2: _vcallsub_with_gmp(0.00,"vecmin"); break;
1112 0           case 3: _vcallsub_with_gmp(0.00,"vecmax"); break;
1113 523           case 4: _vcallsub_with_pp("vecsum"); break;
1114             case 5:
1115 14032           default:_vcallsub_with_pp("vecprod"); break;
1116             }
1117 14564           return; /* skip implicit PUTBACK */
1118              
1119             void
1120             vecextract(IN SV* x, IN SV* svm)
1121             PREINIT:
1122             AV* av;
1123 2           UV i = 0;
1124             PPCODE:
1125 2 50         if ((!SvROK(x)) || (SvTYPE(SvRV(x)) != SVt_PVAV))
    50          
1126 0           croak("vecextract first argument must be an array reference");
1127 2           av = (AV*) SvRV(x);
1128 3 100         if (SvROK(svm) && SvTYPE(SvRV(svm)) == SVt_PVAV) {
    50          
1129 1           AV* avm = (AV*) SvRV(svm);
1130 1           int j, mlen = av_len(avm);
1131 6 100         for (j = 0; j <= mlen; j++) {
1132 5           SV** iv = av_fetch(avm, j, 0);
1133 5 50         if (iv && SvTYPE(*iv) == SVt_IV) {
    50          
1134 5 50         SV **v = av_fetch(av, SvIV(*iv), 0);
1135 5 50         if (v) XPUSHs(*v);
    50          
1136             }
1137             }
1138 1 50         } else if (_validate_int(aTHX_ svm, 0)) {
1139 1 50         UV mask = my_svuv(svm);
1140 25 100         while (mask) {
1141 24 100         if (mask & 1) {
1142 13           SV** v = av_fetch(av, i, 0);
1143 13 50         if (v) XPUSHs(*v);
    50          
1144             }
1145 24           i++;
1146 24           mask >>= 1;
1147             }
1148             } else {
1149 0 0         _vcallsubn(aTHX_ GIMME_V, VCALL_PP, "vecextract", items, 0);
1150 0           return;
1151             }
1152              
1153             void
1154             chinese(...)
1155             PROTOTYPE: @
1156             PREINIT:
1157             int i, status;
1158             UV ret, *an;
1159             SV **psva, **psvn;
1160             PPCODE:
1161 25           status = 1;
1162 25 50         New(0, an, 2*items, UV);
1163 25           ret = 0;
1164 69 100         for (i = 0; i < items; i++) {
1165             AV* av;
1166 47 50         if (!SvROK(ST(i)) || SvTYPE(SvRV(ST(i))) != SVt_PVAV || av_len((AV*)SvRV(ST(i))) != 1)
    50          
    50          
1167 0           croak("chinese arguments are two-element array references");
1168 47           av = (AV*) SvRV(ST(i));
1169 47           psva = av_fetch(av, 0, 0);
1170 47           psvn = av_fetch(av, 1, 0);
1171 47 50         if (psva == 0 || psvn == 0 || _validate_int(aTHX_ *psva, 1) != 1 || !_validate_int(aTHX_ *psvn, 0)) {
    50          
    100          
    50          
1172 3           status = 0;
1173 3           break;
1174             }
1175 44 50         an[i+0] = my_svuv(*psva);
1176 44 50         an[i+items] = my_svuv(*psvn);
1177             }
1178 25 100         if (status)
1179 22           ret = chinese(an, an+items, items, &status);
1180 25           Safefree(an);
1181 25 100         if (status == -1) XSRETURN_UNDEF;
1182 20 100         if (status) XSRETURN_UV(ret);
1183 7           psvn = av_fetch((AV*) SvRV(ST(0)), 1, 0);
1184 7           _vcallsub_with_gmpobj(0.32,"chinese");
1185 7 100         OBJECTIFY_RESULT( (psvn ? *psvn : 0), ST(0));
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1186 25           return; /* skip implicit PUTBACK */
1187              
1188             void
1189             lucas_sequence(...)
1190             ALIAS:
1191             lucasu = 1
1192             lucasv = 2
1193             PREINIT:
1194             UV U, V, Qk;
1195             PPCODE:
1196 26644 100         if (ix == 1 || ix == 2) {
    100          
1197 351 50         if (items != 3) croak("lucasu: P, Q, k");
1198 702 50         if (_validate_int(aTHX_ ST(0), 1) && _validate_int(aTHX_ ST(1), 1) &&
1199 351           _validate_int(aTHX_ ST(2), 0)) {
1200 351 50         IV P = my_sviv(ST(0));
1201 351 50         IV Q = my_sviv(ST(1));
1202 351 50         UV k = my_svuv(ST(2));
1203             IV ret;
1204 351 100         int ok = (ix == 1) ? lucasu(&ret, P, Q, k) : lucasv(&ret, P, Q, k);
1205 351 50         if (ok) XSRETURN_IV(ret);
1206             }
1207 0 0         _vcallsub_with_gmpobj(0.29,(ix==1) ? "lucasu" : "lucasv");
1208 0 0         OBJECTIFY_RESULT(ST(2), ST(0));
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1209 0           return;
1210             }
1211 26293 50         if (items != 4) croak("lucas_sequence: n, P, Q, k");
1212 52584 100         if (_validate_int(aTHX_ ST(0), 0) && _validate_int(aTHX_ ST(1), 1) &&
1213 52582 50         _validate_int(aTHX_ ST(2), 1) && _validate_int(aTHX_ ST(3), 0)) {
1214 26291 50         lucas_seq(&U, &V, &Qk,
    100          
    100          
    50          
1215 210328           my_svuv(ST(0)), my_sviv(ST(1)), my_sviv(ST(2)), my_svuv(ST(3)));
1216 26291           PUSHs(sv_2mortal(newSVuv( U ))); /* 4 args in, 3 out, no EXTEND needed */
1217 26291           PUSHs(sv_2mortal(newSVuv( V )));
1218 26291           PUSHs(sv_2mortal(newSVuv( Qk )));
1219             } else {
1220 2 50         _vcallsubn(aTHX_ GIMME_V, VCALL_PP, "lucas_sequence", items, 0);
1221 26644           return;
1222             }
1223              
1224             void is_prime(IN SV* svn)
1225             ALIAS:
1226             is_prob_prime = 1
1227             is_provable_prime = 2
1228             is_bpsw_prime = 3
1229             is_aks_prime = 4
1230             is_lucas_pseudoprime = 5
1231             is_strong_lucas_pseudoprime = 6
1232             is_extra_strong_lucas_pseudoprime = 7
1233             is_frobenius_underwood_pseudoprime = 8
1234             is_frobenius_khashin_pseudoprime = 9
1235             is_catalan_pseudoprime = 10
1236             is_euler_plumb_pseudoprime = 11
1237             is_ramanujan_prime = 12
1238             is_square_free = 13
1239             is_carmichael = 14
1240             is_quasi_carmichael = 15
1241             is_semiprime = 16
1242             is_square = 17
1243             is_mersenne_prime = 18
1244             is_totient = 19
1245             PREINIT:
1246             int status, ret;
1247             PPCODE:
1248 466193           ret = 0;
1249 466193           status = _validate_int(aTHX_ svn, 1);
1250 466190 100         if (status == 1) {
1251 465806 100         UV n = my_svuv(svn);
1252 465806           switch (ix) {
1253             case 0:
1254             case 1:
1255 425544           case 2: ret = is_prime(n); break;
1256 0           case 3: ret = BPSW(n); break;
1257 7           case 4: ret = is_aks_prime(n); break;
1258 20           case 5: ret = is_lucas_pseudoprime(n, 0); break;
1259 29           case 6: ret = is_lucas_pseudoprime(n, 1); break;
1260 22           case 7: ret = is_lucas_pseudoprime(n, 3); break;
1261 102           case 8: ret = is_frobenius_underwood_pseudoprime(n); break;
1262 102           case 9: ret = is_frobenius_khashin_pseudoprime(n); break;
1263 3           case 10: ret = is_catalan_pseudoprime(n); break;
1264 29           case 11: ret = is_euler_plumb_pseudoprime(n); break;
1265 984           case 12: ret = is_ramanujan_prime(n); break;
1266 28           case 13: ret = is_square_free(n); break;
1267 20000           case 14: ret = is_carmichael(n); break;
1268 5402           case 15: ret = is_quasi_carmichael(n); break;
1269 11110           case 16: ret = is_semiprime(n); break;
1270 18           case 17: ret = is_power(n,2); break;
1271 2282 50         case 18: ret = is_mersenne_prime(n); if (ret == -1) status = 0; break;
1272             case 19:
1273 465806           default: ret = is_totient(n); break;
1274             }
1275 384 100         } else if (status == -1) {
1276             /* Result for negative inputs will be zero unless changed here */
1277 36 100         if (ix == 13) {
1278 26 50         IV sn = my_sviv(svn);
1279 26 50         if (sn > -IV_MAX) ret = is_square_free(-sn);
1280 0           else status = 0;
1281             }
1282             }
1283 466190 100         if (status != 0) RETURN_NPARITY(ret);
    50          
    50          
1284 348           switch (ix) {
1285 44           case 0: _vcallsub_with_gmp(0.01,"is_prime"); break;
1286 278           case 1: _vcallsub_with_gmp(0.01,"is_prob_prime"); break;
1287 5           case 2: _vcallsub_with_gmp(0.04,"is_provable_prime"); break;
1288 1           case 3: _vcallsub_with_gmp(0.17,"is_bpsw_prime"); break;
1289 0           case 4: _vcallsub_with_gmp(0.16,"is_aks_prime"); break;
1290 0           case 5: _vcallsub_with_gmp(0.01,"is_lucas_pseudoprime"); break;
1291 0           case 6: _vcallsub_with_gmp(0.01,"is_strong_lucas_pseudoprime"); break;
1292 12           case 7: _vcallsub_with_gmp(0.01,"is_extra_strong_lucas_pseudoprime"); break;
1293 0           case 8: _vcallsub_with_gmp(0.13,"is_frobenius_underwood_pseudoprime"); break;
1294 0           case 9: _vcallsub_with_gmp(0.30,"is_frobenius_khashin_pseudoprime"); break;
1295 0           case 10:_vcallsub_with_gmp(0.00,"is_catalan_pseudoprime"); break;
1296 0           case 11:_vcallsub_with_gmp(0.39,"is_euler_plumb_pseudoprime"); break;
1297 0           case 12:_vcallsub_with_gmp(0.00,"is_ramanujan_prime"); break;
1298 2           case 13:_vcallsub_with_gmp(0.00,"is_square_free"); break;
1299 1           case 14:_vcallsub_with_gmp(0.47,"is_carmichael"); break;
1300 0           case 15:_vcallsub_with_gmp(0.00,"is_quasi_carmichael"); break;
1301 1           case 16:_vcallsub_with_gmp(0.42,"is_semiprime"); break;
1302 1           case 17:_vcallsub_with_gmp(0.47,"is_square"); break;
1303 0           case 18:_vcallsub_with_gmp(0.28,"is_mersenne_prime"); break;
1304             case 19:
1305 3           default:_vcallsub_with_gmp(0.47,"is_totient"); break;
1306             }
1307 348           return; /* skip implicit PUTBACK */
1308              
1309             void is_fundamental(IN SV* svn)
1310             PREINIT:
1311             int status;
1312             PPCODE:
1313 104           status = _validate_int(aTHX_ svn, 1);
1314 104 100         if (status == 1)
1315 52 50         RETURN_NPARITY(is_fundamental(my_svuv(svn), 0));
    50          
    50          
1316 52 100         if (status == -1) {
1317 50 50         IV sn = my_sviv(svn);
1318 50 50         if (sn > -IV_MAX)
1319 50 50         RETURN_NPARITY(is_fundamental(-sn, 1));
    50          
1320             }
1321 2           _vcallsub_with_gmp(0.00,"is_fundamental");
1322 2           return;
1323              
1324              
1325             void
1326             is_power(IN SV* svn, IN UV k = 0, IN SV* svroot = 0)
1327             PREINIT:
1328             int status;
1329             PPCODE:
1330 10660           status = _validate_int(aTHX_ svn, 1);
1331 10660 100         if (status != 0) {
1332 10404           int ret = 0;
1333 10404 100         UV n = my_svuv(svn);
1334 10404 100         if (status == -1) {
1335 65 100         IV sn = my_sviv(svn);
1336 65 100         if (sn <= -IV_MAX) status = 0;
1337 63           else n = -sn;
1338             }
1339 10404 100         if (status == 1 || (status == -1 && (k == 0 || k & 1))) {
    100          
    100          
    100          
1340 10400           ret = is_power(n, k);
1341 10400 100         if (status == -1 && k == 0) {
    100          
1342 59           ret >>= valuation(ret,2);
1343 59 100         if (ret == 1) ret = 0;
1344             }
1345 10400 100         if (ret && svroot != 0) {
    100          
1346 29 100         UV root = rootof(n, k ? k : (UV)ret);
1347 29 50         if (!SvROK(svroot)) croak("is_power: third argument not a scalar reference");
1348 29 100         if (status == 1) sv_setuv(SvRV(svroot), root);
1349 18           else sv_setiv(SvRV(svroot), -root);
1350             }
1351             }
1352 10404 100         if (status != 0) RETURN_NPARITY(ret);
    50          
    50          
1353             }
1354 258 100         if (svroot == 0) { _vcallsub_with_gmp(0.28, "is_power"); }
1355 128           else { _vcallsub_with_pp("is_power"); }
1356 258           return;
1357              
1358             void
1359             is_prime_power(IN SV* svn, IN SV* svroot = 0)
1360             PREINIT:
1361             int status, ret;
1362             UV n, root;
1363             PPCODE:
1364 10254           status = _validate_int(aTHX_ svn, 1);
1365 10254 50         if (status == -1)
1366 0 0         RETURN_NPARITY(0);
    0          
1367 10254 50         if (status != 0) {
1368 10254 50         n = my_svuv(svn);
1369 10254           ret = primepower(n, &root);
1370 10254 100         if (ret && svroot != 0) {
    100          
1371 17 50         if (!SvROK(svroot))croak("is_prime_power: second argument not a scalar reference");
1372 17           sv_setuv(SvRV(svroot), root);
1373             }
1374 10254 50         RETURN_NPARITY(ret);
    50          
1375             }
1376 0 0         (void)_vcallsubn(aTHX_ G_SCALAR, (svroot == 0) ? (VCALL_GMP|VCALL_PP) : (VCALL_PP), "is_prime_power", items, 40);
1377 10254           return;
1378              
1379             void
1380             is_perrin_pseudoprime(IN SV* svn, IN int k = 0)
1381             ALIAS:
1382             is_almost_extra_strong_lucas_pseudoprime = 1
1383             PREINIT:
1384             int status, ret;
1385             PPCODE:
1386 71           ret = 0;
1387 71           status = _validate_int(aTHX_ svn, 1);
1388 71 100         if (status == 1) {
1389 70 50         UV n = my_svuv(svn);
1390 70 100         if (ix == 0) ret = is_perrin_pseudoprime(n, k);
1391 50           else ret = is_almost_extra_strong_lucas_pseudoprime(n, (k < 1) ? 1 : k);
1392             }
1393 71 100         if (status != 0) RETURN_NPARITY(ret);
    50          
    50          
1394 1 50         if (ix == 0)
1395 1 50         _vcallsub_with_gmp( (k == 0) ? 0.20 : 0.40, "is_perrin_pseudoprime");
1396             else
1397 0           _vcallsub_with_gmp(0.13,"is_almost_extra_strong_lucas_pseudoprime");
1398 1           return;
1399              
1400             void
1401             is_frobenius_pseudoprime(IN SV* svn, IN IV P = 0, IN IV Q = 0)
1402             PREINIT:
1403             int status, ret;
1404             PPCODE:
1405 28           ret = 0;
1406 28           status = _validate_int(aTHX_ svn, 1);
1407 28 50         if (status == 1) {
1408 28 50         UV n = my_svuv(svn);
1409 28           ret = is_frobenius_pseudoprime(n, P, Q);
1410             }
1411 28 50         if (status != 0) RETURN_NPARITY(ret);
    50          
    50          
1412 0           _vcallsub_with_gmp(0.24,"is_frobenius_pseudoprime");
1413 0           return;
1414              
1415             void
1416             is_polygonal(IN SV* svn, IN UV k, IN SV* svroot = 0)
1417             PREINIT:
1418             int status, result, overflow;
1419             UV n, root;
1420             PPCODE:
1421 25302 50         if (k < 3) croak("is_polygonal: k must be >= 3");
1422 25302           status = _validate_int(aTHX_ svn, 1);
1423 25302 100         if (status != 0) {
1424 25300           overflow = 0;
1425 25300 50         if (status == -1) {
1426 0           result = 0;
1427             } else {
1428 25300 50         n = my_svuv(svn);
1429 25300           root = polygonal_root(n, k, &overflow);
1430 25300 50         result = (n == 0) || root;
    100          
1431             }
1432 25300 50         if (!overflow) {
1433 25300 100         if (result && svroot != 0) {
    100          
1434 230 50         if (!SvROK(svroot)) croak("is_polygonal: third argument not a scalar reference");
1435 230           sv_setuv(SvRV(svroot), root);
1436             }
1437 25300 50         RETURN_NPARITY(result);
    50          
1438             }
1439             }
1440 2 50         if (items != 3) { _vcallsub_with_gmp(0.47, "is_polygonal"); }
1441 0           else { _vcallsub_with_pp("is_polygonal"); }
1442 25302           return;
1443              
1444             void
1445             logint(IN SV* svn, IN UV k, IN SV* svret = 0)
1446             ALIAS:
1447             rootint = 1
1448             PREINIT:
1449             int status;
1450             UV n, root;
1451             PPCODE:
1452 626           status = _validate_int(aTHX_ svn, 1);
1453 626 100         if (status != 0) {
1454 624 50         n = my_svuv(svn);
1455 624 100         if (svret != 0 && !SvROK(svret))
    50          
1456 0 0         croak("%s: third argument not a scalar reference",(ix==0)?"logint":"rootint");
1457 624 100         if (ix == 0) {
1458 601 50         if (status != 1 || n <= 0) croak("logint: n must be > 0");
    50          
1459 601 50         if (k <= 1) croak("logint: base must be > 1");
1460 601           root = logint(n, k);
1461 601 100         if (svret) sv_setuv(SvRV(svret), ipow(k,root));
1462             } else {
1463 23 50         if (status == -1) croak("rootint: n must be >= 0");
1464 23 50         if (k <= 0) croak("rootint: k must be > 0");
1465 23           root = rootof(n, k);
1466 23 100         if (svret) sv_setuv(SvRV(svret), ipow(root,k));
1467             }
1468 624           XSRETURN_UV(root);
1469             }
1470 2           switch (ix) {
1471 0 0         case 0: (void)_vcallsubn(aTHX_ G_SCALAR, (svret == 0) ? (VCALL_GMP|VCALL_PP) : (VCALL_PP), "logint", items, 47); break;
1472 2 50         case 1: (void)_vcallsubn(aTHX_ G_SCALAR, (svret == 0) ? (VCALL_GMP|VCALL_PP) : (VCALL_PP), "rootint", items, 40); break;
1473 0           default: break;
1474             }
1475 2           return;
1476              
1477             void
1478             miller_rabin_random(IN SV* svn, IN IV bases = 1, IN char* seed = 0)
1479             PREINIT:
1480             int status;
1481             dMY_CXT;
1482             PPCODE:
1483 9           status = _validate_int(aTHX_ svn, 0);
1484 8 100         if (bases < 0) croak("miller_rabin_random: number of bases must be positive");
1485 7 100         if (status != 0 && seed == 0) {
    50          
1486 5 50         UV n = my_svuv(svn);
1487 5 50         RETURN_NPARITY( is_mr_random(MY_CXT.randcxt, n, bases) );
    50          
1488             }
1489 2           _vcallsub_with_gmp(0.46,"miller_rabin_random");
1490 2           return;
1491              
1492             void
1493             next_prime(IN SV* svn)
1494             ALIAS:
1495             prev_prime = 1
1496             nth_prime = 2
1497             nth_prime_upper = 3
1498             nth_prime_lower = 4
1499             nth_prime_approx = 5
1500             inverse_li = 6
1501             nth_twin_prime = 7
1502             nth_twin_prime_approx = 8
1503             nth_semiprime = 9
1504             nth_semiprime_approx = 10
1505             nth_ramanujan_prime = 11
1506             nth_ramanujan_prime_upper = 12
1507             nth_ramanujan_prime_lower = 13
1508             nth_ramanujan_prime_approx = 14
1509             prime_count_upper = 15
1510             prime_count_lower = 16
1511             prime_count_approx = 17
1512             ramanujan_prime_count_upper = 18
1513             ramanujan_prime_count_lower = 19
1514             twin_prime_count_approx = 20
1515             semiprime_count_approx = 21
1516             urandomm = 22
1517             PPCODE:
1518 12792 100         if (_validate_int(aTHX_ svn, 0)) {
1519 12721 100         UV n = my_svuv(svn);
1520 12725 100         if ( (n >= MPU_MAX_PRIME && ix == 0)
    100          
1521 12717 100         || (n >= MPU_MAX_PRIME_IDX && (ix==2 || ix==3 || ix==4 || ix==5 || ix == 6))
    50          
    100          
    100          
    50          
    50          
1522 12713 100         || (n >= MPU_MAX_TWIN_PRIME_IDX && (ix==7 || ix==8))
    50          
    50          
1523 12713 100         || (n >= MPU_MAX_SEMI_PRIME_IDX && (ix==9 || ix==10))
    50          
    50          
1524 12713 100         || (n >= MPU_MAX_RMJN_PRIME_IDX && (ix==11 || ix==12 || ix==13 || ix==14)) ) {
    50          
    50          
    50          
    50          
1525             /* Out of range. Fall through to Perl. */
1526             } else {
1527             UV ret;
1528             /* Prev prime of 2 or less should return undef */
1529 12713 100         if (ix == 1 && n < 3) XSRETURN_UNDEF;
    100          
1530             /* nth_prime(0) and similar should return undef */
1531 12708 100         if (n == 0 && (ix >= 2 && ix <= 10 && ix != 6)) XSRETURN_UNDEF;
    100          
    100          
    100          
1532 12704           switch (ix) {
1533 4034           case 0: ret = next_prime(n); break;
1534 3754 50         case 1: ret = (n < 3) ? 0 : prev_prime(n); break;
1535 1114           case 2: ret = nth_prime(n); break;
1536 40           case 3: ret = nth_prime_upper(n); break;
1537 25           case 4: ret = nth_prime_lower(n); break;
1538 25           case 5: ret = nth_prime_approx(n); break;
1539 53           case 6: ret = inverse_li(n); break;
1540 53           case 7: ret = nth_twin_prime(n); break;
1541 10           case 8: ret = nth_twin_prime_approx(n); break;
1542 2671           case 9: ret = nth_semiprime(n); break;
1543 4           case 10:ret = nth_semiprime_approx(n);
1544             /* Do the following if we need a semiprime returned. */
1545             /* while (!is_semiprime(ret)) ret++; */
1546 4           break;
1547 75           case 11:ret = nth_ramanujan_prime(n); break;
1548 74           case 12:ret = nth_ramanujan_prime_upper(n); break;
1549 74           case 13:ret = nth_ramanujan_prime_lower(n); break;
1550 2           case 14:ret = nth_ramanujan_prime_approx(n); break;
1551 35           case 15:ret = prime_count_upper(n); break;
1552 35           case 16:ret = prime_count_lower(n); break;
1553 36           case 17:ret = prime_count_approx(n); break;
1554 74           case 18:ret = ramanujan_prime_count_upper(n); break;
1555 74           case 19:ret = ramanujan_prime_count_lower(n); break;
1556 7           case 20:ret = twin_prime_count_approx(n); break;
1557 4           case 21:ret = semiprime_count_approx(n); break;
1558             case 22:
1559 431           default:{ dMY_CXT; ret = urandomm64(MY_CXT.randcxt,n); } break;
1560             }
1561 12704           XSRETURN_UV(ret);
1562             }
1563             }
1564 60 100         if ((ix == 0 || ix == 1) && _XS_get_callgmp() && PERL_REVISION >= 5 && PERL_VERSION > 8) {
    100          
    50          
1565 0 0         _vcallsub_with_gmpobj(0.01, ix ? "prev_prime" : "next_prime");
1566 0 0         OBJECTIFY_RESULT(svn, ST(0));
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1567 0           return;
1568             }
1569 60           switch (ix) {
1570 7           case 0: _vcallsub_with_pp("next_prime"); break;
1571 2           case 1: _vcallsub_with_pp("prev_prime"); break;
1572 0           case 2: _vcallsub_with_pp("nth_prime"); break;
1573 1           case 3: _vcallsub_with_pp("nth_prime_upper"); break;
1574 3           case 4: _vcallsub_with_pp("nth_prime_lower"); break;
1575 0           case 5: _vcallsub_with_pp("nth_prime_approx"); break;
1576 0           case 6: _vcallsub_with_pp("inverse_li"); break;
1577 0           case 7: _vcallsub_with_pp("nth_twin_prime"); break;
1578 0           case 8: _vcallsub_with_pp("nth_twin_prime_approx"); break;
1579 0           case 9: _vcallsub_with_pp("nth_semiprime"); break;
1580 0           case 10: _vcallsub_with_pp("nth_semiprime_approx"); break;
1581 0           case 11: _vcallsub_with_pp("nth_ramanujan_prime"); break;
1582 0           case 12: _vcallsub_with_pp("nth_ramanujan_prime_upper"); break;
1583 0           case 13: _vcallsub_with_pp("nth_ramanujan_prime_lower"); break;
1584 0           case 14: _vcallsub_with_pp("nth_ramanujan_prime_approx"); break;
1585 8           case 15: _vcallsub_with_pp("prime_count_upper"); break;
1586 8           case 16: _vcallsub_with_pp("prime_count_lower"); break;
1587 4           case 17: _vcallsub_with_pp("prime_count_approx"); break;
1588 0           case 18: _vcallsub_with_pp("ramanujan_prime_count_upper"); break;
1589 0           case 19: _vcallsub_with_pp("ramanujan_prime_count_lower"); break;
1590 0           case 20: _vcallsub_with_pp("twin_prime_count_approx"); break;
1591 0           case 21: _vcallsub_with_pp("semiprime_count_approx"); break;
1592             case 22:
1593 27           default: _vcallsub_with_gmpobj(0.44,"urandomm");
1594 27 50         OBJECTIFY_RESULT(svn, ST(0));
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1595 27           break;
1596             }
1597 59           return; /* skip implicit PUTBACK */
1598              
1599             void urandomb(IN UV bits)
1600             ALIAS:
1601             random_ndigit_prime = 1
1602             random_semiprime = 2
1603             random_unrestricted_semiprime = 3
1604             random_nbit_prime = 4
1605             random_shawe_taylor_prime = 5
1606             random_maurer_prime = 6
1607             random_proven_prime = 7
1608             random_strong_prime = 8
1609             PREINIT:
1610             UV res, minarg;
1611             dMY_CXT;
1612             void* cs;
1613             PPCODE:
1614 612           switch (ix) {
1615 23           case 1: minarg = 1; break;
1616 4           case 2: minarg = 4; break;
1617 3           case 3: minarg = 3; break;
1618             case 4:
1619             case 5:
1620             case 6:
1621 263           case 7: minarg = 2; break;
1622 1           case 8: minarg = 128; break;
1623 318           default: minarg = 0; break;
1624             }
1625 612 100         if (minarg > 0 && bits < minarg)
    100          
1626 6           croak("Parameter '%d' must be >= %d", (int)bits, (int)minarg);
1627 606           cs = MY_CXT.randcxt;
1628 606 100         if (bits <= BITS_PER_WORD) {
1629 549           switch (ix) {
1630 272           case 0: res = urandomb(cs,bits); break;
1631 22           case 1: res = random_ndigit_prime(cs,bits); break;
1632 2           case 2: res = random_semiprime(cs,bits); break;
1633 1           case 3: res = random_unrestricted_semiprime(cs,bits); break;
1634             case 4:
1635             case 5:
1636             case 6:
1637             case 7:
1638             case 8:
1639 252           default: res = random_nbit_prime(cs,bits); break;
1640             }
1641 549 100         if (res || ix == 0) XSRETURN_UV(res);
    100          
1642             }
1643 60           switch (ix) {
1644 46           case 0: _vcallsub_with_gmpobj(0.43,"urandomb"); break;
1645 3           case 1: _vcallsub_with_gmpobj(0.42,"random_ndigit_prime"); break;
1646 1           case 2: _vcallsub_with_gmpobj(0.00,"random_semiprime"); break;
1647 1           case 3: _vcallsub_with_gmpobj(0.00,"random_unrestricted_semiprime"); break;
1648 4           case 4: _vcallsub_with_gmpobj(0.42,"random_nbit_prime"); break;
1649 1           case 5: _vcallsub_with_gmpobj(0.43,"random_shawe_taylor_prime"); break;
1650             case 6:
1651 3           case 7: _vcallsub_with_gmpobj(0.43,"random_maurer_prime"); break;
1652             case 8:
1653 1           default: _vcallsub_with_gmpobj(0.43,"random_strong_prime"); break;
1654             }
1655 60 100         OBJECTIFY_RESULT(ST(0), ST(0));
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1656 60           XSRETURN(1);
1657              
1658             void random_factored_integer(IN SV* svn)
1659             PPCODE:
1660 1 50         if (_validate_int(aTHX_ svn, 0)) {
1661             dMY_CXT;
1662             int f, nf, flip;
1663 1 50         UV r, F[MPU_MAX_FACTORS+1], n = my_svuv(svn);
1664 1           AV* av = newAV();
1665 1 50         if (n < 1) croak("random_factored_integer: n must be >= 1");
1666 1           r = random_factored_integer(MY_CXT.randcxt, n, &nf, F);
1667 1           flip = (F[0] >= F[nf-1]); /* Handle results in either sort order */
1668 4 100         for (f = 0; f < nf; f++)
1669 3 50         av_push(av, newSVuv(F[flip ? nf-1-f : f]));
1670 1 50         XPUSHs(sv_2mortal(newSVuv( r )));
1671 1 50         XPUSHs(sv_2mortal(newRV_noinc( (SV*) av )));
1672             } else {
1673 0           (void)_vcallsubn(aTHX_ G_ARRAY, VCALL_PP, "random_factored_integer",items,0);
1674 0           return;
1675             }
1676              
1677             void Pi(IN UV digits = 0)
1678             PREINIT:
1679             #ifdef USE_QUADMATH
1680             #define STRTONV(t) strtoflt128(t,NULL)
1681             const UV mantsize = FLT128_DIG;
1682             const NV pival = 3.141592653589793238462643383279502884197169Q;
1683             #elif defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE)
1684             #define STRTONV(t) strtold(t,NULL)
1685             const UV mantsize = LDBL_DIG;
1686             const NV pival = 3.141592653589793238462643383279502884197169L;
1687             #else
1688             #define STRTONV(t) strtod(t,NULL)
1689 1001           const UV mantsize = DBL_DIG;
1690 1001           const NV pival = 3.141592653589793238462643383279502884197169;
1691             #endif
1692             PPCODE:
1693 1001 100         if (digits == 0) {
1694 1           XSRETURN_NV( pival );
1695 1000 100         } else if (digits <= mantsize) {
1696 15           char* out = pidigits(digits);
1697 15           NV pi = STRTONV(out);
1698 15           Safefree(out);
1699 15           XSRETURN_NV( pi );
1700             } else {
1701 985           _vcallsub_with_pp("Pi");
1702 985           return;
1703             }
1704              
1705             void
1706             _pidigits(IN int digits)
1707             PREINIT:
1708             char* out;
1709             PPCODE:
1710 972 50         if (digits <= 0) XSRETURN_EMPTY;
1711 972           out = pidigits(digits);
1712 972 50         XPUSHs(sv_2mortal(newSVpvn(out, digits+1)));
1713 972           Safefree(out);
1714              
1715             void
1716             factor(IN SV* svn)
1717             ALIAS:
1718             factor_exp = 1
1719             divisors = 2
1720             inverse_totient = 3
1721             PREINIT:
1722             U32 gimme_v;
1723             int status, i, nfactors, it_overflow;
1724             PPCODE:
1725 1642 50         gimme_v = GIMME_V;
1726 1642           status = _validate_int(aTHX_ svn, 0);
1727 1642 100         it_overflow = (status == 1 && ix==3 && gimme_v == G_ARRAY && my_svuv(svn) > UV_MAX/7.5 );
    100          
    100          
    50          
    0          
    50          
1728 3168 100         if (status == 1 && !it_overflow) {
    50          
1729             UV factors[MPU_MAX_FACTORS+1];
1730             UV exponents[MPU_MAX_FACTORS+1];
1731 1526 100         UV n = my_svuv(svn);
1732 1526 100         if (gimme_v == G_SCALAR) {
1733             UV res;
1734 155           switch (ix) {
1735 21           case 0: res = factor(n, factors); break;
1736 10           case 1: res = factor_exp(n, factors, 0); break;
1737 21           case 2: res = divisor_sum(n, 0); break;
1738 103           default: res = inverse_totient_count(n); break;
1739             }
1740 155           PUSHs(sv_2mortal(newSVuv( res )));
1741 1371 50         } else if (gimme_v == G_ARRAY) {
1742 1371           switch (ix) {
1743 188           case 0: nfactors = factor(n, factors);
1744 188 50         EXTEND(SP, nfactors);
    50          
1745 795 100         for (i = 0; i < nfactors; i++)
1746 607           PUSHs(sv_2mortal(newSVuv( factors[i] )));
1747 188           break;
1748 228           case 1: nfactors = factor_exp(n, factors, exponents);
1749             /* if (n == 1) XSRETURN_EMPTY; */
1750 228 50         EXTEND(SP, nfactors);
    50          
1751 717 100         for (i = 0; i < nfactors; i++) {
1752 489           AV* av = newAV();
1753 489           av_push(av, newSVuv(factors[i]));
1754 489           av_push(av, newSVuv(exponents[i]));
1755 489           PUSHs( sv_2mortal(newRV_noinc( (SV*) av )) );
1756             }
1757 228           break;
1758             case 2: {
1759             UV ndivisors;
1760 953           UV* divs = _divisor_list(n, &ndivisors);
1761 953 50         EXTEND(SP, (IV)ndivisors);
    50          
1762 6208 100         for (i = 0; (UV)i < ndivisors; i++)
1763 5255           PUSHs(sv_2mortal(newSVuv( divs[i] )));
1764 953           Safefree(divs);
1765             }
1766 953           break;
1767             default: {
1768             UV ntotients;
1769 2           UV* tots = inverse_totient_list(&ntotients, n);
1770 2 50         EXTEND(SP, (IV)ntotients);
    50          
1771 20 100         for (i = 0; (UV)i < ntotients; i++)
1772 18           PUSHs(sv_2mortal(newSVuv( tots[i] )));
1773 2           Safefree(tots);
1774             }
1775 2           break;
1776             }
1777             }
1778             } else {
1779 116           switch (ix) {
1780 64           case 0: _vcallsubn(aTHX_ gimme_v, VCALL_ROOT, "_generic_factor", 1, 0); break;
1781 14           case 1: _vcallsubn(aTHX_ gimme_v, VCALL_ROOT, "_generic_factor_exp", 1, 0); break;
1782 38           case 2: _vcallsubn(aTHX_ gimme_v, VCALL_GMP|VCALL_PP, "divisors", 1, 0); break;
1783 0           default: _vcallsubn(aTHX_ gimme_v, VCALL_GMP|VCALL_PP, "inverse_totient", 1, 0); break;
1784             }
1785 116           return; /* skip implicit PUTBACK */
1786             }
1787              
1788             void
1789             divisor_sum(IN SV* svn, ...)
1790             PREINIT:
1791             SV* svk;
1792             int nstatus, kstatus;
1793             PPCODE:
1794 2331 100         svk = (items > 1) ? ST(1) : 0;
1795 2331           nstatus = _validate_int(aTHX_ svn, 0);
1796 2331 100         kstatus = (items == 1 || (SvIOK(svk) && SvIV(svk) >= 0)) ? 1 : 0;
    100          
    50          
    50          
    0          
1797             /* The above doesn't understand small bigints */
1798 2331 100         if (nstatus == 1 && kstatus == 0 && SvROK(svk) && (sv_isa(svk, "Math::BigInt") || sv_isa(svk, "Math::GMP") || sv_isa(svk, "Math::GMPz")))
    100          
    50          
    50          
    50          
    50          
1799 0           kstatus = _validate_int(aTHX_ svk, 0);
1800 2331 100         if (nstatus == 1 && kstatus == 1) {
    100          
1801 1411 50         UV n = my_svuv(svn);
1802 1411 100         UV k = (items > 1) ? my_svuv(svk) : 1;
    50          
1803 1411           UV sigma = divisor_sum(n, k);
1804 1411 50         if (sigma != 0) XSRETURN_UV(sigma); /* sigma 0 means overflow */
1805             }
1806 920           _vcallsub_with_gmp(0.00,"divisor_sum");
1807 920           return; /* skip implicit PUTBACK */
1808              
1809             void
1810             znorder(IN SV* sva, IN SV* svn)
1811             ALIAS:
1812             binomial = 1
1813             jordan_totient = 2
1814             ramanujan_sum = 3
1815             factorialmod = 4
1816             legendre_phi = 5
1817             PREINIT:
1818             int astatus, nstatus;
1819             PPCODE:
1820 18855 100         astatus = _validate_int(aTHX_ sva, (ix==1) ? 2 : 0);
1821 18855 100         nstatus = _validate_int(aTHX_ svn, (ix==1) ? 2 : 0);
1822 18855 50         if (astatus != 0 && nstatus != 0) {
    100          
1823 18851 50         UV a = my_svuv(sva);
1824 18851 50         UV n = my_svuv(svn);
1825             UV ret;
1826 18851           switch (ix) {
1827 22           case 0: ret = znorder(a, n);
1828 22           break;
1829 16599 100         case 1: if ( (astatus == 1 && (nstatus == -1 || n > a)) ||
    100          
    100          
    100          
1830 37 100         (astatus ==-1 && (nstatus == -1 && n > a)) )
    100          
1831 35           { ret = 0; break; }
1832 16564 100         if (nstatus == -1)
1833 8           n = a - n; /* n<0,k<=n: (-1)^(n-k) * binomial(-k-1,n-k) */
1834 16564 100         if (astatus == -1) {
1835 28 50         ret = binomial( -my_sviv(sva)+n-1, n );
1836 28 50         if (ret > 0 && ret <= (UV)IV_MAX)
    50          
1837 28 100         XSRETURN_IV( (IV)ret * ((n&1) ? -1 : 1) );
1838 0           goto overflow;
1839             } else {
1840 16536           ret = binomial(a, n);
1841 16536 100         if (ret == 0)
1842 5232           goto overflow;
1843             }
1844 11304           break;
1845 490           case 2: ret = jordan_totient(a, n);
1846 490 100         if (ret == 0 && n > 1)
    50          
1847 22           goto overflow;
1848 468           break;
1849 902 100         case 3: if (a < 1 || n < 1) XSRETURN_IV(0);
    100          
1850             {
1851 900           UV g = a / gcd_ui(a,n);
1852 900           int m = moebius(g);
1853 900 100         if (m == 0 || a == g) RETURN_NPARITY(m);
    100          
    50          
    50          
1854 285           XSRETURN_IV( m * (totient(a) / totient(g)) );
1855             }
1856             break;
1857 821           case 4: ret = factorialmod(a, n);
1858 821           break;
1859             case 5:
1860 17           default: ret = legendre_phi(a, n);
1861 17           break;
1862             }
1863 12667 100         if (ret == 0 && ix == 0) XSRETURN_UNDEF; /* not defined */
    100          
1864 12663           XSRETURN_UV(ret);
1865             }
1866             overflow:
1867 5258           switch (ix) {
1868 2           case 0: _vcallsub_with_pp("znorder"); break;
1869 5232           case 1: _vcallsub_with_pp("binomial"); break;
1870 24           case 2: _vcallsub_with_pp("jordan_totient"); break;
1871 0           case 3: _vcallsub_with_pp("ramanujan_sum"); break;
1872 0           case 4: _vcallsub_with_pp("factorialmod"); break;
1873             case 5:
1874 0           default: _vcallsub_with_pp("legendre_phi"); break;
1875             }
1876 5258           return; /* skip implicit PUTBACK */
1877              
1878             void
1879             znlog(IN SV* sva, IN SV* svg, IN SV* svp)
1880             ALIAS:
1881             addmod = 1
1882             mulmod = 2
1883             divmod = 3
1884             powmod = 4
1885             PREINIT:
1886             int astatus, gstatus, pstatus, retundef;
1887             UV ret;
1888             PPCODE:
1889 8623           astatus = _validate_int(aTHX_ sva, (ix == 0) ? 0 : 1);
1890 8623           gstatus = _validate_int(aTHX_ svg, (ix == 0) ? 0 : 1);
1891 8623           pstatus = _validate_int(aTHX_ svp, 0);
1892 8623 100         if (astatus != 0 && gstatus != 0 && pstatus == 1) {
    100          
    100          
1893 1232 100         UV a, g, p = my_svuv(svp);
1894 1232 100         if (p <= 1) XSRETURN_UV(0);
1895 1008           ret = 0;
1896 1008           retundef = 0;
1897 1008 50         a = (astatus == 1) ? my_svuv(sva) : negmod(my_sviv(sva), p);
    100          
    0          
1898 1008 100         g = (gstatus == 1) ? my_svuv(svg) : negmod(my_sviv(svg), p);
    100          
    50          
1899 1008 100         if (a >= p) a %= p;
1900 1008 100         if (g >= p && ix != 4) g %= p;
    100          
1901 1008           switch (ix) {
1902 20           case 0: ret = znlog(a, g, p);
1903 20 100         if (ret == 0 && a > 1) retundef = 1;
    100          
1904 20 100         if (ret == 0 && (a == 0 || g == 0)) retundef = 1;
    50          
    50          
1905 20           break;
1906 69           case 1: ret = addmod(a, g, p); break;
1907 610           case 2: ret = mulmod(a, g, p); break;
1908 61           case 3: g = modinverse(g, p);
1909 61 100         if (g == 0) retundef = 1;
1910 37           else ret = mulmod(a, g, p);
1911 61           break;
1912             case 4:
1913 248 50         default:if (a == 0) {
1914 0           ret = (g == 0);
1915 0           retundef = (gstatus == -1);
1916             } else {
1917 248 100         if (gstatus == -1) {
1918 30           a = modinverse(a, p);
1919 30 100         if (a == 0) retundef = 1;
1920 14 50         else g = -my_sviv(svg);
1921             }
1922 248           ret = powmod(a, g, p);
1923             }
1924 248           break;
1925             }
1926 1008 100         if (retundef) XSRETURN_UNDEF;
1927 965           XSRETURN_UV(ret);
1928             }
1929 7391           switch (ix) {
1930 1           case 0: _vcallsub_with_gmpobj(0.00,"znlog"); break;
1931 0           case 1: _vcallsub_with_gmpobj(0.36,"addmod"); break;
1932 7368           case 2: _vcallsub_with_gmpobj(0.36,"mulmod"); break;
1933 0           case 3: _vcallsub_with_gmpobj(0.36,"divmod"); break;
1934             case 4:
1935 22           default:_vcallsub_with_gmpobj(0.36,"powmod"); break;
1936             }
1937 7391 50         OBJECTIFY_RESULT(svp, ST(items-1));
    50          
    50          
    50          
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1938 7391           return; /* skip implicit PUTBACK */
1939              
1940             void
1941             kronecker(IN SV* sva, IN SV* svb)
1942             ALIAS:
1943             valuation = 1
1944             invmod = 2
1945             sqrtmod = 3
1946             is_primitive_root = 4
1947             PREINIT:
1948             int astatus, bstatus, abpositive, abnegative;
1949             PPCODE:
1950 236           astatus = _validate_int(aTHX_ sva, 2);
1951 234           bstatus = _validate_int(aTHX_ svb, 2);
1952 233 100         if (astatus != 0 && bstatus != 0) {
    100          
1953 227 100         if (ix == 0) {
1954             /* Are both a and b positive? */
1955 171 100         abpositive = astatus == 1 && bstatus == 1;
    100          
1956             /* Will both fit in IVs? We should use a bitmask return. */
1957 171           abnegative = !abpositive
1958 20 50         && (SvIOK(sva) && !SvIsUV(sva))
    100          
1959 191 100         && (SvIOK(svb) && !SvIsUV(svb));
    50          
    100          
1960 171 100         if (abpositive || abnegative) {
    100          
1961 169 100         UV a = my_svuv(sva);
1962 169 100         UV b = my_svuv(svb);
1963 169 100         int k = (abpositive) ? kronecker_uu(a,b) : kronecker_ss(a,b);
1964 169 50         RETURN_NPARITY(k);
    50          
1965             }
1966 56 100         } else if (ix == 1) {
1967 5 100         UV n = (astatus == -1) ? (UV)(-(my_sviv(sva))) : my_svuv(sva);
    50          
    50          
1968 5 50         UV k = (bstatus == -1) ? (UV)(-(my_sviv(svb))) : my_svuv(svb);
    0          
    50          
1969             /* valuation of 0-2 is very common, so return a constant if possible */
1970 5 50         RETURN_NPARITY( valuation(n, k) );
    50          
1971 51 100         } else if (ix == 2) {
1972 12           UV a, n, ret = 0;
1973 12 100         n = (bstatus != -1) ? my_svuv(svb) : (UV)(-(my_sviv(svb)));
    100          
    50          
1974 12 100         if (n > 0) {
1975 10 100         a = (astatus == 1) ? my_svuv(sva) : negmod(my_sviv(sva), n);
    50          
    50          
1976 10 100         if (a > 0) {
1977 9 100         if (n == 1) XSRETURN_UV(0);
1978 8           ret = modinverse(a, n);
1979             }
1980             }
1981 11 100         if (ret == 0) XSRETURN_UNDEF;
1982 7           XSRETURN_UV(ret);
1983 39 100         } else if (ix == 3) {
1984             UV a, n, s;
1985 12 50         n = (bstatus != -1) ? my_svuv(svb) : (UV)(-(my_sviv(svb)));
    50          
    0          
1986 12 100         a = (n == 0) ? 0 : (astatus != -1) ? my_svuv(sva) % n : negmod(my_sviv(sva), n);
    50          
    50          
    0          
1987 12 100         if (is_prob_prime(n)) {
1988 5 50         if (!sqrtmod(&s, a, n)) XSRETURN_UNDEF;
1989             } else {
1990 7 100         if (!sqrtmod_composite(&s, a, n)) XSRETURN_UNDEF;
1991             }
1992 12           XSRETURN_UV(s);
1993             } else {
1994             UV a, n;
1995 27 100         n = (bstatus != -1) ? my_svuv(svb) : (UV)(-(my_sviv(svb)));
    100          
    50          
1996 27 100         a = (n == 0) ? 0 : (astatus != -1) ? my_svuv(sva) % n : negmod(my_sviv(sva), n);
    50          
    50          
    0          
1997 27 50         RETURN_NPARITY( is_primitive_root(a,n,0) );
    50          
1998             }
1999             }
2000 8           switch (ix) {
2001 5           case 0: _vcallsub_with_gmp(0.17,"kronecker"); break;
2002 2           case 1: _vcallsub_with_gmp(0.20,"valuation"); break;
2003 0           case 2: _vcallsub_with_gmp(0.20,"invmod"); break;
2004 1           case 3: _vcallsub_with_gmp(0.36,"sqrtmod"); break;
2005             case 4:
2006 0           default: _vcallsub_with_gmp(0.36,"is_primitive_root"); break;
2007             }
2008 8           return; /* skip implicit PUTBACK */
2009              
2010             void
2011             gcdext(IN SV* sva, IN SV* svb)
2012             PREINIT:
2013             int astatus, bstatus;
2014             PPCODE:
2015 14           astatus = _validate_int(aTHX_ sva, 2);
2016 14           bstatus = _validate_int(aTHX_ svb, 2);
2017             /* TODO: These should be built into validate_int */
2018 14 100         if ( (astatus == 1 && SvIsUV(sva)) || (astatus == -1 && !SvIOK(sva)) )
    100          
    100          
    50          
2019 1           astatus = 0; /* too large */
2020 14 100         if ( (bstatus == 1 && SvIsUV(svb)) || (bstatus == -1 && !SvIOK(svb)) )
    50          
    100          
    50          
2021 0           bstatus = 0; /* too large */
2022 26 100         if (astatus != 0 && bstatus != 0) {
    50          
2023             IV u, v, d;
2024 12 50         IV a = my_sviv(sva);
2025 12 50         IV b = my_sviv(svb);
2026 12           d = gcdext(a, b, &u, &v, 0, 0);
2027 12 50         XPUSHs(sv_2mortal(newSViv( u )));
2028 12 50         XPUSHs(sv_2mortal(newSViv( v )));
2029 12 50         XPUSHs(sv_2mortal(newSViv( d )));
2030             } else {
2031 2 50         _vcallsubn(aTHX_ GIMME_V, VCALL_PP, "gcdext", items, 0);
2032 2           return; /* skip implicit PUTBACK */
2033             }
2034              
2035             void
2036             stirling(IN UV n, IN UV m, IN UV type = 1)
2037             PPCODE:
2038 1543 100         if (type != 1 && type != 2 && type != 3)
    100          
    100          
2039 1           croak("stirling type must be 1, 2, or 3");
2040 1542 100         if (n == m)
2041 63           XSRETURN_UV(1);
2042 1479 100         else if (n == 0 || m == 0 || m > n)
    100          
    100          
2043 124           XSRETURN_UV(0);
2044 1355 100         else if (type == 3) {
2045 190           UV s = stirling3(n, m);
2046 190 100         if (s != 0) XSRETURN_UV(s);
2047 1165 100         } else if (type == 2) {
2048 973           IV s = stirling2(n, m);
2049 973 100         if (s != 0) XSRETURN_IV(s);
2050 192 50         } else if (type == 1) {
2051 192           IV s = stirling1(n, m);
2052 192 100         if (s != 0) XSRETURN_IV(s);
2053             }
2054 516           _vcallsub_with_gmpobj(0.26,"stirling");
2055 516 100         OBJECTIFY_RESULT(ST(0), ST(0));
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2056 516           return;
2057              
2058             NV
2059             _XS_ExponentialIntegral(IN SV* x)
2060             ALIAS:
2061             _XS_LogarithmicIntegral = 1
2062             _XS_RiemannZeta = 2
2063             _XS_RiemannR = 3
2064             _XS_LambertW = 4
2065             PREINIT:
2066             NV nv, ret;
2067             CODE:
2068 64 100         nv = SvNV(x);
2069 64           switch (ix) {
2070 18           case 0: ret = Ei(nv); break;
2071 22           case 1: ret = Li(nv); break;
2072 6           case 2: ret = (NV) ld_riemann_zeta(nv); break;
2073 9           case 3: ret = (NV) RiemannR(nv); break;
2074             case 4:
2075 9           default:ret = lambertw(nv); break;
2076             }
2077 64           RETVAL = ret;
2078             OUTPUT:
2079             RETVAL
2080              
2081             void
2082             euler_phi(IN SV* svlo, IN SV* svhi = 0)
2083             ALIAS:
2084             moebius = 1
2085             PREINIT:
2086             int lostatus, histatus;
2087             PPCODE:
2088 28191           lostatus = _validate_int(aTHX_ svlo, 2);
2089 28191 100         histatus = (svhi == 0 || _validate_int(aTHX_ svhi, 1));
    100          
2090 28191 100         if (svhi == 0 && lostatus != 0) {
    100          
2091             /* input is a single value and in UV/IV range */
2092 28144 100         if (ix == 0) {
2093 74 100         UV ret = (lostatus == -1) ? 0 : totient(my_svuv(svlo));
    50          
2094 74           XSRETURN_UV(ret);
2095             } else {
2096 28070 100         UV n = (lostatus == -1) ? (UV)(-(my_sviv(svlo))) : my_svuv(svlo);
    50          
    50          
2097 28070 50         RETURN_NPARITY(moebius(n));
    50          
2098             }
2099 79 100         } else if (items == 2 && lostatus == 1 && histatus == 1) {
    100          
    100          
2100             /* input is a range and both lo and hi are non-negative */
2101 32 50         UV lo = my_svuv(svlo);
2102 32 50         UV hi = my_svuv(svhi);
2103 32 100         if (lo <= hi) {
2104 31           UV i, count = hi - lo + 1;
2105 31 50         EXTEND(SP, (IV)count);
    100          
2106 31 100         if (ix == 0) {
2107 8 100         UV arrlo = (lo < 100) ? 0 : lo;
2108 8           UV *totients = range_totient(arrlo, hi);
2109 294 100         for (i = 0; i < count; i++)
2110 286           PUSHs(sv_2mortal(newSVuv(totients[i+lo-arrlo])));
2111 8           Safefree(totients);
2112             } else {
2113 23           signed char* mu = range_moebius(lo, hi);
2114             dMY_CXT;
2115 27909 100         for (i = 0; i < count; i++)
2116 27886 50         PUSH_NPARITY(mu[i]);
    50          
2117 23           Safefree(mu);
2118             }
2119             }
2120             } else {
2121             /* Whatever we didn't handle above */
2122 15 50         U32 gimme_v = GIMME_V;
2123 15           I32 flags = VCALL_PP;
2124 15 100         if (ix == 1 && lostatus == 1 && histatus == 1) flags |= VCALL_GMP;
    50          
    0          
2125 15 100         switch (ix) {
2126 3           case 0: _vcallsubn(aTHX_ gimme_v, flags, "euler_phi", items, 22);break;
2127             case 1:
2128 12           default: _vcallsubn(aTHX_ gimme_v, flags, "moebius", items, 22); break;
2129             }
2130 15           return;
2131             }
2132              
2133             void
2134             carmichael_lambda(IN SV* svn)
2135             ALIAS:
2136             mertens = 1
2137             liouville = 2
2138             chebyshev_theta = 3
2139             chebyshev_psi = 4
2140             factorial = 5
2141             sqrtint = 6
2142             exp_mangoldt = 7
2143             znprimroot = 8
2144             hammingweight = 9
2145             hclassno = 10
2146             is_pillai = 11
2147             ramanujan_tau = 12
2148             PREINIT:
2149             int status;
2150             PPCODE:
2151 2587           status = _validate_int(aTHX_ svn, (ix >= 7) ? 1 : 0);
2152 2587 100         if (status != 0) {
2153 2580 100         UV r, n = my_svuv(svn);
2154 2580           switch (ix) {
2155 210           case 0: XSRETURN_UV(carmichael_lambda(n)); break;
2156 45           case 1: XSRETURN_IV(mertens(n)); break;
2157             case 2: { UV factors[MPU_MAX_FACTORS+1];
2158 60 100         int nfactors = factor(my_svuv(svn), factors);
2159 60 100         RETURN_NPARITY( (nfactors & 1) ? -1 : 1 ); }
    50          
    50          
2160             break;
2161 9           case 3: XSRETURN_NV(chebyshev_theta(n)); break;
2162 9           case 4: XSRETURN_NV(chebyshev_psi(n)); break;
2163 980           case 5: r = factorial(n);
2164 980 100         if (r != 0) XSRETURN_UV(r);
2165 302           status = 0; break;
2166 114           case 6: XSRETURN_UV(isqrt(n)); break;
2167 21 100         case 7: XSRETURN_UV( (status == -1) ? 1 : exp_mangoldt(n) ); break;
2168 25 100         case 8: if (status == -1) n = -(IV)n;
2169 25           r = znprimroot(n);
2170 25 100         if (r == 0 && n != 1) XSRETURN_UNDEF; /* No root */
    100          
2171 21           XSRETURN_UV(r); break;
2172 7 100         case 9: if (status == -1) n = -(IV)n;
2173 7           XSRETURN_UV(popcnt(n)); break;
2174 97 100         case 10: XSRETURN_IV( (status == -1) ? 0 : hclassno(n) ); break;
2175 993 50         case 11: RETURN_NPARITY( (status == -1) ? 0 : pillai_v(n) ); break;
    50          
    100          
2176             case 12:
2177 10 50         default: { IV tau = (status == 1) ? ramanujan_tau(n) : 0;
2178 10 100         if (tau != 0 || status == -1 || n == 0)
    50          
    100          
2179 6           XSRETURN_IV(tau);
2180             } /* Fall through if n > 0 and we got 0 back */
2181 4           break;
2182             }
2183             }
2184 313           switch (ix) {
2185 2           case 0: _vcallsub_with_gmp(0.22,"carmichael_lambda"); break;
2186 0           case 1: _vcallsub_with_pp("mertens"); break;
2187 2           case 2: _vcallsub_with_gmp(0.22,"liouville"); break;
2188 0           case 3: _vcallsub_with_pp("chebyshev_theta"); break;
2189 0           case 4: _vcallsub_with_pp("chebyshev_psi"); break;
2190 302           case 5: _vcallsub_with_pp("factorial"); break;
2191 0           case 6: _vcallsub_with_pp("sqrtint"); break;
2192 0           case 7: _vcallsub_with_gmp(0.19,"exp_mangoldt"); break;
2193 1           case 8: _vcallsub_with_gmp(0.22,"znprimroot"); break;
2194 2 50         case 9: if (_XS_get_callgmp() >= 47) { /* Very fast */
2195 0           _vcallsub_with_gmp(0.47,"hammingweight");
2196             } else { /* Better than PP */
2197 2 50         char* ptr; STRLEN len; ptr = SvPV(svn, len);
2198 2           XSRETURN_UV(mpu_popcount_string(ptr, len));
2199             }
2200 0           break;
2201 0           case 10: _vcallsub_with_pp("hclassno"); break;
2202 0           case 11: _vcallsub_with_gmp(0.00,"is_pillai"); break;
2203             case 12:
2204 4           default: _vcallsub_with_pp("ramanujan_tau"); break;
2205             }
2206 311           return; /* skip implicit PUTBACK */
2207              
2208             void
2209             numtoperm(IN UV n, IN SV* svk)
2210             PREINIT:
2211             UV k;
2212             int i, S[32];
2213             PPCODE:
2214 6 100         if (n == 0)
2215 1           XSRETURN_EMPTY;
2216 5 50         if (n < 32 && _validate_int(aTHX_ svk, 1) == 1) {
    50          
2217 5 50         k = my_svuv(svk);
2218 5 50         if (num_to_perm(k, n, S)) {
2219             dMY_CXT;
2220 5 50         EXTEND(SP, (IV)n);
    50          
2221 50 100         for (i = 0; i < (int)n; i++)
2222 45 50         PUSH_NPARITY( S[i] );
    50          
2223 5           XSRETURN(n);
2224             }
2225             }
2226 0 0         _vcallsubn(aTHX_ GIMME_V, VCALL_PP|VCALL_GMP, "numtoperm", items, 47);
2227 6           return;
2228              
2229             void
2230             permtonum(IN SV* svp)
2231             PREINIT:
2232             AV *av;
2233             UV val, num;
2234             int plen, i;
2235             PPCODE:
2236 6 50         if ((!SvROK(svp)) || (SvTYPE(SvRV(svp)) != SVt_PVAV))
    50          
2237 0           croak("permtonum argument must be an array reference");
2238 6           av = (AV*) SvRV(svp);
2239 6           plen = av_len(av);
2240 6 50         if (plen < 32) {
2241 6           int V[32], A[32] = {0};
2242 74 100         for (i = 0; i <= plen; i++) {
2243 68           SV **iv = av_fetch(av, i, 0);
2244 68 50         if (iv == 0 || _validate_int(aTHX_ *iv, 1) != 1) break;
    50          
2245 68 50         val = my_svuv(*iv);
2246 68 50         if (val > (UV)plen || A[val] != 0) break;
    50          
2247 68           A[val] = i+1;
2248 68           V[i] = val;
2249             }
2250 6 50         if (i > plen && perm_to_num(plen+1, V, &num))
    100          
2251 6           XSRETURN_UV(num);
2252             }
2253 2           _vcallsub_with_gmpobj(0.47,"permtonum");
2254 2 100         OBJECTIFY_RESULT(ST(0), ST(0));
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2255 6           XSRETURN(1);
2256              
2257             void
2258             randperm(IN UV n, IN UV k = 0)
2259             PREINIT:
2260             UV i, *S;
2261             dMY_CXT;
2262             PPCODE:
2263 4 100         if (items == 1) k = n;
2264 4 50         if (k > n) k = n;
2265 4 100         if (k == 0) XSRETURN_EMPTY;
2266 3 50         New(0, S, k, UV);
2267 3           randperm(MY_CXT.randcxt, n, k, S);
2268 3 50         EXTEND(SP, (IV)k);
    50          
2269 108 100         for (i = 0; i < k; i++) {
2270 105 50         if (n < 2*CINTS) PUSH_NPARITY(S[i]);
    50          
    50          
2271 0           else PUSHs(sv_2mortal(newSVuv(S[i])));
2272             }
2273 3           Safefree(S);
2274              
2275             void shuffle(...)
2276             PROTOTYPE: @
2277             PREINIT:
2278             int i, j;
2279             void* randcxt;
2280             dMY_CXT;
2281             PPCODE:
2282 3 100         if (items == 0)
2283 1           XSRETURN_EMPTY;
2284 101 100         for (i = 0, randcxt = MY_CXT.randcxt; i < items-1; i++) {
2285 99           j = urandomm32(randcxt, items-i);
2286 99           { SV* t = ST(i); ST(i) = ST(i+j); ST(i+j) = t; }
2287             }
2288 2           XSRETURN(items);
2289              
2290             void
2291             sumdigits(SV* svn, UV ibase = 255)
2292             PREINIT:
2293             UV base, sum;
2294             STRLEN i, len;
2295             const char* s;
2296             PPCODE:
2297 1007 50         base = (ibase == 255) ? 10 : ibase;
2298 1007 50         if (base < 2 || base > 36) croak("sumdigits: invalid base %"UVuf, base);
    50          
2299 1007           sum = 0;
2300             /* faster for integer input in base 10 */
2301 1007 50         if (base == 10 && SVNUMTEST(svn) && (SvIsUV(svn) || SvIVX(svn) >= 0)) {
    100          
    50          
    50          
2302 1001 50         UV n, t = my_svuv(svn);
2303 3894 100         while ((n=t)) {
2304 2893           t = n / base;
2305 2893           sum += n - base*t;
2306             }
2307 1001           XSRETURN_UV(sum);
2308             }
2309 6 100         s = SvPV(svn, len);
2310             /* If no base given and input is 0x... or 0b..., select base. */
2311 6 50         if (ibase == 255 && len > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'b')){
    50          
    100          
    50          
    0          
2312 1 50         base = (s[1] == 'x') ? 16 : 2;
2313 1           s += 2;
2314 1           len -= 2;
2315             }
2316 38640 100         for (i = 0; i < len; i++) {
2317 38634           UV d = 0;
2318 38634           const char c = s[i];
2319 38634 100         if (c >= '0' && c <= '9') { d = c - '0'; }
    100          
2320 5 100         else if (c >= 'a' && c <= 'z') { d = c - 'a' + 10; }
    50          
2321 4 100         else if (c >= 'A' && c <= 'Z') { d = c - 'A' + 10; }
    50          
2322 38634 50         if (d < base)
2323 38634           sum += d;
2324             }
2325 1007           XSRETURN_UV(sum);
2326              
2327             void todigits(SV* svn, int base=10, int length=-1)
2328             ALIAS:
2329             todigitstring = 1
2330             fromdigits = 2
2331             PREINIT:
2332             int i, status;
2333             UV n;
2334             char *str;
2335             PPCODE:
2336 38 50         if (base < 2) croak("invalid base: %d", base);
2337 38           status = 0;
2338 38 100         if (ix == 0 || ix == 1) {
    100          
2339 19           status = _validate_int(aTHX_ svn, 1);
2340 19 100         n = (status == 0) ? 0 : status * my_svuv(svn);
    50          
2341             }
2342             /* todigits with native input */
2343 38 100         if (ix == 0 && status != 0 && length < 128) {
    100          
    50          
2344             int digits[128];
2345 14           IV len = to_digit_array(digits, n, base, length);
2346 14 50         if (len >= 0) {
2347             dMY_CXT;
2348 14 50         EXTEND(SP, len);
    50          
2349 103 100         for (i = 0; i < len; i++)
2350 89 50         PUSH_NPARITY( digits[len-i-1] );
    50          
2351 14           XSRETURN(len);
2352             }
2353             }
2354             /* todigitstring with native input */
2355 24 100         if (ix == 1 && status != 0 && length < 128) {
    50          
    50          
2356             char s[128+1];
2357 3           IV len = to_digit_string(s, n, base, length);
2358 3 50         if (len >= 0) {
2359 3 50         XPUSHs(sv_2mortal(newSVpv(s, len)));
2360 3           XSRETURN(1);
2361             }
2362             }
2363             /* todigits or todigitstring base 10 (large size) */
2364 21 100         if ((ix == 0 || ix == 1) && base == 10 && length < 0) {
    50          
    100          
    50          
2365             STRLEN len;
2366 1 50         str = SvPV(svn, len);
2367 1 50         if (ix == 1) {
2368 0 0         XPUSHs(sv_2mortal(newSVpv(str, len)));
2369 0           XSRETURN(1);
2370             }
2371 1 50         if (len == 1 && str[0] == '0') XSRETURN(0);
    0          
2372             {
2373             dMY_CXT;
2374 1 50         EXTEND(SP, (IV)len);
    50          
2375 46 100         for (i = 0; i < (int)len; i++)
2376 45 50         PUSH_NPARITY(str[i]-'0');
    50          
2377             }
2378 1           XSRETURN(len);
2379             }
2380 20 100         if (ix == 2) { /* fromdigits */
2381 19 100         if (!SvROK(svn)) { /* string */
2382 6 50         if (from_digit_string(&n, SvPV_nolen(svn), base)) {
    100          
2383 5           XSRETURN_UV(n);
2384             }
2385 13 50         } else if (!_is_sv_bigint(aTHX_ svn)) { /* array ref of digits */
2386 13           UV* r = 0;
2387 13           int len = arrayref_to_int_array(aTHX_ &r, (AV*) SvRV(svn), base);
2388 13 50         if (from_digit_to_UV(&n, r, len, base)) {
2389 13           Safefree(r);
2390 13           XSRETURN_UV(n);
2391 0 0         } else if (from_digit_to_str(&str, r, len, base)){
2392 0           Safefree(r);
2393 0 0         XPUSHs( sv_to_bigint(aTHX_ sv_2mortal(newSVpv(str,0))) );
2394 0           Safefree(str);
2395 0           XSRETURN(1);
2396             }
2397 0           Safefree(r);
2398             }
2399             }
2400 2           switch (ix) {
2401 1 50         case 0: _vcallsubn(aTHX_ GIMME_V, VCALL_GMP|VCALL_PP, "todigits", items, 41); break;
2402 0           case 1: _vcallsub_with_gmp(0.00,"todigitstring"); break;
2403             case 2:
2404 1           default: _vcallsub_with_gmp(0.00,"fromdigits"); break;
2405             }
2406 38           return;
2407              
2408             bool
2409             _validate_num(SV* svn, ...)
2410             PREINIT:
2411             SV* sv1;
2412             SV* sv2;
2413             CODE:
2414             /* Internal function. Emulate the PP version of this:
2415             * $is_valid = _validate_num( $n [, $min [, $max] ] )
2416             * Return 0 if we're befuddled by the input.
2417             * Otherwise croak if n isn't >= 0 and integer, n < min, or n > max.
2418             * Small bigints will be converted to scalars.
2419             */
2420 2041           RETVAL = FALSE;
2421 2041 100         if (_validate_int(aTHX_ svn, 0)) {
2422 1924 100         if (SvROK(svn)) { /* Convert small Math::BigInt object into scalar */
2423 78 50         UV n = my_svuv(svn);
2424             #if PERL_REVISION <= 5 && PERL_VERSION < 8 && BITS_PER_WORD == 64
2425             sv_setpviv(svn, n);
2426             #else
2427 78           sv_setuv(svn, n);
2428             #endif
2429             }
2430 1924 100         if (items > 1 && ((sv1 = ST(1)), SvOK(sv1))) {
    50          
    0          
    0          
    50          
2431 3 50         UV n = my_svuv(svn);
2432 3 50         UV min = my_svuv(sv1);
2433 3 50         if (n < min)
2434 0           croak("Parameter '%"UVuf"' must be >= %"UVuf, n, min);
2435 3 50         if (items > 2 && ((sv2 = ST(2)), SvOK(sv2))) {
    0          
    0          
    0          
    0          
2436 0 0         UV max = my_svuv(sv2);
2437 0 0         if (n > max)
2438 0           croak("Parameter '%"UVuf"' must be <= %"UVuf, n, max);
2439 0 0         MPUassert( items <= 3, "_validate_num takes at most 3 parameters");
2440             }
2441             }
2442 1924           RETVAL = TRUE;
2443             }
2444             OUTPUT:
2445             RETVAL
2446              
2447             void
2448             lastfor()
2449             PREINIT:
2450             dMY_CXT;
2451             PPCODE:
2452             /* printf("last for with count = %u\n", MY_CXT.forcount); */
2453 90 50         if (MY_CXT.forcount == 0) croak("lastfor called outside a loop");
2454 90           MY_CXT.forexit = 1;
2455             /* In some ideal world this would also act like a last */
2456 90           return;
2457              
2458             #define START_FORCOUNT \
2459             do { \
2460             oldforloop = ++MY_CXT.forcount; \
2461             oldforexit = MY_CXT.forexit; \
2462             forexit = &MY_CXT.forexit; \
2463             *forexit = 0; \
2464             } while(0)
2465              
2466             #define CHECK_FORCOUNT \
2467             if (*forexit) break;
2468              
2469             #define END_FORCOUNT \
2470             do { \
2471             /* Put back outer loop's exit request, if any. */ \
2472             *forexit = oldforexit; \
2473             /* Ensure loops are nested and not woven. */ \
2474             if (MY_CXT.forcount-- != oldforloop) croak("for loop mismatch"); \
2475             } while (0)
2476              
2477             #define DECL_FORCOUNT \
2478             uint16_t oldforloop; \
2479             char oldforexit; \
2480             char *forexit
2481              
2482             void
2483             forprimes (SV* block, IN SV* svbeg, IN SV* svend = 0)
2484             PROTOTYPE: &$;$
2485             PREINIT:
2486             GV *gv;
2487             HV *stash;
2488             SV* svarg;
2489             CV *cv;
2490             unsigned char* segment;
2491             UV beg, end, seg_base, seg_low, seg_high;
2492             DECL_FORCOUNT;
2493             dMY_CXT;
2494             PPCODE:
2495 73           cv = sv_2cv(block, &stash, &gv, 0);
2496 73 50         if (cv == Nullcv)
2497 0           croak("Not a subroutine reference");
2498              
2499 73 50         if (!_validate_int(aTHX_ svbeg, 0) || (items >= 3 && !_validate_int(aTHX_ svend,0))) {
    100          
    50          
2500 0           _vcallsubn(aTHX_ G_VOID|G_DISCARD, VCALL_ROOT, "_generic_forprimes", items, 0);
2501 0           return;
2502             }
2503              
2504 65 100         if (items < 3) {
2505 37           beg = 2;
2506 37 50         end = my_svuv(svbeg);
2507             } else {
2508 28 50         beg = my_svuv(svbeg);
2509 28 50         end = my_svuv(svend);
2510             }
2511              
2512 65           START_FORCOUNT;
2513 65           SAVESPTR(GvSV(PL_defgv));
2514 65           svarg = newSVuv(beg);
2515 65           GvSV(PL_defgv) = svarg;
2516             /* Handle early part */
2517 187 100         while (beg < 6) {
2518 123 100         beg = (beg <= 2) ? 2 : (beg <= 3) ? 3 : 5;
    100          
2519 123 100         if (beg <= end) {
2520 116           sv_setuv(svarg, beg);
2521 116 50         PUSHMARK(SP);
2522 116           call_sv((SV*)cv, G_VOID|G_DISCARD);
2523 116 100         CHECK_FORCOUNT;
2524             }
2525 122 100         beg += 1 + (beg > 2);
2526             }
2527             #if USE_MULTICALL
2528 123 50         if (!CvISXSUB(cv) && beg <= end) {
    100          
2529             dMULTICALL;
2530 58           I32 gimme = G_VOID;
2531 58 50         PUSH_MULTICALL(cv);
    50          
2532 89 50         if (
2533             #if BITS_PER_WORD == 64
2534 58 0         (beg >= UVCONST( 100000000000000) && end-beg < 100000) ||
    50          
2535 58 0         (beg >= UVCONST( 10000000000000) && end-beg < 40000) ||
    50          
2536 58 0         (beg >= UVCONST( 1000000000000) && end-beg < 17000) ||
    100          
2537             #endif
2538 58           ((end-beg) < 500) ) { /* MULTICALL next prime */
2539 171 100         for (beg = next_prime(beg-1); beg <= end && beg != 0; beg = next_prime(beg)) {
    50          
2540 141 100         CHECK_FORCOUNT;
2541 140           sv_setuv(svarg, beg);
2542 140           { ENTER; MULTICALL; LEAVE; }
2543             }
2544             } else { /* MULTICALL segment sieve */
2545 27           void* ctx = start_segment_primes(beg, end, &segment);
2546 29 100         while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) {
2547 27 50         int crossuv = (seg_high > IV_MAX) && !SvIsUV(svarg);
    0          
2548 1310 50         START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_base, seg_low, seg_high )
    100          
    100          
    100          
    100          
2549 1261 100         CHECK_FORCOUNT;
2550             /* sv_setuv(svarg, p); */
2551 1147 100         if (SvTYPE(svarg) != SVt_IV) { sv_setuv(svarg, p); }
2552 982 50         else if (crossuv && p > IV_MAX) { sv_setuv(svarg, p); crossuv=0; }
    0          
2553 982           else { SvUV_set(svarg, p); }
2554 1147           { ENTER; MULTICALL; LEAVE; }
2555 133           END_DO_FOR_EACH_SIEVE_PRIME
2556 27 100         CHECK_FORCOUNT;
2557             }
2558 27           end_segment_primes(ctx);
2559             }
2560             FIX_MULTICALL_REFCOUNT;
2561 58 50         POP_MULTICALL;
    50          
2562             }
2563             else
2564             #endif
2565 7 50         if (beg <= end) { /* NO-MULTICALL segment sieve */
2566 0           void* ctx = start_segment_primes(beg, end, &segment);
2567 0 0         while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) {
2568 0 0         START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_base, seg_low, seg_high )
    0          
    0          
    0          
    0          
2569 0 0         CHECK_FORCOUNT;
2570 0           sv_setuv(svarg, p);
2571 0 0         PUSHMARK(SP);
2572 0           call_sv((SV*)cv, G_VOID|G_DISCARD);
2573 0           END_DO_FOR_EACH_SIEVE_PRIME
2574 0 0         CHECK_FORCOUNT;
2575             }
2576 0           end_segment_primes(ctx);
2577             }
2578 65           SvREFCNT_dec(svarg);
2579 65 50         END_FORCOUNT;
2580              
2581             #define FORCOMPTEST(ix,n) \
2582             ( (ix==1) || (ix==0 && n&1) )
2583              
2584             void
2585             foroddcomposites (SV* block, IN SV* svbeg, IN SV* svend = 0)
2586             ALIAS:
2587             forcomposites = 1
2588             PROTOTYPE: &$;$
2589             PREINIT:
2590             UV beg, end;
2591             GV *gv;
2592             HV *stash;
2593             SV* svarg; /* We use svarg to prevent clobbering $_ outside the block */
2594             CV *cv;
2595             DECL_FORCOUNT;
2596             dMY_CXT;
2597             PPCODE:
2598 59           cv = sv_2cv(block, &stash, &gv, 0);
2599 59 50         if (cv == Nullcv)
2600 0           croak("Not a subroutine reference");
2601              
2602 59 50         if (!_validate_int(aTHX_ svbeg, 0) || (items >= 3 && !_validate_int(aTHX_ svend,0))) {
    100          
    50          
2603 0 0         _vcallsubn(aTHX_ G_VOID|G_DISCARD, VCALL_ROOT,
2604             (ix == 0) ? "_generic_foroddcomposites"
2605             : "_generic_forcomposites", items, 0);
2606 0           return;
2607             }
2608              
2609 59 100         if (items < 3) {
2610 57 100         beg = ix ? 4 : 9;
2611 57 50         end = my_svuv(svbeg);
2612             } else {
2613 2 50         beg = my_svuv(svbeg);
2614 2 50         end = my_svuv(svend);
2615             }
2616              
2617 59           START_FORCOUNT;
2618 59           SAVESPTR(GvSV(PL_defgv));
2619 59           svarg = newSVuv(0);
2620 59           GvSV(PL_defgv) = svarg;
2621             #if USE_MULTICALL
2622 116 50         if (!CvISXSUB(cv) && end >= beg) {
    100          
2623             unsigned char* segment;
2624             UV seg_base, seg_low, seg_high, c, cbeg, cend, cinc, prevprime, nextprime;
2625             void* ctx;
2626             dMULTICALL;
2627 57           I32 gimme = G_VOID;
2628 57 50         PUSH_MULTICALL(cv);
    50          
2629 112 50         if (beg >= MPU_MAX_PRIME ||
    50          
2630             #if BITS_PER_WORD == 64
2631 57 0         (beg >= UVCONST( 100000000000000) && end-beg < 120000) ||
    50          
2632 57 0         (beg >= UVCONST( 10000000000000) && end-beg < 50000) ||
    50          
2633 57 0         (beg >= UVCONST( 1000000000000) && end-beg < 20000) ||
    100          
2634             #endif
2635 57           end-beg < 1000 ) {
2636 55 100         beg = (beg <= 4) ? 3 : beg-1;
2637 55           nextprime = next_prime(beg);
2638 3933 100         while (beg++ < end) {
2639 3928 100         if (beg == nextprime)
2640 907           nextprime = next_prime(beg);
2641 3021 100         else if (FORCOMPTEST(ix,beg)) {
    50          
    100          
2642 1716           sv_setuv(svarg, beg);
2643 1716           { ENTER; MULTICALL; LEAVE; }
2644             }
2645 3928 100         CHECK_FORCOUNT;
2646             }
2647             } else {
2648 2 100         if (!ix) {
2649 1 50         if (beg < 8) beg = 8;
2650 1 50         } else if (beg <= 4) { /* sieve starts at 7, so handle this here */
2651 1           sv_setuv(svarg, 4);
2652 1           { ENTER; MULTICALL; LEAVE; }
2653 1           beg = 6;
2654             }
2655             /* Find the two primes that bound their interval. */
2656             /* beg must be < max_prime, and end >= max_prime is special. */
2657 2           prevprime = prev_prime(beg);
2658 2 50         nextprime = (end >= MPU_MAX_PRIME) ? MPU_MAX_PRIME : next_prime(end);
2659 2           ctx = start_segment_primes(beg, nextprime, &segment);
2660 4 100         while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) {
2661 2 50         int crossuv = (seg_high > IV_MAX) && !SvIsUV(svarg);
    0          
2662 9083 50         START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_base, seg_low, seg_high )
    100          
    100          
    100          
    100          
2663 8726           cbeg = prevprime+1;
2664 8726 100         if (cbeg < beg)
2665 1 50         cbeg = beg - (ix == 0 && (beg % 2));
    50          
2666 8726           prevprime = p;
2667 8726 100         cend = prevprime-1; if (cend > end) cend = end;
2668             /* If ix=0, skip evens by starting 1 farther and skipping by 2 */
2669 8726 100         cinc = 1 + (ix==0);
2670 36294 100         for (c = cbeg + (ix==0); c <= cend; c += cinc) {
2671 29528 100         CHECK_FORCOUNT;
2672 27568 50         if (SvTYPE(svarg) != SVt_IV) { sv_setuv(svarg,c); }
2673 27568 50         else if (crossuv && c > IV_MAX) { sv_setuv(svarg,c); crossuv=0;}
    0          
2674 27568           else { SvUV_set(svarg,c); }
2675 27568           { ENTER; MULTICALL; LEAVE; }
2676             }
2677 354           END_DO_FOR_EACH_SIEVE_PRIME
2678             }
2679 2           end_segment_primes(ctx);
2680 2 50         if (end > nextprime) /* Complete the case where end > max_prime */
2681 0 0         while (nextprime++ < end)
2682 0 0         if (FORCOMPTEST(ix,nextprime)) {
    0          
    0          
2683 0 0         CHECK_FORCOUNT;
2684 0           sv_setuv(svarg, nextprime);
2685 0           { ENTER; MULTICALL; LEAVE; }
2686             }
2687             }
2688             FIX_MULTICALL_REFCOUNT;
2689 57 50         POP_MULTICALL;
    50          
2690             }
2691             else
2692             #endif
2693 2 50         if (beg <= end) {
2694 0 0         beg = (beg <= 4) ? 3 : beg-1;
2695 0 0         while (beg++ < end) {
2696 0 0         if (FORCOMPTEST(ix,beg) && !is_prob_prime(beg)) {
    0          
    0          
    0          
2697 0           sv_setuv(svarg, beg);
2698 0 0         PUSHMARK(SP);
2699 0           call_sv((SV*)cv, G_VOID|G_DISCARD);
2700 0 0         CHECK_FORCOUNT;
2701             }
2702             }
2703             }
2704 59           SvREFCNT_dec(svarg);
2705 59 50         END_FORCOUNT;
2706              
2707             void
2708             forsemiprimes (SV* block, IN SV* svbeg, IN SV* svend = 0)
2709             PROTOTYPE: &$;$
2710             PREINIT:
2711             UV beg, end;
2712             GV *gv;
2713             HV *stash;
2714             SV* svarg; /* We use svarg to prevent clobbering $_ outside the block */
2715             CV *cv;
2716             DECL_FORCOUNT;
2717             dMY_CXT;
2718             PPCODE:
2719 2           cv = sv_2cv(block, &stash, &gv, 0);
2720 2 50         if (cv == Nullcv)
2721 0           croak("Not a subroutine reference");
2722              
2723 2 50         if (!_validate_int(aTHX_ svbeg, 0) || (items >= 3 && !_validate_int(aTHX_ svend,0))) {
    100          
    50          
2724 0           _vcallsubn(aTHX_ G_VOID|G_DISCARD, VCALL_ROOT, "_generic_forsemiprimes", items, 0);
2725 0           return;
2726             }
2727              
2728 2 100         if (items < 3) {
2729 1           beg = 4;
2730 1 50         end = my_svuv(svbeg);
2731             } else {
2732 1 50         beg = my_svuv(svbeg);
2733 1 50         end = my_svuv(svend);
2734             }
2735 2 50         if (beg < 4) beg = 4;
2736 2 50         if (end > MPU_MAX_SEMI_PRIME) end = MPU_MAX_SEMI_PRIME;
2737              
2738 2           START_FORCOUNT;
2739 2           SAVESPTR(GvSV(PL_defgv));
2740 2           svarg = newSVuv(0);
2741 2           GvSV(PL_defgv) = svarg;
2742             #if USE_MULTICALL
2743 4 50         if (!CvISXSUB(cv) && end >= beg) {
    50          
2744             UV c, seg_beg, seg_end, *S, count;
2745             dMULTICALL;
2746 2           I32 gimme = G_VOID;
2747 2 50         PUSH_MULTICALL(cv);
    50          
2748 3 50         if (beg >= MPU_MAX_SEMI_PRIME ||
    50          
2749             #if BITS_PER_WORD == 64
2750 2 0         (beg >= UVCONST(10000000000000000000) && end-beg < 1400000) ||
    50          
2751 2 0         (beg >= UVCONST( 1000000000000000000) && end-beg < 950000) ||
    50          
2752 2 0         (beg >= UVCONST( 100000000000000000) && end-beg < 440000) ||
    50          
2753 2 0         (beg >= UVCONST( 10000000000000000) && end-beg < 240000) ||
    50          
2754 2 0         (beg >= UVCONST( 1000000000000000) && end-beg < 65000) ||
    50          
2755 2 0         (beg >= UVCONST( 100000000000000) && end-beg < 29000) ||
    50          
2756 2 0         (beg >= UVCONST( 10000000000000) && end-beg < 11000) ||
    50          
2757 2 0         (beg >= UVCONST( 1000000000000) && end-beg < 5000) ||
    100          
2758             #endif
2759 2           end-beg < 200 ) {
2760 1 50         beg = (beg <= 4) ? 3 : beg-1;
2761 22 100         while (beg++ < end) {
2762 21 100         if (is_semiprime(beg)) {
2763 3           sv_setuv(svarg, beg);
2764 3           { ENTER; MULTICALL; LEAVE; }
2765             }
2766 21 50         CHECK_FORCOUNT;
2767             }
2768             } else {
2769 2 100         while (beg < end) {
2770 1           seg_beg = beg;
2771 1           seg_end = end;
2772 1 50         if ((seg_end - seg_beg) > 50000000) seg_end = seg_beg + 50000000 - 1;
2773 1           count = range_semiprime_sieve(&S, seg_beg, seg_end);
2774 300 100         for (c = 0; c < count; c++) {
2775 299           sv_setuv(svarg, S[c]);
2776 299           { ENTER; MULTICALL; LEAVE; }
2777 299 50         CHECK_FORCOUNT;
2778             }
2779 1           Safefree(S);
2780 1           beg = seg_end+1;
2781 1 50         CHECK_FORCOUNT;
2782             }
2783             }
2784             FIX_MULTICALL_REFCOUNT;
2785 2 50         POP_MULTICALL;
    50          
2786             }
2787             else
2788             #endif
2789 0 0         if (beg <= end) {
2790 0 0         beg = (beg <= 4) ? 3 : beg-1;
2791 0 0         while (beg++ < end) {
2792 0 0         if (is_semiprime(beg)) {
2793 0           sv_setuv(svarg, beg);
2794 0 0         PUSHMARK(SP);
2795 0           call_sv((SV*)cv, G_VOID|G_DISCARD);
2796 0 0         CHECK_FORCOUNT;
2797             }
2798             }
2799             }
2800 2           SvREFCNT_dec(svarg);
2801 2 50         END_FORCOUNT;
2802              
2803             void
2804             fordivisors (SV* block, IN SV* svn)
2805             PROTOTYPE: &$
2806             PREINIT:
2807             UV i, n, ndivisors;
2808             UV *divs;
2809             GV *gv;
2810             HV *stash;
2811             SV* svarg; /* We use svarg to prevent clobbering $_ outside the block */
2812             CV *cv;
2813             DECL_FORCOUNT;
2814             dMY_CXT;
2815             PPCODE:
2816 71           cv = sv_2cv(block, &stash, &gv, 0);
2817 71 50         if (cv == Nullcv)
2818 0           croak("Not a subroutine reference");
2819              
2820 71 50         if (!_validate_int(aTHX_ svn, 0)) {
2821 0           _vcallsubn(aTHX_ G_VOID|G_DISCARD, VCALL_ROOT, "_generic_fordivisors", 2, 0);
2822 0           return;
2823             }
2824              
2825 71 50         n = my_svuv(svn);
2826 71           divs = _divisor_list(n, &ndivisors);
2827              
2828 71           START_FORCOUNT;
2829 71           SAVESPTR(GvSV(PL_defgv));
2830 71           svarg = newSVuv(0);
2831 71           GvSV(PL_defgv) = svarg;
2832             #if USE_MULTICALL
2833 71 50         if (!CvISXSUB(cv)) {
2834             dMULTICALL;
2835 71           I32 gimme = G_VOID;
2836 71 50         PUSH_MULTICALL(cv);
    50          
2837 336 100         for (i = 0; i < ndivisors; i++) {
2838 272           sv_setuv(svarg, divs[i]);
2839 272           { ENTER; MULTICALL; LEAVE; }
2840 272 100         CHECK_FORCOUNT;
2841             }
2842             FIX_MULTICALL_REFCOUNT;
2843 71 50         POP_MULTICALL;
    50          
2844             }
2845             else
2846             #endif
2847             {
2848 0 0         for (i = 0; i < ndivisors; i++) {
2849 0           sv_setuv(svarg, divs[i]);
2850 0 0         PUSHMARK(SP);
2851 0           call_sv((SV*)cv, G_VOID|G_DISCARD);
2852 0 0         CHECK_FORCOUNT;
2853             }
2854             }
2855 71           SvREFCNT_dec(svarg);
2856 71           Safefree(divs);
2857 71 50         END_FORCOUNT;
2858              
2859             void
2860             forpart (SV* block, IN SV* svn, IN SV* svh = 0)
2861             ALIAS:
2862             forcomp = 1
2863             PROTOTYPE: &$;$
2864             PREINIT:
2865             UV i, n, amin, amax, nmin, nmax;
2866             int primeq;
2867             GV *gv;
2868             HV *stash;
2869             CV *cv;
2870             SV** svals;
2871             DECL_FORCOUNT;
2872             dMY_CXT;
2873             PPCODE:
2874 34           cv = sv_2cv(block, &stash, &gv, 0);
2875 34 50         if (cv == Nullcv)
2876 0           croak("Not a subroutine reference");
2877 34 50         if (!_validate_int(aTHX_ svn, 0)) {
2878 0           _vcallsub_with_pp("forpart");
2879 0           return;
2880             }
2881 34 50         n = my_svuv(svn);
2882 34 50         if (n > (UV_MAX-2)) croak("forpart argument overflow");
2883              
2884 34 50         New(0, svals, n+1, SV*);
2885 707 100         for (i = 0; i <= n; i++) {
2886 673           svals[i] = newSVuv(i);
2887 673           SvREADONLY_on(svals[i]);
2888             }
2889              
2890 34           amin = 1; amax = n; nmin = 1; nmax = n; primeq = -1;
2891 34 100         if (svh != 0) {
2892             HV* rhash;
2893             SV** svp;
2894 16 50         if (!SvROK(svh) || SvTYPE(SvRV(svh)) != SVt_PVHV)
    50          
2895 0           croak("forpart second argument must be a hash reference");
2896 16           rhash = (HV*) SvRV(svh);
2897 16 100         if ((svp = hv_fetchs(rhash, "n", 0)) != NULL)
2898 8 50         { nmin = my_svuv(*svp); nmax = nmin; }
2899 16 100         if ((svp = hv_fetchs(rhash, "amin", 0)) != NULL) amin = my_svuv(*svp);
    50          
2900 16 100         if ((svp = hv_fetchs(rhash, "amax", 0)) != NULL) amax = my_svuv(*svp);
    50          
2901 16 100         if ((svp = hv_fetchs(rhash, "nmin", 0)) != NULL) nmin = my_svuv(*svp);
    50          
2902 16 100         if ((svp = hv_fetchs(rhash, "nmax", 0)) != NULL) nmax = my_svuv(*svp);
    50          
2903 16 100         if ((svp = hv_fetchs(rhash, "prime",0)) != NULL) primeq=my_svuv(*svp);
    50          
2904              
2905 16 50         if (amin < 1) amin = 1;
2906 16 50         if (amax > n) amax = n;
2907 16 50         if (nmin < 1) nmin = 1;
2908 16 50         if (nmax > n) nmax = n;
2909 16 100         if (primeq != 0 && primeq != -1) primeq = 2; /* -1, 0, or 2 */
    100          
2910             }
2911              
2912 34 100         if (primeq == 2) {
2913 2           UV prev = prev_prime(amax+1);
2914 2 100         UV next = amin <= 2 ? 2 : next_prime(amin-1);
2915 2 50         if (amin < next) amin = next;
2916 2 50         if (amax > prev) amax = prev;
2917             }
2918              
2919 34 100         if (n==0 && nmin <= 1) {
    50          
2920 2 50         { PUSHMARK(SP);
2921             /* Nothing */
2922 2           PUTBACK; call_sv((SV*)cv, G_VOID|G_DISCARD); SPAGAIN;
2923             }
2924             }
2925 34 100         if (n >= nmin && nmin <= nmax && amin <= amax && nmax > 0 && amax > 0)
    50          
    100          
    50          
    50          
2926             { /* RuleAsc algorithm from Kelleher and O'Sullivan 2009/2014) */
2927             UV *a, k, x, y, r;
2928 31 50         New(0, a, n+1, UV);
2929 31           k = 1;
2930 31           a[0] = amin-1;
2931 31           a[1] = n-amin+1;
2932 31           START_FORCOUNT;
2933 15860 100         while (k != 0) {
2934 15843           x = a[k-1]+1;
2935 15843           y = a[k]-1;
2936 15843           k--;
2937 15843 100         r = (ix == 0) ? x : 1;
2938 36217 100         while (r <= y) {
2939 20374           a[k++] = x;
2940 20374           x = r;
2941 20374           y -= x;
2942             }
2943 15843           a[k] = x + y;
2944              
2945             /* ------ length restrictions ------ */
2946 20391 100         while (k+1 > nmax) { /* Skip range if over max size */
2947 4548           a[k-1] += a[k];
2948 4548           k--;
2949             }
2950             /* Look into: quick skip over nmin range */
2951 15843 100         if (k+1 < nmin) { /* Skip if not over min size */
2952 3617 100         if (a[0] >= n-nmin+1 && a[k] > 1) break; /* early exit check */
    50          
2953 3608           continue;
2954             }
2955              
2956             /* ------ value restrictions ------ */
2957 12226 100         if (amin > 1 || amax < n) {
    100          
2958             /* Lexical order allows us to start at amin, and exit early */
2959 3452 100         if (a[0] > amax) break;
2960              
2961 3449 100         if (ix == 0) { /* value restrictions for partitions */
2962 3428 100         if (a[k] > amax) continue;
2963             } else { /* restrictions for compositions */
2964             /* TODO: maybe skip forward? */
2965 58 100         for (i = 0; i <= k; i++)
2966 51 100         if (a[i] < amin || a[i] > amax)
    100          
2967             break;
2968 21 100         if (i <= k) continue;
2969             }
2970             }
2971 11631 100         if (primeq != -1) {
2972 3791 100         for (i = 0; i <= k; i++) if (is_prime(a[i]) != primeq) break;
    100          
2973 2602 100         if (i <= k) continue;
2974             }
2975              
2976 9121 50         PUSHMARK(SP); EXTEND(SP, (IV)k);
    50          
    50          
2977 85120 100         for (i = 0; i <= k; i++) { PUSHs(svals[a[i]]); }
2978 9121           PUTBACK; call_sv((SV*)cv, G_VOID|G_DISCARD); SPAGAIN;
2979 9121 100         CHECK_FORCOUNT;
2980             }
2981 31           Safefree(a);
2982 31 50         END_FORCOUNT;
2983             }
2984 707 100         for (i = 0; i <= n; i++)
2985 673           SvREFCNT_dec(svals[i]);
2986 34           Safefree(svals);
2987              
2988             void
2989             forcomb (SV* block, IN SV* svn, IN SV* svk = 0)
2990             ALIAS:
2991             forperm = 1
2992             forderange = 2
2993             PROTOTYPE: &$;$
2994             PREINIT:
2995             UV i, n, k, begk, endk;
2996             GV *gv;
2997             HV *stash;
2998             CV *cv;
2999             SV** svals;
3000             UV* cm;
3001             DECL_FORCOUNT;
3002             dMY_CXT;
3003             PPCODE:
3004 24           cv = sv_2cv(block, &stash, &gv, 0);
3005 24 50         if (cv == Nullcv)
3006 0           croak("Not a subroutine reference");
3007 24 100         if (ix > 0 && svk != 0)
    50          
3008 0           croak("Too many arguments for forperm");
3009              
3010 24 50         if (!_validate_int(aTHX_ svn, 0) || (svk != 0 && !_validate_int(aTHX_ svk, 0))) {
    100          
    50          
3011 0 0         _vcallsub_with_pp( (ix == 0) ? "forcomb"
    0          
3012             : (ix == 1) ? "forperm"
3013             : "forderange" );
3014 0           return;
3015             }
3016              
3017 24 50         n = my_svuv(svn);
3018 24 100         if (svk == 0) {
3019 16 100         begk = (ix == 0) ? 0 : n;
3020 16           endk = n;
3021             } else {
3022 8 50         begk = endk = my_svuv(svk);
3023 8 100         if (begk > n)
3024 1           return;
3025             }
3026              
3027 23 50         New(0, svals, n, SV*);
3028 115 100         for (i = 0; i < n; i++) {
3029 92           svals[i] = newSVuv(i);
3030 92           SvREADONLY_on(svals[i]);
3031             }
3032 23 50         New(0, cm, endk+1, UV);
3033              
3034 23           START_FORCOUNT;
3035             #if USE_MULTICALL
3036 23 50         if (!CvISXSUB(cv)) {
3037             dMULTICALL;
3038 23           I32 gimme = G_VOID;
3039 23           AV *av = save_ary(PL_defgv);
3040 23           AvREAL_off(av);
3041 23 50         PUSH_MULTICALL(cv);
    50          
3042 47 100         for (k = begk; k <= endk; k++) {
3043 27           _comb_init(cm, k, ix == 2);
3044             while (1) {
3045 22487 100         if (ix < 2 || k != 1) {
    100          
3046             IV j;
3047 22486           av_extend(av, k-1);
3048 22486           av_fill(av, k-1);
3049 303640 100         for (j = k-1; j >= 0; j--)
3050 281154           AvARRAY(av)[j] = svals[ cm[k-j-1]-1 ];
3051 22486           { ENTER; MULTICALL; LEAVE; }
3052             }
3053 22487 100         CHECK_FORCOUNT;
3054 22484 100         if (_comb_iterate(cm, k, n, ix)) break;
3055 22460           }
3056 27 100         CHECK_FORCOUNT;
3057             }
3058             FIX_MULTICALL_REFCOUNT;
3059 23 50         POP_MULTICALL;
    50          
3060             } else
3061             #endif
3062             {
3063 0 0         for (k = begk; k <= endk; k++) {
3064 0           _comb_init(cm, k, ix == 2);
3065             while (1) {
3066 0 0         if (ix < 2 || k != 1) {
    0          
3067 0 0         PUSHMARK(SP); EXTEND(SP, ((IV)k));
    0          
    0          
3068 0 0         for (i = 0; i < k; i++) { PUSHs(svals[ cm[k-i-1]-1 ]); }
3069 0           PUTBACK; call_sv((SV*)cv, G_VOID|G_DISCARD); SPAGAIN;
3070             }
3071 0 0         CHECK_FORCOUNT;
3072 0 0         if (_comb_iterate(cm, k, n, ix)) break;
3073 0           }
3074 0 0         CHECK_FORCOUNT;
3075             }
3076             }
3077              
3078 23           Safefree(cm);
3079 115 100         for (i = 0; i < n; i++)
3080 92           SvREFCNT_dec(svals[i]);
3081 23           Safefree(svals);
3082 23 50         END_FORCOUNT;
3083              
3084             void
3085             forsetproduct (SV* block, ...)
3086             PROTOTYPE: &@
3087             PREINIT:
3088             IV narrays, i, *arlen, *arcnt;
3089             AV **arptr;
3090             SV **arout;
3091             GV *gv;
3092             HV *stash;
3093             CV *cv;
3094             DECL_FORCOUNT;
3095             dMY_CXT;
3096             PPCODE:
3097 9           cv = sv_2cv(block, &stash, &gv, 0);
3098 9 50         if (cv == Nullcv) croak("Not a subroutine reference");
3099              
3100 9           narrays = items-1;
3101 9 100         if (narrays < 1) return;
3102              
3103 22 100         for (i = 1; i <= narrays; i++) {
3104 17 50         SvGETMAGIC(ST(i));
    0          
3105 17 100         if ((!SvROK(ST(i))) || (SvTYPE(SvRV(ST(i))) != SVt_PVAV))
    50          
3106 1           croak("forsetproduct arguments must be array references");
3107 16 100         if (av_len((AV *)SvRV(ST(i))) < 0)
3108 2           return;
3109             }
3110              
3111 5 50         Newz(0, arcnt, narrays, IV);
3112 5 50         New(0, arlen, narrays, IV);
3113 5 50         New(0, arptr, narrays, AV*);
3114 5 50         New(0, arout, narrays, SV*);
3115 17 100         for (i = 0; i < narrays; i++) {
3116 12           arptr[i] = (AV*) SvRV(ST(i+1));
3117 12           arlen[i] = 1 + av_len(arptr[i]);
3118 12           arout[i] = AvARRAY(arptr[i])[0];
3119             }
3120              
3121 5           START_FORCOUNT;
3122             #if USE_MULTICALL
3123 5 50         if (!CvISXSUB(cv)) {
3124             dMULTICALL;
3125 5           I32 gimme = G_VOID;
3126 5           AV *av = save_ary(PL_defgv);
3127 5           AvREAL_off(av);
3128 5 50         PUSH_MULTICALL(cv);
    50          
3129             do {
3130 22           av_extend(av, narrays-1);
3131 22           av_fill(av, narrays-1);
3132 66 100         for (i = narrays-1; i >= 0; i--) /* Faster to fill backwards */
3133 44           AvARRAY(av)[i] = arout[i];
3134 22           { ENTER; MULTICALL; LEAVE; }
3135 22 50         CHECK_FORCOUNT;
3136 37 100         for (i = narrays-1; i >= 0; i--) {
3137 32 100         if (++arcnt[i] >= arlen[i]) arcnt[i] = 0;
3138 32           arout[i] = AvARRAY(arptr[i])[arcnt[i]];
3139 32 100         if (arcnt[i] > 0) break;
3140             }
3141 22 100         } while (i >= 0);
3142             FIX_MULTICALL_REFCOUNT;
3143 5 50         POP_MULTICALL;
    50          
3144             }
3145             else
3146             #endif
3147             do {
3148 0 0         PUSHMARK(SP); EXTEND(SP, narrays);
    0          
    0          
3149 0 0         for (i = 0; i < narrays; i++) { PUSHs(arout[i]); }
3150 0           PUTBACK; call_sv((SV*)cv, G_VOID|G_DISCARD); SPAGAIN;
3151 0 0         CHECK_FORCOUNT;
3152 0 0         for (i = narrays-1; i >= 0; i--) {
3153 0 0         if (++arcnt[i] >= arlen[i]) arcnt[i] = 0;
3154 0           arout[i] = AvARRAY(arptr[i])[arcnt[i]];
3155 0 0         if (arcnt[i] > 0) break;
3156             }
3157 0 0         } while (i >= 0);
3158 5           Safefree(arout);
3159 5           Safefree(arptr);
3160 5           Safefree(arlen);
3161 5           Safefree(arcnt);
3162 5 50         END_FORCOUNT;
3163              
3164             void
3165             forfactored (SV* block, IN SV* svbeg, IN SV* svend = 0)
3166             ALIAS:
3167             forsquarefree = 1
3168             PROTOTYPE: &$;$
3169             PREINIT:
3170             UV beg, end, n, *factors;
3171             int i, nfactors, maxfactors;
3172             factor_range_context_t fctx;
3173             GV *gv;
3174             HV *stash;
3175             SV* svarg; /* We use svarg to prevent clobbering $_ outside the block */
3176             CV *cv;
3177             SV* svals[64];
3178             DECL_FORCOUNT;
3179             dMY_CXT;
3180             PPCODE:
3181 5           cv = sv_2cv(block, &stash, &gv, 0);
3182 5 50         if (cv == Nullcv)
3183 0           croak("Not a subroutine reference");
3184              
3185 5 50         if (!_validate_int(aTHX_ svbeg, 0) || (items >= 3 && !_validate_int(aTHX_ svend,0))) {
    100          
    50          
3186 0 0         _vcallsubn(aTHX_ G_VOID|G_DISCARD, VCALL_ROOT, (ix == 0) ? "_generic_forfactored" : "_generic_forsquarefree", items, 0);
3187 0           return;
3188             }
3189              
3190 5 100         if (items < 3) {
3191 4           beg = 1;
3192 4 50         end = my_svuv(svbeg);
3193             } else {
3194 1 50         beg = my_svuv(svbeg);
3195 1 50         end = my_svuv(svend);
3196             }
3197 5 50         if (beg > end) return;
3198              
3199 52 100         for (maxfactors = 0, n = end >> 1; n; n >>= 1)
3200 47           maxfactors++;
3201 52 100         for (i = 0; i < maxfactors; i++) {
3202 47           svals[i] = newSVuv(UV_MAX);
3203 47           SvREADONLY_on(svals[i]);
3204             }
3205              
3206 5           SAVESPTR(GvSV(PL_defgv));
3207 5           svarg = newSVuv(0);
3208 5           GvSV(PL_defgv) = svarg;
3209 5           START_FORCOUNT;
3210 5 100         if (beg <= 1) {
3211 4 50         PUSHMARK(SP);
3212 4           sv_setuv(svarg, 1);
3213 4           PUTBACK; call_sv((SV*)cv, G_VOID|G_DISCARD); SPAGAIN;
3214 4           beg = 2;
3215             }
3216 5           fctx = factor_range_init(beg, end, ix);
3217             #if USE_MULTICALL
3218 5 50         if (!CvISXSUB(cv)) {
3219             dMULTICALL;
3220 5           I32 gimme = G_VOID;
3221 5           AV *av = save_ary(PL_defgv);
3222 5           AvREAL_off(av);
3223 5 50         PUSH_MULTICALL(cv);
    50          
3224 1212 100         for (n = 0; n < end-beg+1; n++) {
3225 1207 50         CHECK_FORCOUNT;
3226 1207           nfactors = factor_range_next(&fctx);
3227 1207 100         if (nfactors > 0) {
3228 777           sv_setuv(svarg, fctx.n);
3229 777           factors = fctx.factors;
3230 777           av_extend(av, nfactors-1);
3231 777           av_fill(av, nfactors-1);
3232 2382 100         for (i = nfactors-1; i >= 0; i--) {
3233 1605           SV* sv = svals[i];
3234 1605           SvREADONLY_off(sv);
3235 1605           sv_setuv(sv, factors[i]);
3236 1605           SvREADONLY_on(sv);
3237 1605           AvARRAY(av)[i] = sv;
3238             }
3239 777           { ENTER; MULTICALL; LEAVE; }
3240             }
3241             }
3242             FIX_MULTICALL_REFCOUNT;
3243 5 50         POP_MULTICALL;
    50          
3244             }
3245             else
3246             #endif
3247 0 0         for (n = 0; n < end-beg+1; n++) {
3248 0 0         CHECK_FORCOUNT;
3249 0           nfactors = factor_range_next(&fctx);
3250 0 0         if (nfactors > 0) {
3251 0 0         PUSHMARK(SP); EXTEND(SP, nfactors);
    0          
    0          
3252 0           sv_setuv(svarg, fctx.n);
3253 0           factors = fctx.factors;
3254 0 0         for (i = 0; i < nfactors; i++) {
3255 0           SV* sv = svals[i];
3256 0           SvREADONLY_off(sv);
3257 0           sv_setuv(sv, factors[i]);
3258 0           SvREADONLY_on(sv);
3259 0           PUSHs(sv);
3260             }
3261 0           PUTBACK; call_sv((SV*)cv, G_VOID|G_DISCARD); SPAGAIN;
3262             }
3263             }
3264 5           SvREFCNT_dec(svarg);
3265 52 100         for (i = 0; i < maxfactors; i++)
3266 47           SvREFCNT_dec(svals[i]);
3267 5 50         END_FORCOUNT;
3268              
3269             void
3270             vecreduce(SV* block, ...)
3271             PROTOTYPE: &@
3272             CODE:
3273             { /* This is basically reduce from List::Util. Try to maintain compat. */
3274 4           SV *ret = sv_newmortal();
3275             int i;
3276             GV *agv,*bgv,*gv;
3277             HV *stash;
3278 4           SV **args = &PL_stack_base[ax];
3279 4           CV *cv = sv_2cv(block, &stash, &gv, 0);
3280              
3281 4 50         if (cv == Nullcv) croak("Not a subroutine reference");
3282 4 100         if (items <= 1) XSRETURN_UNDEF;
3283              
3284 3           agv = gv_fetchpv("a", GV_ADD, SVt_PV);
3285 3           bgv = gv_fetchpv("b", GV_ADD, SVt_PV);
3286 3           SAVESPTR(GvSV(agv));
3287 3           SAVESPTR(GvSV(bgv));
3288 3           GvSV(agv) = ret;
3289 3 50         SvSetMagicSV(ret, args[1]);
    50          
3290             #ifdef dMULTICALL
3291 3 50         if (!CvISXSUB(cv)) {
3292             dMULTICALL;
3293 3           I32 gimme = G_SCALAR;
3294 3 50         PUSH_MULTICALL(cv);
    50          
3295 7 100         for (i = 2; i < items; i++) {
3296 4           GvSV(bgv) = args[i];
3297 4           { ENTER; MULTICALL; LEAVE; }
3298 4 50         SvSetMagicSV(ret, *PL_stack_sp);
    50          
3299             }
3300             FIX_MULTICALL_REFCOUNT;
3301 3 50         POP_MULTICALL;
    50          
3302             }
3303             else
3304             #endif
3305             {
3306 0 0         for (i = 2; i < items; i++) {
3307 0           dSP;
3308 0           GvSV(bgv) = args[i];
3309 0 0         PUSHMARK(SP);
3310 0           call_sv((SV*)cv, G_SCALAR);
3311 0 0         SvSetMagicSV(ret, *PL_stack_sp);
    0          
3312             }
3313             }
3314 3           ST(0) = ret;
3315 4           XSRETURN(1);
3316             }
3317              
3318             void
3319             vecnone(SV* block, ...)
3320             ALIAS:
3321             vecall = 1
3322             vecany = 2
3323             vecnotall = 3
3324             vecfirst = 4
3325             vecfirstidx = 6
3326             PROTOTYPE: &@
3327             PPCODE:
3328             { /* This is very similar to List::Util. Try to maintain compat. */
3329 27           int ret_true = !(ix & 2); /* return true at end of loop for none/all; false for any/notall */
3330 27           int invert = (ix & 1); /* invert block test for all/notall */
3331             int index;
3332             GV *gv;
3333             HV *stash;
3334 27           SV **args = &PL_stack_base[ax];
3335 27           CV *cv = sv_2cv(block, &stash, &gv, 0);
3336              
3337 27 50         if (cv == Nullcv) croak("Not a subroutine reference");
3338              
3339 27           SAVESPTR(GvSV(PL_defgv));
3340             #ifdef dMULTICALL
3341 27 50         if (!CvISXSUB(cv)) {
3342             dMULTICALL;
3343 27           I32 gimme = G_SCALAR;
3344              
3345 27 50         PUSH_MULTICALL(cv);
    50          
3346 5057 100         for (index = 1; index < items; index++) {
3347 5040           GvSV(PL_defgv) = args[index];
3348 5040           { ENTER; MULTICALL; LEAVE; }
3349 5040 50         if (SvTRUEx(*PL_stack_sp) ^ invert)
    50          
    0          
    50          
    0          
    0          
    100          
    50          
    50          
    100          
    50          
    100          
    50          
    50          
    50          
    50          
    0          
    50          
    0          
    100          
3350 10           break;
3351             }
3352             FIX_MULTICALL_REFCOUNT;
3353 27 50         POP_MULTICALL;
    50          
3354             }
3355             else
3356             #endif
3357             {
3358 0 0         for (index = 1; index < items; index++) {
3359 0           dSP;
3360 0           GvSV(PL_defgv) = args[index];
3361 0 0         PUSHMARK(SP);
3362 0           call_sv((SV*)cv, G_SCALAR);
3363 0 0         if (SvTRUEx(*PL_stack_sp) ^ invert)
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3364 0           break;
3365             }
3366             }
3367              
3368 27 100         if (ix == 4) {
3369 5 100         if (index == items)
3370 2           XSRETURN_UNDEF;
3371 3           ST(0) = ST(index);
3372 3           XSRETURN(1);
3373             }
3374 22 100         if (ix == 6) {
3375 5 100         if (index == items)
3376 2           XSRETURN_IV(-1);
3377 3           XSRETURN_UV(index-1);
3378             }
3379              
3380 17 100         if (index != items) /* We exited the loop early */
3381 4           ret_true = !ret_true;
3382              
3383 17 100         if (ret_true) XSRETURN_YES;
3384 27           else XSRETURN_NO;
3385             }
3386              
3387             #ifdef FACTORING_HARNESSES
3388             void
3389             factor_test_harness1(...)
3390             PROTOTYPE: @
3391             PPCODE:
3392             /* Pass in a big array of numbers, we factor them in a timed loop */
3393             {
3394             UV res, factors[MPU_MAX_FACTORS+1], *comp;
3395             struct timeval gstart, gstop;
3396             double t_time;
3397             int i, j, k, correct, nf, num = items;
3398              
3399             //num = (items > 100000) ? 100000 : items;
3400             New(0, comp, num, UV);
3401             for (i = 0; i < num; i++)
3402             comp[i] = my_svuv(ST(i));
3403             gettimeofday(&gstart, NULL);
3404             for (j = 0; j < 1; j++) {
3405             correct = 0;
3406             for (i = 0; i < num; i++) {
3407             nf = factor(comp[i], factors);
3408             //nf = squfof_factor(comp[i], factors, 140000);
3409             //nf = pbrent_factor(comp[i], factors, 500000, 1);
3410             //nf = holf_factor(comp[i], factors, 1000000);
3411             //nf = lehman_factor(comp[i], factors, 1);
3412             //nf = lehman_factor(comp[i], factors, 0); if (nf < 2) nf=pbrent_factor(comp[i], factors, 500000, 3);
3413             //nf = factor63(comp[i], factors);
3414             //nf = pminus1_factor(comp[i], factors, 1000,10000);
3415             //nf = prho_factor(comp[i], factors, 10000);
3416             if (nf >= 2) {
3417             for (res = factors[0], k = 1; k < nf; k++)
3418             res *= factors[k];
3419             if (res == comp[i])
3420             correct++;
3421             }
3422             //printf("%lu:",comp[i]);for(k=0;k
3423             }
3424             }
3425             gettimeofday(&gstop, NULL);
3426             t_time = my_difftime(&gstart, &gstop);
3427             Safefree(comp);
3428             printf("factoring got %d of %d correct in %2.2f sec\n", correct, num, t_time);
3429             printf("percent correct = %.3f\n", 100.0*(double)correct / (double)num);
3430             printf("average time per input = %1.4f ms\n", 1000 * t_time / (double)num);
3431             XSRETURN_UV(correct);
3432             }
3433              
3434             void
3435             factor_test_harness2(IN int count, IN int bits = 63)
3436             PPCODE:
3437             /* We'll factor -bit numbers */
3438             {
3439             UV factors[MPU_MAX_FACTORS+1], exponents[MPU_MAX_FACTORS+1];
3440             FILE *fid = 0; // fopen("results.txt", "w");
3441             uint64_t n, state = 28953;
3442             int i, nfactors, totfactors = 0;
3443             /* Use Knuth MMIX -- simple and no worse than Chacha20 for this */
3444             for (i = 0; i < count; i++) {
3445             state = 6364136223846793005ULL * state + 1442695040888963407ULL;
3446             n = state >> (64-bits);
3447             nfactors = factor_exp(n, factors, exponents);
3448             if (fid) fprintf(fid, "%llu has %d factors\n", n, nfactors);
3449             totfactors += nfactors;
3450             }
3451             if (fid) fclose(fid);
3452             XSRETURN_IV(totfactors);
3453             }
3454              
3455             void
3456             factor_test_harness3(IN UV start, IN UV end)
3457             PPCODE:
3458             /* We'll factor -bit numbers */
3459             {
3460             UV totf = 0, i, factors[MPU_MAX_FACTORS];
3461             for (i = start; i < end; i++) {
3462             totf += factor(i, factors);
3463             }
3464             XSRETURN_UV(totf);
3465             }
3466              
3467             #endif