File Coverage

XS.xs
Criterion Covered Total %
statement 1370 1565 87.5
branch 1591 2634 60.4
condition n/a
subroutine n/a
pod n/a
total 2961 4199 70.5


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