| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#define PERL_NO_GET_CONTEXT 1 /* Define at top for more efficiency. */ |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
#if defined(__clang__) && defined(__clang_major__) && __clang_major__ > 11 |
|
4
|
|
|
|
|
|
|
#pragma clang diagnostic ignored "-Wcompound-token-split-by-macro" |
|
5
|
|
|
|
|
|
|
#endif |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
#include "EXTERN.h" |
|
8
|
|
|
|
|
|
|
#include "perl.h" |
|
9
|
|
|
|
|
|
|
#include "XSUB.h" |
|
10
|
|
|
|
|
|
|
#include "multicall.h" /* only works in 5.6 and newer */ |
|
11
|
|
|
|
|
|
|
#include /* For fileno and stdout */ |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
#define NEED_newCONSTSUB |
|
14
|
|
|
|
|
|
|
#define NEED_newRV_noinc |
|
15
|
|
|
|
|
|
|
#define NEED_sv_2pv_flags |
|
16
|
|
|
|
|
|
|
#define NEED_HvNAME_get |
|
17
|
|
|
|
|
|
|
#include "ppport.h" |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
#define FUNC_gcd_ui 1 |
|
20
|
|
|
|
|
|
|
#define FUNC_isqrt 1 |
|
21
|
|
|
|
|
|
|
#define FUNC_ipow 1 |
|
22
|
|
|
|
|
|
|
#define FUNC_popcnt 1 |
|
23
|
|
|
|
|
|
|
#include "ptypes.h" |
|
24
|
|
|
|
|
|
|
#include "cache.h" |
|
25
|
|
|
|
|
|
|
#include "sieve.h" |
|
26
|
|
|
|
|
|
|
#include "sieve_cluster.h" |
|
27
|
|
|
|
|
|
|
#include "util.h" |
|
28
|
|
|
|
|
|
|
#include "sort.h" |
|
29
|
|
|
|
|
|
|
#include "primality.h" |
|
30
|
|
|
|
|
|
|
#include "lucas_seq.h" |
|
31
|
|
|
|
|
|
|
#include "factor.h" |
|
32
|
|
|
|
|
|
|
#include "totients.h" |
|
33
|
|
|
|
|
|
|
#include "lehmer.h" |
|
34
|
|
|
|
|
|
|
#include "lmo.h" |
|
35
|
|
|
|
|
|
|
#include "legendre_phi.h" |
|
36
|
|
|
|
|
|
|
#include "aks.h" |
|
37
|
|
|
|
|
|
|
#include "constants.h" |
|
38
|
|
|
|
|
|
|
#include "mulmod.h" |
|
39
|
|
|
|
|
|
|
#include "entropy.h" |
|
40
|
|
|
|
|
|
|
#include "csprng.h" |
|
41
|
|
|
|
|
|
|
#include "random_prime.h" |
|
42
|
|
|
|
|
|
|
#include "perfect_powers.h" |
|
43
|
|
|
|
|
|
|
#include "prime_powers.h" |
|
44
|
|
|
|
|
|
|
#include "ramanujan_primes.h" |
|
45
|
|
|
|
|
|
|
#include "semi_primes.h" |
|
46
|
|
|
|
|
|
|
#include "twin_primes.h" |
|
47
|
|
|
|
|
|
|
#include "almost_primes.h" |
|
48
|
|
|
|
|
|
|
#include "omega_primes.h" |
|
49
|
|
|
|
|
|
|
#include "prime_counts.h" |
|
50
|
|
|
|
|
|
|
#include "prime_sums.h" |
|
51
|
|
|
|
|
|
|
#include "congruent_numbers.h" |
|
52
|
|
|
|
|
|
|
#include "powerfree.h" |
|
53
|
|
|
|
|
|
|
#include "powerful.h" |
|
54
|
|
|
|
|
|
|
#include "lucky_numbers.h" |
|
55
|
|
|
|
|
|
|
#include "goldbach.h" |
|
56
|
|
|
|
|
|
|
#include "rootmod.h" |
|
57
|
|
|
|
|
|
|
#include "rational.h" |
|
58
|
|
|
|
|
|
|
#include "real.h" |
|
59
|
|
|
|
|
|
|
#include "ds_iset.h" /* Used for sumset, setbinop, is_sidon_set, vecuniq */ |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
#ifdef FACTORING_HARNESSES |
|
62
|
|
|
|
|
|
|
#include |
|
63
|
|
|
|
|
|
|
static double my_difftime (struct timeval * start, struct timeval * end) { |
|
64
|
|
|
|
|
|
|
double secs, usecs; |
|
65
|
|
|
|
|
|
|
if (start->tv_sec == end->tv_sec) { |
|
66
|
|
|
|
|
|
|
secs = 0; |
|
67
|
|
|
|
|
|
|
usecs = end->tv_usec - start->tv_usec; |
|
68
|
|
|
|
|
|
|
} else { |
|
69
|
|
|
|
|
|
|
usecs = 1000000 - start->tv_usec; |
|
70
|
|
|
|
|
|
|
secs = end->tv_sec - (start->tv_sec + 1); |
|
71
|
|
|
|
|
|
|
usecs += end->tv_usec; |
|
72
|
|
|
|
|
|
|
if (usecs >= 1000000) { |
|
73
|
|
|
|
|
|
|
usecs -= 1000000; |
|
74
|
|
|
|
|
|
|
secs += 1; |
|
75
|
|
|
|
|
|
|
} |
|
76
|
|
|
|
|
|
|
} |
|
77
|
|
|
|
|
|
|
return secs + usecs / 1000000.; |
|
78
|
|
|
|
|
|
|
} |
|
79
|
|
|
|
|
|
|
#endif |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
#if BITS_PER_WORD == 64 |
|
82
|
|
|
|
|
|
|
#if defined(_MSC_VER) |
|
83
|
|
|
|
|
|
|
#include |
|
84
|
|
|
|
|
|
|
#define strtoull _strtoui64 |
|
85
|
|
|
|
|
|
|
#define strtoll _strtoi64 |
|
86
|
|
|
|
|
|
|
#endif |
|
87
|
|
|
|
|
|
|
#define PSTRTOULL(str, end, base) strtoull (str, end, base) |
|
88
|
|
|
|
|
|
|
#define PSTRTOLL(str, end, base) strtoll (str, end, base) |
|
89
|
|
|
|
|
|
|
#else |
|
90
|
|
|
|
|
|
|
#define PSTRTOULL(str, end, base) strtoul (str, end, base) |
|
91
|
|
|
|
|
|
|
#define PSTRTOLL(str, end, base) strtol (str, end, base) |
|
92
|
|
|
|
|
|
|
#endif |
|
93
|
|
|
|
|
|
|
#if defined(_MSC_VER) && !defined(strtold) |
|
94
|
|
|
|
|
|
|
#define strtold strtod |
|
95
|
|
|
|
|
|
|
#endif |
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
#ifdef USE_QUADMATH |
|
98
|
|
|
|
|
|
|
#define STRTONV(t) strtoflt128(t,NULL) |
|
99
|
|
|
|
|
|
|
#elif defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE) |
|
100
|
|
|
|
|
|
|
#define STRTONV(t) strtold(t,NULL) |
|
101
|
|
|
|
|
|
|
#else |
|
102
|
|
|
|
|
|
|
#define STRTONV(t) strtod(t,NULL) |
|
103
|
|
|
|
|
|
|
#endif |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
#if PERL_VERSION_LT(5,7,0) && BITS_PER_WORD == 64 |
|
106
|
|
|
|
|
|
|
/* Workaround perl 5.6 UVs and bigints */ |
|
107
|
|
|
|
|
|
|
#define my_svuv(sv) PSTRTOULL(SvPV_nolen(sv), NULL, 10) |
|
108
|
|
|
|
|
|
|
#define my_sviv(sv) PSTRTOLL(SvPV_nolen(sv), NULL, 10) |
|
109
|
|
|
|
|
|
|
#elif PERL_VERSION_LT(5,14,0) && BITS_PER_WORD == 64 |
|
110
|
|
|
|
|
|
|
/* Workaround RT 49569 in Math::BigInt::FastCalc (pre 5.14.0) */ |
|
111
|
|
|
|
|
|
|
/* TODO: Math::BigInt::Pari has the same problem with negs pre-5.18.0 */ |
|
112
|
|
|
|
|
|
|
#define my_svuv(sv) ( (!SvROK(sv)) ? SvUV(sv) : PSTRTOULL(SvPV_nolen(sv),NULL,10) ) |
|
113
|
|
|
|
|
|
|
#define my_sviv(sv) ( (!SvROK(sv)) ? SvIV(sv) : PSTRTOLL(SvPV_nolen(sv),NULL,10) ) |
|
114
|
|
|
|
|
|
|
#else |
|
115
|
|
|
|
|
|
|
#define my_svuv(sv) SvUV(sv) |
|
116
|
|
|
|
|
|
|
#define my_sviv(sv) SvIV(sv) |
|
117
|
|
|
|
|
|
|
#endif |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
#if PERL_VERSION_GE(5,9,4) || PERL_VERSION_EQ(5,8,9) |
|
120
|
|
|
|
|
|
|
#define SVf_MAGTEST SVf_ROK |
|
121
|
|
|
|
|
|
|
#else |
|
122
|
|
|
|
|
|
|
#define SVf_MAGTEST SVf_AMAGIC |
|
123
|
|
|
|
|
|
|
#define GV_NOTQUAL 0 |
|
124
|
|
|
|
|
|
|
#endif |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
#define SVNUMTEST(n) \ |
|
127
|
|
|
|
|
|
|
((SvFLAGS(n) & (SVf_IOK | SVf_MAGTEST | SVs_GMG )) == SVf_IOK) |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
/* multicall compatibility stuff */ |
|
130
|
|
|
|
|
|
|
#if PERL_VERSION_LT(5,7,0) || !defined(dMULTICALL) |
|
131
|
|
|
|
|
|
|
# define USE_MULTICALL 0 /* Too much trouble to work around it */ |
|
132
|
|
|
|
|
|
|
#else |
|
133
|
|
|
|
|
|
|
# define USE_MULTICALL 1 |
|
134
|
|
|
|
|
|
|
#endif |
|
135
|
|
|
|
|
|
|
#if PERL_VERSION_LT(5,13,9) |
|
136
|
|
|
|
|
|
|
# define FIX_MULTICALL_REFCOUNT \ |
|
137
|
|
|
|
|
|
|
if (CvDEPTH(multicall_cv) > 1) SvREFCNT_inc(multicall_cv); |
|
138
|
|
|
|
|
|
|
#else |
|
139
|
|
|
|
|
|
|
# define FIX_MULTICALL_REFCOUNT |
|
140
|
|
|
|
|
|
|
#endif |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
/* Perl globals we use for setting a and b inside the called block */ |
|
143
|
|
|
|
|
|
|
#define plAgv PL_firstgv |
|
144
|
|
|
|
|
|
|
#define plBgv PL_secondgv |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
#ifndef CvISXSUB |
|
147
|
|
|
|
|
|
|
# define CvISXSUB(cv) CvXSUB(cv) |
|
148
|
|
|
|
|
|
|
#endif |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
/* Not right, but close. We don't use it ourselves, but core macros do. */ |
|
151
|
|
|
|
|
|
|
#if !defined cxinc && PERL_VERSION_GE(5,8,1) && PERL_VERSION_LT(5,11,0) |
|
152
|
|
|
|
|
|
|
# define cxinc() Perl_cxinc(aTHX) |
|
153
|
|
|
|
|
|
|
#endif |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
#if PERL_VERSION_LT(5,17,7) |
|
156
|
|
|
|
|
|
|
# define SvREFCNT_dec_NN(sv) SvREFCNT_dec(sv) |
|
157
|
|
|
|
|
|
|
#endif |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
#if PERL_VERSION_LT(5,20,0) |
|
160
|
|
|
|
|
|
|
# define EXTEND_TYPE int |
|
161
|
|
|
|
|
|
|
#else |
|
162
|
|
|
|
|
|
|
# define EXTEND_TYPE SSize_t |
|
163
|
|
|
|
|
|
|
#endif |
|
164
|
|
|
|
|
|
|
#define MAX_EXTEND ((Size_t)((EXTEND_TYPE)-1)) |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
/******************************************************************************/ |
|
167
|
|
|
|
|
|
|
/******************************************************************************/ |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
/* Information about the GMP back end. |
|
170
|
|
|
|
|
|
|
* |
|
171
|
|
|
|
|
|
|
* This is not ideal in a couple ways. |
|
172
|
|
|
|
|
|
|
* |
|
173
|
|
|
|
|
|
|
* - The return type info would be useful for non-GMP functions also. The |
|
174
|
|
|
|
|
|
|
* thought was to use this to automatically apply objectify. The PP |
|
175
|
|
|
|
|
|
|
* backend should take care of the result itself. |
|
176
|
|
|
|
|
|
|
* |
|
177
|
|
|
|
|
|
|
* - The versioning is limited. Having more fine grain info, e.g. the GMP |
|
178
|
|
|
|
|
|
|
* module provides semantics 20210808 of modint, while we need 20250212. |
|
179
|
|
|
|
|
|
|
* |
|
180
|
|
|
|
|
|
|
* No matter what we do it's going to be tricky with things like adding |
|
181
|
|
|
|
|
|
|
* support for negative inputs, while positive ones remain unchanged. |
|
182
|
|
|
|
|
|
|
*/ |
|
183
|
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
typedef enum { |
|
185
|
|
|
|
|
|
|
R_VOID, |
|
186
|
|
|
|
|
|
|
R_BOOL, |
|
187
|
|
|
|
|
|
|
R_NATIVE, |
|
188
|
|
|
|
|
|
|
R_BIGINT, |
|
189
|
|
|
|
|
|
|
R_OTHER, |
|
190
|
|
|
|
|
|
|
} gmp_return_type_t; |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
typedef struct { |
|
193
|
|
|
|
|
|
|
const char *name; |
|
194
|
|
|
|
|
|
|
uint32_t version; |
|
195
|
|
|
|
|
|
|
uint16_t nretvals; |
|
196
|
|
|
|
|
|
|
gmp_return_type_t rettype; |
|
197
|
|
|
|
|
|
|
} gmp_info_t; |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
static const gmp_info_t gmp_info[] = { |
|
200
|
|
|
|
|
|
|
{ "sqrtint", 40, 1, R_BIGINT }, |
|
201
|
|
|
|
|
|
|
{ "addint", 52, 1, R_BIGINT }, |
|
202
|
|
|
|
|
|
|
{ "subint", 52, 1, R_BIGINT }, |
|
203
|
|
|
|
|
|
|
{ "mulint", 52, 1, R_BIGINT }, |
|
204
|
|
|
|
|
|
|
{ "divint", 52, 1, R_BIGINT }, |
|
205
|
|
|
|
|
|
|
{ "modint", 52, 1, R_BIGINT }, |
|
206
|
|
|
|
|
|
|
{ "powint", 52, 1, R_BIGINT }, |
|
207
|
|
|
|
|
|
|
{ "absint", 52, 1, R_BIGINT }, |
|
208
|
|
|
|
|
|
|
{ "negint", 52, 1, R_BIGINT }, |
|
209
|
|
|
|
|
|
|
{ "cdivint", 53, 1, R_BIGINT }, |
|
210
|
|
|
|
|
|
|
{ "add1int", 53, 1, R_BIGINT }, |
|
211
|
|
|
|
|
|
|
{ "sub1int", 53, 1, R_BIGINT }, |
|
212
|
|
|
|
|
|
|
{ "lshiftint", 53, 1, R_BIGINT }, |
|
213
|
|
|
|
|
|
|
{ "rshiftint", 53, 1, R_BIGINT }, |
|
214
|
|
|
|
|
|
|
{ "rashiftint", 53, 1, R_BIGINT }, |
|
215
|
|
|
|
|
|
|
{ "logint", 47, 1, R_BIGINT }, /* no root return */ |
|
216
|
|
|
|
|
|
|
{ "rootint", 40, 1, R_BIGINT }, /* no root return */ |
|
217
|
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
{ "invmod", 20, 1, R_BIGINT }, |
|
219
|
|
|
|
|
|
|
{ "znorder", 22, 1, R_BIGINT }, |
|
220
|
|
|
|
|
|
|
{ "zinprimroot", 22, 1, R_BIGINT }, |
|
221
|
|
|
|
|
|
|
{ "addmod", 53, 1, R_BIGINT }, /* 36 with n > 0 */ |
|
222
|
|
|
|
|
|
|
{ "submod", 53, 1, R_BIGINT }, |
|
223
|
|
|
|
|
|
|
{ "mulmod", 53, 1, R_BIGINT }, /* 36 with n > 0 */ |
|
224
|
|
|
|
|
|
|
{ "powmod", 53, 1, R_BIGINT }, /* 36 with n > 0 */ |
|
225
|
|
|
|
|
|
|
{ "divmod", 53, 1, R_BIGINT }, /* 36 with n > 0 */ |
|
226
|
|
|
|
|
|
|
{ "muladdmod", 53, 1, R_BIGINT }, |
|
227
|
|
|
|
|
|
|
{ "mulsubmod", 53, 1, R_BIGINT }, |
|
228
|
|
|
|
|
|
|
{ "factorialmod", 53, 1, R_BIGINT }, /* 47 with m > 0 */ |
|
229
|
|
|
|
|
|
|
{ "binomialmod", 53, 1, R_BIGINT }, |
|
230
|
|
|
|
|
|
|
{ "sqrtmod", 53, 1, R_BIGINT }, /* 53 for composites */ |
|
231
|
|
|
|
|
|
|
{ "divrem", 52, 2, R_BIGINT }, |
|
232
|
|
|
|
|
|
|
{ "tdivrem", 52, 2, R_BIGINT }, |
|
233
|
|
|
|
|
|
|
{ "fdivrem", 53, 2, R_BIGINT }, |
|
234
|
|
|
|
|
|
|
{ "cdivrem", 53, 2, R_BIGINT }, |
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
{ "is_primitive_root", 36, 1, R_BOOL }, |
|
237
|
|
|
|
|
|
|
{ "is_semiprime", 42, 1, R_BOOL }, |
|
238
|
|
|
|
|
|
|
{ "is_square", 47, 1, R_BOOL }, |
|
239
|
|
|
|
|
|
|
{ "is_carmichael", 47, 1, R_BOOL }, |
|
240
|
|
|
|
|
|
|
{ "is_perfect_power", 47, 1, R_BOOL }, |
|
241
|
|
|
|
|
|
|
{ "is_fundamental", 47, 1, R_BOOL }, |
|
242
|
|
|
|
|
|
|
{ "is_totient", 47, 1, R_BOOL }, |
|
243
|
|
|
|
|
|
|
{ "is_lucky", 48, 1, R_BOOL }, |
|
244
|
|
|
|
|
|
|
{ "is_practical", 53, 1, R_BOOL }, |
|
245
|
|
|
|
|
|
|
{ "is_perfect_number", 53, 1, R_BOOL }, |
|
246
|
|
|
|
|
|
|
{ "is_square_free", 53, 1, R_BOOL }, |
|
247
|
|
|
|
|
|
|
{ "is_powerfree", 53, 1, R_BOOL }, |
|
248
|
|
|
|
|
|
|
{ "is_smooth", 53, 1, R_BOOL }, |
|
249
|
|
|
|
|
|
|
{ "is_rough", 53, 1, R_BOOL }, |
|
250
|
|
|
|
|
|
|
{ "is_almost_prime", 53, 1, R_BOOL }, |
|
251
|
|
|
|
|
|
|
{ "is_divisible", 53, 1, R_BOOL }, |
|
252
|
|
|
|
|
|
|
{ "is_congruent", 53, 1, R_BOOL }, |
|
253
|
|
|
|
|
|
|
{ "is_powerful", 53, 1, R_BOOL }, |
|
254
|
|
|
|
|
|
|
{ "is_qr", 53, 1, R_BOOL }, |
|
255
|
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
{ "is_prime", 1, 1, R_BOOL }, |
|
257
|
|
|
|
|
|
|
{ "is_prob_prime", 1, 1, R_BOOL }, |
|
258
|
|
|
|
|
|
|
{ "is_provable_prime", 4, 1, R_BOOL }, |
|
259
|
|
|
|
|
|
|
{ "is_bpsw_prime", 17, 1, R_BOOL }, |
|
260
|
|
|
|
|
|
|
{ "is_aks_prime", 16, 1, R_BOOL }, |
|
261
|
|
|
|
|
|
|
{ "is_mersenne_prime", 28, 1, R_BOOL }, |
|
262
|
|
|
|
|
|
|
{ "is_gaussian_prime", 52, 1, R_BOOL }, |
|
263
|
|
|
|
|
|
|
{ "is_pseudoprime", 53, 1, R_BOOL }, /* v0.41 with bases */ |
|
264
|
|
|
|
|
|
|
{ "is_euler_pseudoprime", 53, 1, R_BOOL }, /* v0.41 with bases */ |
|
265
|
|
|
|
|
|
|
{ "is_strong_pseudoprime", 53, 1, R_BOOL }, /* v0.41 with bases */ |
|
266
|
|
|
|
|
|
|
{ "is_euler_plumb_pseudoprime", 39, 1, R_BOOL }, |
|
267
|
|
|
|
|
|
|
{ "is_perrin_pseudoprime", 40, 1, R_BOOL }, |
|
268
|
|
|
|
|
|
|
{ "is_lucas_pseudoprime", 1, 1, R_BOOL }, |
|
269
|
|
|
|
|
|
|
{ "is_strong_lucas_pseudoprime", 1, 1, R_BOOL }, |
|
270
|
|
|
|
|
|
|
{ "is_extra_strong_lucas_pseudoprime", 1, 1, R_BOOL }, |
|
271
|
|
|
|
|
|
|
{ "is_almost_extra_strong_lucas_pseudoprime", 13, 1, R_BOOL }, |
|
272
|
|
|
|
|
|
|
{ "is_frobenius_pseudoprime", 24, 1, R_BOOL }, |
|
273
|
|
|
|
|
|
|
{ "is_frobenius_underwood_pseudoprime", 13, 1, R_BOOL }, |
|
274
|
|
|
|
|
|
|
{ "is_frobenius_khashin_pseudoprime", 30, 1, R_BOOL }, |
|
275
|
|
|
|
|
|
|
{ "miller_rabin_random", 46, 1, R_BOOL }, |
|
276
|
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
{ "next_prime", 1, 1, R_BIGINT }, |
|
278
|
|
|
|
|
|
|
{ "prev_prime", 1, 1, R_BIGINT }, |
|
279
|
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
{ "kronecker", 17, 1, R_NATIVE }, |
|
281
|
|
|
|
|
|
|
{ "valuation", 20, 1, R_NATIVE }, |
|
282
|
|
|
|
|
|
|
{ "liouville", 22, 1, R_NATIVE }, |
|
283
|
|
|
|
|
|
|
{ "hammingweight", 47, 1, R_NATIVE }, |
|
284
|
|
|
|
|
|
|
{ "moebius", 49, 1, R_NATIVE }, /* v0.22 with non-neg */ |
|
285
|
|
|
|
|
|
|
{ "prime_omega", 53, 1, R_NATIVE }, |
|
286
|
|
|
|
|
|
|
{ "prime_bigomega", 53, 1, R_NATIVE }, |
|
287
|
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
{ "consecutive_integer_lcm", 4, 1, R_BIGINT }, |
|
289
|
|
|
|
|
|
|
{ "partitions", 16, 1, R_BIGINT }, |
|
290
|
|
|
|
|
|
|
{ "gcd", 17, 1, R_BIGINT }, |
|
291
|
|
|
|
|
|
|
{ "lcm", 17, 1, R_BIGINT }, |
|
292
|
|
|
|
|
|
|
{ "exp_mangoldt", 19, 1, R_BIGINT }, |
|
293
|
|
|
|
|
|
|
{ "jordan_totient", 22, 1, R_BIGINT }, |
|
294
|
|
|
|
|
|
|
{ "carmichael_lambda", 22, 1, R_BIGINT }, |
|
295
|
|
|
|
|
|
|
{ "binomial", 22, 1, R_BIGINT }, |
|
296
|
|
|
|
|
|
|
{ "stirling", 26, 1, R_BIGINT }, |
|
297
|
|
|
|
|
|
|
{ "lucasu", 29, 1, R_BIGINT }, |
|
298
|
|
|
|
|
|
|
{ "lucasv", 29, 1, R_BIGINT }, |
|
299
|
|
|
|
|
|
|
{ "chinese", 32, 1, R_BIGINT }, |
|
300
|
|
|
|
|
|
|
{ "ramanujan_tau", 53, 1, R_BIGINT }, /* v0.53 much faster */ |
|
301
|
|
|
|
|
|
|
{ "gcdext", 35, 3, R_BIGINT }, |
|
302
|
|
|
|
|
|
|
{ "primorial", 37, 1, R_BIGINT }, |
|
303
|
|
|
|
|
|
|
{ "pn_primorial", 37, 1, R_BIGINT }, |
|
304
|
|
|
|
|
|
|
{ "permtonum", 47, 1, R_BIGINT }, |
|
305
|
|
|
|
|
|
|
{ "subfactorial", 51, 1, R_BIGINT }, |
|
306
|
|
|
|
|
|
|
{ "falling_factorial", 51, 1, R_BIGINT }, |
|
307
|
|
|
|
|
|
|
{ "rising_factorial", 51, 1, R_BIGINT }, |
|
308
|
|
|
|
|
|
|
{ "lucasumod", 53, 1, R_BIGINT }, |
|
309
|
|
|
|
|
|
|
{ "lucasvmod", 53, 1, R_BIGINT }, |
|
310
|
|
|
|
|
|
|
{ "lucasuv", 53, 2, R_BIGINT }, |
|
311
|
|
|
|
|
|
|
{ "lucasuvmod", 53, 2, R_BIGINT }, |
|
312
|
|
|
|
|
|
|
{ "pisano_period", 53, 1, R_BIGINT }, |
|
313
|
|
|
|
|
|
|
{ "powersum", 53, 1, R_BIGINT }, |
|
314
|
|
|
|
|
|
|
{ "fromdigits", 53, 1, R_BIGINT }, |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
{ "urandomb", 43, 1, R_BIGINT }, |
|
317
|
|
|
|
|
|
|
{ "urandomm", 44, 1, R_BIGINT }, |
|
318
|
|
|
|
|
|
|
{ "random_nbit_prime", 42, 1, R_BIGINT }, |
|
319
|
|
|
|
|
|
|
{ "random_ndigit_prime", 42, 1, R_BIGINT }, |
|
320
|
|
|
|
|
|
|
{ "random_strong_prime", 43, 1, R_BIGINT }, |
|
321
|
|
|
|
|
|
|
{ "random_maurer_prime", 43, 1, R_BIGINT }, |
|
322
|
|
|
|
|
|
|
{"random_shawe_taylor_prime", 43, 1, R_BIGINT }, |
|
323
|
|
|
|
|
|
|
{ "random_prime", 44, 1, R_BIGINT }, |
|
324
|
|
|
|
|
|
|
{ "random_safe_prime", 52, 1, R_BIGINT }, |
|
325
|
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
{ "sieve_range", 36, 0xFF, R_BIGINT }, /* needs objectify */ |
|
327
|
|
|
|
|
|
|
{ "sieve_prime_cluster", 34, 0xFF, R_BIGINT }, /* needs objectify */ |
|
328
|
|
|
|
|
|
|
{ "divisors", 53, 0xFF, R_BIGINT }, /* needs objectify */ |
|
329
|
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
{ "numtoperm", 47, 0xFF, R_NATIVE }, |
|
331
|
|
|
|
|
|
|
{ "todigits", 41, 0xFF, R_NATIVE }, |
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
{ "powerful_count", 53, 1, R_BIGINT }, |
|
334
|
|
|
|
|
|
|
{ "powerfree_count", 53, 1, R_BIGINT }, |
|
335
|
|
|
|
|
|
|
{ "prime_power_count", 53, 1, R_BIGINT }, |
|
336
|
|
|
|
|
|
|
{ "perfect_power_count", 53, 1, R_BIGINT }, |
|
337
|
|
|
|
|
|
|
{ "nth_powerfree", 53, 1, R_BIGINT }, |
|
338
|
|
|
|
|
|
|
{ "nth_perfect_power", 53, 1, R_BIGINT }, |
|
339
|
|
|
|
|
|
|
{ "nth_perfect_power_approx", 53, 1, R_BIGINT }, |
|
340
|
|
|
|
|
|
|
{ "next_perfect_power", 53, 1, R_BIGINT }, |
|
341
|
|
|
|
|
|
|
{ "prev_perfect_power", 53, 1, R_BIGINT }, |
|
342
|
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
{ "is_power", 42, 1, R_NATIVE }, /* no root return */ |
|
344
|
|
|
|
|
|
|
{ "is_prime_power", 40, 1, R_NATIVE }, /* no root return */ |
|
345
|
|
|
|
|
|
|
{ "is_polygonal", 47, 1, R_BOOL }, /* no root return */ |
|
346
|
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
{ "bernfrac", 24, 2, R_BIGINT }, |
|
348
|
|
|
|
|
|
|
{ "harmfrac", 30, 2, R_BIGINT }, |
|
349
|
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
/* if the input is already a bigint type, we want to use that */ |
|
351
|
|
|
|
|
|
|
/* { "factorial", 24, 1, R_BIGINT }, */ |
|
352
|
|
|
|
|
|
|
#if 0 /* need to objectify a return list */ |
|
353
|
|
|
|
|
|
|
{ "factor", 41, 0xFF, R_BIGINT }, |
|
354
|
|
|
|
|
|
|
#endif |
|
355
|
|
|
|
|
|
|
#if 0 /* objectify list, and the API isn't identical */ |
|
356
|
|
|
|
|
|
|
{ "trial_factor", 47, 0xFF, R_BIGINT }, |
|
357
|
|
|
|
|
|
|
{ "holf_factor", 47, 0xFF, R_BIGINT }, |
|
358
|
|
|
|
|
|
|
{ "squfof_factor", 47, 0xFF, R_BIGINT }, |
|
359
|
|
|
|
|
|
|
{ "phro_factor", 47, 0xFF, R_BIGINT }, |
|
360
|
|
|
|
|
|
|
{ "pplus1_factor", 47, 0xFF, R_BIGINT }, |
|
361
|
|
|
|
|
|
|
{ "pbrent_factor", 47, 0xFF, R_BIGINT }, |
|
362
|
|
|
|
|
|
|
{ "pminus1_factor", 47, 0xFF, R_BIGINT }, |
|
363
|
|
|
|
|
|
|
{ "ecm_factor", 47, 0xFF, R_BIGINT }, |
|
364
|
|
|
|
|
|
|
{ "cheb_factor", 53, 0xFF, R_BIGINT }, |
|
365
|
|
|
|
|
|
|
#endif |
|
366
|
|
|
|
|
|
|
}; |
|
367
|
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
/******************************************************************************/ |
|
369
|
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
#if BITS_PER_WORD == 32 |
|
371
|
|
|
|
|
|
|
static const unsigned int uvmax_maxlen = 10; |
|
372
|
|
|
|
|
|
|
static const unsigned int ivmax_maxlen = 10; |
|
373
|
|
|
|
|
|
|
static const char uvmax_str[] = "4294967295"; |
|
374
|
|
|
|
|
|
|
/* static const char ivmax_str[] = "2147483648"; */ |
|
375
|
|
|
|
|
|
|
static const char ivmin_str[] = "2147483648"; |
|
376
|
|
|
|
|
|
|
#else |
|
377
|
|
|
|
|
|
|
static const unsigned int uvmax_maxlen = 20; |
|
378
|
|
|
|
|
|
|
static const unsigned int ivmax_maxlen = 19; |
|
379
|
|
|
|
|
|
|
static const char uvmax_str[] = "18446744073709551615"; |
|
380
|
|
|
|
|
|
|
/* static const char ivmax_str[] = "9223372036854775808"; */ |
|
381
|
|
|
|
|
|
|
static const char ivmin_str[] = "9223372036854775808"; |
|
382
|
|
|
|
|
|
|
#endif |
|
383
|
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
#define MY_CXT_KEY "Math::Prime::Util::API_guts" |
|
385
|
|
|
|
|
|
|
#define CINTS 100 |
|
386
|
|
|
|
|
|
|
typedef struct { |
|
387
|
|
|
|
|
|
|
HV* MPUroot; |
|
388
|
|
|
|
|
|
|
HV* MPUGMP; |
|
389
|
|
|
|
|
|
|
HV* MPUPP; |
|
390
|
|
|
|
|
|
|
SV* const_int[CINTS+1]; /* -1, 0, 1, ..., 99 */ |
|
391
|
|
|
|
|
|
|
void* randcxt; /* per-thread csprng context */ |
|
392
|
|
|
|
|
|
|
uint16_t forcount; /* Track nesting level of for loops */ |
|
393
|
|
|
|
|
|
|
char forexit; /* Boolean whether we should exit early */ |
|
394
|
|
|
|
|
|
|
} my_cxt_t; |
|
395
|
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
START_MY_CXT |
|
397
|
|
|
|
|
|
|
|
|
398
|
391920
|
|
|
|
|
|
static int _is_sv_bigint(pTHX_ SV* n) |
|
399
|
|
|
|
|
|
|
{ |
|
400
|
391920
|
100
|
|
|
|
|
if (sv_isobject(n)) { |
|
401
|
390993
|
50
|
|
|
|
|
const char *hvname = HvNAME_get(SvSTASH(SvRV(n))); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
402
|
390993
|
50
|
|
|
|
|
if (hvname != 0) { |
|
403
|
390993
|
100
|
|
|
|
|
if (strEQ(hvname, "Math::BigInt") || /* BigFloat not here, force to PP */ |
|
404
|
8
|
50
|
|
|
|
|
strEQ(hvname, "Math::GMPz") || strEQ(hvname, "Math::GMP") || |
|
|
|
50
|
|
|
|
|
|
|
405
|
8
|
50
|
|
|
|
|
strEQ(hvname, "Math::GMPq") || strEQ(hvname, "Math::AnyNum") || |
|
|
|
50
|
|
|
|
|
|
|
406
|
8
|
50
|
|
|
|
|
strEQ(hvname, "Math::Pari") || strEQ(hvname, "Math::BigInt::Lite")) |
|
|
|
50
|
|
|
|
|
|
|
407
|
390985
|
|
|
|
|
|
return 1; |
|
408
|
|
|
|
|
|
|
} |
|
409
|
|
|
|
|
|
|
} |
|
410
|
935
|
|
|
|
|
|
return 0; |
|
411
|
|
|
|
|
|
|
} |
|
412
|
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
/******************************************************************************/ |
|
414
|
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
/* Is this a pedantically valid integer? |
|
416
|
|
|
|
|
|
|
* Croaks if undefined or invalid. |
|
417
|
|
|
|
|
|
|
* Returns 0 if it is an object or a string too large for a UV. |
|
418
|
|
|
|
|
|
|
* Returns 1/-1 if it is good to process by XS. |
|
419
|
|
|
|
|
|
|
* TODO: it would be useful to know the sign even if returning 0 for bigint. |
|
420
|
|
|
|
|
|
|
*/ |
|
421
|
286854
|
|
|
|
|
|
static int _validate_int(pTHX_ SV* n, int negok) |
|
422
|
|
|
|
|
|
|
{ |
|
423
|
286854
|
100
|
|
|
|
|
const char* mustbe = (negok) ? "must be an integer" : "must be a non-negative integer"; |
|
424
|
|
|
|
|
|
|
const char* maxstr; |
|
425
|
|
|
|
|
|
|
char* ptr; |
|
426
|
|
|
|
|
|
|
STRLEN i, len, maxlen; |
|
427
|
286854
|
|
|
|
|
|
int ret, isbignum = 0, isneg = 0; |
|
428
|
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
/* TODO: magic, grok_number, etc. */ |
|
430
|
286854
|
50
|
|
|
|
|
if (SVNUMTEST(n)) { /* If defined as number, use it */ |
|
431
|
0
|
0
|
|
|
|
|
if (SvIsUV(n) || SvIVX(n) >= 0) return 1; /* The normal case */ |
|
|
|
0
|
|
|
|
|
|
|
432
|
0
|
0
|
|
|
|
|
if (negok) return -1; |
|
433
|
0
|
|
|
|
|
|
else croak("Parameter '%" SVf "' %s", n, mustbe); |
|
434
|
|
|
|
|
|
|
} |
|
435
|
286854
|
100
|
|
|
|
|
if (sv_isobject(n)) { |
|
436
|
278228
|
|
|
|
|
|
isbignum = _is_sv_bigint(aTHX_ n); |
|
437
|
278228
|
100
|
|
|
|
|
if (!isbignum) return 0; |
|
438
|
|
|
|
|
|
|
} |
|
439
|
286849
|
100
|
|
|
|
|
if (!SvOK(n)) croak("Parameter must be defined"); |
|
440
|
286829
|
100
|
|
|
|
|
if (SvGAMAGIC(n) && !isbignum) ptr = SvPV(n, len); |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
441
|
286828
|
|
|
|
|
|
else ptr = SvPV_nomg(n, len); |
|
442
|
286829
|
100
|
|
|
|
|
if (len == 0 || ptr == 0) croak("Parameter %s", mustbe); |
|
|
|
50
|
|
|
|
|
|
|
443
|
286828
|
100
|
|
|
|
|
if (ptr[0] == '-' && negok) { |
|
|
|
100
|
|
|
|
|
|
|
444
|
2103
|
|
|
|
|
|
isneg = 1; ptr++; len--; /* Read negative sign */ |
|
445
|
284725
|
100
|
|
|
|
|
} else if (ptr[0] == '+') { |
|
446
|
5
|
|
|
|
|
|
ptr++; len--; /* Allow a single plus sign */ |
|
447
|
|
|
|
|
|
|
} |
|
448
|
|
|
|
|
|
|
/* Empty string or non-numeric */ |
|
449
|
286828
|
100
|
|
|
|
|
if (len == 0 || !isDIGIT(ptr[0])) croak("Parameter '%" SVf "' %s", n, mustbe); |
|
|
|
100
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
/* Leading zeros and if left with only zero */ |
|
451
|
287033
|
100
|
|
|
|
|
while (len > 0 && *ptr == '0') /* Strip all leading zeros */ |
|
|
|
100
|
|
|
|
|
|
|
452
|
230
|
|
|
|
|
|
{ ptr++; len--; } |
|
453
|
286803
|
100
|
|
|
|
|
if (len == 0) /* 0 or -0 */ |
|
454
|
223
|
|
|
|
|
|
return 1; |
|
455
|
|
|
|
|
|
|
/* We're going to look more carefully at the string to ensure it's a number */ |
|
456
|
286580
|
100
|
|
|
|
|
if (isneg) { ret = -1; maxlen = ivmax_maxlen; maxstr = ivmin_str; } |
|
457
|
284479
|
|
|
|
|
|
else { ret = 1; maxlen = uvmax_maxlen; maxstr = uvmax_str; } |
|
458
|
21751170
|
100
|
|
|
|
|
for (i = 0; i < len; i++) /* Ensure all characters are digits */ |
|
459
|
21464602
|
100
|
|
|
|
|
if (!isDIGIT(ptr[i])) |
|
460
|
12
|
|
|
|
|
|
croak("Parameter '%" SVf "' %s", n, mustbe); |
|
461
|
286568
|
100
|
|
|
|
|
if (len > maxlen) return 0; /* Obvious bigint */ |
|
462
|
48815
|
100
|
|
|
|
|
if (len < maxlen) return ret; /* Valid small integer */ |
|
463
|
229899
|
100
|
|
|
|
|
for (i = 0; i < maxlen; i++) /* Check if in range */ |
|
464
|
229764
|
100
|
|
|
|
|
if (ptr[i] != maxstr[i]) |
|
465
|
41754
|
100
|
|
|
|
|
return ptr[i] < maxstr[i] ? ret : 0; |
|
466
|
135
|
|
|
|
|
|
return ret; /* value = UV_MAX/UV_MIN. That's ok */ |
|
467
|
|
|
|
|
|
|
} |
|
468
|
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
#define IFLAG_ANY 0x00000000U |
|
470
|
|
|
|
|
|
|
#define IFLAG_POS 0x00000001U /* Must be non-negative */ |
|
471
|
|
|
|
|
|
|
#define IFLAG_NONZERO 0x00000002U /* Must not be zero */ |
|
472
|
|
|
|
|
|
|
#define IFLAG_ABS 0x00000004U /* Absolute value returned */ |
|
473
|
|
|
|
|
|
|
#define IFLAG_IV 0x00000008U /* Value returned as IV */ |
|
474
|
|
|
|
|
|
|
|
|
475
|
5311135
|
|
|
|
|
|
static int _validate_and_set(UV* val, pTHX_ SV* svn, uint32_t mask) { |
|
476
|
|
|
|
|
|
|
int status; |
|
477
|
|
|
|
|
|
|
|
|
478
|
5311135
|
50
|
|
|
|
|
if (svn == 0) croak("Parameter must be defined"); |
|
479
|
|
|
|
|
|
|
/* Streamline the typical path of input being a native integer. */ |
|
480
|
5311135
|
100
|
|
|
|
|
if (SVNUMTEST(svn)) { |
|
481
|
5024281
|
|
|
|
|
|
IV n = SvIVX(svn); |
|
482
|
5024281
|
100
|
|
|
|
|
if (n >= 0) { |
|
483
|
4121759
|
100
|
|
|
|
|
if (n == 0 && (mask & IFLAG_NONZERO)) |
|
|
|
100
|
|
|
|
|
|
|
484
|
1
|
|
|
|
|
|
croak("Parameter '%" SVf "' must be a positive integer", svn); |
|
485
|
4121758
|
|
|
|
|
|
*val = (UV)n; |
|
486
|
4121758
|
|
|
|
|
|
return 1; |
|
487
|
|
|
|
|
|
|
} |
|
488
|
902522
|
100
|
|
|
|
|
if (SvIsUV(svn)) { |
|
489
|
127250
|
100
|
|
|
|
|
if (mask & IFLAG_IV) |
|
490
|
27
|
|
|
|
|
|
return 0; |
|
491
|
127223
|
|
|
|
|
|
*val = (UV)n; |
|
492
|
127223
|
|
|
|
|
|
return 1; |
|
493
|
|
|
|
|
|
|
} |
|
494
|
775272
|
100
|
|
|
|
|
if (mask & IFLAG_ABS) { *val = (UV)(-n); return 1; } |
|
495
|
414238
|
100
|
|
|
|
|
if (mask & IFLAG_POS) croak("Parameter '%" SVf "' must be a non-negative integer", svn); |
|
496
|
414222
|
|
|
|
|
|
*val = n; |
|
497
|
414222
|
|
|
|
|
|
return -1; |
|
498
|
|
|
|
|
|
|
} |
|
499
|
|
|
|
|
|
|
|
|
500
|
286854
|
|
|
|
|
|
status = _validate_int( aTHX_ svn, !(mask & IFLAG_POS) ); |
|
501
|
286796
|
100
|
|
|
|
|
if (status == 1) { |
|
502
|
7613
|
|
|
|
|
|
UV n = my_svuv(svn); |
|
503
|
7613
|
100
|
|
|
|
|
if (n == 0 && (mask & IFLAG_NONZERO)) |
|
|
|
50
|
|
|
|
|
|
|
504
|
0
|
|
|
|
|
|
croak("Parameter '%" SVf "' must be a positive integer", svn); |
|
505
|
7613
|
100
|
|
|
|
|
if (n > (UV)IV_MAX && (mask & IFLAG_IV)) |
|
|
|
50
|
|
|
|
|
|
|
506
|
0
|
|
|
|
|
|
return 0; |
|
507
|
7613
|
|
|
|
|
|
*val = n; |
|
508
|
279183
|
100
|
|
|
|
|
} else if (status == -1) { |
|
509
|
257
|
|
|
|
|
|
IV n = my_sviv(svn); |
|
510
|
257
|
100
|
|
|
|
|
if (mask & IFLAG_ABS) { *val = (UV)(-n); status = 1; } |
|
511
|
226
|
|
|
|
|
|
else { *val = (UV)n; } |
|
512
|
|
|
|
|
|
|
} |
|
513
|
286796
|
|
|
|
|
|
return status; |
|
514
|
|
|
|
|
|
|
} |
|
515
|
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
/******************************************************************************/ |
|
517
|
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
#if 1 |
|
519
|
|
|
|
|
|
|
/* This is NEGATE_2UV(iv) from handy.h */ |
|
520
|
|
|
|
|
|
|
#define neg_iv(n) ((UV)-((n)+1) + 1U) |
|
521
|
|
|
|
|
|
|
#else |
|
522
|
|
|
|
|
|
|
static UV neg_iv(UV n) { |
|
523
|
|
|
|
|
|
|
if ((IV)n == IV_MIN) return (UV_MAX >> 1) + 1; |
|
524
|
|
|
|
|
|
|
else return (UV) (-(IV)n); |
|
525
|
|
|
|
|
|
|
} |
|
526
|
|
|
|
|
|
|
#endif |
|
527
|
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
/* Given 'a' and astatus (-1 means 'a' is an IV), properly mod with n */ |
|
529
|
160652
|
|
|
|
|
|
static void _mod_with(UV *a, int astatus, UV n) { |
|
530
|
160652
|
50
|
|
|
|
|
if (n == 0) return; |
|
531
|
160652
|
100
|
|
|
|
|
if (astatus != -1) { |
|
532
|
140456
|
|
|
|
|
|
*a %= n; |
|
533
|
|
|
|
|
|
|
} else { |
|
534
|
20196
|
|
|
|
|
|
UV r = neg_iv(*a) % n; |
|
535
|
20196
|
50
|
|
|
|
|
*a = (r == 0) ? 0 : n-r; |
|
536
|
|
|
|
|
|
|
} |
|
537
|
|
|
|
|
|
|
} |
|
538
|
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
/******************************************************************************/ |
|
540
|
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
#define VCALL_ROOT 0x0 |
|
542
|
|
|
|
|
|
|
#define VCALL_PP 0x1 |
|
543
|
|
|
|
|
|
|
#define VCALL_GMP 0x2 |
|
544
|
|
|
|
|
|
|
/* Call a Perl sub to handle work for us. */ |
|
545
|
115115
|
|
|
|
|
|
static int _vcallsubn(pTHX_ I32 flags, I32 stashflags, const char* name, int nargs, int minversion) |
|
546
|
|
|
|
|
|
|
{ |
|
547
|
115115
|
|
|
|
|
|
GV* gv = NULL; |
|
548
|
|
|
|
|
|
|
dMY_CXT; |
|
549
|
115115
|
|
|
|
|
|
Size_t namelen = strlen(name); |
|
550
|
|
|
|
|
|
|
/* If given a GMP function, and GMP enabled, and function exists, use it. */ |
|
551
|
115115
|
100
|
|
|
|
|
int use_gmp = stashflags & VCALL_GMP && _XS_get_callgmp() && _XS_get_callgmp() >= minversion; |
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
assert(!(stashflags & ~(VCALL_PP|VCALL_GMP))); |
|
553
|
115115
|
50
|
|
|
|
|
if (use_gmp && hv_exists(MY_CXT.MPUGMP,name,namelen)) { |
|
|
|
0
|
|
|
|
|
|
|
554
|
0
|
|
|
|
|
|
GV ** gvp = (GV**)hv_fetch(MY_CXT.MPUGMP,name,namelen,0); |
|
555
|
0
|
0
|
|
|
|
|
if (gvp) gv = *gvp; |
|
556
|
|
|
|
|
|
|
} |
|
557
|
115115
|
50
|
|
|
|
|
if (!gv && (stashflags & VCALL_PP)) |
|
|
|
100
|
|
|
|
|
|
|
558
|
115114
|
|
|
|
|
|
perl_require_pv("Math/Prime/Util/PP.pm"); |
|
559
|
115115
|
50
|
|
|
|
|
if (!gv) { |
|
560
|
115115
|
100
|
|
|
|
|
GV ** gvp = (GV**)hv_fetch(stashflags & VCALL_PP? MY_CXT.MPUPP : MY_CXT.MPUroot, name,namelen,0); |
|
561
|
115115
|
50
|
|
|
|
|
if (gvp) gv = *gvp; |
|
562
|
|
|
|
|
|
|
} |
|
563
|
|
|
|
|
|
|
/* use PL_stack_sp in PUSHMARK macro directly it will be read after |
|
564
|
|
|
|
|
|
|
the possible mark stack extend */ |
|
565
|
115115
|
50
|
|
|
|
|
PUSHMARK(PL_stack_sp-nargs); |
|
566
|
|
|
|
|
|
|
/* no PUTBACK bc we didn't move global SP */ |
|
567
|
115115
|
|
|
|
|
|
return call_sv((SV*)gv, flags); |
|
568
|
|
|
|
|
|
|
} |
|
569
|
|
|
|
|
|
|
|
|
570
|
283
|
|
|
|
|
|
static NOINLINE const char* _subname(pTHX_ const CV *cv) { return GvNAME(CvGV(cv)); } |
|
571
|
|
|
|
|
|
|
#define SUBNAME _subname(aTHX_ cv) |
|
572
|
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
/* -1 if not found, array entry if found */ |
|
574
|
115092
|
|
|
|
|
|
static int find_gmp_info(const char *name) { |
|
575
|
115092
|
|
|
|
|
|
const int ngmpinfo = sizeof(gmp_info)/sizeof(gmp_info[0]); |
|
576
|
|
|
|
|
|
|
int i; |
|
577
|
|
|
|
|
|
|
/* Stupid linear scan */ |
|
578
|
2694497
|
100
|
|
|
|
|
for (i = 0; i < ngmpinfo; i++) |
|
579
|
2690376
|
100
|
|
|
|
|
if (strcmp(gmp_info[i].name, name) == 0) |
|
580
|
110971
|
|
|
|
|
|
return i; |
|
581
|
4121
|
|
|
|
|
|
return -1; |
|
582
|
|
|
|
|
|
|
} |
|
583
|
115092
|
|
|
|
|
|
static NOINLINE void dispatch_external(pTHX_ const CV* thiscv, I32 context, int nitems, bool gmp_is_ok) |
|
584
|
|
|
|
|
|
|
{ |
|
585
|
115092
|
|
|
|
|
|
const char *name = GvNAME(CvGV(thiscv)); |
|
586
|
115092
|
|
|
|
|
|
const int ginfoi = find_gmp_info(name); |
|
587
|
115092
|
|
|
|
|
|
I32 callflags = VCALL_PP; |
|
588
|
115092
|
|
|
|
|
|
uint32_t ver = 0; |
|
589
|
115092
|
100
|
|
|
|
|
bool usegmp = ginfoi >= 0 && gmp_is_ok; |
|
|
|
100
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
|
|
591
|
115092
|
100
|
|
|
|
|
if (usegmp) { |
|
592
|
107650
|
|
|
|
|
|
ver = gmp_info[ginfoi].version; |
|
593
|
107650
|
|
|
|
|
|
callflags |= VCALL_GMP; |
|
594
|
|
|
|
|
|
|
} |
|
595
|
|
|
|
|
|
|
|
|
596
|
115092
|
|
|
|
|
|
_vcallsubn(aTHX_ context, callflags, name, nitems, ver); |
|
597
|
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
/* TODO: _vcallsubn returns the number of values we got back. Use this |
|
599
|
|
|
|
|
|
|
* together with the gmp_info type to decide what to objectify. |
|
600
|
|
|
|
|
|
|
* We're missing the input sv that gives us the desired return class. |
|
601
|
|
|
|
|
|
|
*/ |
|
602
|
115091
|
|
|
|
|
|
} |
|
603
|
|
|
|
|
|
|
#define DISPATCHPP() dispatch_external(aTHX_ cv, GIMME_V, items, TRUE) |
|
604
|
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
#define DISPATCHPP_GMPONLYIF(expr) \ |
|
606
|
|
|
|
|
|
|
dispatch_external(aTHX_ cv, GIMME_V, items, !!(expr)) |
|
607
|
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
#define DISPATCH_VOIDPP() \ |
|
609
|
|
|
|
|
|
|
(void)_vcallsubn(aTHX_ G_VOID|G_DISCARD, VCALL_PP, SUBNAME, items, 0) |
|
610
|
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
#define CALLROOTSUB(fn) \ |
|
612
|
|
|
|
|
|
|
(void)_vcallsubn(aTHX_ GIMME_V, VCALL_ROOT, fn, items, 0) |
|
613
|
|
|
|
|
|
|
#define CALLROOTSUB_ONE_SCALAR(fn) \ |
|
614
|
|
|
|
|
|
|
(void)_vcallsubn(aTHX_ G_SCALAR, VCALL_ROOT, fn, 1, 0) |
|
615
|
|
|
|
|
|
|
#define CALLROOTSUB_VOID(fn) \ |
|
616
|
|
|
|
|
|
|
(void)_vcallsubn(aTHX_ G_VOID|G_DISCARD, VCALL_ROOT, fn, items, 0) |
|
617
|
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
#define OBJECTIFY_STACK(n) \ |
|
619
|
|
|
|
|
|
|
do { \ |
|
620
|
|
|
|
|
|
|
uint32_t i_, nargs_ = n; \ |
|
621
|
|
|
|
|
|
|
for (i_ = 0; i_ < nargs_; i_++) \ |
|
622
|
|
|
|
|
|
|
if (SvOK(ST(i_)) && !sv_isobject(ST(i_)) && !SVNUMTEST(ST(i_))) \ |
|
623
|
|
|
|
|
|
|
break; \ |
|
624
|
|
|
|
|
|
|
if (i_ < nargs_) \ |
|
625
|
|
|
|
|
|
|
_vcallsubn(aTHX_ G_ARRAY,VCALL_ROOT,"_maybe_bigint_allargs",nargs_,0); \ |
|
626
|
|
|
|
|
|
|
} while (0) |
|
627
|
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
/* Returns 0 if we see no reason to wrap this sub inside it's own scope. |
|
629
|
|
|
|
|
|
|
Returns 1 if we need to because of locals created. |
|
630
|
|
|
|
|
|
|
Returns 1 if it's too complicated (long, infinite loop, deep branches) */ |
|
631
|
1246
|
|
|
|
|
|
static bool cv_needs_scope(pTHX_ const CV *cv) { |
|
632
|
1246
|
|
|
|
|
|
OP *o = CvSTART(cv); |
|
633
|
1246
|
|
|
|
|
|
size_t nops = 0; |
|
634
|
|
|
|
|
|
|
OP *branches[8]; |
|
635
|
1246
|
|
|
|
|
|
int nbranch = 0; |
|
636
|
5171
|
100
|
|
|
|
|
for (; nops < 500; o = o->op_next) { |
|
637
|
5169
|
100
|
|
|
|
|
if (!o) { |
|
638
|
56
|
50
|
|
|
|
|
if (nbranch > 0) { o = branches[--nbranch]; continue; } |
|
639
|
56
|
|
|
|
|
|
break; |
|
640
|
|
|
|
|
|
|
} |
|
641
|
|
|
|
|
|
|
/* printf(" %s\n",PL_op_name[o->op_type]); */ |
|
642
|
5113
|
|
|
|
|
|
nops++; |
|
643
|
5113
|
|
|
|
|
|
switch (o->op_type) { |
|
644
|
1188
|
|
|
|
|
|
case OP_PADSV: case OP_PADAV: case OP_PADHV: |
|
645
|
|
|
|
|
|
|
case OP_ANONCODE: |
|
646
|
|
|
|
|
|
|
#if PERL_VERSION_GE(5,17,6) |
|
647
|
|
|
|
|
|
|
case OP_PADRANGE: |
|
648
|
|
|
|
|
|
|
#endif |
|
649
|
|
|
|
|
|
|
#if PERL_VERSION_GE(5,27,6) |
|
650
|
|
|
|
|
|
|
case OP_MULTICONCAT: /* This could hide a PADSV -- we don't know */ |
|
651
|
|
|
|
|
|
|
#endif |
|
652
|
|
|
|
|
|
|
#if PERL_VERSION_GE(5,37,3) |
|
653
|
|
|
|
|
|
|
case OP_PADSV_STORE: |
|
654
|
|
|
|
|
|
|
#endif |
|
655
|
1188
|
|
|
|
|
|
return 1; |
|
656
|
|
|
|
|
|
|
|
|
657
|
28
|
|
|
|
|
|
case OP_AND: case OP_OR: case OP_COND_EXPR: |
|
658
|
|
|
|
|
|
|
case OP_ANDASSIGN: case OP_ORASSIGN: |
|
659
|
|
|
|
|
|
|
#if PERL_VERSION_GE(5,9,0) |
|
660
|
|
|
|
|
|
|
case OP_DOR: |
|
661
|
|
|
|
|
|
|
case OP_DORASSIGN: |
|
662
|
|
|
|
|
|
|
#endif |
|
663
|
28
|
50
|
|
|
|
|
if (nbranch >= 8) return 1; /* Too deep */ |
|
664
|
28
|
|
|
|
|
|
branches[nbranch++] = cLOGOPx(o)->op_other; |
|
665
|
28
|
|
|
|
|
|
break; |
|
666
|
78
|
|
|
|
|
|
case OP_LEAVESUB: |
|
667
|
78
|
100
|
|
|
|
|
if (nbranch > 0) { o = branches[--nbranch]; continue; } |
|
668
|
56
|
|
|
|
|
|
break; |
|
669
|
|
|
|
|
|
|
} |
|
670
|
|
|
|
|
|
|
} |
|
671
|
58
|
100
|
|
|
|
|
if (nops >= 500) return 1; |
|
672
|
56
|
|
|
|
|
|
return 0; |
|
673
|
|
|
|
|
|
|
} |
|
674
|
|
|
|
|
|
|
#define DECL_MULTICALL_SCOPE(cv) bool addscope = cv_needs_scope(aTHX_ cv) |
|
675
|
|
|
|
|
|
|
#define SCOPED_MULTICALL \ |
|
676
|
|
|
|
|
|
|
do { if(addscope) {ENTER;} MULTICALL; if(addscope) {LEAVE;} } while(0) |
|
677
|
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
/******************************************************************************/ |
|
679
|
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
#define SETSUBREF(cv, block) \ |
|
681
|
|
|
|
|
|
|
do { \ |
|
682
|
|
|
|
|
|
|
GV *gv_; \ |
|
683
|
|
|
|
|
|
|
HV *stash_; \ |
|
684
|
|
|
|
|
|
|
cv = sv_2cv(block, &stash_, &gv_, 0); \ |
|
685
|
|
|
|
|
|
|
if (cv == Nullcv) croak("%s: Not a subroutine reference", SUBNAME); \ |
|
686
|
|
|
|
|
|
|
} while (0) |
|
687
|
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
/* In my testing, this constant return works fine with threads, but to be |
|
689
|
|
|
|
|
|
|
* correct (see perlxs) one has to make a context, store separate copies in |
|
690
|
|
|
|
|
|
|
* each one, then retrieve them from a struct using a hash index. This |
|
691
|
|
|
|
|
|
|
* defeats the purpose if only done once. */ |
|
692
|
|
|
|
|
|
|
#define RETURN_NPARITY(ret) \ |
|
693
|
|
|
|
|
|
|
do { int r_ = ret; \ |
|
694
|
|
|
|
|
|
|
dMY_CXT; \ |
|
695
|
|
|
|
|
|
|
if (r_ >= -1 && r_
|
|
696
|
|
|
|
|
|
|
else { XSRETURN_IV(r_); } \ |
|
697
|
|
|
|
|
|
|
} while (0) |
|
698
|
|
|
|
|
|
|
#define PUSH_NPARITY(ret) \ |
|
699
|
|
|
|
|
|
|
do { int r_ = ret; \ |
|
700
|
|
|
|
|
|
|
if (r_ >= -1 && r_
|
|
701
|
|
|
|
|
|
|
else { PUSHs(sv_2mortal(newSViv(r_))); } \ |
|
702
|
|
|
|
|
|
|
} while (0) |
|
703
|
|
|
|
|
|
|
|
|
704
|
108154
|
|
|
|
|
|
static void objectify_result(pTHX_ SV* input, SV* output) { |
|
705
|
|
|
|
|
|
|
/* Leave unchanged: undef, objects, small integers */ |
|
706
|
108154
|
100
|
|
|
|
|
if (!SvOK(output) || sv_isobject(output) || SVNUMTEST(output)) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
707
|
108153
|
|
|
|
|
|
return; |
|
708
|
|
|
|
|
|
|
/* If they didn't give us a bigint, then try to be smart */ |
|
709
|
1
|
50
|
|
|
|
|
if (!input || !sv_isobject(input)) { |
|
|
|
50
|
|
|
|
|
|
|
710
|
1
|
|
|
|
|
|
CALLROOTSUB_ONE_SCALAR("_to_bigint_if_needed"); |
|
711
|
|
|
|
|
|
|
} else { |
|
712
|
0
|
0
|
|
|
|
|
const char *iname = HvNAME_get(SvSTASH(SvRV(input))); |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
713
|
0
|
0
|
|
|
|
|
if (strEQ(iname, "Math::BigInt")) { |
|
714
|
0
|
|
|
|
|
|
CALLROOTSUB_ONE_SCALAR("_to_bigint"); |
|
715
|
0
|
0
|
|
|
|
|
} else if (strEQ(iname, "Math::GMPz")) { |
|
716
|
0
|
|
|
|
|
|
CALLROOTSUB_ONE_SCALAR("_to_gmpz"); |
|
717
|
0
|
0
|
|
|
|
|
} else if (strEQ(iname, "Math::GMP")) { |
|
718
|
0
|
|
|
|
|
|
CALLROOTSUB_ONE_SCALAR("_to_gmp"); |
|
719
|
|
|
|
|
|
|
} else { /* Return it as: ref(input)->new(result) */ |
|
720
|
0
|
0
|
|
|
|
|
dSP; (void)POPs; ENTER; PUSHMARK(SP); |
|
721
|
0
|
0
|
|
|
|
|
XPUSHs(sv_2mortal(newSVpv(iname, 0))); XPUSHs(output); |
|
|
|
0
|
|
|
|
|
|
|
722
|
0
|
|
|
|
|
|
PUTBACK; call_method("new", G_SCALAR); LEAVE; |
|
723
|
|
|
|
|
|
|
} |
|
724
|
|
|
|
|
|
|
} |
|
725
|
|
|
|
|
|
|
} |
|
726
|
|
|
|
|
|
|
|
|
727
|
2575
|
|
|
|
|
|
static SV* call_sv_to_func(pTHX_ SV* r, const char* name) { |
|
728
|
2575
|
50
|
|
|
|
|
dSP; ENTER; PUSHMARK(SP); |
|
729
|
2575
|
50
|
|
|
|
|
XPUSHs(r); |
|
730
|
2575
|
|
|
|
|
|
PUTBACK; |
|
731
|
2575
|
|
|
|
|
|
call_pv(name, G_SCALAR); |
|
732
|
2574
|
|
|
|
|
|
SPAGAIN; |
|
733
|
2574
|
|
|
|
|
|
r = POPs; |
|
734
|
2574
|
|
|
|
|
|
PUTBACK; LEAVE; |
|
735
|
2574
|
|
|
|
|
|
return r; |
|
736
|
|
|
|
|
|
|
} |
|
737
|
876
|
|
|
|
|
|
static SV* sv_to_bigint(pTHX_ SV* r) { |
|
738
|
876
|
|
|
|
|
|
return call_sv_to_func(aTHX_ r, "Math::Prime::Util::_to_bigint"); |
|
739
|
|
|
|
|
|
|
} |
|
740
|
1650
|
|
|
|
|
|
static SV* sv_to_bigint_abs(pTHX_ SV* r) { |
|
741
|
1650
|
|
|
|
|
|
return call_sv_to_func(aTHX_ r, "Math::Prime::Util::_to_bigint_abs"); |
|
742
|
|
|
|
|
|
|
} |
|
743
|
49
|
|
|
|
|
|
static SV* sv_to_bigint_nonneg(pTHX_ SV* r) { |
|
744
|
49
|
|
|
|
|
|
return call_sv_to_func(aTHX_ r, "Math::Prime::Util::_to_bigint_nonneg"); |
|
745
|
|
|
|
|
|
|
} |
|
746
|
|
|
|
|
|
|
|
|
747
|
|
|
|
|
|
|
#define NEWSVINT(sign,v) (((sign) > 0) ? newSVuv(v) : newSViv(v)) |
|
748
|
|
|
|
|
|
|
#define SETSVINT(sv,setpos,posv,negv) \ |
|
749
|
|
|
|
|
|
|
do { if (setpos) sv_setuv(sv,posv); \ |
|
750
|
|
|
|
|
|
|
else sv_setiv(sv,negv); } while(0) |
|
751
|
|
|
|
|
|
|
#if 1 |
|
752
|
|
|
|
|
|
|
#define FASTSETSVINT(sv,setpos,val) \ |
|
753
|
|
|
|
|
|
|
do { \ |
|
754
|
|
|
|
|
|
|
const UV val_ = val; \ |
|
755
|
|
|
|
|
|
|
if ((setpos) && (UV)(val_) > (UV)IV_MAX) { \ |
|
756
|
|
|
|
|
|
|
if (SvTYPE(sv) != SVt_IV) sv_setuv(sv,val_); \ |
|
757
|
|
|
|
|
|
|
else { SvUV_set(sv,val_); SvIsUV_on(sv); } \ |
|
758
|
|
|
|
|
|
|
} else { \ |
|
759
|
|
|
|
|
|
|
if (SvTYPE(sv) != SVt_IV) sv_setiv(sv,(IV)val_); \ |
|
760
|
|
|
|
|
|
|
else { SvIV_set(sv,(IV)val_); SvIsUV_off(sv); } \ |
|
761
|
|
|
|
|
|
|
} \ |
|
762
|
|
|
|
|
|
|
} while(0) |
|
763
|
|
|
|
|
|
|
#else |
|
764
|
|
|
|
|
|
|
#define FASTSETSVINT(sv,setpos,val) SETSVINT(sv,setpos,val,(IV)val) |
|
765
|
|
|
|
|
|
|
#endif |
|
766
|
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
#define RETURN_128(hi,lo) \ |
|
768
|
|
|
|
|
|
|
do { char str_[40]; \ |
|
769
|
|
|
|
|
|
|
uint32_t slen_ = to_string_128(str_, hi, lo); \ |
|
770
|
|
|
|
|
|
|
ST(0) = sv_to_bigint( aTHX_ sv_2mortal(newSVpv(str_,slen_)) ); \ |
|
771
|
|
|
|
|
|
|
XSRETURN(1); } while(0) |
|
772
|
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
#define CREATE_RETURN_AV(av) \ |
|
774
|
|
|
|
|
|
|
do { \ |
|
775
|
|
|
|
|
|
|
av = newAV(); \ |
|
776
|
|
|
|
|
|
|
{ \ |
|
777
|
|
|
|
|
|
|
SV * retsv = sv_2mortal(newRV_noinc( (SV*) av )); \ |
|
778
|
|
|
|
|
|
|
PUSHs(retsv); \ |
|
779
|
|
|
|
|
|
|
PUTBACK; \ |
|
780
|
|
|
|
|
|
|
SP = NULL; /* never use SP again, poison */ \ |
|
781
|
|
|
|
|
|
|
} \ |
|
782
|
|
|
|
|
|
|
} while(0) |
|
783
|
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
#define PUSH_2ELEM_AREF(p, q) \ |
|
785
|
|
|
|
|
|
|
do { \ |
|
786
|
|
|
|
|
|
|
AV* av_ = newAV(); \ |
|
787
|
|
|
|
|
|
|
av_push(av_, newSVuv(p)); \ |
|
788
|
|
|
|
|
|
|
av_push(av_, newSVuv(q)); \ |
|
789
|
|
|
|
|
|
|
PUSHs(sv_2mortal(newRV_noinc((SV*) av_))); \ |
|
790
|
|
|
|
|
|
|
} while (0) |
|
791
|
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
#define RETURN_LIST_VALS(in_alen,arr,sign) /* Return array values */ \ |
|
793
|
|
|
|
|
|
|
{ \ |
|
794
|
|
|
|
|
|
|
size_t k_, alen_ = in_alen; \ |
|
795
|
|
|
|
|
|
|
if (GIMME_V == G_SCALAR) { \ |
|
796
|
|
|
|
|
|
|
Safefree(arr); \ |
|
797
|
|
|
|
|
|
|
XSRETURN_UV(alen_); \ |
|
798
|
|
|
|
|
|
|
} \ |
|
799
|
|
|
|
|
|
|
EXTEND(SP,(EXTEND_TYPE)alen_); \ |
|
800
|
|
|
|
|
|
|
for (k_ = 0; k_ < alen_; k_++) \ |
|
801
|
|
|
|
|
|
|
ST(k_) = sv_2mortal(NEWSVINT(sign,arr[k_])); \ |
|
802
|
|
|
|
|
|
|
Safefree(arr); \ |
|
803
|
|
|
|
|
|
|
XSRETURN(alen_); \ |
|
804
|
|
|
|
|
|
|
} |
|
805
|
|
|
|
|
|
|
|
|
806
|
|
|
|
|
|
|
#define RETURN_LIST_REF(in_alen,arr,sign) /* Return array values as ref */ \ |
|
807
|
|
|
|
|
|
|
{ \ |
|
808
|
|
|
|
|
|
|
size_t k_, alen_ = in_alen; \ |
|
809
|
|
|
|
|
|
|
AV* av_ = newAV(); \ |
|
810
|
|
|
|
|
|
|
av_extend(av_, (SSize_t)alen_-1); \ |
|
811
|
|
|
|
|
|
|
SV **ar_ = AvARRAY(av_); \ |
|
812
|
|
|
|
|
|
|
for (k_ = 0; k_ < alen_; k_++) \ |
|
813
|
|
|
|
|
|
|
ar_[k_] = NEWSVINT(sign,arr[k_]); \ |
|
814
|
|
|
|
|
|
|
AvFILLp(av_) = (SSize_t)alen_-1; \ |
|
815
|
|
|
|
|
|
|
Safefree(arr); \ |
|
816
|
|
|
|
|
|
|
ST(0) = sv_2mortal(newRV_noinc((SV*) av_)); \ |
|
817
|
|
|
|
|
|
|
XSRETURN(1); \ |
|
818
|
|
|
|
|
|
|
} |
|
819
|
|
|
|
|
|
|
|
|
820
|
|
|
|
|
|
|
#define RETURN_EMPTY_LIST_REF() \ |
|
821
|
|
|
|
|
|
|
{ \ |
|
822
|
|
|
|
|
|
|
AV* av_ = newAV(); \ |
|
823
|
|
|
|
|
|
|
ST(0) = sv_2mortal(newRV_noinc((SV*) av_)); \ |
|
824
|
|
|
|
|
|
|
XSRETURN(1); \ |
|
825
|
|
|
|
|
|
|
} |
|
826
|
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
/******************************************************************************/ |
|
828
|
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
|
|
830
|
|
|
|
|
|
|
#define IARR_TYPE_ANY 0x00 |
|
831
|
|
|
|
|
|
|
#define IARR_TYPE_NEG 0x01 |
|
832
|
|
|
|
|
|
|
#define IARR_TYPE_POS 0x02 |
|
833
|
|
|
|
|
|
|
#define IARR_TYPE_BAD 0x03 |
|
834
|
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
/* BAD always bad, ANY with ANY/POS/NEG, POS and NEG only with ANY and self. */ |
|
836
|
|
|
|
|
|
|
#define CAN_COMBINE_IARR_TYPES(t1,t2) ( ((t1) | (t2)) != IARR_TYPE_BAD ) |
|
837
|
|
|
|
|
|
|
/* Convert to 0/1/-1 status */ |
|
838
|
|
|
|
|
|
|
#define IARR_TYPE_TO_STATUS(t) \ |
|
839
|
|
|
|
|
|
|
(((t) == IARR_TYPE_BAD) ? 0 : ((t) == IARR_TYPE_NEG) ? -1 : 1) |
|
840
|
|
|
|
|
|
|
#define STATUS_TO_IARR_TYPE(s,n) \ |
|
841
|
|
|
|
|
|
|
(((s) == 0) ? IARR_TYPE_BAD : ((s) == -1) ? IARR_TYPE_NEG : ((n) > (UV)IV_MAX) ? IARR_TYPE_POS : IARR_TYPE_ANY) |
|
842
|
|
|
|
|
|
|
|
|
843
|
|
|
|
|
|
|
/* Compare using first argument non-zero to indicate UV, otherwise IV */ |
|
844
|
|
|
|
|
|
|
#define SIGNED_CMP_LE(pos,x,y) ((pos) ? (x <= y) : ((IV)x <= (IV)y)) |
|
845
|
|
|
|
|
|
|
#define SIGNED_CMP_LT(pos,x,y) ((pos) ? (x < y) : ((IV)x < (IV)y)) |
|
846
|
|
|
|
|
|
|
#define SIGNED_CMP_GT(pos,x,y) ((pos) ? (x > y) : ((IV)x > (IV)y)) |
|
847
|
|
|
|
|
|
|
|
|
848
|
|
|
|
|
|
|
/* Given values and a sign indicating IV or UV, returns -1 (<), 0 (eq), 1 (>) */ |
|
849
|
1035
|
|
|
|
|
|
static int _sign_cmp(int xsign, UV x, int ysign, UV y) { |
|
850
|
|
|
|
|
|
|
/* Convert sign to -1 (neg), 0 (small pos), 1 (big pos) */ |
|
851
|
1035
|
100
|
|
|
|
|
if (x <= (UV)IV_MAX) xsign = 0; |
|
852
|
1035
|
100
|
|
|
|
|
if (y <= (UV)IV_MAX) ysign = 0; |
|
853
|
1035
|
100
|
|
|
|
|
if (xsign == ysign && x == y) return 0; |
|
|
|
100
|
|
|
|
|
|
|
854
|
|
|
|
|
|
|
/* neg < small pos < big pos */ |
|
855
|
947
|
100
|
|
|
|
|
if (xsign != ysign) return (xsign < ysign) ? -1 : 1; |
|
|
|
100
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
/* Numerical comparison as IV or UV */ |
|
857
|
880
|
100
|
|
|
|
|
return ((xsign == -1 && (IV)x < (IV)y) || (xsign != -1 && x < y)) ? -1 : 1; |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
} |
|
859
|
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
/******************************************************************************/ |
|
861
|
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
#define CHECK_ARRAYREF1(sv,name) \ |
|
863
|
|
|
|
|
|
|
do { \ |
|
864
|
|
|
|
|
|
|
if ( !SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVAV ) \ |
|
865
|
|
|
|
|
|
|
croak("%s: expected array reference", name); \ |
|
866
|
|
|
|
|
|
|
} while (0) |
|
867
|
|
|
|
|
|
|
#define CHECK_ARRAYREF(sv) CHECK_ARRAYREF1(sv,SUBNAME) |
|
868
|
|
|
|
|
|
|
|
|
869
|
|
|
|
|
|
|
#define CHECK_AV_NOT_READONLY1(av,name) \ |
|
870
|
|
|
|
|
|
|
do { \ |
|
871
|
|
|
|
|
|
|
if (SvREADONLY(av)) \ |
|
872
|
|
|
|
|
|
|
croak("%s: array reference is readonly", name); \ |
|
873
|
|
|
|
|
|
|
} while (0) |
|
874
|
|
|
|
|
|
|
#define CHECK_AV_NOT_READONLY(av) CHECK_AV_NOT_READONLY1(av, SUBNAME) |
|
875
|
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
#define DECL_ARREF(name) \ |
|
877
|
|
|
|
|
|
|
AV * avp_ ## name; \ |
|
878
|
|
|
|
|
|
|
SV ** svarr_ ## name; \ |
|
879
|
|
|
|
|
|
|
Size_t len_ ## name |
|
880
|
|
|
|
|
|
|
|
|
881
|
|
|
|
|
|
|
#define AR_READ 0 |
|
882
|
|
|
|
|
|
|
#define AR_WRITE 1 |
|
883
|
|
|
|
|
|
|
#define USE_ARREF(name, sv, subname, will_modify) \ |
|
884
|
|
|
|
|
|
|
do { \ |
|
885
|
|
|
|
|
|
|
CHECK_ARRAYREF1(sv, subname); \ |
|
886
|
|
|
|
|
|
|
avp_ ## name = (AV*) SvRV(sv); \ |
|
887
|
|
|
|
|
|
|
len_ ## name = av_count(avp_ ## name); \ |
|
888
|
|
|
|
|
|
|
if (will_modify) \ |
|
889
|
|
|
|
|
|
|
CHECK_AV_NOT_READONLY1(avp_ ## name, subname); \ |
|
890
|
|
|
|
|
|
|
if (SvMAGICAL(avp_ ## name) || (will_modify && !AvREAL(avp_ ## name) && AvREIFY(avp_ ## name))) \ |
|
891
|
|
|
|
|
|
|
svarr_ ## name = 0; \ |
|
892
|
|
|
|
|
|
|
else \ |
|
893
|
|
|
|
|
|
|
svarr_ ## name = AvARRAY(avp_ ## name); \ |
|
894
|
|
|
|
|
|
|
} while(0) |
|
895
|
|
|
|
|
|
|
|
|
896
|
2314
|
|
|
|
|
|
static SV* _fetch_arref(pTHX_ AV* av, SV** svarr, size_t i) { |
|
897
|
2314
|
50
|
|
|
|
|
if (svarr == 0) { |
|
898
|
0
|
|
|
|
|
|
SV **svp = av_fetch(av, i, 0); |
|
899
|
0
|
0
|
|
|
|
|
return svp ? *svp : &PL_sv_undef; |
|
900
|
|
|
|
|
|
|
} |
|
901
|
2314
|
|
|
|
|
|
return svarr[i]; |
|
902
|
|
|
|
|
|
|
} |
|
903
|
|
|
|
|
|
|
#define FETCH_ARREF(name,i) _fetch_arref(aTHX_ avp_ ## name, svarr_ ## name, i) |
|
904
|
|
|
|
|
|
|
|
|
905
|
|
|
|
|
|
|
#define STORE_ARREF(name, i, sv) \ |
|
906
|
|
|
|
|
|
|
do { (use_direct_ ## name ? (svarr_ ## name)[i] = sv : av_store(avp_ ## name, i, sv)) } while(0) |
|
907
|
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
#define DEBUG_PRINT_ARRAY(name,av) \ |
|
909
|
|
|
|
|
|
|
{ Size_t j_; SV** arr_ = AvARRAY(av); printf("%s: [",name); for(j_=0; j_
|
|
910
|
|
|
|
|
|
|
|
|
911
|
|
|
|
|
|
|
#define READ_UV_IARR(dst, src, itype) \ |
|
912
|
|
|
|
|
|
|
{ \ |
|
913
|
|
|
|
|
|
|
UV n; \ |
|
914
|
|
|
|
|
|
|
int istatus = _validate_and_set(&n, aTHX_ src, IFLAG_ANY); \ |
|
915
|
|
|
|
|
|
|
if (istatus == -1) itype |= IARR_TYPE_NEG; \ |
|
916
|
|
|
|
|
|
|
else if (istatus == 1 && n > (UV)IV_MAX) itype |= IARR_TYPE_POS; \ |
|
917
|
|
|
|
|
|
|
if (istatus == 0 || itype == IARR_TYPE_BAD) break; \ |
|
918
|
|
|
|
|
|
|
dst = n; \ |
|
919
|
|
|
|
|
|
|
} |
|
920
|
|
|
|
|
|
|
|
|
921
|
462
|
|
|
|
|
|
static int arrayref_to_int_array(pTHX_ size_t *retlen, UV** ret, bool want_sort, SV* sva, const char* fstr) |
|
922
|
|
|
|
|
|
|
{ |
|
923
|
|
|
|
|
|
|
Size_t len, i; |
|
924
|
462
|
|
|
|
|
|
int itype = IARR_TYPE_ANY; |
|
925
|
|
|
|
|
|
|
UV *r; |
|
926
|
|
|
|
|
|
|
DECL_ARREF(avp); |
|
927
|
|
|
|
|
|
|
|
|
928
|
462
|
50
|
|
|
|
|
USE_ARREF(avp, sva, fstr, AR_READ); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
929
|
462
|
|
|
|
|
|
len = len_avp; |
|
930
|
462
|
|
|
|
|
|
*retlen = len; |
|
931
|
462
|
100
|
|
|
|
|
if (len == 0) { |
|
932
|
50
|
|
|
|
|
|
*ret = 0; |
|
933
|
50
|
|
|
|
|
|
return itype; |
|
934
|
|
|
|
|
|
|
} |
|
935
|
412
|
50
|
|
|
|
|
New(0, r, len, UV); |
|
936
|
2488
|
100
|
|
|
|
|
for (i = 0; i < len; i++) { |
|
937
|
2159
|
|
|
|
|
|
SV *iv = FETCH_ARREF(avp,i); |
|
938
|
2159
|
50
|
|
|
|
|
if (iv == 0) continue; |
|
939
|
2159
|
100
|
|
|
|
|
if (SVNUMTEST(iv)) { |
|
940
|
1903
|
|
|
|
|
|
IV n = SvIVX(iv); |
|
941
|
1903
|
100
|
|
|
|
|
if (n < 0) { |
|
942
|
424
|
100
|
|
|
|
|
if (SvIsUV(iv)) itype |= IARR_TYPE_POS; |
|
943
|
351
|
|
|
|
|
|
else itype |= IARR_TYPE_NEG; |
|
944
|
424
|
100
|
|
|
|
|
if (itype == IARR_TYPE_BAD) break; |
|
945
|
|
|
|
|
|
|
} |
|
946
|
1883
|
|
|
|
|
|
r[i] = (UV)n; |
|
947
|
|
|
|
|
|
|
} else { |
|
948
|
256
|
100
|
|
|
|
|
READ_UV_IARR(r[i], iv, itype); |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
949
|
|
|
|
|
|
|
} |
|
950
|
|
|
|
|
|
|
} |
|
951
|
412
|
100
|
|
|
|
|
if (i < len) { |
|
952
|
83
|
|
|
|
|
|
Safefree(r); |
|
953
|
83
|
|
|
|
|
|
*ret = 0; |
|
954
|
83
|
|
|
|
|
|
return IARR_TYPE_BAD; |
|
955
|
|
|
|
|
|
|
} |
|
956
|
329
|
|
|
|
|
|
*ret = r; |
|
957
|
329
|
100
|
|
|
|
|
if (want_sort) { |
|
958
|
318
|
100
|
|
|
|
|
if (itype == IARR_TYPE_NEG) { |
|
959
|
637
|
100
|
|
|
|
|
for (i = 1; i < len; i++) |
|
960
|
555
|
100
|
|
|
|
|
if ( (IV)r[i] <= (IV)r[i-1] ) |
|
961
|
17
|
|
|
|
|
|
break; |
|
962
|
|
|
|
|
|
|
} else { |
|
963
|
1240
|
100
|
|
|
|
|
for (i = 1; i < len; i++) |
|
964
|
1042
|
100
|
|
|
|
|
if (r[i] <= r[i-1]) |
|
965
|
21
|
|
|
|
|
|
break; |
|
966
|
|
|
|
|
|
|
} |
|
967
|
318
|
100
|
|
|
|
|
if (i < len) |
|
968
|
38
|
|
|
|
|
|
sort_dedup_uv_array(r, itype == IARR_TYPE_NEG, retlen); |
|
969
|
|
|
|
|
|
|
} |
|
970
|
329
|
|
|
|
|
|
return itype; |
|
971
|
|
|
|
|
|
|
} |
|
972
|
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
/* Check whether an SV is a non-magical arrayref whose elements are all native |
|
974
|
|
|
|
|
|
|
* non-negative integers in strictly increasing order (i.e. sorted and unique). |
|
975
|
|
|
|
|
|
|
* On success returns the AvARRAY pointer and sets *lenp; otherwise NULL. |
|
976
|
|
|
|
|
|
|
* Used by the set-op fast path to skip intermediate UV array allocation. */ |
|
977
|
70
|
|
|
|
|
|
static SV** _check_sorted_nonneg_arrayref(pTHX_ SV *sv, size_t *lenp) |
|
978
|
|
|
|
|
|
|
{ |
|
979
|
|
|
|
|
|
|
AV *av; |
|
980
|
|
|
|
|
|
|
SV **arr; |
|
981
|
|
|
|
|
|
|
size_t len, i; |
|
982
|
70
|
50
|
|
|
|
|
if (!SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVAV) return NULL; |
|
|
|
50
|
|
|
|
|
|
|
983
|
70
|
|
|
|
|
|
av = (AV*)SvRV(sv); |
|
984
|
70
|
50
|
|
|
|
|
if (SvMAGICAL(av)) return NULL; |
|
985
|
70
|
|
|
|
|
|
arr = AvARRAY(av); |
|
986
|
70
|
|
|
|
|
|
len = av_count(av); |
|
987
|
150
|
100
|
|
|
|
|
for (i = 0; i < len; i++) { |
|
988
|
116
|
|
|
|
|
|
SV *elem = arr[i]; |
|
989
|
116
|
100
|
|
|
|
|
if (!SVNUMTEST(elem) || (!SvIsUV(elem) && SvIVX(elem) < 0)) return NULL; |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
990
|
88
|
100
|
|
|
|
|
if (i > 0 && SvUVX(elem) <= SvUVX(arr[i-1])) return NULL; |
|
|
|
100
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
} |
|
992
|
34
|
|
|
|
|
|
*lenp = len; |
|
993
|
34
|
|
|
|
|
|
return arr; |
|
994
|
|
|
|
|
|
|
} |
|
995
|
|
|
|
|
|
|
|
|
996
|
202
|
|
|
|
|
|
static int array_to_int_array(pTHX_ size_t *retlen, UV** ret, bool want_sort, SV** svbase, size_t len) |
|
997
|
|
|
|
|
|
|
{ |
|
998
|
|
|
|
|
|
|
size_t i; |
|
999
|
202
|
|
|
|
|
|
int itype = IARR_TYPE_ANY; |
|
1000
|
|
|
|
|
|
|
UV *r; |
|
1001
|
202
|
|
|
|
|
|
*retlen = len; |
|
1002
|
202
|
50
|
|
|
|
|
if (len == 0) { |
|
1003
|
0
|
|
|
|
|
|
*ret = 0; |
|
1004
|
0
|
|
|
|
|
|
return itype; |
|
1005
|
|
|
|
|
|
|
} |
|
1006
|
202
|
50
|
|
|
|
|
New(0, r, len, UV); |
|
1007
|
1070
|
100
|
|
|
|
|
for (i = 0; i < len; i++) { |
|
1008
|
923
|
|
|
|
|
|
SV *iv = svbase[i]; |
|
1009
|
923
|
100
|
|
|
|
|
if (SVNUMTEST(iv)) { |
|
1010
|
800
|
|
|
|
|
|
IV n = SvIVX(iv); |
|
1011
|
800
|
100
|
|
|
|
|
if (n < 0) { |
|
1012
|
85
|
100
|
|
|
|
|
if (SvIsUV(iv)) itype |= IARR_TYPE_POS; |
|
1013
|
49
|
|
|
|
|
|
else itype |= IARR_TYPE_NEG; |
|
1014
|
85
|
100
|
|
|
|
|
if (itype == IARR_TYPE_BAD) break; |
|
1015
|
|
|
|
|
|
|
} |
|
1016
|
794
|
|
|
|
|
|
r[i] = (UV)n; |
|
1017
|
|
|
|
|
|
|
} else { |
|
1018
|
123
|
100
|
|
|
|
|
READ_UV_IARR(r[i], iv, itype); |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
1019
|
|
|
|
|
|
|
} |
|
1020
|
|
|
|
|
|
|
} |
|
1021
|
202
|
100
|
|
|
|
|
if (i < len) { |
|
1022
|
55
|
|
|
|
|
|
Safefree(r); |
|
1023
|
55
|
|
|
|
|
|
*ret = 0; |
|
1024
|
55
|
|
|
|
|
|
return IARR_TYPE_BAD; |
|
1025
|
|
|
|
|
|
|
} |
|
1026
|
147
|
|
|
|
|
|
*ret = r; |
|
1027
|
147
|
100
|
|
|
|
|
if (want_sort) { |
|
1028
|
87
|
100
|
|
|
|
|
if (itype == IARR_TYPE_NEG) { |
|
1029
|
45
|
100
|
|
|
|
|
for (i = 1; i < len; i++) |
|
1030
|
32
|
100
|
|
|
|
|
if ( (IV)r[i] <= (IV)r[i-1] ) |
|
1031
|
10
|
|
|
|
|
|
break; |
|
1032
|
|
|
|
|
|
|
} else { |
|
1033
|
204
|
100
|
|
|
|
|
for (i = 1; i < len; i++) |
|
1034
|
160
|
100
|
|
|
|
|
if (r[i] <= r[i-1]) |
|
1035
|
20
|
|
|
|
|
|
break; |
|
1036
|
|
|
|
|
|
|
} |
|
1037
|
87
|
100
|
|
|
|
|
if (i < len) |
|
1038
|
30
|
|
|
|
|
|
sort_dedup_uv_array(r, itype == IARR_TYPE_NEG, retlen); |
|
1039
|
|
|
|
|
|
|
} |
|
1040
|
147
|
|
|
|
|
|
return itype; |
|
1041
|
|
|
|
|
|
|
} |
|
1042
|
|
|
|
|
|
|
|
|
1043
|
14
|
|
|
|
|
|
static int arrayref_to_digit_array(pTHX_ UV** ret, AV* av, int base) |
|
1044
|
|
|
|
|
|
|
{ |
|
1045
|
|
|
|
|
|
|
SSize_t len, i; |
|
1046
|
14
|
|
|
|
|
|
UV *r, carry = 0; |
|
1047
|
14
|
50
|
|
|
|
|
if (SvTYPE((SV*)av) != SVt_PVAV) |
|
1048
|
0
|
|
|
|
|
|
croak("fromdigits first argument must be a string or array reference"); |
|
1049
|
14
|
|
|
|
|
|
len = av_count(av); |
|
1050
|
14
|
50
|
|
|
|
|
New(0, r, len, UV); |
|
1051
|
122
|
100
|
|
|
|
|
for (i = len-1; i >= 0; i--) { |
|
1052
|
108
|
|
|
|
|
|
SV** psvd = av_fetch(av, i, 0); |
|
1053
|
108
|
50
|
|
|
|
|
if (_validate_and_set(r+i, aTHX_ *psvd, IFLAG_ANY) != 1) break; |
|
1054
|
108
|
|
|
|
|
|
r[i] += carry; |
|
1055
|
108
|
100
|
|
|
|
|
if (r[i] >= (UV)base && i > 0) { |
|
|
|
100
|
|
|
|
|
|
|
1056
|
11
|
|
|
|
|
|
carry = r[i] / base; |
|
1057
|
11
|
|
|
|
|
|
r[i] -= carry * base; |
|
1058
|
|
|
|
|
|
|
} else { |
|
1059
|
97
|
|
|
|
|
|
carry = 0; |
|
1060
|
|
|
|
|
|
|
} |
|
1061
|
|
|
|
|
|
|
} |
|
1062
|
14
|
50
|
|
|
|
|
if (i >= 0) { |
|
1063
|
0
|
|
|
|
|
|
Safefree(r); |
|
1064
|
0
|
|
|
|
|
|
return -1; |
|
1065
|
|
|
|
|
|
|
} |
|
1066
|
|
|
|
|
|
|
/* printf("array is ["); for(i=0;i
|
|
1067
|
14
|
|
|
|
|
|
*ret = r; |
|
1068
|
14
|
|
|
|
|
|
return len; |
|
1069
|
|
|
|
|
|
|
} |
|
1070
|
|
|
|
|
|
|
|
|
1071
|
|
|
|
|
|
|
/******************************************************************************/ |
|
1072
|
|
|
|
|
|
|
|
|
1073
|
28
|
|
|
|
|
|
static int type_of_sumset(int typea, int typeb, UV amin, UV amax, UV bmin, UV bmax) { |
|
1074
|
28
|
50
|
|
|
|
|
if (typea == IARR_TYPE_BAD || typeb == IARR_TYPE_BAD) |
|
|
|
50
|
|
|
|
|
|
|
1075
|
0
|
|
|
|
|
|
return IARR_TYPE_BAD; |
|
1076
|
28
|
100
|
|
|
|
|
if (typea != IARR_TYPE_NEG && typeb != IARR_TYPE_NEG) { |
|
|
|
50
|
|
|
|
|
|
|
1077
|
|
|
|
|
|
|
/* ANY+ANY ANY+POS POS+ANY POS+POS */ |
|
1078
|
17
|
100
|
|
|
|
|
if (UV_MAX-amax < bmax) return IARR_TYPE_BAD; |
|
1079
|
14
|
100
|
|
|
|
|
if (amax+bmax > (UV)IV_MAX) return IARR_TYPE_POS; |
|
1080
|
12
|
|
|
|
|
|
return IARR_TYPE_ANY; |
|
1081
|
|
|
|
|
|
|
} |
|
1082
|
|
|
|
|
|
|
/* For simplicity, throw out NEG+POS to avoid UV+IV */ |
|
1083
|
11
|
50
|
|
|
|
|
if (typea == IARR_TYPE_POS || typeb == IARR_TYPE_POS) |
|
|
|
100
|
|
|
|
|
|
|
1084
|
3
|
|
|
|
|
|
return IARR_TYPE_BAD; |
|
1085
|
|
|
|
|
|
|
/* NEG+NEG NEG+ANY ANY+NEG */ |
|
1086
|
8
|
100
|
|
|
|
|
if ((IV)amax > 0 && (IV)bmax > 0 && amax + bmax > (UV)IV_MAX) |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
1087
|
2
|
|
|
|
|
|
return IARR_TYPE_BAD; /* overflow */ |
|
1088
|
6
|
50
|
|
|
|
|
if ((IV)amin < 0 && (IV)bmin < 0 && (UV)(-(IV)amin) + (UV)(-(IV)bmin) > (UV)IV_MAX) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
1089
|
2
|
|
|
|
|
|
return IARR_TYPE_BAD; /* underflow */ |
|
1090
|
4
|
50
|
|
|
|
|
if (((IV)amin > 0 || (IV)bmin > 0) && (IV)(amin+bmin) >= 0) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
1091
|
1
|
|
|
|
|
|
return IARR_TYPE_ANY; /* Result is all positive */ |
|
1092
|
3
|
|
|
|
|
|
return IARR_TYPE_NEG; |
|
1093
|
|
|
|
|
|
|
} |
|
1094
|
|
|
|
|
|
|
|
|
1095
|
|
|
|
|
|
|
/******************************************************************************/ |
|
1096
|
|
|
|
|
|
|
|
|
1097
|
|
|
|
|
|
|
#define MPU_SC_SIZE 257 /* Choose 131, 257, 521, 1031, 2053 */ |
|
1098
|
|
|
|
|
|
|
typedef struct { /* lo in 0, hi in 1, cached values in rest */ |
|
1099
|
|
|
|
|
|
|
UV value[2+MPU_SC_SIZE]; |
|
1100
|
|
|
|
|
|
|
size_t index[2+MPU_SC_SIZE]; |
|
1101
|
|
|
|
|
|
|
signed char status[2+MPU_SC_SIZE]; |
|
1102
|
|
|
|
|
|
|
} set_data_t; |
|
1103
|
|
|
|
|
|
|
|
|
1104
|
36
|
|
|
|
|
|
static void _sc_clear_cache(set_data_t *cache) { |
|
1105
|
36
|
|
|
|
|
|
memset(cache->status, 0, sizeof(signed char) * (2+MPU_SC_SIZE)); |
|
1106
|
36
|
|
|
|
|
|
} |
|
1107
|
|
|
|
|
|
|
|
|
1108
|
|
|
|
|
|
|
#define _SC_GET_VALUE(statvar, var, arr, i) \ |
|
1109
|
|
|
|
|
|
|
statvar = _validate_and_set(&var, aTHX_ arr[i], IFLAG_ANY); \ |
|
1110
|
|
|
|
|
|
|
if (statvar == 0) return -1; |
|
1111
|
|
|
|
|
|
|
|
|
1112
|
|
|
|
|
|
|
#define SC_SET_MID_VALUE(statvar, var, arr, i, cache) \ |
|
1113
|
|
|
|
|
|
|
do { \ |
|
1114
|
|
|
|
|
|
|
if (cache == 0) { \ |
|
1115
|
|
|
|
|
|
|
_SC_GET_VALUE(statvar, var, arr, i) \ |
|
1116
|
|
|
|
|
|
|
} else { \ |
|
1117
|
|
|
|
|
|
|
unsigned int imod_ = 2 + ((i) % MPU_SC_SIZE); \ |
|
1118
|
|
|
|
|
|
|
if (cache->status[imod_] != 0 && cache->index[imod_] == i) { \ |
|
1119
|
|
|
|
|
|
|
statvar = cache->status[imod_]; \ |
|
1120
|
|
|
|
|
|
|
var = cache->value[imod_]; \ |
|
1121
|
|
|
|
|
|
|
} else { \ |
|
1122
|
|
|
|
|
|
|
_SC_GET_VALUE(statvar, var, arr, i) \ |
|
1123
|
|
|
|
|
|
|
cache->status[imod_] = statvar; \ |
|
1124
|
|
|
|
|
|
|
cache->value[imod_] = var; \ |
|
1125
|
|
|
|
|
|
|
cache->index[imod_] = i; \ |
|
1126
|
|
|
|
|
|
|
} \ |
|
1127
|
|
|
|
|
|
|
} \ |
|
1128
|
|
|
|
|
|
|
} while (0) |
|
1129
|
|
|
|
|
|
|
|
|
1130
|
166
|
|
|
|
|
|
static int _sc_set_lohi(pTHX_ SV** avarr, set_data_t *cache, int loindex, int hiindex, int *lostatus, int *histatus, UV *loval, UV *hival) |
|
1131
|
|
|
|
|
|
|
{ |
|
1132
|
166
|
100
|
|
|
|
|
if (cache && cache->status[0] != 0) { |
|
|
|
100
|
|
|
|
|
|
|
1133
|
45
|
|
|
|
|
|
*lostatus = cache->status[0]; *loval = cache->value[0]; |
|
1134
|
|
|
|
|
|
|
} else { |
|
1135
|
121
|
100
|
|
|
|
|
_SC_GET_VALUE(*lostatus, *loval, avarr, loindex); |
|
1136
|
117
|
100
|
|
|
|
|
if (cache) { |
|
1137
|
23
|
|
|
|
|
|
cache->status[0] = *lostatus; |
|
1138
|
23
|
|
|
|
|
|
cache->value[0] = *loval; |
|
1139
|
|
|
|
|
|
|
} |
|
1140
|
|
|
|
|
|
|
} |
|
1141
|
162
|
100
|
|
|
|
|
if (cache && cache->status[1] != 0) { |
|
|
|
100
|
|
|
|
|
|
|
1142
|
45
|
|
|
|
|
|
*histatus = cache->status[1]; *hival = cache->value[1]; |
|
1143
|
|
|
|
|
|
|
} else { |
|
1144
|
117
|
50
|
|
|
|
|
_SC_GET_VALUE(*histatus, *hival, avarr, hiindex); |
|
1145
|
117
|
100
|
|
|
|
|
if (cache) { |
|
1146
|
23
|
|
|
|
|
|
cache->status[1] = *histatus; |
|
1147
|
23
|
|
|
|
|
|
cache->value[1] = *hival; |
|
1148
|
|
|
|
|
|
|
} |
|
1149
|
|
|
|
|
|
|
} |
|
1150
|
162
|
|
|
|
|
|
return 1; |
|
1151
|
|
|
|
|
|
|
} |
|
1152
|
|
|
|
|
|
|
|
|
1153
|
|
|
|
|
|
|
|
|
1154
|
|
|
|
|
|
|
|
|
1155
|
|
|
|
|
|
|
/* index of val in a set (array ref of sorted unique integers) |
|
1156
|
|
|
|
|
|
|
* -1 bigint |
|
1157
|
|
|
|
|
|
|
* n nth-position (0 .. count-1) |
|
1158
|
|
|
|
|
|
|
* eq will be set to 1 if the element in that position is the input value. |
|
1159
|
|
|
|
|
|
|
*/ |
|
1160
|
169
|
|
|
|
|
|
static int index_for_set(pTHX_ AV* av, set_data_t *cache, int sign, UV val, int *eq) |
|
1161
|
|
|
|
|
|
|
{ |
|
1162
|
|
|
|
|
|
|
Size_t len; |
|
1163
|
|
|
|
|
|
|
int lo, hi, lostatus, histatus, midstatus, cmp; |
|
1164
|
|
|
|
|
|
|
UV rlo, rhi, rmid; |
|
1165
|
|
|
|
|
|
|
SV** arr; |
|
1166
|
|
|
|
|
|
|
|
|
1167
|
169
|
100
|
|
|
|
|
if (sign != 1 && sign != -1) |
|
|
|
100
|
|
|
|
|
|
|
1168
|
3
|
|
|
|
|
|
return -1; |
|
1169
|
166
|
|
|
|
|
|
len = av_count(av); |
|
1170
|
166
|
100
|
|
|
|
|
if (len == 0) { |
|
1171
|
3
|
|
|
|
|
|
*eq = 0; |
|
1172
|
3
|
|
|
|
|
|
return 0; |
|
1173
|
|
|
|
|
|
|
} |
|
1174
|
163
|
|
|
|
|
|
arr = AvARRAY(av); |
|
1175
|
|
|
|
|
|
|
|
|
1176
|
163
|
|
|
|
|
|
lo = 0; |
|
1177
|
163
|
|
|
|
|
|
hi = len-1; |
|
1178
|
163
|
100
|
|
|
|
|
if (_sc_set_lohi(aTHX_ arr, cache, lo, hi, &lostatus, &histatus, &rlo, &rhi) < 0) |
|
1179
|
4
|
|
|
|
|
|
return -1; |
|
1180
|
|
|
|
|
|
|
|
|
1181
|
159
|
|
|
|
|
|
cmp = _sign_cmp(sign, val, lostatus, rlo); |
|
1182
|
159
|
100
|
|
|
|
|
if (cmp <= 0) { *eq = cmp==0; return lo; } |
|
1183
|
|
|
|
|
|
|
/* val > rlo */ |
|
1184
|
108
|
|
|
|
|
|
cmp = _sign_cmp(sign, val, histatus, rhi); |
|
1185
|
108
|
100
|
|
|
|
|
if (cmp >= 0) { *eq = cmp==0; return hi + (cmp>0); } |
|
1186
|
|
|
|
|
|
|
/* val < rhi */ |
|
1187
|
|
|
|
|
|
|
|
|
1188
|
247
|
100
|
|
|
|
|
while (hi-lo > 1) { |
|
1189
|
218
|
|
|
|
|
|
int mid = lo + ((hi-lo) >> 1); |
|
1190
|
218
|
100
|
|
|
|
|
SC_SET_MID_VALUE(midstatus, rmid, arr, (size_t)mid, cache); |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
1191
|
218
|
|
|
|
|
|
cmp = _sign_cmp(midstatus, rmid, sign, val); |
|
1192
|
218
|
100
|
|
|
|
|
if (cmp == 0) { *eq = 1; return mid; } |
|
1193
|
173
|
100
|
|
|
|
|
if (cmp < 0) { lo = mid; rlo = rmid; lostatus = midstatus; } |
|
1194
|
84
|
|
|
|
|
|
else { hi = mid; rhi = rmid; histatus = midstatus; } |
|
1195
|
|
|
|
|
|
|
} |
|
1196
|
29
|
100
|
|
|
|
|
if (sign == histatus && rhi == val) |
|
|
|
50
|
|
|
|
|
|
|
1197
|
0
|
|
|
|
|
|
*eq = 1; |
|
1198
|
29
|
50
|
|
|
|
|
else if (_sign_cmp(sign,val, histatus,rhi) > 0) |
|
1199
|
0
|
|
|
|
|
|
croak("internal index error"); |
|
1200
|
29
|
|
|
|
|
|
return hi; |
|
1201
|
|
|
|
|
|
|
} |
|
1202
|
|
|
|
|
|
|
|
|
1203
|
|
|
|
|
|
|
/* Find index to insert in a set (array ref of sorted unique integers) |
|
1204
|
|
|
|
|
|
|
* -1 bigint |
|
1205
|
|
|
|
|
|
|
* 0 already in set |
|
1206
|
|
|
|
|
|
|
* n should be in n-th position (1 means should be first element) |
|
1207
|
|
|
|
|
|
|
*/ |
|
1208
|
64
|
|
|
|
|
|
static int insert_index_in_set(pTHX_ AV* av, set_data_t *cache, int sign, UV val) { |
|
1209
|
64
|
|
|
|
|
|
int eq = 0; |
|
1210
|
64
|
|
|
|
|
|
int index = index_for_set(aTHX_ av, cache, sign, val, &eq); |
|
1211
|
64
|
50
|
|
|
|
|
return (index < 0) ? index : eq ? 0 : index+1; |
|
|
|
100
|
|
|
|
|
|
|
1212
|
|
|
|
|
|
|
} |
|
1213
|
|
|
|
|
|
|
|
|
1214
|
|
|
|
|
|
|
/* Find index of element in a set (array ref of sorted unique integers) |
|
1215
|
|
|
|
|
|
|
* -1 bigint |
|
1216
|
|
|
|
|
|
|
* 0 not in set |
|
1217
|
|
|
|
|
|
|
* n in n-th position (1 means first element) |
|
1218
|
|
|
|
|
|
|
*/ |
|
1219
|
33
|
|
|
|
|
|
static int index_in_set(pTHX_ AV* av, set_data_t *cache, int sign, UV val) { |
|
1220
|
33
|
|
|
|
|
|
int eq = 0; |
|
1221
|
33
|
|
|
|
|
|
int index = index_for_set(aTHX_ av, cache, sign, val, &eq); |
|
1222
|
33
|
50
|
|
|
|
|
return (index < 0) ? index : eq ? index+1 : 0; |
|
|
|
100
|
|
|
|
|
|
|
1223
|
|
|
|
|
|
|
} |
|
1224
|
|
|
|
|
|
|
|
|
1225
|
|
|
|
|
|
|
/* See if an element is in a set (array ref of sorted unique integers) */ |
|
1226
|
|
|
|
|
|
|
/* -1 = bigint, 0 = not found, 1 = found */ |
|
1227
|
72
|
|
|
|
|
|
static int is_in_set(pTHX_ AV* av, set_data_t *cache, int sign, UV val) |
|
1228
|
|
|
|
|
|
|
{ |
|
1229
|
72
|
|
|
|
|
|
int eq = 0; |
|
1230
|
72
|
|
|
|
|
|
int index = index_for_set(aTHX_ av, cache, sign, val, &eq); |
|
1231
|
72
|
100
|
|
|
|
|
return (index < 0) ? index : eq ? 1 : 0; |
|
1232
|
|
|
|
|
|
|
} |
|
1233
|
|
|
|
|
|
|
|
|
1234
|
|
|
|
|
|
|
/* 1 if deleted, 0 if not deleted, -1 if need to punt to PP */ |
|
1235
|
33
|
|
|
|
|
|
static int del_from_set(pTHX_ AV* ava, int bstatus, UV b) { |
|
1236
|
33
|
|
|
|
|
|
int index = index_in_set(aTHX_ ava, 0, bstatus, b); |
|
1237
|
33
|
100
|
|
|
|
|
if (index <= 0) |
|
1238
|
8
|
|
|
|
|
|
return index; |
|
1239
|
|
|
|
|
|
|
{ |
|
1240
|
25
|
|
|
|
|
|
SV **arr = AvARRAY(ava); |
|
1241
|
25
|
|
|
|
|
|
SV *savep = arr[index-1]; |
|
1242
|
25
|
|
|
|
|
|
Size_t pos = index, alen = av_count(ava); |
|
1243
|
25
|
100
|
|
|
|
|
if (pos > alen/2) { |
|
1244
|
13
|
100
|
|
|
|
|
if (pos < alen) { |
|
1245
|
5
|
|
|
|
|
|
memmove(arr+pos-1, arr+pos, sizeof(SV*) * (alen-pos)); |
|
1246
|
5
|
|
|
|
|
|
arr[alen-1] = savep; |
|
1247
|
|
|
|
|
|
|
} |
|
1248
|
13
|
|
|
|
|
|
SvREFCNT_dec_NN(av_pop(ava)); |
|
1249
|
|
|
|
|
|
|
} else { |
|
1250
|
12
|
50
|
|
|
|
|
if (pos > 1) { |
|
1251
|
0
|
|
|
|
|
|
memmove(arr+1, arr+0, sizeof(SV*) * (pos-1)); |
|
1252
|
0
|
|
|
|
|
|
arr[0] = savep; |
|
1253
|
|
|
|
|
|
|
} |
|
1254
|
12
|
|
|
|
|
|
SvREFCNT_dec_NN(av_shift(ava)); |
|
1255
|
|
|
|
|
|
|
} |
|
1256
|
|
|
|
|
|
|
} |
|
1257
|
25
|
|
|
|
|
|
return 1; |
|
1258
|
|
|
|
|
|
|
} |
|
1259
|
|
|
|
|
|
|
/* 1 if inserted, 0 if not inserted, -1 if need to punt to PP */ |
|
1260
|
49
|
|
|
|
|
|
static int ins_into_set(pTHX_ AV* ava, int bstatus, UV b) { |
|
1261
|
49
|
|
|
|
|
|
int index = insert_index_in_set(aTHX_ ava, 0, bstatus, b); |
|
1262
|
49
|
100
|
|
|
|
|
if (index <= 0) |
|
1263
|
2
|
|
|
|
|
|
return index; |
|
1264
|
|
|
|
|
|
|
{ |
|
1265
|
|
|
|
|
|
|
SV *newb, **arr; |
|
1266
|
47
|
100
|
|
|
|
|
SV* newsvb = NEWSVINT(bstatus, b); |
|
1267
|
47
|
|
|
|
|
|
Size_t alen = av_count(ava); |
|
1268
|
47
|
100
|
|
|
|
|
if ((Size_t)index > alen/2) { |
|
1269
|
38
|
|
|
|
|
|
av_push(ava, newsvb); |
|
1270
|
38
|
100
|
|
|
|
|
if ((Size_t)index <= alen) { |
|
1271
|
19
|
|
|
|
|
|
arr = AvARRAY(ava); |
|
1272
|
19
|
|
|
|
|
|
newb = arr[alen]; |
|
1273
|
19
|
|
|
|
|
|
memmove(arr+index, arr+index-1, sizeof(SV*) * (alen-(index-1))); |
|
1274
|
19
|
|
|
|
|
|
arr[index-1] = newb; |
|
1275
|
|
|
|
|
|
|
} |
|
1276
|
|
|
|
|
|
|
} else { |
|
1277
|
9
|
|
|
|
|
|
av_unshift(ava, 1); |
|
1278
|
9
|
|
|
|
|
|
av_store(ava, 0, newsvb); |
|
1279
|
9
|
100
|
|
|
|
|
if (index > 1) { |
|
1280
|
3
|
|
|
|
|
|
arr = AvARRAY(ava); |
|
1281
|
3
|
|
|
|
|
|
newb = arr[0]; |
|
1282
|
3
|
|
|
|
|
|
memmove(arr+0, arr+1, sizeof(SV*) * index); |
|
1283
|
3
|
|
|
|
|
|
arr[index-1] = newb; |
|
1284
|
|
|
|
|
|
|
} |
|
1285
|
|
|
|
|
|
|
} |
|
1286
|
|
|
|
|
|
|
} |
|
1287
|
47
|
|
|
|
|
|
return 1; |
|
1288
|
|
|
|
|
|
|
} |
|
1289
|
|
|
|
|
|
|
|
|
1290
|
|
|
|
|
|
|
/******************************************************************************/ |
|
1291
|
|
|
|
|
|
|
|
|
1292
|
39
|
|
|
|
|
|
static int _compare_array_refs(pTHX_ SV* a, SV* b) |
|
1293
|
|
|
|
|
|
|
{ |
|
1294
|
|
|
|
|
|
|
AV *ava, *avb; |
|
1295
|
|
|
|
|
|
|
SSize_t i, alen, blen; |
|
1296
|
39
|
50
|
|
|
|
|
if ( ((!SvROK(a)) || (SvTYPE(SvRV(a)) != SVt_PVAV)) || |
|
|
|
50
|
|
|
|
|
|
|
1297
|
39
|
50
|
|
|
|
|
((!SvROK(b)) || (SvTYPE(SvRV(b)) != SVt_PVAV)) ) |
|
|
|
50
|
|
|
|
|
|
|
1298
|
0
|
|
|
|
|
|
return -1; |
|
1299
|
39
|
|
|
|
|
|
ava = (AV*) SvRV(a); |
|
1300
|
39
|
|
|
|
|
|
avb = (AV*) SvRV(b); |
|
1301
|
39
|
|
|
|
|
|
alen = av_len(ava); |
|
1302
|
39
|
|
|
|
|
|
blen = av_len(avb); |
|
1303
|
39
|
100
|
|
|
|
|
if (alen != blen) |
|
1304
|
3
|
|
|
|
|
|
return 0; |
|
1305
|
214
|
100
|
|
|
|
|
for (i = 0; i <= alen; i++) { |
|
1306
|
184
|
|
|
|
|
|
SV** iva = av_fetch(ava, i, 0); |
|
1307
|
184
|
|
|
|
|
|
SV** ivb = av_fetch(avb, i, 0); |
|
1308
|
|
|
|
|
|
|
SV *sva, *svb; |
|
1309
|
|
|
|
|
|
|
int res; |
|
1310
|
|
|
|
|
|
|
|
|
1311
|
184
|
50
|
|
|
|
|
if (!iva || !ivb) return -1; |
|
|
|
50
|
|
|
|
|
|
|
1312
|
184
|
|
|
|
|
|
sva = *iva; |
|
1313
|
184
|
|
|
|
|
|
svb = *ivb; |
|
1314
|
|
|
|
|
|
|
|
|
1315
|
184
|
100
|
|
|
|
|
if (!SvOK(sva) && !SvOK(svb)) /* Two undefs are fine. */ |
|
|
|
100
|
|
|
|
|
|
|
1316
|
2
|
|
|
|
|
|
continue; |
|
1317
|
182
|
100
|
|
|
|
|
if (!SvOK(sva) || !SvOK(svb)) /* One undef isn't ok. */ |
|
|
|
50
|
|
|
|
|
|
|
1318
|
1
|
|
|
|
|
|
return 0; |
|
1319
|
|
|
|
|
|
|
/* Hashes, I/O, etc. are not ok. */ |
|
1320
|
181
|
50
|
|
|
|
|
if (SvTYPE(sva) >= SVt_PVAV || SvTYPE(svb) >= SVt_PVAV) |
|
|
|
50
|
|
|
|
|
|
|
1321
|
0
|
|
|
|
|
|
return -1; |
|
1322
|
|
|
|
|
|
|
|
|
1323
|
|
|
|
|
|
|
/* One of them is a non-object reference */ |
|
1324
|
181
|
100
|
|
|
|
|
if ( (SvROK(sva) && !sv_isobject(sva)) || |
|
|
|
100
|
|
|
|
|
|
|
1325
|
160
|
100
|
|
|
|
|
(SvROK(svb) && !sv_isobject(svb)) ) { |
|
|
|
100
|
|
|
|
|
|
|
1326
|
|
|
|
|
|
|
/* Always error if either one is not an array reference. */ |
|
1327
|
22
|
100
|
|
|
|
|
if ( (SvROK(sva) && SvTYPE(SvRV(sva)) != SVt_PVAV) || |
|
|
|
100
|
|
|
|
|
|
|
1328
|
21
|
50
|
|
|
|
|
(SvROK(svb) && SvTYPE(SvRV(svb)) != SVt_PVAV) ) |
|
|
|
50
|
|
|
|
|
|
|
1329
|
1
|
|
|
|
|
|
return -1; |
|
1330
|
|
|
|
|
|
|
/* One reference, one non-reference = not equal */ |
|
1331
|
21
|
100
|
|
|
|
|
if (SvROK(sva) != SvROK(svb)) |
|
1332
|
1
|
|
|
|
|
|
return 0; |
|
1333
|
|
|
|
|
|
|
/* Now we know both are array references. Compare. */ |
|
1334
|
20
|
|
|
|
|
|
res = _compare_array_refs(aTHX_ sva, svb); |
|
1335
|
20
|
50
|
|
|
|
|
if (res == 1) continue; |
|
1336
|
0
|
|
|
|
|
|
return res; |
|
1337
|
|
|
|
|
|
|
} |
|
1338
|
|
|
|
|
|
|
|
|
1339
|
|
|
|
|
|
|
/* Common case: two simple integers */ |
|
1340
|
159
|
100
|
|
|
|
|
if ( SVNUMTEST(sva) && SVNUMTEST(svb) |
|
|
|
100
|
|
|
|
|
|
|
1341
|
116
|
50
|
|
|
|
|
&& (SvTYPE(sva) == SVt_IV || SvTYPE(sva) == SVt_PVIV) |
|
|
|
0
|
|
|
|
|
|
|
1342
|
116
|
50
|
|
|
|
|
&& (SvTYPE(svb) == SVt_IV || SvTYPE(svb) == SVt_PVIV) ) { |
|
|
|
0
|
|
|
|
|
|
|
1343
|
116
|
|
|
|
|
|
UV va = my_svuv(sva), vb = my_svuv(svb); |
|
1344
|
116
|
100
|
|
|
|
|
if (va != vb) return 0; |
|
1345
|
115
|
|
|
|
|
|
continue; |
|
1346
|
|
|
|
|
|
|
} |
|
1347
|
|
|
|
|
|
|
|
|
1348
|
|
|
|
|
|
|
/* This function is more useful if we allow more than strictly integers */ |
|
1349
|
|
|
|
|
|
|
{ /* Compare the string representation */ |
|
1350
|
|
|
|
|
|
|
STRLEN alen, blen; |
|
1351
|
43
|
|
|
|
|
|
const char* stra = SvPV(sva, alen); |
|
1352
|
43
|
|
|
|
|
|
const char* strb = SvPV(svb, blen); |
|
1353
|
43
|
100
|
|
|
|
|
if (alen != blen || strcmp(stra,strb) != 0) |
|
|
|
100
|
|
|
|
|
|
|
1354
|
2
|
|
|
|
|
|
return 0; |
|
1355
|
|
|
|
|
|
|
} |
|
1356
|
|
|
|
|
|
|
} |
|
1357
|
30
|
|
|
|
|
|
return 1; |
|
1358
|
|
|
|
|
|
|
} |
|
1359
|
|
|
|
|
|
|
|
|
1360
|
121
|
|
|
|
|
|
static void csprng_init_seed(void* ctx) { |
|
1361
|
|
|
|
|
|
|
unsigned char* data; |
|
1362
|
121
|
|
|
|
|
|
New(0, data, 64, unsigned char); |
|
1363
|
121
|
|
|
|
|
|
get_entropy_bytes(64, data); |
|
1364
|
121
|
|
|
|
|
|
csprng_seed(ctx, 64, data); |
|
1365
|
121
|
|
|
|
|
|
Safefree(data); |
|
1366
|
121
|
|
|
|
|
|
} |
|
1367
|
|
|
|
|
|
|
|
|
1368
|
39
|
|
|
|
|
|
static void _comb_init(UV* cm, UV k, int derangement) { |
|
1369
|
|
|
|
|
|
|
UV i; |
|
1370
|
39
|
|
|
|
|
|
cm[0] = UV_MAX; |
|
1371
|
142
|
100
|
|
|
|
|
for (i = 0; i < k; i++) |
|
1372
|
103
|
|
|
|
|
|
cm[i] = k-i; |
|
1373
|
39
|
100
|
|
|
|
|
if (derangement && k >= 2) { /* Make derangements start deranged */ |
|
|
|
100
|
|
|
|
|
|
|
1374
|
23
|
100
|
|
|
|
|
for (i = 0; i < k; i++) |
|
1375
|
19
|
100
|
|
|
|
|
cm[k-i-1] = (i&1) ? i : i+2; |
|
1376
|
4
|
100
|
|
|
|
|
if (k & 1) { |
|
1377
|
3
|
|
|
|
|
|
cm[0] = k-2; |
|
1378
|
3
|
|
|
|
|
|
cm[1] = k; |
|
1379
|
|
|
|
|
|
|
} |
|
1380
|
|
|
|
|
|
|
} |
|
1381
|
39
|
|
|
|
|
|
} |
|
1382
|
|
|
|
|
|
|
|
|
1383
|
22534
|
|
|
|
|
|
static int _comb_iterate(UV* cm, UV k, UV n, int ix) { |
|
1384
|
|
|
|
|
|
|
UV i, j, m; |
|
1385
|
22534
|
100
|
|
|
|
|
if (ix == 0) { |
|
1386
|
15584
|
100
|
|
|
|
|
if (cm[0]++ < n) return 0; /* Increment last value */ |
|
1387
|
38836
|
100
|
|
|
|
|
for (i = 1; i < k && cm[i] >= n-i; i++) ; /* Find next index to incr */ |
|
|
|
100
|
|
|
|
|
|
|
1388
|
11674
|
100
|
|
|
|
|
if (i >= k) return 1; /* Done! */ |
|
1389
|
11649
|
|
|
|
|
|
cm[i]++; /* Increment this one */ |
|
1390
|
50423
|
100
|
|
|
|
|
while (i-- > 0) cm[i] = cm[i+1] + 1; /* Set the rest */ |
|
1391
|
6950
|
100
|
|
|
|
|
} else if (ix == 1) { |
|
1392
|
8736
|
100
|
|
|
|
|
for (j = 1; j < k && cm[j] > cm[j-1]; j++) ; /* Find last decrease */ |
|
|
|
100
|
|
|
|
|
|
|
1393
|
5086
|
100
|
|
|
|
|
if (j >= k) return 1; /* Done! */ |
|
1394
|
6898
|
100
|
|
|
|
|
for (m = 0; cm[j] > cm[m]; m++) ; /* Find next greater */ |
|
1395
|
5080
|
|
|
|
|
|
{ UV t = cm[j]; cm[j] = cm[m]; cm[m] = t; } /* Swap */ |
|
1396
|
7833
|
100
|
|
|
|
|
for (i = j-1, m = 0; m < i; i--, m++) /* Reverse the end */ |
|
1397
|
2753
|
|
|
|
|
|
{ UV t = cm[i]; cm[i] = cm[m]; cm[m] = t; } |
|
1398
|
|
|
|
|
|
|
} else { |
|
1399
|
2737
|
|
|
|
|
|
REDERANGE: |
|
1400
|
5005
|
100
|
|
|
|
|
for (j = 1; j < k && cm[j] > cm[j-1]; j++) ; /* Find last decrease */ |
|
|
|
100
|
|
|
|
|
|
|
1401
|
2737
|
100
|
|
|
|
|
if (j >= k) return 1; /* Done! */ |
|
1402
|
3866
|
100
|
|
|
|
|
for (m = 0; cm[j] > cm[m]; m++) ; /* Find next greater */ |
|
1403
|
2732
|
|
|
|
|
|
{ UV t = cm[j]; cm[j] = cm[m]; cm[m] = t; } /* Swap */ |
|
1404
|
2732
|
100
|
|
|
|
|
if (cm[j] == k-j) goto REDERANGE; /* Skip? */ |
|
1405
|
3567
|
100
|
|
|
|
|
for (i = j-1, m = 0; m < i; i--, m++) /* Reverse the end */ |
|
1406
|
1371
|
|
|
|
|
|
{ UV t = cm[i]; cm[i] = cm[m]; cm[m] = t; } |
|
1407
|
17120
|
100
|
|
|
|
|
for (i = 0; i < k; i++) /* Check deranged */ |
|
1408
|
15261
|
100
|
|
|
|
|
if (cm[k-i-1]-1 == i) |
|
1409
|
337
|
|
|
|
|
|
break; |
|
1410
|
2196
|
100
|
|
|
|
|
if (i != k) goto REDERANGE; |
|
1411
|
|
|
|
|
|
|
} |
|
1412
|
18588
|
|
|
|
|
|
return 0; |
|
1413
|
|
|
|
|
|
|
} |
|
1414
|
|
|
|
|
|
|
|
|
1415
|
|
|
|
|
|
|
/******************************************************************************/ |
|
1416
|
|
|
|
|
|
|
/******************************************************************************/ |
|
1417
|
|
|
|
|
|
|
|
|
1418
|
|
|
|
|
|
|
MODULE = Math::Prime::Util PACKAGE = Math::Prime::Util |
|
1419
|
|
|
|
|
|
|
|
|
1420
|
|
|
|
|
|
|
PROTOTYPES: ENABLE |
|
1421
|
|
|
|
|
|
|
|
|
1422
|
|
|
|
|
|
|
BOOT: |
|
1423
|
|
|
|
|
|
|
{ |
|
1424
|
|
|
|
|
|
|
int i; |
|
1425
|
120
|
|
|
|
|
|
HV * stash = gv_stashpv("Math::Prime::Util", TRUE); |
|
1426
|
|
|
|
|
|
|
|
|
1427
|
120
|
|
|
|
|
|
newCONSTSUB(stash, "_XS_prime_maxbits", newSViv(BITS_PER_WORD)); |
|
1428
|
120
|
|
|
|
|
|
newCONSTSUB(stash, "_ivsize", newSViv(IVSIZE)); |
|
1429
|
120
|
|
|
|
|
|
newCONSTSUB(stash, "_uvsize", newSViv(UVSIZE)); |
|
1430
|
120
|
|
|
|
|
|
newCONSTSUB(stash, "_uvbits", newSViv(UVSIZE * 8)); |
|
1431
|
120
|
|
|
|
|
|
newCONSTSUB(stash, "_nvsize", newSViv(NVSIZE)); |
|
1432
|
120
|
|
|
|
|
|
newCONSTSUB(stash, "_nvmantbits", newSViv(NVMANTBITS)); |
|
1433
|
120
|
|
|
|
|
|
newCONSTSUB(stash, "_nvmantdigits", newSViv((IV)((NVMANTBITS+1) / 3.322))); |
|
1434
|
|
|
|
|
|
|
|
|
1435
|
|
|
|
|
|
|
{ |
|
1436
|
|
|
|
|
|
|
MY_CXT_INIT; |
|
1437
|
120
|
|
|
|
|
|
MY_CXT.MPUroot = stash; |
|
1438
|
120
|
|
|
|
|
|
MY_CXT.MPUGMP = gv_stashpv("Math::Prime::Util::GMP", TRUE); |
|
1439
|
120
|
|
|
|
|
|
MY_CXT.MPUPP = gv_stashpv("Math::Prime::Util::PP", TRUE); |
|
1440
|
12240
|
100
|
|
|
|
|
for (i = 0; i <= CINTS; i++) { |
|
1441
|
12120
|
|
|
|
|
|
MY_CXT.const_int[i] = newSViv(i-1); |
|
1442
|
12120
|
|
|
|
|
|
SvREADONLY_on(MY_CXT.const_int[i]); |
|
1443
|
|
|
|
|
|
|
} |
|
1444
|
120
|
|
|
|
|
|
New(0, MY_CXT.randcxt, csprng_context_size(), char); |
|
1445
|
120
|
|
|
|
|
|
csprng_init_seed(MY_CXT.randcxt); |
|
1446
|
120
|
|
|
|
|
|
MY_CXT.forcount = 0; |
|
1447
|
120
|
|
|
|
|
|
MY_CXT.forexit = 0; |
|
1448
|
|
|
|
|
|
|
} |
|
1449
|
|
|
|
|
|
|
} |
|
1450
|
|
|
|
|
|
|
|
|
1451
|
|
|
|
|
|
|
#if defined(USE_ITHREADS) && defined(MY_CXT_KEY) |
|
1452
|
|
|
|
|
|
|
|
|
1453
|
|
|
|
|
|
|
void |
|
1454
|
|
|
|
|
|
|
CLONE(...) |
|
1455
|
|
|
|
|
|
|
PREINIT: |
|
1456
|
|
|
|
|
|
|
int i; |
|
1457
|
|
|
|
|
|
|
PPCODE: |
|
1458
|
|
|
|
|
|
|
{ |
|
1459
|
|
|
|
|
|
|
MY_CXT_CLONE; /* possible declaration */ |
|
1460
|
|
|
|
|
|
|
MY_CXT.MPUroot = gv_stashpv("Math::Prime::Util", TRUE); |
|
1461
|
|
|
|
|
|
|
MY_CXT.MPUGMP = gv_stashpv("Math::Prime::Util::GMP", TRUE); |
|
1462
|
|
|
|
|
|
|
MY_CXT.MPUPP = gv_stashpv("Math::Prime::Util::PP", TRUE); |
|
1463
|
|
|
|
|
|
|
/* These should be shared between threads, but that's dodgy. */ |
|
1464
|
|
|
|
|
|
|
for (i = 0; i <= CINTS; i++) { |
|
1465
|
|
|
|
|
|
|
MY_CXT.const_int[i] = newSViv(i-1); |
|
1466
|
|
|
|
|
|
|
SvREADONLY_on(MY_CXT.const_int[i]); |
|
1467
|
|
|
|
|
|
|
} |
|
1468
|
|
|
|
|
|
|
/* Make a new CSPRNG context for this thread */ |
|
1469
|
|
|
|
|
|
|
New(0, MY_CXT.randcxt, csprng_context_size(), char); |
|
1470
|
|
|
|
|
|
|
csprng_init_seed(MY_CXT.randcxt); |
|
1471
|
|
|
|
|
|
|
/* NOTE: There is no thread destroy, so these never get freed... */ |
|
1472
|
|
|
|
|
|
|
MY_CXT.forcount = 0; |
|
1473
|
|
|
|
|
|
|
MY_CXT.forexit = 0; |
|
1474
|
|
|
|
|
|
|
} |
|
1475
|
|
|
|
|
|
|
return; /* skip implicit PUTBACK, returning @_ to caller, more efficient*/ |
|
1476
|
|
|
|
|
|
|
|
|
1477
|
|
|
|
|
|
|
#endif |
|
1478
|
|
|
|
|
|
|
|
|
1479
|
|
|
|
|
|
|
void |
|
1480
|
|
|
|
|
|
|
END(...) |
|
1481
|
|
|
|
|
|
|
PREINIT: |
|
1482
|
|
|
|
|
|
|
dMY_CXT; |
|
1483
|
|
|
|
|
|
|
int i; |
|
1484
|
|
|
|
|
|
|
PPCODE: |
|
1485
|
120
|
|
|
|
|
|
_prime_memfreeall(); |
|
1486
|
120
|
|
|
|
|
|
MY_CXT.MPUroot = NULL; |
|
1487
|
120
|
|
|
|
|
|
MY_CXT.MPUGMP = NULL; |
|
1488
|
120
|
|
|
|
|
|
MY_CXT.MPUPP = NULL; |
|
1489
|
12240
|
100
|
|
|
|
|
for (i = 0; i <= CINTS; i++) { |
|
1490
|
12120
|
|
|
|
|
|
SV * const sv = MY_CXT.const_int[i]; |
|
1491
|
12120
|
|
|
|
|
|
MY_CXT.const_int[i] = NULL; |
|
1492
|
12120
|
|
|
|
|
|
SvREFCNT_dec_NN(sv); |
|
1493
|
|
|
|
|
|
|
} /* stashes are owned by stash tree, no refcount on them in MY_CXT */ |
|
1494
|
120
|
|
|
|
|
|
Safefree(MY_CXT.randcxt); MY_CXT.randcxt = 0; |
|
1495
|
120
|
|
|
|
|
|
return; /* skip implicit PUTBACK, returning @_ to caller, more efficient*/ |
|
1496
|
|
|
|
|
|
|
|
|
1497
|
|
|
|
|
|
|
|
|
1498
|
|
|
|
|
|
|
void csrand(IN SV* seed = 0) |
|
1499
|
|
|
|
|
|
|
PREINIT: |
|
1500
|
|
|
|
|
|
|
unsigned char* data; |
|
1501
|
|
|
|
|
|
|
STRLEN size; |
|
1502
|
|
|
|
|
|
|
dMY_CXT; |
|
1503
|
|
|
|
|
|
|
PPCODE: |
|
1504
|
11
|
100
|
|
|
|
|
if (items == 0) { |
|
1505
|
1
|
|
|
|
|
|
csprng_init_seed(MY_CXT.randcxt); |
|
1506
|
10
|
50
|
|
|
|
|
} else if (_XS_get_secure()) { |
|
1507
|
0
|
|
|
|
|
|
croak("secure option set, manual seeding disabled"); |
|
1508
|
|
|
|
|
|
|
} else { |
|
1509
|
10
|
|
|
|
|
|
data = (unsigned char*) SvPV(seed, size); |
|
1510
|
10
|
|
|
|
|
|
csprng_seed(MY_CXT.randcxt, size, data); |
|
1511
|
|
|
|
|
|
|
} |
|
1512
|
11
|
50
|
|
|
|
|
if (_XS_get_callgmp() >= 42) CALLROOTSUB("_csrand_p"); |
|
1513
|
11
|
|
|
|
|
|
return; |
|
1514
|
|
|
|
|
|
|
|
|
1515
|
|
|
|
|
|
|
UV srand(IN UV seedval = 0) |
|
1516
|
|
|
|
|
|
|
PREINIT: |
|
1517
|
|
|
|
|
|
|
dMY_CXT; |
|
1518
|
|
|
|
|
|
|
CODE: |
|
1519
|
5
|
50
|
|
|
|
|
if (_XS_get_secure()) |
|
1520
|
0
|
|
|
|
|
|
croak("secure option set, manual seeding disabled"); |
|
1521
|
5
|
100
|
|
|
|
|
if (items == 0) |
|
1522
|
1
|
|
|
|
|
|
get_entropy_bytes(sizeof(UV), (unsigned char*) &seedval); |
|
1523
|
5
|
|
|
|
|
|
csprng_srand(MY_CXT.randcxt, seedval); |
|
1524
|
5
|
50
|
|
|
|
|
if (_XS_get_callgmp() >= 42) CALLROOTSUB("_srand_p"); |
|
1525
|
5
|
50
|
|
|
|
|
RETVAL = seedval; |
|
1526
|
|
|
|
|
|
|
OUTPUT: |
|
1527
|
|
|
|
|
|
|
RETVAL |
|
1528
|
|
|
|
|
|
|
|
|
1529
|
|
|
|
|
|
|
UV irand() |
|
1530
|
|
|
|
|
|
|
ALIAS: |
|
1531
|
|
|
|
|
|
|
irand64 = 1 |
|
1532
|
|
|
|
|
|
|
PREINIT: |
|
1533
|
|
|
|
|
|
|
dMY_CXT; |
|
1534
|
|
|
|
|
|
|
CODE: |
|
1535
|
|
|
|
|
|
|
#if BITS_PER_WORD == 32 |
|
1536
|
|
|
|
|
|
|
/* TODO: what should irand64 on 32-bit perl do? */ |
|
1537
|
|
|
|
|
|
|
RETVAL = irand32(MY_CXT.randcxt); |
|
1538
|
|
|
|
|
|
|
#else |
|
1539
|
120116
|
100
|
|
|
|
|
RETVAL = ix == 0 ? irand32(MY_CXT.randcxt) : irand64(MY_CXT.randcxt); |
|
|
|
100
|
|
|
|
|
|
|
1540
|
|
|
|
|
|
|
#endif |
|
1541
|
|
|
|
|
|
|
OUTPUT: |
|
1542
|
|
|
|
|
|
|
RETVAL |
|
1543
|
|
|
|
|
|
|
|
|
1544
|
|
|
|
|
|
|
NV drand(NV m = 0.0) |
|
1545
|
|
|
|
|
|
|
ALIAS: |
|
1546
|
|
|
|
|
|
|
rand = 1 |
|
1547
|
|
|
|
|
|
|
PREINIT: |
|
1548
|
|
|
|
|
|
|
dMY_CXT; |
|
1549
|
|
|
|
|
|
|
CODE: |
|
1550
|
|
|
|
|
|
|
PERL_UNUSED_VAR(ix); |
|
1551
|
6037
|
|
|
|
|
|
RETVAL = drand64(MY_CXT.randcxt); |
|
1552
|
6037
|
100
|
|
|
|
|
if (m != 0) RETVAL *= m; |
|
1553
|
|
|
|
|
|
|
OUTPUT: |
|
1554
|
|
|
|
|
|
|
RETVAL |
|
1555
|
|
|
|
|
|
|
|
|
1556
|
|
|
|
|
|
|
SV* random_bytes(IN UV n) |
|
1557
|
|
|
|
|
|
|
PREINIT: |
|
1558
|
|
|
|
|
|
|
char* sptr; |
|
1559
|
|
|
|
|
|
|
dMY_CXT; |
|
1560
|
|
|
|
|
|
|
CODE: |
|
1561
|
33
|
100
|
|
|
|
|
RETVAL = newSV(n == 0 ? 1 : n); |
|
1562
|
33
|
|
|
|
|
|
SvPOK_only(RETVAL); |
|
1563
|
33
|
|
|
|
|
|
SvCUR_set(RETVAL, n); |
|
1564
|
33
|
|
|
|
|
|
sptr = SvPVX(RETVAL); |
|
1565
|
33
|
|
|
|
|
|
csprng_rand_bytes(MY_CXT.randcxt, n, (unsigned char*)sptr); |
|
1566
|
33
|
|
|
|
|
|
sptr[n] = '\0'; |
|
1567
|
|
|
|
|
|
|
OUTPUT: |
|
1568
|
|
|
|
|
|
|
RETVAL |
|
1569
|
|
|
|
|
|
|
|
|
1570
|
|
|
|
|
|
|
SV* entropy_bytes(IN UV n) |
|
1571
|
|
|
|
|
|
|
PREINIT: |
|
1572
|
|
|
|
|
|
|
char* sptr; |
|
1573
|
|
|
|
|
|
|
CODE: |
|
1574
|
2
|
50
|
|
|
|
|
RETVAL = newSV(n == 0 ? 1 : n); |
|
1575
|
2
|
|
|
|
|
|
SvPOK_only(RETVAL); |
|
1576
|
2
|
|
|
|
|
|
SvCUR_set(RETVAL, n); |
|
1577
|
2
|
|
|
|
|
|
sptr = SvPVX(RETVAL); |
|
1578
|
2
|
|
|
|
|
|
get_entropy_bytes(n, (unsigned char*)sptr); |
|
1579
|
2
|
|
|
|
|
|
sptr[n] = '\0'; |
|
1580
|
|
|
|
|
|
|
OUTPUT: |
|
1581
|
|
|
|
|
|
|
RETVAL |
|
1582
|
|
|
|
|
|
|
|
|
1583
|
|
|
|
|
|
|
UV _is_csprng_well_seeded() |
|
1584
|
|
|
|
|
|
|
ALIAS: |
|
1585
|
|
|
|
|
|
|
_XS_get_verbose = 1 |
|
1586
|
|
|
|
|
|
|
_XS_get_callgmp = 2 |
|
1587
|
|
|
|
|
|
|
_XS_get_secure = 3 |
|
1588
|
|
|
|
|
|
|
_XS_set_secure = 4 |
|
1589
|
|
|
|
|
|
|
_get_forexit = 5 |
|
1590
|
|
|
|
|
|
|
_start_for_loop = 6 |
|
1591
|
|
|
|
|
|
|
_get_prime_cache_size = 7 |
|
1592
|
|
|
|
|
|
|
CODE: |
|
1593
|
2408
|
|
|
|
|
|
switch (ix) { |
|
1594
|
1
|
|
|
|
|
|
case 0: { dMY_CXT; RETVAL = is_csprng_well_seeded(MY_CXT.randcxt); } break; |
|
1595
|
0
|
|
|
|
|
|
case 1: RETVAL = _XS_get_verbose(); break; |
|
1596
|
0
|
|
|
|
|
|
case 2: RETVAL = _XS_get_callgmp(); break; |
|
1597
|
0
|
|
|
|
|
|
case 3: RETVAL = _XS_get_secure(); break; |
|
1598
|
0
|
|
|
|
|
|
case 4: _XS_set_secure(); RETVAL = 1; break; |
|
1599
|
158
|
|
|
|
|
|
case 5: { dMY_CXT; RETVAL = MY_CXT.forexit; } break; |
|
1600
|
17
|
|
|
|
|
|
case 6: { dMY_CXT; MY_CXT.forcount++; RETVAL = MY_CXT.forexit; MY_CXT.forexit = 0; } break; |
|
1601
|
2232
|
|
|
|
|
|
case 7: |
|
1602
|
2232
|
|
|
|
|
|
default: RETVAL = get_prime_cache(0,0); break; |
|
1603
|
|
|
|
|
|
|
} |
|
1604
|
|
|
|
|
|
|
OUTPUT: |
|
1605
|
|
|
|
|
|
|
RETVAL |
|
1606
|
|
|
|
|
|
|
|
|
1607
|
|
|
|
|
|
|
bool _validate_integer(SV* svn) |
|
1608
|
|
|
|
|
|
|
ALIAS: |
|
1609
|
|
|
|
|
|
|
_validate_integer_nonneg = 1 |
|
1610
|
|
|
|
|
|
|
_validate_integer_positive = 2 |
|
1611
|
|
|
|
|
|
|
_validate_integer_abs = 3 |
|
1612
|
|
|
|
|
|
|
PREINIT: |
|
1613
|
|
|
|
|
|
|
uint32_t mask; |
|
1614
|
|
|
|
|
|
|
int status; |
|
1615
|
|
|
|
|
|
|
UV n; |
|
1616
|
|
|
|
|
|
|
CODE: |
|
1617
|
|
|
|
|
|
|
/* Flag: 0 neg ok, 1 neg err, 2 zero or neg err, 3 abs */ |
|
1618
|
225972
|
|
|
|
|
|
switch (ix) { |
|
1619
|
209639
|
|
|
|
|
|
case 0: mask = IFLAG_ANY; break; |
|
1620
|
8018
|
|
|
|
|
|
case 1: mask = IFLAG_POS; break; |
|
1621
|
4820
|
|
|
|
|
|
case 2: mask = IFLAG_POS | IFLAG_NONZERO; break; |
|
1622
|
3495
|
|
|
|
|
|
case 3: mask = IFLAG_ABS; break; |
|
1623
|
0
|
|
|
|
|
|
default: croak("_validate_integer unknown flag value"); |
|
1624
|
|
|
|
|
|
|
} |
|
1625
|
225972
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, mask); |
|
1626
|
225966
|
100
|
|
|
|
|
if (status != 0) { |
|
1627
|
110638
|
100
|
|
|
|
|
SETSVINT(svn, status == 1, n, (IV)n); |
|
1628
|
|
|
|
|
|
|
#if PERL_VERSION_LT(5,8,0) && BITS_PER_WORD == 64 |
|
1629
|
|
|
|
|
|
|
if (status == 1 && n > 562949953421312UL) |
|
1630
|
|
|
|
|
|
|
sv_setpvf(svn, "%"UVuf, n); |
|
1631
|
|
|
|
|
|
|
if (status == -1 && (IV)n < -562949953421312) |
|
1632
|
|
|
|
|
|
|
sv_setpvf(svn, "%"IVdf, n); |
|
1633
|
|
|
|
|
|
|
#endif |
|
1634
|
|
|
|
|
|
|
} else { /* Status 0 = bigint */ |
|
1635
|
115328
|
100
|
|
|
|
|
if (mask & IFLAG_ABS) { |
|
1636
|
|
|
|
|
|
|
/* TODO: if given a positive bigint, no need for this */ |
|
1637
|
1650
|
|
|
|
|
|
sv_setsv(svn, sv_to_bigint_abs(aTHX_ svn)); |
|
1638
|
113678
|
100
|
|
|
|
|
} else if (mask & IFLAG_POS) { |
|
1639
|
4639
|
100
|
|
|
|
|
if (!_is_sv_bigint(aTHX_ svn)) |
|
1640
|
49
|
|
|
|
|
|
sv_setsv(svn, sv_to_bigint_nonneg(aTHX_ svn)); |
|
1641
|
|
|
|
|
|
|
} else { |
|
1642
|
109039
|
100
|
|
|
|
|
if (!_is_sv_bigint(aTHX_ svn)) |
|
1643
|
867
|
|
|
|
|
|
sv_setsv(svn, sv_to_bigint(aTHX_ svn)); |
|
1644
|
|
|
|
|
|
|
} |
|
1645
|
|
|
|
|
|
|
} |
|
1646
|
225965
|
50
|
|
|
|
|
RETVAL = TRUE; |
|
1647
|
|
|
|
|
|
|
OUTPUT: |
|
1648
|
|
|
|
|
|
|
RETVAL |
|
1649
|
|
|
|
|
|
|
|
|
1650
|
|
|
|
|
|
|
void prime_memfree() |
|
1651
|
|
|
|
|
|
|
PREINIT: |
|
1652
|
|
|
|
|
|
|
dMY_CXT; |
|
1653
|
|
|
|
|
|
|
PPCODE: |
|
1654
|
10
|
|
|
|
|
|
prime_memfree(); |
|
1655
|
|
|
|
|
|
|
/* (void) _vcallgmpsubn(aTHX_ G_VOID|G_DISCARD, "_GMP_memfree", 0, 49); */ |
|
1656
|
10
|
50
|
|
|
|
|
if (MY_CXT.MPUPP != NULL) DISPATCH_VOIDPP(); |
|
1657
|
10
|
|
|
|
|
|
XSRETURN(0); |
|
1658
|
|
|
|
|
|
|
|
|
1659
|
|
|
|
|
|
|
void |
|
1660
|
|
|
|
|
|
|
prime_precalc(IN UV n) |
|
1661
|
|
|
|
|
|
|
ALIAS: |
|
1662
|
|
|
|
|
|
|
_XS_set_verbose = 1 |
|
1663
|
|
|
|
|
|
|
_XS_set_callgmp = 2 |
|
1664
|
|
|
|
|
|
|
_end_for_loop = 3 |
|
1665
|
|
|
|
|
|
|
PPCODE: |
|
1666
|
272
|
|
|
|
|
|
PUTBACK; /* SP is never used again, the 3 next func calls are tailcall |
|
1667
|
|
|
|
|
|
|
friendly since this XSUB has nothing to do after the 3 calls return */ |
|
1668
|
272
|
|
|
|
|
|
switch (ix) { |
|
1669
|
127
|
|
|
|
|
|
case 0: prime_precalc(n); break; |
|
1670
|
8
|
|
|
|
|
|
case 1: _XS_set_verbose(n); break; |
|
1671
|
120
|
|
|
|
|
|
case 2: _XS_set_callgmp(n); break; |
|
1672
|
17
|
|
|
|
|
|
case 3: |
|
1673
|
17
|
|
|
|
|
|
default: { dMY_CXT; MY_CXT.forcount--; MY_CXT.forexit = n>0; } break; |
|
1674
|
|
|
|
|
|
|
} |
|
1675
|
272
|
|
|
|
|
|
return; /* skip implicit PUTBACK */ |
|
1676
|
|
|
|
|
|
|
|
|
1677
|
|
|
|
|
|
|
|
|
1678
|
|
|
|
|
|
|
void prime_count(IN SV* svlo, IN SV* svhi = 0) |
|
1679
|
|
|
|
|
|
|
ALIAS: |
|
1680
|
|
|
|
|
|
|
semiprime_count = 1 |
|
1681
|
|
|
|
|
|
|
twin_prime_count = 2 |
|
1682
|
|
|
|
|
|
|
ramanujan_prime_count = 3 |
|
1683
|
|
|
|
|
|
|
perfect_power_count = 4 |
|
1684
|
|
|
|
|
|
|
prime_power_count = 5 |
|
1685
|
|
|
|
|
|
|
lucky_count = 6 |
|
1686
|
|
|
|
|
|
|
PREINIT: |
|
1687
|
3238
|
100
|
|
|
|
|
UV lo = 0, hi, count = 0; |
|
1688
|
|
|
|
|
|
|
PPCODE: |
|
1689
|
3238
|
100
|
|
|
|
|
if ((items == 1 && _validate_and_set(&hi, aTHX_ svlo, IFLAG_POS)) || |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
1690
|
1833
|
100
|
|
|
|
|
(items == 2 && _validate_and_set(&lo, aTHX_ svlo, IFLAG_POS) && _validate_and_set(&hi, aTHX_ svhi, IFLAG_POS))) { |
|
|
|
50
|
|
|
|
|
|
|
1691
|
3237
|
100
|
|
|
|
|
if (lo <= hi) { |
|
1692
|
2416
|
|
|
|
|
|
switch (ix) { |
|
1693
|
150
|
|
|
|
|
|
case 0: count = prime_count_range(lo, hi); break; |
|
1694
|
20
|
|
|
|
|
|
case 1: count = semiprime_count_range(lo, hi); break; |
|
1695
|
11
|
|
|
|
|
|
case 2: count = twin_prime_count_range(lo, hi); break; |
|
1696
|
10
|
|
|
|
|
|
case 3: count = ramanujan_prime_count_range(lo, hi); break; |
|
1697
|
59
|
|
|
|
|
|
case 4: count = perfect_power_count_range(lo, hi); break; |
|
1698
|
206
|
|
|
|
|
|
case 5: count = prime_power_count_range(lo, hi); break; |
|
1699
|
1960
|
|
|
|
|
|
case 6: count = lucky_count_range(lo, hi); break; |
|
1700
|
|
|
|
|
|
|
} |
|
1701
|
|
|
|
|
|
|
} |
|
1702
|
3237
|
|
|
|
|
|
XSRETURN_UV(count); |
|
1703
|
|
|
|
|
|
|
} |
|
1704
|
1
|
|
|
|
|
|
DISPATCHPP(); |
|
1705
|
1
|
|
|
|
|
|
XSRETURN(1); |
|
1706
|
|
|
|
|
|
|
|
|
1707
|
|
|
|
|
|
|
|
|
1708
|
|
|
|
|
|
|
void prime_count_upper(IN SV* svn) |
|
1709
|
|
|
|
|
|
|
ALIAS: |
|
1710
|
|
|
|
|
|
|
prime_count_lower = 1 |
|
1711
|
|
|
|
|
|
|
prime_count_approx = 2 |
|
1712
|
|
|
|
|
|
|
prime_power_count_upper = 3 |
|
1713
|
|
|
|
|
|
|
prime_power_count_lower = 4 |
|
1714
|
|
|
|
|
|
|
prime_power_count_approx = 5 |
|
1715
|
|
|
|
|
|
|
perfect_power_count_upper = 6 |
|
1716
|
|
|
|
|
|
|
perfect_power_count_lower = 7 |
|
1717
|
|
|
|
|
|
|
perfect_power_count_approx = 8 |
|
1718
|
|
|
|
|
|
|
ramanujan_prime_count_upper = 9 |
|
1719
|
|
|
|
|
|
|
ramanujan_prime_count_lower = 10 |
|
1720
|
|
|
|
|
|
|
ramanujan_prime_count_approx = 11 |
|
1721
|
|
|
|
|
|
|
twin_prime_count_approx = 12 |
|
1722
|
|
|
|
|
|
|
semiprime_count_approx = 13 |
|
1723
|
|
|
|
|
|
|
lucky_count_upper = 14 |
|
1724
|
|
|
|
|
|
|
lucky_count_lower = 15 |
|
1725
|
|
|
|
|
|
|
lucky_count_approx = 16 |
|
1726
|
|
|
|
|
|
|
PREINIT: |
|
1727
|
|
|
|
|
|
|
UV n, ret; |
|
1728
|
|
|
|
|
|
|
PPCODE: |
|
1729
|
871
|
100
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) { |
|
1730
|
849
|
|
|
|
|
|
switch (ix) { |
|
1731
|
35
|
|
|
|
|
|
case 0: ret = prime_count_upper(n); break; |
|
1732
|
35
|
|
|
|
|
|
case 1: ret = prime_count_lower(n); break; |
|
1733
|
36
|
|
|
|
|
|
case 2: ret = prime_count_approx(n); break; |
|
1734
|
41
|
|
|
|
|
|
case 3: ret = prime_power_count_upper(n); break; |
|
1735
|
41
|
|
|
|
|
|
case 4: ret = prime_power_count_lower(n); break; |
|
1736
|
41
|
|
|
|
|
|
case 5: ret = prime_power_count_approx(n); break; |
|
1737
|
57
|
|
|
|
|
|
case 6: ret = perfect_power_count_upper(n); break; |
|
1738
|
57
|
|
|
|
|
|
case 7: ret = perfect_power_count_lower(n); break; |
|
1739
|
3
|
|
|
|
|
|
case 8: ret = perfect_power_count_approx(n); break; |
|
1740
|
74
|
|
|
|
|
|
case 9: ret = ramanujan_prime_count_upper(n); break; |
|
1741
|
74
|
|
|
|
|
|
case 10: ret = ramanujan_prime_count_lower(n); break; |
|
1742
|
2
|
|
|
|
|
|
case 11: ret = ramanujan_prime_count_approx(n); break; |
|
1743
|
7
|
|
|
|
|
|
case 12: ret = twin_prime_count_approx(n); break; |
|
1744
|
4
|
|
|
|
|
|
case 13: ret = semiprime_count_approx(n); break; |
|
1745
|
114
|
|
|
|
|
|
case 14: ret = lucky_count_upper(n); break; |
|
1746
|
114
|
|
|
|
|
|
case 15: ret = lucky_count_lower(n); break; |
|
1747
|
114
|
|
|
|
|
|
case 16: |
|
1748
|
114
|
|
|
|
|
|
default: ret = lucky_count_approx(n); break; |
|
1749
|
|
|
|
|
|
|
} |
|
1750
|
849
|
|
|
|
|
|
XSRETURN_UV(ret); |
|
1751
|
|
|
|
|
|
|
} |
|
1752
|
22
|
|
|
|
|
|
DISPATCHPP(); |
|
1753
|
22
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
1754
|
22
|
|
|
|
|
|
XSRETURN(1); |
|
1755
|
|
|
|
|
|
|
|
|
1756
|
|
|
|
|
|
|
|
|
1757
|
|
|
|
|
|
|
void sum_primes(IN SV* svlo, IN SV* svhi = 0) |
|
1758
|
|
|
|
|
|
|
PREINIT: |
|
1759
|
1030
|
100
|
|
|
|
|
UV lo = 2, hi; |
|
1760
|
|
|
|
|
|
|
PPCODE: |
|
1761
|
1030
|
100
|
|
|
|
|
if ((items == 1 && _validate_and_set(&hi, aTHX_ svlo, IFLAG_POS)) || |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
1762
|
29
|
50
|
|
|
|
|
(items == 2 && _validate_and_set(&lo, aTHX_ svlo, IFLAG_POS) && _validate_and_set(&hi, aTHX_ svhi, IFLAG_POS))) { |
|
|
|
50
|
|
|
|
|
|
|
1763
|
1030
|
|
|
|
|
|
UV count = 0; |
|
1764
|
1030
|
|
|
|
|
|
int retok = 1; |
|
1765
|
|
|
|
|
|
|
/* 32/64-bit, Legendre or table-accelerated sieving. */ |
|
1766
|
1030
|
|
|
|
|
|
retok = sum_primes(lo, hi, &count); |
|
1767
|
|
|
|
|
|
|
/* If that didn't work, try the 128-bit version if supported. */ |
|
1768
|
1030
|
100
|
|
|
|
|
if (retok == 0 && HAVE_SUM_PRIMES128) { |
|
1769
|
|
|
|
|
|
|
UV hicount, lo_hic, lo_loc; |
|
1770
|
1
|
|
|
|
|
|
retok = sum_primes128(hi, &hicount, &count); |
|
1771
|
1
|
50
|
|
|
|
|
if (retok == 1 && lo > 2) { |
|
|
|
50
|
|
|
|
|
|
|
1772
|
0
|
|
|
|
|
|
retok = sum_primes128(lo-1, &lo_hic, &lo_loc); |
|
1773
|
0
|
|
|
|
|
|
hicount -= lo_hic; |
|
1774
|
0
|
0
|
|
|
|
|
if (count < lo_loc) hicount--; |
|
1775
|
0
|
|
|
|
|
|
count -= lo_loc; |
|
1776
|
|
|
|
|
|
|
} |
|
1777
|
1
|
50
|
|
|
|
|
if (retok == 1 && hicount > 0) |
|
|
|
50
|
|
|
|
|
|
|
1778
|
1
|
|
|
|
|
|
RETURN_128(hicount, count); |
|
1779
|
|
|
|
|
|
|
} |
|
1780
|
1029
|
50
|
|
|
|
|
if (retok == 1) |
|
1781
|
1029
|
|
|
|
|
|
XSRETURN_UV(count); |
|
1782
|
|
|
|
|
|
|
} |
|
1783
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
1784
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
1785
|
|
|
|
|
|
|
|
|
1786
|
|
|
|
|
|
|
void random_prime(IN SV* svlo, IN SV* svhi = 0) |
|
1787
|
|
|
|
|
|
|
PREINIT: |
|
1788
|
11041
|
100
|
|
|
|
|
UV lo = 2, hi, ret; |
|
1789
|
|
|
|
|
|
|
dMY_CXT; |
|
1790
|
|
|
|
|
|
|
PPCODE: |
|
1791
|
11041
|
100
|
|
|
|
|
if ((items == 1 && _validate_and_set(&hi, aTHX_ svlo, IFLAG_POS)) || |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
1792
|
36
|
100
|
|
|
|
|
(items == 2 && _validate_and_set(&lo, aTHX_ svlo, IFLAG_POS) && _validate_and_set(&hi, aTHX_ svhi, IFLAG_POS))) { |
|
|
|
50
|
|
|
|
|
|
|
1793
|
11027
|
|
|
|
|
|
ret = random_prime(MY_CXT.randcxt,lo,hi); |
|
1794
|
11027
|
100
|
|
|
|
|
if (ret) XSRETURN_UV(ret); |
|
1795
|
6
|
|
|
|
|
|
else XSRETURN_UNDEF; |
|
1796
|
|
|
|
|
|
|
} |
|
1797
|
1
|
|
|
|
|
|
DISPATCHPP(); |
|
1798
|
1
|
|
|
|
|
|
objectify_result(aTHX_ svlo, ST(0)); |
|
1799
|
1
|
|
|
|
|
|
XSRETURN(1); |
|
1800
|
|
|
|
|
|
|
|
|
1801
|
|
|
|
|
|
|
void print_primes(IN SV* svlo, IN SV* svhi = 0, IN int infd = -1) |
|
1802
|
|
|
|
|
|
|
PREINIT: |
|
1803
|
0
|
0
|
|
|
|
|
UV lo = 2, hi; |
|
1804
|
|
|
|
|
|
|
PPCODE: |
|
1805
|
0
|
0
|
|
|
|
|
if ((items == 1 && _validate_and_set(&hi, aTHX_ svlo, IFLAG_POS)) || |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
1806
|
0
|
0
|
|
|
|
|
(items >= 2 && _validate_and_set(&lo, aTHX_ svlo, IFLAG_POS) && _validate_and_set(&hi, aTHX_ svhi, IFLAG_POS))) { |
|
|
|
0
|
|
|
|
|
|
|
1807
|
0
|
0
|
|
|
|
|
if (lo <= hi) { |
|
1808
|
0
|
0
|
|
|
|
|
int fd = (infd == -1) ? fileno(stdout) : infd; |
|
1809
|
0
|
|
|
|
|
|
print_primes(lo, hi, fd); |
|
1810
|
|
|
|
|
|
|
} |
|
1811
|
|
|
|
|
|
|
} else { |
|
1812
|
0
|
|
|
|
|
|
DISPATCH_VOIDPP(); |
|
1813
|
|
|
|
|
|
|
} |
|
1814
|
0
|
|
|
|
|
|
return; |
|
1815
|
|
|
|
|
|
|
|
|
1816
|
|
|
|
|
|
|
UV |
|
1817
|
|
|
|
|
|
|
_LMO_pi(IN UV n) |
|
1818
|
|
|
|
|
|
|
ALIAS: |
|
1819
|
|
|
|
|
|
|
_legendre_pi = 1 |
|
1820
|
|
|
|
|
|
|
_meissel_pi = 2 |
|
1821
|
|
|
|
|
|
|
_lehmer_pi = 3 |
|
1822
|
|
|
|
|
|
|
_LMOS_pi = 4 |
|
1823
|
|
|
|
|
|
|
_segment_pi = 5 |
|
1824
|
|
|
|
|
|
|
PREINIT: |
|
1825
|
|
|
|
|
|
|
UV ret; |
|
1826
|
|
|
|
|
|
|
CODE: |
|
1827
|
6
|
|
|
|
|
|
switch (ix) { |
|
1828
|
1
|
|
|
|
|
|
case 0: ret = LMO_prime_count(n); break; |
|
1829
|
1
|
|
|
|
|
|
case 1: ret = legendre_prime_count(n); break; |
|
1830
|
1
|
|
|
|
|
|
case 2: ret = meissel_prime_count(n); break; |
|
1831
|
1
|
|
|
|
|
|
case 3: ret = lehmer_prime_count(n); break; |
|
1832
|
1
|
|
|
|
|
|
case 4: ret = LMOS_prime_count(n); break; |
|
1833
|
1
|
|
|
|
|
|
default:ret = segment_prime_count(2,n); break; |
|
1834
|
|
|
|
|
|
|
} |
|
1835
|
6
|
50
|
|
|
|
|
RETVAL = ret; |
|
1836
|
|
|
|
|
|
|
OUTPUT: |
|
1837
|
|
|
|
|
|
|
RETVAL |
|
1838
|
|
|
|
|
|
|
|
|
1839
|
|
|
|
|
|
|
|
|
1840
|
|
|
|
|
|
|
|
|
1841
|
|
|
|
|
|
|
|
|
1842
|
|
|
|
|
|
|
void |
|
1843
|
|
|
|
|
|
|
sieve_primes(IN UV low, IN UV high) |
|
1844
|
|
|
|
|
|
|
ALIAS: |
|
1845
|
|
|
|
|
|
|
trial_primes = 1 |
|
1846
|
|
|
|
|
|
|
erat_primes = 2 |
|
1847
|
|
|
|
|
|
|
segment_primes = 3 |
|
1848
|
|
|
|
|
|
|
PREINIT: |
|
1849
|
|
|
|
|
|
|
AV* av; |
|
1850
|
|
|
|
|
|
|
PPCODE: |
|
1851
|
52
|
|
|
|
|
|
CREATE_RETURN_AV(av); |
|
1852
|
52
|
100
|
|
|
|
|
if ((low <= 2) && (high >= 2)) av_push(av, newSVuv( 2 )); |
|
|
|
100
|
|
|
|
|
|
|
1853
|
52
|
100
|
|
|
|
|
if ((low <= 3) && (high >= 3)) av_push(av, newSVuv( 3 )); |
|
|
|
100
|
|
|
|
|
|
|
1854
|
52
|
100
|
|
|
|
|
if ((low <= 5) && (high >= 5)) av_push(av, newSVuv( 5 )); |
|
|
|
100
|
|
|
|
|
|
|
1855
|
52
|
100
|
|
|
|
|
if (low < 7) low = 7; |
|
1856
|
52
|
100
|
|
|
|
|
if (low <= high) { |
|
1857
|
36
|
100
|
|
|
|
|
if (ix == 0) { /* Sieve with primary cache */ |
|
1858
|
555
|
50
|
|
|
|
|
START_DO_FOR_EACH_PRIME(low, high) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
1859
|
538
|
|
|
|
|
|
av_push(av,newSVuv(p)); |
|
1860
|
|
|
|
|
|
|
} END_DO_FOR_EACH_PRIME |
|
1861
|
27
|
100
|
|
|
|
|
} else if (ix == 1) { /* Trial */ |
|
1862
|
9
|
|
|
|
|
|
for (low = next_prime(low-1); |
|
1863
|
547
|
100
|
|
|
|
|
low <= high && low != 0; |
|
|
|
50
|
|
|
|
|
|
|
1864
|
538
|
|
|
|
|
|
low = next_prime(low) ) { |
|
1865
|
538
|
|
|
|
|
|
av_push(av,newSVuv(low)); |
|
1866
|
|
|
|
|
|
|
} |
|
1867
|
18
|
100
|
|
|
|
|
} else if (ix == 2) { /* Erat with private memory */ |
|
1868
|
9
|
|
|
|
|
|
unsigned char* sieve = sieve_erat30(high); |
|
1869
|
665
|
50
|
|
|
|
|
START_DO_FOR_EACH_SIEVE_PRIME( sieve, 0, low, high ) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
1870
|
538
|
|
|
|
|
|
av_push(av,newSVuv(p)); |
|
1871
|
26
|
|
|
|
|
|
} END_DO_FOR_EACH_SIEVE_PRIME |
|
1872
|
9
|
|
|
|
|
|
Safefree(sieve); |
|
1873
|
9
|
50
|
|
|
|
|
} else if (ix == 3) { /* Segment */ |
|
1874
|
|
|
|
|
|
|
unsigned char* segment; |
|
1875
|
|
|
|
|
|
|
UV seg_base, seg_low, seg_high; |
|
1876
|
9
|
|
|
|
|
|
void* ctx = start_segment_primes(low, high, &segment); |
|
1877
|
18
|
100
|
|
|
|
|
while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) { |
|
1878
|
583
|
50
|
|
|
|
|
START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_base, seg_low, seg_high ) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
1879
|
538
|
|
|
|
|
|
av_push(av,newSVuv( p )); |
|
1880
|
23
|
|
|
|
|
|
END_DO_FOR_EACH_SIEVE_PRIME |
|
1881
|
|
|
|
|
|
|
} |
|
1882
|
9
|
|
|
|
|
|
end_segment_primes(ctx); |
|
1883
|
|
|
|
|
|
|
} |
|
1884
|
|
|
|
|
|
|
} |
|
1885
|
52
|
|
|
|
|
|
return; /* skip implicit PUTBACK */ |
|
1886
|
|
|
|
|
|
|
|
|
1887
|
|
|
|
|
|
|
|
|
1888
|
|
|
|
|
|
|
void primes(IN SV* svlo, IN SV* svhi = 0) |
|
1889
|
|
|
|
|
|
|
PREINIT: |
|
1890
|
|
|
|
|
|
|
AV* av; |
|
1891
|
1179
|
100
|
|
|
|
|
UV lo = 0, hi, i; |
|
1892
|
|
|
|
|
|
|
PPCODE: |
|
1893
|
1179
|
100
|
|
|
|
|
if ((items == 1 && _validate_and_set(&hi, aTHX_ svlo, IFLAG_POS)) || |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
1894
|
102
|
100
|
|
|
|
|
(items == 2 && _validate_and_set(&lo, aTHX_ svlo, IFLAG_POS) && _validate_and_set(&hi, aTHX_ svhi, IFLAG_POS))) { |
|
|
|
50
|
|
|
|
|
|
|
1895
|
1163
|
|
|
|
|
|
CREATE_RETURN_AV(av); |
|
1896
|
1163
|
100
|
|
|
|
|
if ((lo <= 2) && (hi >= 2)) av_push(av, newSVuv( 2 )); |
|
|
|
100
|
|
|
|
|
|
|
1897
|
1163
|
100
|
|
|
|
|
if ((lo <= 3) && (hi >= 3)) av_push(av, newSVuv( 3 )); |
|
|
|
100
|
|
|
|
|
|
|
1898
|
1163
|
100
|
|
|
|
|
if ((lo <= 5) && (hi >= 5)) av_push(av, newSVuv( 5 )); |
|
|
|
100
|
|
|
|
|
|
|
1899
|
1163
|
100
|
|
|
|
|
if (lo < 7) lo = 7; |
|
1900
|
1163
|
100
|
|
|
|
|
if (lo <= hi) { |
|
1901
|
1126
|
100
|
|
|
|
|
if ( hi-lo <= 10 |
|
1902
|
1106
|
100
|
|
|
|
|
|| (hi > 100000000UL && hi-lo <= 330) |
|
|
|
50
|
|
|
|
|
|
|
1903
|
1106
|
100
|
|
|
|
|
|| (hi > 4000000000UL && hi-lo <= 1500) |
|
|
|
100
|
|
|
|
|
|
|
1904
|
|
|
|
|
|
|
) { |
|
1905
|
729
|
100
|
|
|
|
|
for (i = !(lo&1); i <= hi-lo; i += 2) |
|
1906
|
708
|
100
|
|
|
|
|
if (is_prime(lo+i)) |
|
1907
|
47
|
|
|
|
|
|
av_push(av,newSVuv(lo+i)); |
|
1908
|
1105
|
100
|
|
|
|
|
} else if (hi < (65536*30) || hi <= get_prime_cache(0,0)) { |
|
|
|
50
|
|
|
|
|
|
|
1909
|
586736
|
50
|
|
|
|
|
START_DO_FOR_EACH_PRIME(lo, hi) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
1910
|
576865
|
|
|
|
|
|
av_push(av,newSVuv(p)); |
|
1911
|
|
|
|
|
|
|
} END_DO_FOR_EACH_PRIME |
|
1912
|
|
|
|
|
|
|
} else { |
|
1913
|
|
|
|
|
|
|
unsigned char* segment; |
|
1914
|
|
|
|
|
|
|
UV seg_base, seg_low, seg_high; |
|
1915
|
9
|
|
|
|
|
|
void* ctx = start_segment_primes(lo, hi, &segment); |
|
1916
|
21
|
100
|
|
|
|
|
while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) { |
|
1917
|
325969
|
50
|
|
|
|
|
START_DO_FOR_EACH_SIEVE_PRIME(segment, seg_base, seg_low, seg_high) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
1918
|
307612
|
|
|
|
|
|
av_push(av,newSVuv( p )); |
|
1919
|
18329
|
|
|
|
|
|
END_DO_FOR_EACH_SIEVE_PRIME |
|
1920
|
|
|
|
|
|
|
} |
|
1921
|
9
|
|
|
|
|
|
end_segment_primes(ctx); |
|
1922
|
|
|
|
|
|
|
} |
|
1923
|
|
|
|
|
|
|
} |
|
1924
|
|
|
|
|
|
|
} else { |
|
1925
|
1
|
|
|
|
|
|
DISPATCHPP(); |
|
1926
|
|
|
|
|
|
|
} |
|
1927
|
1164
|
|
|
|
|
|
return; |
|
1928
|
|
|
|
|
|
|
|
|
1929
|
|
|
|
|
|
|
void almost_primes(IN UV k, IN SV* svlo, IN SV* svhi = 0) |
|
1930
|
|
|
|
|
|
|
ALIAS: |
|
1931
|
|
|
|
|
|
|
omega_primes = 1 |
|
1932
|
|
|
|
|
|
|
PREINIT: |
|
1933
|
|
|
|
|
|
|
AV* av; |
|
1934
|
22
|
|
|
|
|
|
UV lo = 1, hi, i, n, *S; |
|
1935
|
|
|
|
|
|
|
PPCODE: |
|
1936
|
22
|
100
|
|
|
|
|
if ((items == 2 && _validate_and_set(&hi, aTHX_ svlo, IFLAG_POS)) || |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
1937
|
8
|
100
|
|
|
|
|
(items >= 3 && _validate_and_set(&lo, aTHX_ svlo, IFLAG_POS) && _validate_and_set(&hi, aTHX_ svhi, IFLAG_POS))) { |
|
|
|
50
|
|
|
|
|
|
|
1938
|
20
|
|
|
|
|
|
CREATE_RETURN_AV(av); |
|
1939
|
20
|
|
|
|
|
|
S = 0; |
|
1940
|
20
|
100
|
|
|
|
|
if (ix == 0) n = generate_almost_primes(&S, k, lo, hi); |
|
1941
|
5
|
|
|
|
|
|
else n = range_omega_prime_sieve(&S, k, lo, hi); |
|
1942
|
432
|
100
|
|
|
|
|
for (i = 0; i < n; i++) |
|
1943
|
412
|
|
|
|
|
|
av_push(av, newSVuv(S[i])); |
|
1944
|
20
|
100
|
|
|
|
|
if (S != 0) Safefree(S); |
|
1945
|
|
|
|
|
|
|
} else { |
|
1946
|
2
|
|
|
|
|
|
DISPATCHPP(); |
|
1947
|
|
|
|
|
|
|
} |
|
1948
|
22
|
|
|
|
|
|
return; |
|
1949
|
|
|
|
|
|
|
|
|
1950
|
|
|
|
|
|
|
|
|
1951
|
|
|
|
|
|
|
void prime_powers(IN SV* svlo, IN SV* svhi = 0) |
|
1952
|
|
|
|
|
|
|
ALIAS: |
|
1953
|
|
|
|
|
|
|
twin_primes = 1 |
|
1954
|
|
|
|
|
|
|
semi_primes = 2 |
|
1955
|
|
|
|
|
|
|
ramanujan_primes = 3 |
|
1956
|
|
|
|
|
|
|
PREINIT: |
|
1957
|
|
|
|
|
|
|
AV* av; |
|
1958
|
102
|
100
|
|
|
|
|
UV lo = 0, hi, i, num, *L; |
|
1959
|
|
|
|
|
|
|
PPCODE: |
|
1960
|
102
|
100
|
|
|
|
|
if ((items == 1 && _validate_and_set(&hi, aTHX_ svlo, IFLAG_POS)) || |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
1961
|
48
|
100
|
|
|
|
|
(items == 2 && _validate_and_set(&lo, aTHX_ svlo, IFLAG_POS) && _validate_and_set(&hi, aTHX_ svhi, IFLAG_POS))) { |
|
|
|
50
|
|
|
|
|
|
|
1962
|
101
|
|
|
|
|
|
CREATE_RETURN_AV(av); |
|
1963
|
101
|
100
|
|
|
|
|
if (ix == 0) { /* Prime power */ |
|
1964
|
52
|
100
|
|
|
|
|
if ((lo <= 2) && (hi >= 2)) av_push(av, newSVuv( 2 )); |
|
|
|
100
|
|
|
|
|
|
|
1965
|
52
|
100
|
|
|
|
|
if ((lo <= 3) && (hi >= 3)) av_push(av, newSVuv( 3 )); |
|
|
|
100
|
|
|
|
|
|
|
1966
|
52
|
100
|
|
|
|
|
if ((lo <= 4) && (hi >= 4)) av_push(av, newSVuv( 4 )); |
|
|
|
100
|
|
|
|
|
|
|
1967
|
52
|
100
|
|
|
|
|
if ((lo <= 5) && (hi >= 5)) av_push(av, newSVuv( 5 )); |
|
|
|
100
|
|
|
|
|
|
|
1968
|
49
|
100
|
|
|
|
|
} else if (ix == 1) { /* Twin */ |
|
1969
|
16
|
100
|
|
|
|
|
if ((lo <= 3) && (hi >= 3)) av_push(av, newSVuv( 3 )); |
|
|
|
50
|
|
|
|
|
|
|
1970
|
16
|
100
|
|
|
|
|
if ((lo <= 5) && (hi >= 5)) av_push(av, newSVuv( 5 )); |
|
|
|
50
|
|
|
|
|
|
|
1971
|
33
|
100
|
|
|
|
|
} else if (ix == 2) { /* Semi */ |
|
1972
|
18
|
100
|
|
|
|
|
if ((lo <= 4) && (hi >= 4)) av_push(av, newSVuv( 4 )); |
|
|
|
50
|
|
|
|
|
|
|
1973
|
18
|
100
|
|
|
|
|
if ((lo <= 6) && (hi >= 6)) av_push(av, newSVuv( 6 )); |
|
|
|
50
|
|
|
|
|
|
|
1974
|
15
|
50
|
|
|
|
|
} else if (ix == 3) { /* Ramanujan */ |
|
1975
|
15
|
100
|
|
|
|
|
if ((lo <= 2) && (hi >= 2)) av_push(av, newSVuv( 2 )); |
|
|
|
50
|
|
|
|
|
|
|
1976
|
|
|
|
|
|
|
} |
|
1977
|
101
|
100
|
|
|
|
|
if (lo < 7) lo = 7; |
|
1978
|
101
|
100
|
|
|
|
|
if (lo <= hi) { |
|
1979
|
95
|
|
|
|
|
|
switch (ix) { |
|
1980
|
46
|
|
|
|
|
|
case 0: num = prime_power_sieve(&L,lo,hi); break; |
|
1981
|
16
|
|
|
|
|
|
case 1: num = range_twin_prime_sieve(&L,lo,hi); break; |
|
1982
|
18
|
|
|
|
|
|
case 2: num = range_semiprime_sieve(&L,lo,hi); break; |
|
1983
|
15
|
|
|
|
|
|
case 3: num = range_ramanujan_prime_sieve(&L,lo,hi); break; |
|
1984
|
0
|
|
|
|
|
|
default: num = 0; L = 0; break; |
|
1985
|
|
|
|
|
|
|
} |
|
1986
|
1059
|
100
|
|
|
|
|
for (i = 0; i < num; i++) |
|
1987
|
964
|
|
|
|
|
|
av_push(av,newSVuv(L[i])); |
|
1988
|
95
|
|
|
|
|
|
Safefree(L); |
|
1989
|
|
|
|
|
|
|
} |
|
1990
|
|
|
|
|
|
|
} else { |
|
1991
|
1
|
|
|
|
|
|
DISPATCHPP(); |
|
1992
|
|
|
|
|
|
|
} |
|
1993
|
102
|
|
|
|
|
|
return; |
|
1994
|
|
|
|
|
|
|
|
|
1995
|
|
|
|
|
|
|
void |
|
1996
|
|
|
|
|
|
|
lucky_numbers(IN SV* svlo, IN SV* svhi = 0) |
|
1997
|
|
|
|
|
|
|
PREINIT: |
|
1998
|
|
|
|
|
|
|
AV* av; |
|
1999
|
207
|
100
|
|
|
|
|
UV lo = 0, hi, i, nlucky = 0; |
|
2000
|
|
|
|
|
|
|
PPCODE: |
|
2001
|
207
|
100
|
|
|
|
|
if ((items == 1 && _validate_and_set(&hi, aTHX_ svlo, IFLAG_POS)) || |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
2002
|
1
|
50
|
|
|
|
|
(items == 2 && _validate_and_set(&lo, aTHX_ svlo, IFLAG_POS) && _validate_and_set(&hi, aTHX_ svhi, IFLAG_POS))) { |
|
|
|
50
|
|
|
|
|
|
|
2003
|
207
|
|
|
|
|
|
CREATE_RETURN_AV(av); |
|
2004
|
413
|
100
|
|
|
|
|
if (lo == 0 && hi <= UVCONST(4000000000)) { |
|
|
|
50
|
|
|
|
|
|
|
2005
|
206
|
|
|
|
|
|
uint32_t* lucky = lucky_sieve32(&nlucky, hi); |
|
2006
|
45922
|
100
|
|
|
|
|
for (i = 0; i < nlucky; i++) |
|
2007
|
45716
|
|
|
|
|
|
av_push(av,newSVuv(lucky[i])); |
|
2008
|
206
|
|
|
|
|
|
Safefree(lucky); |
|
2009
|
|
|
|
|
|
|
} else { |
|
2010
|
1
|
|
|
|
|
|
UV* lucky = lucky_sieve_range(&nlucky, lo, hi); |
|
2011
|
7
|
100
|
|
|
|
|
for (i = 0; i < nlucky; i++) |
|
2012
|
6
|
|
|
|
|
|
av_push(av,newSVuv(lucky[i])); |
|
2013
|
1
|
|
|
|
|
|
Safefree(lucky); |
|
2014
|
|
|
|
|
|
|
} |
|
2015
|
|
|
|
|
|
|
} else { |
|
2016
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
2017
|
|
|
|
|
|
|
} |
|
2018
|
207
|
|
|
|
|
|
return; |
|
2019
|
|
|
|
|
|
|
|
|
2020
|
|
|
|
|
|
|
void minimal_goldbach_pair(IN SV* svn) |
|
2021
|
|
|
|
|
|
|
ALIAS: |
|
2022
|
|
|
|
|
|
|
goldbach_pair_count = 1 |
|
2023
|
|
|
|
|
|
|
PREINIT: |
|
2024
|
|
|
|
|
|
|
UV n, res; |
|
2025
|
|
|
|
|
|
|
PPCODE: |
|
2026
|
80
|
100
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) { |
|
2027
|
79
|
100
|
|
|
|
|
if (ix == 0) { |
|
2028
|
41
|
|
|
|
|
|
res = minimal_goldbach_pair(n); |
|
2029
|
41
|
100
|
|
|
|
|
if (res == 0) XSRETURN_UNDEF; |
|
2030
|
|
|
|
|
|
|
} else { |
|
2031
|
38
|
|
|
|
|
|
res = goldbach_pair_count(n); |
|
2032
|
|
|
|
|
|
|
} |
|
2033
|
70
|
|
|
|
|
|
XSRETURN_UV(res); |
|
2034
|
|
|
|
|
|
|
} |
|
2035
|
1
|
|
|
|
|
|
DISPATCHPP(); |
|
2036
|
1
|
|
|
|
|
|
XSRETURN(1); |
|
2037
|
|
|
|
|
|
|
|
|
2038
|
|
|
|
|
|
|
void goldbach_pairs(IN SV* svn) |
|
2039
|
|
|
|
|
|
|
PREINIT: |
|
2040
|
|
|
|
|
|
|
size_t npairs, i; |
|
2041
|
|
|
|
|
|
|
UV n, *L; |
|
2042
|
|
|
|
|
|
|
PPCODE: |
|
2043
|
38
|
50
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS) == 1) { |
|
2044
|
38
|
50
|
|
|
|
|
if (GIMME_V != G_ARRAY) |
|
2045
|
0
|
|
|
|
|
|
XSRETURN_UV(goldbach_pair_count(n)); |
|
2046
|
38
|
|
|
|
|
|
L = goldbach_pairs(&npairs, n); |
|
2047
|
38
|
100
|
|
|
|
|
if (L == 0) XSRETURN_EMPTY; |
|
2048
|
29
|
50
|
|
|
|
|
EXTEND(SP, (EXTEND_TYPE)npairs); |
|
|
|
50
|
|
|
|
|
|
|
2049
|
142
|
100
|
|
|
|
|
for (i = 0; i < npairs; i++) |
|
2050
|
113
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv(L[i]))); |
|
2051
|
29
|
|
|
|
|
|
Safefree(L); |
|
2052
|
|
|
|
|
|
|
} else { |
|
2053
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
2054
|
0
|
|
|
|
|
|
return; |
|
2055
|
|
|
|
|
|
|
} |
|
2056
|
|
|
|
|
|
|
|
|
2057
|
|
|
|
|
|
|
void powerful_numbers(IN SV* svlo, IN SV* svhi = 0, IN UV k = 2) |
|
2058
|
|
|
|
|
|
|
PREINIT: |
|
2059
|
|
|
|
|
|
|
AV* av; |
|
2060
|
10
|
100
|
|
|
|
|
UV lo = 1, hi, i, npowerful, *powerful; |
|
2061
|
|
|
|
|
|
|
PPCODE: |
|
2062
|
10
|
100
|
|
|
|
|
if ((items == 1 && _validate_and_set(&hi, aTHX_ svlo, IFLAG_POS)) || |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
2063
|
9
|
50
|
|
|
|
|
(items >= 2 && _validate_and_set(&lo, aTHX_ svlo, IFLAG_POS) && _validate_and_set(&hi, aTHX_ svhi, IFLAG_POS))) { |
|
|
|
50
|
|
|
|
|
|
|
2064
|
10
|
|
|
|
|
|
CREATE_RETURN_AV(av); |
|
2065
|
10
|
|
|
|
|
|
powerful = powerful_numbers_range(&npowerful, lo, hi, k); |
|
2066
|
111
|
100
|
|
|
|
|
for (i = 0; i < npowerful; i++) |
|
2067
|
101
|
|
|
|
|
|
av_push(av,newSVuv(powerful[i])); |
|
2068
|
10
|
|
|
|
|
|
Safefree(powerful); |
|
2069
|
|
|
|
|
|
|
} else { |
|
2070
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
2071
|
|
|
|
|
|
|
} |
|
2072
|
10
|
|
|
|
|
|
return; |
|
2073
|
|
|
|
|
|
|
|
|
2074
|
|
|
|
|
|
|
void |
|
2075
|
|
|
|
|
|
|
sieve_range(IN SV* svn, IN UV width, IN UV depth) |
|
2076
|
|
|
|
|
|
|
PREINIT: |
|
2077
|
|
|
|
|
|
|
int status; |
|
2078
|
|
|
|
|
|
|
UV i, n; |
|
2079
|
|
|
|
|
|
|
PPCODE: |
|
2080
|
|
|
|
|
|
|
/* Return index of every n unless it is a composite with factor > depth */ |
|
2081
|
10
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, IFLAG_POS); |
|
2082
|
10
|
50
|
|
|
|
|
if (status == 1) { |
|
2083
|
10
|
50
|
|
|
|
|
if ((n+width) < n) { |
|
2084
|
0
|
|
|
|
|
|
status = 0; /* range will overflow */ |
|
2085
|
|
|
|
|
|
|
} else { /* TODO: actually sieve */ |
|
2086
|
1620
|
100
|
|
|
|
|
for (i = (n<2)?2-n:0; i < width; i++) |
|
|
|
100
|
|
|
|
|
|
|
2087
|
1610
|
100
|
|
|
|
|
if (is_rough(n+i, (depth+1) >= (n+i) ? n+i : depth+1)) |
|
2088
|
316
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSVuv( i ))); |
|
2089
|
|
|
|
|
|
|
} |
|
2090
|
|
|
|
|
|
|
} |
|
2091
|
10
|
50
|
|
|
|
|
if (status != 1) { |
|
2092
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
2093
|
0
|
|
|
|
|
|
return; |
|
2094
|
|
|
|
|
|
|
} |
|
2095
|
|
|
|
|
|
|
|
|
2096
|
|
|
|
|
|
|
void |
|
2097
|
|
|
|
|
|
|
sieve_prime_cluster(IN SV* svlo, IN SV* svhi, ...) |
|
2098
|
|
|
|
|
|
|
PREINIT: |
|
2099
|
|
|
|
|
|
|
uint32_t nc, cl[100]; |
|
2100
|
|
|
|
|
|
|
UV i, lo, hi, cval, nprimes, *list; |
|
2101
|
|
|
|
|
|
|
int done; |
|
2102
|
|
|
|
|
|
|
PPCODE: |
|
2103
|
41
|
|
|
|
|
|
nc = items-1; |
|
2104
|
41
|
50
|
|
|
|
|
if (items > 100) croak("sieve_prime_cluster: too many entries"); |
|
2105
|
41
|
|
|
|
|
|
cl[0] = 0; |
|
2106
|
256
|
100
|
|
|
|
|
for (i = 1; i < nc; i++) { |
|
2107
|
215
|
50
|
|
|
|
|
if (!_validate_and_set(&cval, aTHX_ ST(1+i), IFLAG_POS)) |
|
2108
|
0
|
|
|
|
|
|
croak("sieve_prime_cluster: cluster values must be standard integers"); |
|
2109
|
215
|
50
|
|
|
|
|
if (cval & 1) croak("sieve_prime_cluster: values must be even"); |
|
2110
|
215
|
50
|
|
|
|
|
if (cval > 2147483647UL) croak("sieve_prime_cluster: values must be 31-bit"); |
|
2111
|
215
|
50
|
|
|
|
|
if (cval <= cl[i-1]) croak("sieve_prime_cluster: values must be increasing"); |
|
2112
|
215
|
|
|
|
|
|
cl[i] = cval; |
|
2113
|
|
|
|
|
|
|
} |
|
2114
|
41
|
|
|
|
|
|
done = 0; |
|
2115
|
73
|
|
|
|
|
|
if (_validate_and_set(&lo, aTHX_ svlo, IFLAG_POS) && |
|
2116
|
32
|
|
|
|
|
|
_validate_and_set(&hi, aTHX_ svhi, IFLAG_POS)) { |
|
2117
|
32
|
|
|
|
|
|
list = sieve_cluster(lo, hi, nc, cl, &nprimes); |
|
2118
|
32
|
50
|
|
|
|
|
if (list != 0) { |
|
2119
|
32
|
|
|
|
|
|
done = 1; |
|
2120
|
32
|
50
|
|
|
|
|
EXTEND(SP, (EXTEND_TYPE)nprimes); |
|
|
|
100
|
|
|
|
|
|
|
2121
|
12308
|
100
|
|
|
|
|
for (i = 0; i < nprimes; i++) |
|
2122
|
12276
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv( list[i] ))); |
|
2123
|
32
|
|
|
|
|
|
Safefree(list); |
|
2124
|
|
|
|
|
|
|
} |
|
2125
|
|
|
|
|
|
|
} |
|
2126
|
41
|
100
|
|
|
|
|
if (!done) { |
|
2127
|
9
|
|
|
|
|
|
DISPATCHPP(); |
|
2128
|
9
|
|
|
|
|
|
return; |
|
2129
|
|
|
|
|
|
|
} |
|
2130
|
|
|
|
|
|
|
|
|
2131
|
|
|
|
|
|
|
void is_pseudoprime(IN SV* svn, ...) |
|
2132
|
|
|
|
|
|
|
ALIAS: |
|
2133
|
|
|
|
|
|
|
is_euler_pseudoprime = 1 |
|
2134
|
|
|
|
|
|
|
is_strong_pseudoprime = 2 |
|
2135
|
|
|
|
|
|
|
PREINIT: |
|
2136
|
14937
|
|
|
|
|
|
int i, status, ret = 0; |
|
2137
|
|
|
|
|
|
|
UV n, base; |
|
2138
|
|
|
|
|
|
|
PPCODE: |
|
2139
|
14937
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY); |
|
2140
|
14937
|
100
|
|
|
|
|
if (status == 1) { |
|
2141
|
14813
|
100
|
|
|
|
|
if (n < 3) { |
|
2142
|
4
|
|
|
|
|
|
ret = (n == 2); |
|
2143
|
14809
|
100
|
|
|
|
|
} else if (ix == 2 && !(n&1)) { |
|
|
|
100
|
|
|
|
|
|
|
2144
|
7031
|
|
|
|
|
|
ret = 0; |
|
2145
|
7778
|
100
|
|
|
|
|
} else if (items == 1) { |
|
2146
|
4106
|
100
|
|
|
|
|
ret = (ix == 0) ? is_pseudoprime(n, 2) : |
|
2147
|
2051
|
100
|
|
|
|
|
(ix == 1) ? is_euler_pseudoprime(n, 2) : |
|
2148
|
2015
|
|
|
|
|
|
is_strong_pseudoprime(n, 2); |
|
2149
|
|
|
|
|
|
|
} else { |
|
2150
|
12249
|
100
|
|
|
|
|
for (i = 1, ret = 1; i < items && ret == 1; i++) { |
|
|
|
100
|
|
|
|
|
|
|
2151
|
6526
|
|
|
|
|
|
status = _validate_and_set(&base, aTHX_ ST(i), IFLAG_POS); |
|
2152
|
6526
|
50
|
|
|
|
|
if (status != 1) break; |
|
2153
|
12952
|
100
|
|
|
|
|
ret = (ix == 0) ? is_pseudoprime(n, base) : |
|
2154
|
6426
|
100
|
|
|
|
|
(ix == 1) ? is_euler_pseudoprime(n, base) : |
|
2155
|
6353
|
|
|
|
|
|
is_strong_pseudoprime(n, base); |
|
2156
|
|
|
|
|
|
|
} |
|
2157
|
|
|
|
|
|
|
} |
|
2158
|
|
|
|
|
|
|
} |
|
2159
|
14937
|
100
|
|
|
|
|
if (status != 0) RETURN_NPARITY(ret); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
2160
|
126
|
|
|
|
|
|
DISPATCHPP(); |
|
2161
|
124
|
|
|
|
|
|
XSRETURN(1); |
|
2162
|
|
|
|
|
|
|
|
|
2163
|
|
|
|
|
|
|
|
|
2164
|
|
|
|
|
|
|
void is_prime(IN SV* svn) |
|
2165
|
|
|
|
|
|
|
ALIAS: |
|
2166
|
|
|
|
|
|
|
is_prob_prime = 1 |
|
2167
|
|
|
|
|
|
|
is_provable_prime = 2 |
|
2168
|
|
|
|
|
|
|
is_bpsw_prime = 3 |
|
2169
|
|
|
|
|
|
|
is_aks_prime = 4 |
|
2170
|
|
|
|
|
|
|
is_lucas_pseudoprime = 5 |
|
2171
|
|
|
|
|
|
|
is_strong_lucas_pseudoprime = 6 |
|
2172
|
|
|
|
|
|
|
is_extra_strong_lucas_pseudoprime = 7 |
|
2173
|
|
|
|
|
|
|
is_frobenius_underwood_pseudoprime = 8 |
|
2174
|
|
|
|
|
|
|
is_frobenius_khashin_pseudoprime = 9 |
|
2175
|
|
|
|
|
|
|
is_catalan_pseudoprime = 10 |
|
2176
|
|
|
|
|
|
|
is_euler_plumb_pseudoprime = 11 |
|
2177
|
|
|
|
|
|
|
is_ramanujan_prime = 12 |
|
2178
|
|
|
|
|
|
|
is_semiprime = 13 |
|
2179
|
|
|
|
|
|
|
is_chen_prime = 14 |
|
2180
|
|
|
|
|
|
|
is_mersenne_prime = 15 |
|
2181
|
|
|
|
|
|
|
PREINIT: |
|
2182
|
|
|
|
|
|
|
int status, ret; |
|
2183
|
|
|
|
|
|
|
UV n; |
|
2184
|
|
|
|
|
|
|
PPCODE: |
|
2185
|
49722
|
|
|
|
|
|
ret = 0; |
|
2186
|
49722
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY); |
|
2187
|
49719
|
100
|
|
|
|
|
if (status == 1) { |
|
2188
|
48475
|
|
|
|
|
|
switch (ix) { |
|
2189
|
29560
|
|
|
|
|
|
case 0: ret = 2*is_prime(n); break; |
|
2190
|
3969
|
|
|
|
|
|
case 1: ret = 2*is_prob_prime(n); break; |
|
2191
|
2
|
|
|
|
|
|
case 2: ret = 2*is_prime(n); break; |
|
2192
|
0
|
|
|
|
|
|
case 3: ret = BPSW(n); break; |
|
2193
|
11
|
|
|
|
|
|
case 4: ret = is_aks_prime(n); break; |
|
2194
|
29
|
|
|
|
|
|
case 5: ret = is_lucas_pseudoprime(n, 0); break; |
|
2195
|
20
|
|
|
|
|
|
case 6: ret = is_lucas_pseudoprime(n, 1); break; |
|
2196
|
121
|
|
|
|
|
|
case 7: ret = is_lucas_pseudoprime(n, 3); break; |
|
2197
|
48
|
|
|
|
|
|
case 8: ret = is_frobenius_underwood_pseudoprime(n); break; |
|
2198
|
48
|
|
|
|
|
|
case 9: ret = is_frobenius_khashin_pseudoprime(n); break; |
|
2199
|
3
|
|
|
|
|
|
case 10: ret = is_catalan_pseudoprime(n); break; |
|
2200
|
29
|
|
|
|
|
|
case 11: ret = is_euler_plumb_pseudoprime(n); break; |
|
2201
|
984
|
|
|
|
|
|
case 12: ret = is_ramanujan_prime(n); break; |
|
2202
|
11165
|
|
|
|
|
|
case 13: ret = is_semiprime(n); break; |
|
2203
|
202
|
|
|
|
|
|
case 14: ret = is_chen_prime(n); break; |
|
2204
|
2284
|
50
|
|
|
|
|
case 15: ret = is_mersenne_prime(n); if (ret == -1) status = 0; break; |
|
2205
|
0
|
|
|
|
|
|
default: break; |
|
2206
|
|
|
|
|
|
|
} |
|
2207
|
|
|
|
|
|
|
} |
|
2208
|
49719
|
100
|
|
|
|
|
if (status != 0) RETURN_NPARITY(ret); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
2209
|
1076
|
|
|
|
|
|
DISPATCHPP(); |
|
2210
|
1076
|
|
|
|
|
|
XSRETURN(1); |
|
2211
|
|
|
|
|
|
|
|
|
2212
|
|
|
|
|
|
|
void |
|
2213
|
|
|
|
|
|
|
is_perrin_pseudoprime(IN SV* svn, IN UV k = 0) |
|
2214
|
|
|
|
|
|
|
ALIAS: |
|
2215
|
|
|
|
|
|
|
is_almost_extra_strong_lucas_pseudoprime = 1 |
|
2216
|
|
|
|
|
|
|
is_delicate_prime = 2 |
|
2217
|
|
|
|
|
|
|
PREINIT: |
|
2218
|
|
|
|
|
|
|
int status, ret; |
|
2219
|
|
|
|
|
|
|
UV n; |
|
2220
|
|
|
|
|
|
|
PPCODE: |
|
2221
|
|
|
|
|
|
|
/* k is a UV, so always positive. */ |
|
2222
|
|
|
|
|
|
|
/* ix = 0 k = 0 - 3 n below 2 returns 0 for all k |
|
2223
|
|
|
|
|
|
|
* ix = 1 k = 0 - 256 n below 2 returns 0 for all k |
|
2224
|
|
|
|
|
|
|
* ix = 2 k = 0 - 2^32 n below 2 returns 0 for all k |
|
2225
|
|
|
|
|
|
|
*/ |
|
2226
|
1066161
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY); |
|
2227
|
1066161
|
|
|
|
|
|
ret = 0; |
|
2228
|
1066161
|
100
|
|
|
|
|
if (status == 1) { |
|
2229
|
1066160
|
|
|
|
|
|
switch (ix) { |
|
2230
|
20
|
100
|
|
|
|
|
case 0: if (items == 1) k = 0; |
|
2231
|
20
|
|
|
|
|
|
ret = is_perrin_pseudoprime(n, k); break; |
|
2232
|
49
|
100
|
|
|
|
|
case 1: if (items == 1) k = 1; |
|
2233
|
49
|
|
|
|
|
|
ret = is_almost_extra_strong_lucas_pseudoprime(n, k); break; |
|
2234
|
1066091
|
100
|
|
|
|
|
case 2: if (items == 1) k = 10; |
|
2235
|
1066091
|
|
|
|
|
|
ret = is_delicate_prime(n, k); |
|
2236
|
1066091
|
50
|
|
|
|
|
if (ret < 0) status = 0; break; |
|
2237
|
0
|
|
|
|
|
|
default: break; |
|
2238
|
|
|
|
|
|
|
} |
|
2239
|
|
|
|
|
|
|
} |
|
2240
|
1066161
|
100
|
|
|
|
|
if (status != 0) RETURN_NPARITY(ret); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
2241
|
1
|
|
|
|
|
|
DISPATCHPP(); |
|
2242
|
1
|
|
|
|
|
|
XSRETURN(1); |
|
2243
|
|
|
|
|
|
|
|
|
2244
|
|
|
|
|
|
|
void |
|
2245
|
|
|
|
|
|
|
is_frobenius_pseudoprime(IN SV* svn, IN IV P = 0, IN IV Q = 0) |
|
2246
|
|
|
|
|
|
|
PREINIT: |
|
2247
|
|
|
|
|
|
|
int status; |
|
2248
|
|
|
|
|
|
|
UV n; |
|
2249
|
|
|
|
|
|
|
PPCODE: |
|
2250
|
28
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY); |
|
2251
|
28
|
50
|
|
|
|
|
if (status != 0) |
|
2252
|
28
|
50
|
|
|
|
|
RETURN_NPARITY((status == 1) ? is_frobenius_pseudoprime(n, P, Q) : 0); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
2253
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
2254
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
2255
|
|
|
|
|
|
|
|
|
2256
|
|
|
|
|
|
|
void |
|
2257
|
|
|
|
|
|
|
miller_rabin_random(IN SV* svn, IN IV bases = 1, IN char* seed = 0) |
|
2258
|
|
|
|
|
|
|
PREINIT: |
|
2259
|
|
|
|
|
|
|
int status; |
|
2260
|
|
|
|
|
|
|
UV n; |
|
2261
|
|
|
|
|
|
|
dMY_CXT; |
|
2262
|
|
|
|
|
|
|
PPCODE: |
|
2263
|
8
|
100
|
|
|
|
|
if (bases < 0) croak("miller_rabin_random: expected positive number of bases"); |
|
2264
|
7
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY); |
|
2265
|
6
|
50
|
|
|
|
|
if (status == -1) RETURN_NPARITY(0); |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
2266
|
6
|
50
|
|
|
|
|
if (seed == 0 && status == 1) |
|
|
|
100
|
|
|
|
|
|
|
2267
|
4
|
50
|
|
|
|
|
RETURN_NPARITY( is_mr_random(MY_CXT.randcxt, n, bases) ); |
|
|
|
50
|
|
|
|
|
|
|
2268
|
2
|
|
|
|
|
|
DISPATCHPP(); |
|
2269
|
2
|
|
|
|
|
|
XSRETURN(1); |
|
2270
|
|
|
|
|
|
|
|
|
2271
|
|
|
|
|
|
|
void is_gaussian_prime(IN SV* sva, IN SV* svb) |
|
2272
|
|
|
|
|
|
|
PREINIT: |
|
2273
|
|
|
|
|
|
|
UV a, b; |
|
2274
|
|
|
|
|
|
|
PPCODE: |
|
2275
|
14
|
|
|
|
|
|
if (_validate_and_set(&a, aTHX_ sva, IFLAG_ABS) && |
|
2276
|
7
|
|
|
|
|
|
_validate_and_set(&b, aTHX_ svb, IFLAG_ABS)) { |
|
2277
|
7
|
100
|
|
|
|
|
if (a == 0) RETURN_NPARITY( ((b % 4) == 3) ? 2*is_prime(b) : 0 ); |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
2278
|
5
|
100
|
|
|
|
|
if (b == 0) RETURN_NPARITY( ((a % 4) == 3) ? 2*is_prime(a) : 0 ); |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
2279
|
3
|
50
|
|
|
|
|
if (a < HALF_WORD && b < HALF_WORD) { |
|
|
|
50
|
|
|
|
|
|
|
2280
|
3
|
|
|
|
|
|
UV aa = a*a, bb = b*b; |
|
2281
|
3
|
50
|
|
|
|
|
if (UV_MAX-aa >= bb) |
|
2282
|
3
|
50
|
|
|
|
|
RETURN_NPARITY( 2*is_prime(aa+bb) ); |
|
|
|
50
|
|
|
|
|
|
|
2283
|
|
|
|
|
|
|
} |
|
2284
|
|
|
|
|
|
|
} |
|
2285
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
2286
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
2287
|
|
|
|
|
|
|
|
|
2288
|
|
|
|
|
|
|
|
|
2289
|
|
|
|
|
|
|
void |
|
2290
|
|
|
|
|
|
|
gcd(...) |
|
2291
|
|
|
|
|
|
|
PROTOTYPE: @ |
|
2292
|
|
|
|
|
|
|
ALIAS: |
|
2293
|
|
|
|
|
|
|
lcm = 1 |
|
2294
|
|
|
|
|
|
|
vecmin = 2 |
|
2295
|
|
|
|
|
|
|
vecmax = 3 |
|
2296
|
|
|
|
|
|
|
vecsum = 4 |
|
2297
|
|
|
|
|
|
|
vecprod = 5 |
|
2298
|
|
|
|
|
|
|
PREINIT: |
|
2299
|
63070
|
|
|
|
|
|
int i, status = 1; |
|
2300
|
|
|
|
|
|
|
UV ret, nullv, n; |
|
2301
|
|
|
|
|
|
|
PPCODE: |
|
2302
|
63076
|
100
|
|
|
|
|
if (ix == 2 || ix == 3) { |
|
|
|
100
|
|
|
|
|
|
|
2303
|
145
|
|
|
|
|
|
UV retindex = 0; |
|
2304
|
145
|
|
|
|
|
|
int sign, minmax = (ix == 2); |
|
2305
|
145
|
100
|
|
|
|
|
if (items == 0) XSRETURN_UNDEF; |
|
2306
|
143
|
100
|
|
|
|
|
if (items == 1) XSRETURN(1); |
|
2307
|
81
|
50
|
|
|
|
|
if (items > 1 && (status = _validate_and_set(&ret, aTHX_ ST(0), IFLAG_ANY))) { |
|
|
|
100
|
|
|
|
|
|
|
2308
|
75
|
|
|
|
|
|
sign = status; |
|
2309
|
248
|
100
|
|
|
|
|
for (i = 1; i < items; i++) { |
|
2310
|
173
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ ST(i), IFLAG_ANY); |
|
2311
|
173
|
50
|
|
|
|
|
if (status == 0) break; |
|
2312
|
340
|
100
|
|
|
|
|
if (( (sign == -1 && status == 1) || |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
2313
|
167
|
100
|
|
|
|
|
(n >= ret && sign == status) |
|
|
|
100
|
|
|
|
|
|
|
2314
|
|
|
|
|
|
|
) ? !minmax : minmax ) { |
|
2315
|
83
|
|
|
|
|
|
sign = status; |
|
2316
|
83
|
|
|
|
|
|
ret = n; |
|
2317
|
83
|
|
|
|
|
|
retindex = i; |
|
2318
|
|
|
|
|
|
|
} |
|
2319
|
|
|
|
|
|
|
} |
|
2320
|
|
|
|
|
|
|
} |
|
2321
|
81
|
100
|
|
|
|
|
if (status != 0) { |
|
2322
|
75
|
|
|
|
|
|
ST(0) = ST(retindex); |
|
2323
|
75
|
|
|
|
|
|
XSRETURN(1); |
|
2324
|
|
|
|
|
|
|
} |
|
2325
|
62925
|
100
|
|
|
|
|
} else if (ix == 4) { |
|
2326
|
4706
|
|
|
|
|
|
UV lo = 0; |
|
2327
|
4706
|
|
|
|
|
|
IV hi = 0; |
|
2328
|
207394
|
100
|
|
|
|
|
for (ret = i = 0; i < items; i++) { |
|
2329
|
202706
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ ST(i), IFLAG_ANY); |
|
2330
|
202706
|
100
|
|
|
|
|
if (status == 0) break; |
|
2331
|
202688
|
100
|
|
|
|
|
if (status == 1) hi += (n > (UV_MAX - lo)); |
|
2332
|
83
|
|
|
|
|
|
else hi -= ((UV_MAX-n) >= lo); |
|
2333
|
202688
|
|
|
|
|
|
lo += n; |
|
2334
|
|
|
|
|
|
|
} |
|
2335
|
4706
|
100
|
|
|
|
|
if (status != 0 && hi != 0) { |
|
|
|
100
|
|
|
|
|
|
|
2336
|
15
|
100
|
|
|
|
|
if (hi == -1 && lo > IV_MAX) XSRETURN_IV((IV)lo); |
|
|
|
100
|
|
|
|
|
|
|
2337
|
7
|
|
|
|
|
|
else RETURN_128(hi, lo); |
|
2338
|
|
|
|
|
|
|
} |
|
2339
|
4691
|
|
|
|
|
|
ret = lo; |
|
2340
|
58219
|
100
|
|
|
|
|
} else if (ix == 5) { |
|
2341
|
470
|
|
|
|
|
|
int sign = 1; |
|
2342
|
470
|
|
|
|
|
|
ret = 1; |
|
2343
|
2800
|
100
|
|
|
|
|
for (i = 0; i < items; i++) { |
|
2344
|
2660
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ ST(i), IFLAG_ANY); |
|
2345
|
2660
|
100
|
|
|
|
|
if (status == 0) break; |
|
2346
|
2560
|
50
|
|
|
|
|
if (ret > 0 && n > UV_MAX/ret) { status = 0; break; } |
|
|
|
100
|
|
|
|
|
|
|
2347
|
2330
|
|
|
|
|
|
sign *= status; |
|
2348
|
2330
|
|
|
|
|
|
ret *= n; |
|
2349
|
|
|
|
|
|
|
} |
|
2350
|
470
|
100
|
|
|
|
|
if (sign == -1 && status != 0) { |
|
|
|
100
|
|
|
|
|
|
|
2351
|
2
|
50
|
|
|
|
|
if (ret <= (UV)IV_MAX) XSRETURN_IV(neg_iv(ret)); |
|
2352
|
2
|
|
|
|
|
|
else status = 0; |
|
2353
|
|
|
|
|
|
|
} |
|
2354
|
|
|
|
|
|
|
} else { |
|
2355
|
|
|
|
|
|
|
/* For each arg, while valid input, validate+gcd/lcm. Shortcut stop. */ |
|
2356
|
57749
|
100
|
|
|
|
|
if (ix == 0) { ret = 0; nullv = 1; } |
|
2357
|
35
|
|
|
|
|
|
else { ret = 1; nullv = 0; } |
|
2358
|
153946
|
100
|
|
|
|
|
for (i = 0; i < items && ret != nullv && status != 0; i++) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
2359
|
101190
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ ST(i), IFLAG_ABS); |
|
2360
|
101190
|
100
|
|
|
|
|
if (status == 0) break; |
|
2361
|
96197
|
100
|
|
|
|
|
if (i == 0) { |
|
2362
|
53267
|
|
|
|
|
|
ret = n; |
|
2363
|
|
|
|
|
|
|
} else { |
|
2364
|
42930
|
|
|
|
|
|
UV gcd = gcd_ui(ret, n); |
|
2365
|
42930
|
100
|
|
|
|
|
if (ix == 0) { |
|
2366
|
42883
|
|
|
|
|
|
ret = gcd; |
|
2367
|
|
|
|
|
|
|
} else { |
|
2368
|
47
|
|
|
|
|
|
n /= gcd; |
|
2369
|
47
|
100
|
|
|
|
|
if (n <= (UV_MAX / ret) ) ret *= n; |
|
2370
|
4
|
|
|
|
|
|
else status = 0; /* Overflow */ |
|
2371
|
|
|
|
|
|
|
} |
|
2372
|
|
|
|
|
|
|
} |
|
2373
|
|
|
|
|
|
|
} |
|
2374
|
|
|
|
|
|
|
} |
|
2375
|
62916
|
100
|
|
|
|
|
if (status != 0) |
|
2376
|
57563
|
|
|
|
|
|
XSRETURN_UV(ret); |
|
2377
|
|
|
|
|
|
|
/* For min/max, use string compare if not an object */ |
|
2378
|
5353
|
100
|
|
|
|
|
if ((ix == 2 || ix == 3) && !sv_isobject(ST(0))) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
2379
|
2
|
|
|
|
|
|
int retindex = 0; |
|
2380
|
2
|
|
|
|
|
|
int minmax = (ix == 2); |
|
2381
|
|
|
|
|
|
|
STRLEN alen, blen; |
|
2382
|
|
|
|
|
|
|
char *aptr, *bptr; |
|
2383
|
2
|
|
|
|
|
|
aptr = SvPV(ST(0), alen); |
|
2384
|
2
|
|
|
|
|
|
(void) strnum_minmax(minmax, 0, 0, aptr, alen); |
|
2385
|
4
|
100
|
|
|
|
|
for (i = 1; i < items; i++) { |
|
2386
|
2
|
|
|
|
|
|
bptr = SvPV(ST(i), blen); |
|
2387
|
2
|
50
|
|
|
|
|
if (strnum_minmax(minmax, aptr, alen, bptr, blen)) { |
|
2388
|
2
|
|
|
|
|
|
aptr = bptr; |
|
2389
|
2
|
|
|
|
|
|
alen = blen; |
|
2390
|
2
|
|
|
|
|
|
retindex = i; |
|
2391
|
|
|
|
|
|
|
} |
|
2392
|
|
|
|
|
|
|
} |
|
2393
|
2
|
|
|
|
|
|
ST(0) = ST(retindex); |
|
2394
|
2
|
|
|
|
|
|
XSRETURN(1); |
|
2395
|
|
|
|
|
|
|
} |
|
2396
|
5351
|
|
|
|
|
|
DISPATCHPP(); |
|
2397
|
5351
|
100
|
|
|
|
|
if (ix == 0 || ix == 1) objectify_result(aTHX_ 0, ST(0)); |
|
|
|
100
|
|
|
|
|
|
|
2398
|
5351
|
|
|
|
|
|
XSRETURN(1); |
|
2399
|
|
|
|
|
|
|
|
|
2400
|
|
|
|
|
|
|
void |
|
2401
|
|
|
|
|
|
|
vecextract(IN SV* x, IN SV* svm) |
|
2402
|
|
|
|
|
|
|
PREINIT: |
|
2403
|
|
|
|
|
|
|
AV* av; |
|
2404
|
2
|
50
|
|
|
|
|
UV mask, i = 0; |
|
2405
|
|
|
|
|
|
|
PPCODE: |
|
2406
|
2
|
50
|
|
|
|
|
CHECK_ARRAYREF(x); |
|
|
|
50
|
|
|
|
|
|
|
2407
|
2
|
|
|
|
|
|
av = (AV*) SvRV(x); |
|
2408
|
3
|
100
|
|
|
|
|
if (SvROK(svm) && SvTYPE(SvRV(svm)) == SVt_PVAV) { |
|
|
|
50
|
|
|
|
|
|
|
2409
|
|
|
|
|
|
|
SSize_t j, index; |
|
2410
|
|
|
|
|
|
|
DECL_ARREF(mav); |
|
2411
|
1
|
50
|
|
|
|
|
USE_ARREF(mav, svm, SUBNAME, AR_READ); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
2412
|
6
|
100
|
|
|
|
|
for (j = 0; (Size_t)j < len_mav; j++) { |
|
2413
|
5
|
|
|
|
|
|
SV* v = FETCH_ARREF(mav, j); |
|
2414
|
5
|
50
|
|
|
|
|
if (_validate_and_set(&mask, aTHX_ v, IFLAG_IV) == 0) |
|
2415
|
0
|
|
|
|
|
|
croak("vecextract invalid index"); |
|
2416
|
5
|
|
|
|
|
|
index = (SSize_t)mask; |
|
2417
|
5
|
50
|
|
|
|
|
{ SV **v = av_fetch(av, index, 0); if (v) XPUSHs(*v); } |
|
|
|
50
|
|
|
|
|
|
|
2418
|
|
|
|
|
|
|
} |
|
2419
|
1
|
50
|
|
|
|
|
} else if (_validate_and_set(&mask, aTHX_ svm, IFLAG_POS)) { |
|
2420
|
25
|
100
|
|
|
|
|
while (mask) { |
|
2421
|
24
|
100
|
|
|
|
|
if (mask & 1) { |
|
2422
|
13
|
|
|
|
|
|
SV** v = av_fetch(av, i, 0); |
|
2423
|
13
|
50
|
|
|
|
|
if (v) XPUSHs(*v); |
|
|
|
50
|
|
|
|
|
|
|
2424
|
|
|
|
|
|
|
} |
|
2425
|
24
|
|
|
|
|
|
i++; |
|
2426
|
24
|
|
|
|
|
|
mask >>= 1; |
|
2427
|
|
|
|
|
|
|
} |
|
2428
|
|
|
|
|
|
|
} else { |
|
2429
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
2430
|
0
|
|
|
|
|
|
return; |
|
2431
|
|
|
|
|
|
|
} |
|
2432
|
|
|
|
|
|
|
|
|
2433
|
|
|
|
|
|
|
void |
|
2434
|
|
|
|
|
|
|
vecequal(IN SV* a, IN SV* b) |
|
2435
|
|
|
|
|
|
|
PREINIT: |
|
2436
|
|
|
|
|
|
|
int res; |
|
2437
|
|
|
|
|
|
|
PPCODE: |
|
2438
|
19
|
|
|
|
|
|
res = _compare_array_refs(aTHX_ a, b); |
|
2439
|
19
|
100
|
|
|
|
|
if (res == -1) |
|
2440
|
1
|
|
|
|
|
|
croak("vecequal: expected scalar or array reference"); |
|
2441
|
18
|
50
|
|
|
|
|
RETURN_NPARITY(res); |
|
|
|
50
|
|
|
|
|
|
|
2442
|
|
|
|
|
|
|
XSRETURN(1); |
|
2443
|
|
|
|
|
|
|
|
|
2444
|
|
|
|
|
|
|
void |
|
2445
|
|
|
|
|
|
|
vecmex(...) |
|
2446
|
|
|
|
|
|
|
ALIAS: |
|
2447
|
|
|
|
|
|
|
vecpmex = 1 |
|
2448
|
|
|
|
|
|
|
PROTOTYPE: @ |
|
2449
|
|
|
|
|
|
|
PREINIT: |
|
2450
|
|
|
|
|
|
|
char *setv; |
|
2451
|
154
|
|
|
|
|
|
int i, status = 1; |
|
2452
|
|
|
|
|
|
|
UV min, n; |
|
2453
|
|
|
|
|
|
|
uint32_t mask; |
|
2454
|
|
|
|
|
|
|
PPCODE: |
|
2455
|
154
|
100
|
|
|
|
|
if (ix == 0) { |
|
2456
|
8
|
|
|
|
|
|
min = 0; |
|
2457
|
8
|
|
|
|
|
|
mask = IFLAG_POS; |
|
2458
|
|
|
|
|
|
|
} else { |
|
2459
|
146
|
|
|
|
|
|
min = 1; |
|
2460
|
146
|
|
|
|
|
|
mask = IFLAG_POS | IFLAG_NONZERO; |
|
2461
|
|
|
|
|
|
|
} |
|
2462
|
154
|
100
|
|
|
|
|
if (items == 0) |
|
2463
|
2
|
|
|
|
|
|
XSRETURN_UV(min); |
|
2464
|
152
|
|
|
|
|
|
Newz(0, setv, items, char); |
|
2465
|
731
|
100
|
|
|
|
|
for (i = 0; i < items; i++) { |
|
2466
|
579
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ ST(i), mask); |
|
2467
|
|
|
|
|
|
|
/* Ignore any bigint */ |
|
2468
|
579
|
100
|
|
|
|
|
if (status == 1 && n-min < (UV)items) |
|
|
|
100
|
|
|
|
|
|
|
2469
|
493
|
|
|
|
|
|
setv[n-min] = 1; |
|
2470
|
|
|
|
|
|
|
} |
|
2471
|
327
|
100
|
|
|
|
|
for (i = 0; i < items; i++) |
|
2472
|
321
|
100
|
|
|
|
|
if (setv[i] == 0) |
|
2473
|
146
|
|
|
|
|
|
break; |
|
2474
|
152
|
|
|
|
|
|
Safefree(setv); |
|
2475
|
152
|
|
|
|
|
|
XSRETURN_UV(i+min); |
|
2476
|
|
|
|
|
|
|
|
|
2477
|
|
|
|
|
|
|
void |
|
2478
|
|
|
|
|
|
|
frobenius_number(...) |
|
2479
|
|
|
|
|
|
|
PROTOTYPE: @ |
|
2480
|
|
|
|
|
|
|
PREINIT: |
|
2481
|
67
|
|
|
|
|
|
int i, found1 = 0; |
|
2482
|
|
|
|
|
|
|
UV fn, n, *A; |
|
2483
|
|
|
|
|
|
|
PPCODE: |
|
2484
|
67
|
100
|
|
|
|
|
if (items == 0) XSRETURN_UNDEF; |
|
2485
|
66
|
|
|
|
|
|
Newz(0, A, items, UV); |
|
2486
|
503
|
100
|
|
|
|
|
for (i = 0; i < items; i++) { |
|
2487
|
439
|
50
|
|
|
|
|
if (!_validate_and_set(&n, aTHX_ ST(i), IFLAG_POS | IFLAG_NONZERO)) break; |
|
2488
|
439
|
100
|
|
|
|
|
if (n == 1) { found1 = 1; break; } |
|
2489
|
437
|
|
|
|
|
|
A[i] = n; |
|
2490
|
|
|
|
|
|
|
} |
|
2491
|
66
|
100
|
|
|
|
|
if (i == items) { |
|
2492
|
64
|
|
|
|
|
|
fn = frobenius_number(A, i); |
|
2493
|
63
|
|
|
|
|
|
Safefree(A); |
|
2494
|
63
|
100
|
|
|
|
|
if (fn == 0) XSRETURN_UNDEF; |
|
2495
|
62
|
100
|
|
|
|
|
if (fn != UV_MAX) XSRETURN_UV(fn); |
|
2496
|
|
|
|
|
|
|
} else { |
|
2497
|
2
|
|
|
|
|
|
Safefree(A); |
|
2498
|
2
|
50
|
|
|
|
|
if (found1) XSRETURN_IV(-1); |
|
2499
|
|
|
|
|
|
|
} |
|
2500
|
2
|
|
|
|
|
|
DISPATCHPP(); |
|
2501
|
2
|
|
|
|
|
|
XSRETURN(1); |
|
2502
|
|
|
|
|
|
|
|
|
2503
|
|
|
|
|
|
|
void |
|
2504
|
|
|
|
|
|
|
chinese(...) |
|
2505
|
|
|
|
|
|
|
ALIAS: |
|
2506
|
|
|
|
|
|
|
chinese2 = 1 |
|
2507
|
|
|
|
|
|
|
PROTOTYPE: @ |
|
2508
|
|
|
|
|
|
|
PREINIT: |
|
2509
|
|
|
|
|
|
|
int i, status, astatus, nstatus; |
|
2510
|
|
|
|
|
|
|
UV ret, lcm, *an; |
|
2511
|
|
|
|
|
|
|
SV **psva, **psvn; |
|
2512
|
|
|
|
|
|
|
SV *svfirstmod; |
|
2513
|
|
|
|
|
|
|
PPCODE: |
|
2514
|
68
|
|
|
|
|
|
status = 1; |
|
2515
|
68
|
|
|
|
|
|
New(0, an, 2*items, UV); |
|
2516
|
68
|
|
|
|
|
|
ret = 0; |
|
2517
|
68
|
|
|
|
|
|
svfirstmod = 0; |
|
2518
|
198
|
100
|
|
|
|
|
for (i = 0; i < items; i++) { |
|
2519
|
|
|
|
|
|
|
AV* av; |
|
2520
|
140
|
50
|
|
|
|
|
CHECK_ARRAYREF(ST(i)); |
|
|
|
50
|
|
|
|
|
|
|
2521
|
140
|
|
|
|
|
|
av = (AV*) SvRV(ST(i)); |
|
2522
|
140
|
50
|
|
|
|
|
if (av_count(av) != 2) croak("%s: expected 2-element array reference",SUBNAME); |
|
2523
|
140
|
|
|
|
|
|
psva = av_fetch(av, 0, 0); |
|
2524
|
140
|
|
|
|
|
|
psvn = av_fetch(av, 1, 0); |
|
2525
|
140
|
50
|
|
|
|
|
if (psva == 0 || psvn == 0) { status = 0; break; } |
|
|
|
50
|
|
|
|
|
|
|
2526
|
140
|
100
|
|
|
|
|
if (i == 0) svfirstmod = *psvn; |
|
2527
|
140
|
|
|
|
|
|
astatus = _validate_and_set(an+i, aTHX_ *psva, IFLAG_ANY); |
|
2528
|
140
|
|
|
|
|
|
nstatus = _validate_and_set(an+i+items, aTHX_ *psvn, IFLAG_ABS); |
|
2529
|
140
|
50
|
|
|
|
|
if (astatus == 0 || nstatus == 0) { status = 0; break; } |
|
|
|
50
|
|
|
|
|
|
|
2530
|
140
|
100
|
|
|
|
|
if (an[i+items] == 0) { |
|
2531
|
10
|
50
|
|
|
|
|
XPUSHs(&PL_sv_undef); |
|
2532
|
10
|
100
|
|
|
|
|
if (ix == 1) XPUSHs(&PL_sv_undef); |
|
|
|
50
|
|
|
|
|
|
|
2533
|
10
|
|
|
|
|
|
XSRETURN(1 + ix); |
|
2534
|
|
|
|
|
|
|
} |
|
2535
|
130
|
|
|
|
|
|
_mod_with(an+i, astatus, an[i+items]); |
|
2536
|
|
|
|
|
|
|
} |
|
2537
|
58
|
50
|
|
|
|
|
if (status) |
|
2538
|
58
|
|
|
|
|
|
status = chinese(&ret, &lcm, an, an+items, items); |
|
2539
|
58
|
|
|
|
|
|
Safefree(an); |
|
2540
|
58
|
100
|
|
|
|
|
if (status) { |
|
2541
|
46
|
100
|
|
|
|
|
if (ix == 0) { |
|
2542
|
23
|
100
|
|
|
|
|
if (status < 0) XSRETURN_UNDEF; |
|
2543
|
21
|
|
|
|
|
|
else XSRETURN_UV(ret); |
|
2544
|
|
|
|
|
|
|
} else { |
|
2545
|
23
|
100
|
|
|
|
|
if (status < 0) { |
|
2546
|
2
|
50
|
|
|
|
|
XPUSHs(&PL_sv_undef); |
|
2547
|
2
|
50
|
|
|
|
|
XPUSHs(&PL_sv_undef); |
|
2548
|
|
|
|
|
|
|
} else { |
|
2549
|
21
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSVuv( ret ))); |
|
2550
|
21
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSVuv( lcm ))); |
|
2551
|
|
|
|
|
|
|
} |
|
2552
|
23
|
|
|
|
|
|
XSRETURN(2); |
|
2553
|
|
|
|
|
|
|
} |
|
2554
|
|
|
|
|
|
|
} |
|
2555
|
12
|
|
|
|
|
|
DISPATCHPP(); |
|
2556
|
12
|
100
|
|
|
|
|
if (ix == 0) objectify_result(aTHX_ svfirstmod, ST(0)); |
|
2557
|
12
|
|
|
|
|
|
XSRETURN(1 + ix); |
|
2558
|
|
|
|
|
|
|
|
|
2559
|
|
|
|
|
|
|
void cornacchia(IN SV* svd, IN SV* svn) |
|
2560
|
|
|
|
|
|
|
PREINIT: |
|
2561
|
|
|
|
|
|
|
UV d, n, x, y; |
|
2562
|
|
|
|
|
|
|
PPCODE: |
|
2563
|
30
|
|
|
|
|
|
if (_validate_and_set(&d, aTHX_ svd, IFLAG_POS) && |
|
2564
|
15
|
|
|
|
|
|
_validate_and_set(&n, aTHX_ svn, IFLAG_POS) ) { |
|
2565
|
15
|
100
|
|
|
|
|
if (!cornacchia(&x, &y, d, n)) XSRETURN_UNDEF; |
|
2566
|
14
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv( x ))); |
|
2567
|
14
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv( y ))); |
|
2568
|
|
|
|
|
|
|
} else { |
|
2569
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
2570
|
0
|
|
|
|
|
|
return; /* Can return undef or two values */ |
|
2571
|
|
|
|
|
|
|
} |
|
2572
|
|
|
|
|
|
|
|
|
2573
|
|
|
|
|
|
|
void lucas_sequence(...) |
|
2574
|
|
|
|
|
|
|
PREINIT: |
|
2575
|
|
|
|
|
|
|
UV U, V, Qk, n, P, Q, k; |
|
2576
|
|
|
|
|
|
|
PPCODE: |
|
2577
|
0
|
0
|
|
|
|
|
if (items != 4) croak("lucas_sequence: n, P, Q, k"); |
|
2578
|
0
|
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ ST(0), IFLAG_POS | IFLAG_NONZERO) && |
|
2579
|
0
|
0
|
|
|
|
|
_validate_and_set(&P, aTHX_ ST(1), IFLAG_ANY | IFLAG_IV) && |
|
2580
|
0
|
0
|
|
|
|
|
_validate_and_set(&Q, aTHX_ ST(2), IFLAG_ANY | IFLAG_IV) && |
|
2581
|
0
|
|
|
|
|
|
_validate_and_set(&k, aTHX_ ST(3), IFLAG_POS)) { |
|
2582
|
0
|
|
|
|
|
|
lucas_seq(&U, &V, &Qk, n, (IV)P, (IV)Q, k); |
|
2583
|
0
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv( U ))); /* 4 args in, 3 out, no EXTEND needed */ |
|
2584
|
0
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv( V ))); |
|
2585
|
0
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv( Qk ))); |
|
2586
|
|
|
|
|
|
|
} else { |
|
2587
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
2588
|
0
|
0
|
|
|
|
|
OBJECTIFY_STACK(3); |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
2589
|
0
|
|
|
|
|
|
XSRETURN(3); |
|
2590
|
|
|
|
|
|
|
} |
|
2591
|
|
|
|
|
|
|
|
|
2592
|
|
|
|
|
|
|
void lucasuvmod(IN SV* svp, IN SV* svq, IN SV* svk, IN SV* svn) |
|
2593
|
|
|
|
|
|
|
ALIAS: |
|
2594
|
|
|
|
|
|
|
lucasumod = 1 |
|
2595
|
|
|
|
|
|
|
lucasvmod = 2 |
|
2596
|
|
|
|
|
|
|
PREINIT: |
|
2597
|
|
|
|
|
|
|
int pstatus, qstatus; |
|
2598
|
|
|
|
|
|
|
UV P, Q, k, n, U, V; |
|
2599
|
|
|
|
|
|
|
PPCODE: |
|
2600
|
26708
|
|
|
|
|
|
pstatus = _validate_and_set(&P, aTHX_ svp, IFLAG_ANY); |
|
2601
|
26708
|
|
|
|
|
|
qstatus = _validate_and_set(&Q, aTHX_ svq, IFLAG_ANY); |
|
2602
|
53407
|
100
|
|
|
|
|
if ((pstatus != 0) && (qstatus != 0) && |
|
2603
|
53394
|
100
|
|
|
|
|
_validate_and_set(&k, aTHX_ svk, IFLAG_POS) && |
|
2604
|
26695
|
|
|
|
|
|
_validate_and_set(&n, aTHX_ svn, IFLAG_ABS) |
|
2605
|
|
|
|
|
|
|
) { |
|
2606
|
26692
|
50
|
|
|
|
|
if (n == 0) XSRETURN_UNDEF; |
|
2607
|
26692
|
100
|
|
|
|
|
P = (pstatus == 1) ? P % n : ivmod((IV)P,n); |
|
2608
|
26692
|
100
|
|
|
|
|
Q = (qstatus == 1) ? Q % n : ivmod((IV)Q,n); |
|
2609
|
26692
|
|
|
|
|
|
switch (ix) { |
|
2610
|
505
|
|
|
|
|
|
case 0: lucasuvmod(&U, &V, P, Q, k, n); |
|
2611
|
505
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv( U ))); |
|
2612
|
505
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv( V ))); |
|
2613
|
505
|
|
|
|
|
|
break; |
|
2614
|
26059
|
|
|
|
|
|
case 1: XSRETURN_UV(lucasumod(P, Q, k, n)); break; |
|
2615
|
128
|
|
|
|
|
|
case 2: |
|
2616
|
128
|
|
|
|
|
|
default: XSRETURN_UV(lucasvmod(P, Q, k, n)); break; |
|
2617
|
|
|
|
|
|
|
} |
|
2618
|
|
|
|
|
|
|
} else { |
|
2619
|
16
|
|
|
|
|
|
DISPATCHPP(); |
|
2620
|
35
|
100
|
|
|
|
|
OBJECTIFY_STACK(ix==0 ? 2 : 1); |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
2621
|
16
|
100
|
|
|
|
|
XSRETURN(ix==0 ? 2 : 1); |
|
2622
|
|
|
|
|
|
|
} |
|
2623
|
|
|
|
|
|
|
|
|
2624
|
|
|
|
|
|
|
void lucasuv(IN SV* svp, IN SV* svq, IN SV* svk) |
|
2625
|
|
|
|
|
|
|
ALIAS: |
|
2626
|
|
|
|
|
|
|
lucasu = 1 |
|
2627
|
|
|
|
|
|
|
lucasv = 2 |
|
2628
|
|
|
|
|
|
|
PREINIT: |
|
2629
|
|
|
|
|
|
|
UV k; |
|
2630
|
|
|
|
|
|
|
IV P, Q, U, V; |
|
2631
|
|
|
|
|
|
|
PPCODE: |
|
2632
|
1398
|
|
|
|
|
|
if (_validate_and_set((UV*)&P, aTHX_ svp, IFLAG_IV) && |
|
2633
|
1392
|
50
|
|
|
|
|
_validate_and_set((UV*)&Q, aTHX_ svq, IFLAG_IV) && |
|
2634
|
1386
|
100
|
|
|
|
|
_validate_and_set(&k, aTHX_ svk, IFLAG_POS) && |
|
2635
|
693
|
|
|
|
|
|
lucasuv(&U, &V, P, Q, k)) { |
|
2636
|
621
|
100
|
|
|
|
|
if (ix == 1) XSRETURN_IV(U); /* U = lucasu(P,Q,k) */ |
|
2637
|
332
|
100
|
|
|
|
|
if (ix == 2) XSRETURN_IV(V); /* V = lucasv(P,Q,k) */ |
|
2638
|
90
|
|
|
|
|
|
PUSHs(sv_2mortal(newSViv( U ))); /* (U,V) = lucasuv(P,Q,k) */ |
|
2639
|
90
|
|
|
|
|
|
PUSHs(sv_2mortal(newSViv( V ))); |
|
2640
|
|
|
|
|
|
|
} else { |
|
2641
|
78
|
|
|
|
|
|
DISPATCHPP(); |
|
2642
|
182
|
100
|
|
|
|
|
OBJECTIFY_STACK(ix==0 ? 2 : 1); |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
2643
|
78
|
100
|
|
|
|
|
XSRETURN(ix==0 ? 2 : 1); |
|
2644
|
|
|
|
|
|
|
} |
|
2645
|
|
|
|
|
|
|
|
|
2646
|
|
|
|
|
|
|
|
|
2647
|
|
|
|
|
|
|
void is_sum_of_squares(IN SV* svn, IN UV k = 2) |
|
2648
|
|
|
|
|
|
|
PREINIT: |
|
2649
|
|
|
|
|
|
|
int status, ret; |
|
2650
|
|
|
|
|
|
|
UV n; |
|
2651
|
|
|
|
|
|
|
PPCODE: |
|
2652
|
299
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, IFLAG_ABS); |
|
2653
|
299
|
100
|
|
|
|
|
if (status != 0) { |
|
2654
|
298
|
|
|
|
|
|
switch (k) { |
|
2655
|
21
|
|
|
|
|
|
case 0: ret = (n==0); break; |
|
2656
|
21
|
|
|
|
|
|
case 1: ret = is_power(n,2); break; |
|
2657
|
116
|
|
|
|
|
|
case 2: ret = is_sum_of_two_squares(n); break; |
|
2658
|
119
|
|
|
|
|
|
case 3: ret = is_sum_of_three_squares(n); break; |
|
2659
|
21
|
|
|
|
|
|
default: ret = 1; break; |
|
2660
|
|
|
|
|
|
|
} |
|
2661
|
298
|
50
|
|
|
|
|
RETURN_NPARITY(ret); |
|
|
|
50
|
|
|
|
|
|
|
2662
|
|
|
|
|
|
|
} |
|
2663
|
1
|
|
|
|
|
|
DISPATCHPP(); |
|
2664
|
1
|
|
|
|
|
|
XSRETURN(1); |
|
2665
|
|
|
|
|
|
|
|
|
2666
|
|
|
|
|
|
|
|
|
2667
|
|
|
|
|
|
|
void is_square(IN SV* svn) |
|
2668
|
|
|
|
|
|
|
ALIAS: |
|
2669
|
|
|
|
|
|
|
is_carmichael = 1 |
|
2670
|
|
|
|
|
|
|
is_quasi_carmichael = 2 |
|
2671
|
|
|
|
|
|
|
is_perfect_power = 3 |
|
2672
|
|
|
|
|
|
|
is_fundamental = 4 |
|
2673
|
|
|
|
|
|
|
is_lucky = 5 |
|
2674
|
|
|
|
|
|
|
is_practical = 6 |
|
2675
|
|
|
|
|
|
|
is_perfect_number = 7 |
|
2676
|
|
|
|
|
|
|
is_cyclic = 8 |
|
2677
|
|
|
|
|
|
|
is_totient = 9 |
|
2678
|
|
|
|
|
|
|
PREINIT: |
|
2679
|
|
|
|
|
|
|
int status, ret; |
|
2680
|
|
|
|
|
|
|
UV n; |
|
2681
|
|
|
|
|
|
|
PPCODE: |
|
2682
|
59773
|
|
|
|
|
|
ret = 0; |
|
2683
|
59773
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY); |
|
2684
|
59773
|
100
|
|
|
|
|
if (status == 1) { |
|
2685
|
59577
|
|
|
|
|
|
switch (ix) { |
|
2686
|
18
|
|
|
|
|
|
case 0: ret = is_power(n,2); break; |
|
2687
|
20006
|
|
|
|
|
|
case 1: ret = is_carmichael(n); break; |
|
2688
|
5402
|
|
|
|
|
|
case 2: ret = is_quasi_carmichael(n); break; |
|
2689
|
113
|
|
|
|
|
|
case 3: ret = is_perfect_power(n); break; |
|
2690
|
52
|
|
|
|
|
|
case 4: ret = is_fundamental(n,0); break; |
|
2691
|
218
|
|
|
|
|
|
case 5: ret = is_lucky(n); break; |
|
2692
|
297
|
|
|
|
|
|
case 6: ret = is_practical(n); break; |
|
2693
|
517
|
|
|
|
|
|
case 7: ret = is_perfect_number(n); break; |
|
2694
|
32829
|
|
|
|
|
|
case 8: ret = is_cyclic(n); break; |
|
2695
|
125
|
|
|
|
|
|
case 9: |
|
2696
|
125
|
|
|
|
|
|
default:ret = is_totient(n); break; |
|
2697
|
|
|
|
|
|
|
} |
|
2698
|
196
|
100
|
|
|
|
|
} else if (status == -1) { |
|
2699
|
184
|
|
|
|
|
|
switch (ix) { |
|
2700
|
100
|
|
|
|
|
|
case 3: ret = is_perfect_power_neg(neg_iv(n)); break; |
|
2701
|
50
|
|
|
|
|
|
case 4: ret = is_fundamental(neg_iv(n),1); break; |
|
2702
|
34
|
|
|
|
|
|
default:break; |
|
2703
|
|
|
|
|
|
|
} |
|
2704
|
|
|
|
|
|
|
} |
|
2705
|
59773
|
100
|
|
|
|
|
if (status != 0) RETURN_NPARITY(ret); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
2706
|
12
|
|
|
|
|
|
DISPATCHPP(); |
|
2707
|
12
|
|
|
|
|
|
XSRETURN(1); |
|
2708
|
|
|
|
|
|
|
|
|
2709
|
|
|
|
|
|
|
void squarefree_kernel(IN SV* svn) |
|
2710
|
|
|
|
|
|
|
PREINIT: |
|
2711
|
|
|
|
|
|
|
int status; |
|
2712
|
|
|
|
|
|
|
UV n; |
|
2713
|
|
|
|
|
|
|
PPCODE: |
|
2714
|
9
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY); |
|
2715
|
9
|
100
|
|
|
|
|
if (status == -1) |
|
2716
|
1
|
|
|
|
|
|
XSRETURN_IV( neg_iv(squarefree_kernel(neg_iv(n))) ); |
|
2717
|
8
|
50
|
|
|
|
|
if (status == 1) |
|
2718
|
8
|
|
|
|
|
|
XSRETURN_UV( squarefree_kernel(n) ); |
|
2719
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
2720
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
2721
|
|
|
|
|
|
|
|
|
2722
|
|
|
|
|
|
|
void is_powerfree(IN SV* svn, IN int k = 2) |
|
2723
|
|
|
|
|
|
|
ALIAS: |
|
2724
|
|
|
|
|
|
|
powerfree_sum = 1 |
|
2725
|
|
|
|
|
|
|
powerfree_part = 2 |
|
2726
|
|
|
|
|
|
|
powerfree_part_sum = 3 |
|
2727
|
|
|
|
|
|
|
PREINIT: |
|
2728
|
|
|
|
|
|
|
int status; |
|
2729
|
|
|
|
|
|
|
UV n, res; |
|
2730
|
|
|
|
|
|
|
PPCODE: |
|
2731
|
116937
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY); |
|
2732
|
116937
|
100
|
|
|
|
|
if (status == -1) { |
|
2733
|
98
|
|
|
|
|
|
n = neg_iv(n); |
|
2734
|
98
|
100
|
|
|
|
|
if (ix == 2) |
|
2735
|
2
|
|
|
|
|
|
XSRETURN_IV( neg_iv(powerfree_part(n,k)) ); |
|
2736
|
|
|
|
|
|
|
} |
|
2737
|
116935
|
100
|
|
|
|
|
if (status != 0) { |
|
2738
|
116927
|
|
|
|
|
|
switch (ix) { |
|
2739
|
111277
|
|
|
|
|
|
case 0: res = is_powerfree(n,k); break; |
|
2740
|
1115
|
|
|
|
|
|
case 1: res = powerfree_sum(n,k); break; |
|
2741
|
4263
|
|
|
|
|
|
case 2: res = powerfree_part(n,k); break; |
|
2742
|
272
|
|
|
|
|
|
case 3: |
|
2743
|
272
|
|
|
|
|
|
default: res = powerfree_part_sum(n,k); break; |
|
2744
|
|
|
|
|
|
|
} |
|
2745
|
116927
|
100
|
|
|
|
|
if (ix == 0) |
|
2746
|
111277
|
50
|
|
|
|
|
RETURN_NPARITY(res); |
|
|
|
50
|
|
|
|
|
|
|
2747
|
5650
|
100
|
|
|
|
|
if (res != 0 || n == 0) |
|
|
|
100
|
|
|
|
|
|
|
2748
|
4658
|
|
|
|
|
|
XSRETURN_UV(res); |
|
2749
|
|
|
|
|
|
|
/* res is 0 and n > 0, so we overflowed. Fall through to PP. */ |
|
2750
|
|
|
|
|
|
|
} |
|
2751
|
1000
|
|
|
|
|
|
DISPATCHPP(); |
|
2752
|
1000
|
|
|
|
|
|
XSRETURN(1); |
|
2753
|
|
|
|
|
|
|
|
|
2754
|
|
|
|
|
|
|
void powerfree_count(IN SV* svn, IN int k = 2) |
|
2755
|
|
|
|
|
|
|
ALIAS: |
|
2756
|
|
|
|
|
|
|
nth_powerfree = 1 |
|
2757
|
|
|
|
|
|
|
PREINIT: |
|
2758
|
|
|
|
|
|
|
int status; |
|
2759
|
|
|
|
|
|
|
UV n, res; |
|
2760
|
|
|
|
|
|
|
PPCODE: |
|
2761
|
1122
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, (ix==0) ? IFLAG_ANY : IFLAG_POS); |
|
2762
|
1122
|
50
|
|
|
|
|
if (status != 0) { |
|
2763
|
1122
|
50
|
|
|
|
|
if (status == -1) |
|
2764
|
0
|
|
|
|
|
|
XSRETURN_UV(0); |
|
2765
|
1122
|
100
|
|
|
|
|
if (ix == 0) { |
|
2766
|
1115
|
|
|
|
|
|
res = powerfree_count(n,k); |
|
2767
|
1115
|
|
|
|
|
|
XSRETURN_UV(res); |
|
2768
|
|
|
|
|
|
|
} else { |
|
2769
|
7
|
50
|
|
|
|
|
if (n == 0 || k < 2) |
|
|
|
50
|
|
|
|
|
|
|
2770
|
0
|
|
|
|
|
|
XSRETURN_UNDEF; |
|
2771
|
7
|
|
|
|
|
|
res = nth_powerfree(n,k); |
|
2772
|
7
|
50
|
|
|
|
|
if (res != 0) |
|
2773
|
7
|
|
|
|
|
|
XSRETURN_UV(res); |
|
2774
|
|
|
|
|
|
|
/* if res = 0, overflow */ |
|
2775
|
|
|
|
|
|
|
} |
|
2776
|
|
|
|
|
|
|
} |
|
2777
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
2778
|
0
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
2779
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
2780
|
|
|
|
|
|
|
|
|
2781
|
|
|
|
|
|
|
void |
|
2782
|
|
|
|
|
|
|
is_power(IN SV* svn, IN UV k = 0, IN SV* svroot = 0) |
|
2783
|
|
|
|
|
|
|
PREINIT: |
|
2784
|
|
|
|
|
|
|
int status, ret; |
|
2785
|
|
|
|
|
|
|
UV n; |
|
2786
|
|
|
|
|
|
|
uint32_t root; |
|
2787
|
|
|
|
|
|
|
PPCODE: |
|
2788
|
10789
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY); |
|
2789
|
10789
|
100
|
|
|
|
|
if (status != 0) { |
|
2790
|
10500
|
100
|
|
|
|
|
if (k != 0) { |
|
2791
|
61
|
100
|
|
|
|
|
if (status == -1) { |
|
2792
|
14
|
100
|
|
|
|
|
if (k % 2 == 0) RETURN_NPARITY(0); /* negative n even k return 0 */ |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
2793
|
12
|
|
|
|
|
|
n = neg_iv(n); |
|
2794
|
|
|
|
|
|
|
} |
|
2795
|
59
|
|
|
|
|
|
ret = is_power_ret(n, k, &root); |
|
2796
|
|
|
|
|
|
|
} else { /* k = 0 */ |
|
2797
|
10439
|
100
|
|
|
|
|
if (status == -1) |
|
2798
|
61
|
|
|
|
|
|
n = neg_iv(n); |
|
2799
|
|
|
|
|
|
|
/* Following Pari/GP: ispower(0) = ispower(1) = ispower(-1) = 0 */ |
|
2800
|
10439
|
100
|
|
|
|
|
ret = (n <= 1) ? 0 : powerof_ret(n, &root); |
|
2801
|
10439
|
100
|
|
|
|
|
if (status == -1 && ret > 0 && ret % 2 == 0) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
2802
|
27
|
|
|
|
|
|
uint32_t v = valuation(ret,2); |
|
2803
|
27
|
|
|
|
|
|
ret >>= v; |
|
2804
|
27
|
100
|
|
|
|
|
if (ret == 1) ret = 0; |
|
2805
|
27
|
100
|
|
|
|
|
if (ret) root = ipow(root,1U << v); |
|
2806
|
|
|
|
|
|
|
} |
|
2807
|
|
|
|
|
|
|
} |
|
2808
|
10498
|
100
|
|
|
|
|
if (ret && svroot != 0) { |
|
|
|
100
|
|
|
|
|
|
|
2809
|
29
|
50
|
|
|
|
|
if (!SvROK(svroot)) croak("is_power: third argument not a scalar reference"); |
|
2810
|
29
|
100
|
|
|
|
|
SETSVINT(SvRV(svroot), status == 1, root, -(IV)root); |
|
2811
|
|
|
|
|
|
|
} |
|
2812
|
10498
|
50
|
|
|
|
|
RETURN_NPARITY(ret); |
|
|
|
50
|
|
|
|
|
|
|
2813
|
|
|
|
|
|
|
} |
|
2814
|
289
|
|
|
|
|
|
DISPATCHPP_GMPONLYIF(svroot == 0); |
|
2815
|
289
|
|
|
|
|
|
XSRETURN(1); |
|
2816
|
|
|
|
|
|
|
|
|
2817
|
|
|
|
|
|
|
void |
|
2818
|
|
|
|
|
|
|
is_prime_power(IN SV* svn, IN SV* svroot = 0) |
|
2819
|
|
|
|
|
|
|
PREINIT: |
|
2820
|
|
|
|
|
|
|
int status, ret; |
|
2821
|
|
|
|
|
|
|
UV n, root; |
|
2822
|
|
|
|
|
|
|
PPCODE: |
|
2823
|
10559
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY); |
|
2824
|
10559
|
100
|
|
|
|
|
if (status != 0) { |
|
2825
|
10549
|
50
|
|
|
|
|
ret = (status == 1) ? prime_power(n, &root) : 0; |
|
2826
|
10549
|
100
|
|
|
|
|
if (ret && svroot != 0) { |
|
|
|
100
|
|
|
|
|
|
|
2827
|
14
|
50
|
|
|
|
|
if (!SvROK(svroot))croak("is_prime_power: second argument not a scalar reference"); |
|
2828
|
14
|
|
|
|
|
|
sv_setuv(SvRV(svroot), root); |
|
2829
|
|
|
|
|
|
|
} |
|
2830
|
10549
|
50
|
|
|
|
|
RETURN_NPARITY(ret); |
|
|
|
50
|
|
|
|
|
|
|
2831
|
|
|
|
|
|
|
} |
|
2832
|
10
|
|
|
|
|
|
DISPATCHPP_GMPONLYIF(svroot == 0); |
|
2833
|
10
|
|
|
|
|
|
XSRETURN(1); |
|
2834
|
|
|
|
|
|
|
|
|
2835
|
|
|
|
|
|
|
void |
|
2836
|
|
|
|
|
|
|
is_polygonal(IN SV* svn, IN UV k, IN SV* svroot = 0) |
|
2837
|
|
|
|
|
|
|
PREINIT: |
|
2838
|
|
|
|
|
|
|
UV n; |
|
2839
|
|
|
|
|
|
|
int status; |
|
2840
|
|
|
|
|
|
|
PPCODE: |
|
2841
|
25305
|
100
|
|
|
|
|
if (svroot != 0 && !SvROK(svroot)) |
|
|
|
50
|
|
|
|
|
|
|
2842
|
0
|
|
|
|
|
|
croak("is_polygonal: third argument not a scalar reference"); |
|
2843
|
25305
|
50
|
|
|
|
|
if (k < 3) |
|
2844
|
0
|
|
|
|
|
|
croak("is_polygonal: k must be >= 3"); |
|
2845
|
|
|
|
|
|
|
|
|
2846
|
25305
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY); |
|
2847
|
25305
|
100
|
|
|
|
|
if (status == -1) |
|
2848
|
1
|
50
|
|
|
|
|
RETURN_NPARITY(0); |
|
|
|
50
|
|
|
|
|
|
|
2849
|
25304
|
100
|
|
|
|
|
if (status == 1) { |
|
2850
|
25302
|
|
|
|
|
|
bool overflow = 0; |
|
2851
|
25302
|
|
|
|
|
|
UV root = polygonal_root(n, k, &overflow); |
|
2852
|
25302
|
100
|
|
|
|
|
UV result = (n == 0) || root; |
|
|
|
100
|
|
|
|
|
|
|
2853
|
25302
|
50
|
|
|
|
|
if (!overflow) { |
|
2854
|
25302
|
100
|
|
|
|
|
if (result && svroot != 0) |
|
|
|
100
|
|
|
|
|
|
|
2855
|
232
|
|
|
|
|
|
sv_setuv(SvRV(svroot), root); |
|
2856
|
25302
|
50
|
|
|
|
|
RETURN_NPARITY(result); |
|
|
|
50
|
|
|
|
|
|
|
2857
|
|
|
|
|
|
|
} |
|
2858
|
|
|
|
|
|
|
} |
|
2859
|
2
|
|
|
|
|
|
DISPATCHPP_GMPONLYIF(svroot == 0); |
|
2860
|
2
|
|
|
|
|
|
XSRETURN(1); |
|
2861
|
|
|
|
|
|
|
|
|
2862
|
|
|
|
|
|
|
|
|
2863
|
|
|
|
|
|
|
void inverse_li(IN SV* svn) |
|
2864
|
|
|
|
|
|
|
PREINIT: |
|
2865
|
|
|
|
|
|
|
UV n; |
|
2866
|
|
|
|
|
|
|
PPCODE: |
|
2867
|
53
|
50
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) { |
|
2868
|
53
|
50
|
|
|
|
|
if (n < MPU_MAX_PRIME_IDX) /* Fall through to Perl if out of range. */ |
|
2869
|
53
|
|
|
|
|
|
XSRETURN_UV(inverse_li(n)); |
|
2870
|
|
|
|
|
|
|
} |
|
2871
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
2872
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
2873
|
|
|
|
|
|
|
|
|
2874
|
|
|
|
|
|
|
NV inverse_li_nv(IN NV x) |
|
2875
|
|
|
|
|
|
|
CODE: |
|
2876
|
4
|
50
|
|
|
|
|
RETVAL = ld_inverse_li(x); |
|
2877
|
|
|
|
|
|
|
OUTPUT: |
|
2878
|
|
|
|
|
|
|
RETVAL |
|
2879
|
|
|
|
|
|
|
|
|
2880
|
|
|
|
|
|
|
void nth_prime(IN SV* svn) |
|
2881
|
|
|
|
|
|
|
ALIAS: |
|
2882
|
|
|
|
|
|
|
nth_prime_upper = 1 |
|
2883
|
|
|
|
|
|
|
nth_prime_lower = 2 |
|
2884
|
|
|
|
|
|
|
nth_prime_approx = 3 |
|
2885
|
|
|
|
|
|
|
PREINIT: |
|
2886
|
|
|
|
|
|
|
UV n, ret; |
|
2887
|
|
|
|
|
|
|
PPCODE: |
|
2888
|
256
|
50
|
|
|
|
|
if ( _validate_and_set(&n, aTHX_ svn, IFLAG_POS) && |
|
2889
|
256
|
100
|
|
|
|
|
n <= MPU_MAX_PRIME_IDX ) { |
|
2890
|
255
|
100
|
|
|
|
|
if (n == 0) XSRETURN_UNDEF; |
|
2891
|
253
|
|
|
|
|
|
switch (ix) { |
|
2892
|
173
|
|
|
|
|
|
case 0: ret = nth_prime(n); break; |
|
2893
|
28
|
|
|
|
|
|
case 1: ret = nth_prime_upper(n); break; |
|
2894
|
27
|
|
|
|
|
|
case 2: ret = nth_prime_lower(n); break; |
|
2895
|
25
|
|
|
|
|
|
case 3: |
|
2896
|
25
|
|
|
|
|
|
default: ret = nth_prime_approx(n); break; |
|
2897
|
|
|
|
|
|
|
} |
|
2898
|
253
|
|
|
|
|
|
XSRETURN_UV(ret); |
|
2899
|
|
|
|
|
|
|
} |
|
2900
|
1
|
|
|
|
|
|
DISPATCHPP(); |
|
2901
|
1
|
|
|
|
|
|
XSRETURN(1); |
|
2902
|
|
|
|
|
|
|
|
|
2903
|
|
|
|
|
|
|
void nth_prime_power(IN SV* svn) |
|
2904
|
|
|
|
|
|
|
ALIAS: |
|
2905
|
|
|
|
|
|
|
nth_prime_power_upper = 1 |
|
2906
|
|
|
|
|
|
|
nth_prime_power_lower = 2 |
|
2907
|
|
|
|
|
|
|
nth_prime_power_approx = 3 |
|
2908
|
|
|
|
|
|
|
PREINIT: |
|
2909
|
|
|
|
|
|
|
UV n, ret; |
|
2910
|
|
|
|
|
|
|
PPCODE: |
|
2911
|
193
|
50
|
|
|
|
|
if ( _validate_and_set(&n, aTHX_ svn, IFLAG_POS) && |
|
2912
|
193
|
50
|
|
|
|
|
n <= MPU_MAX_PRIME_IDX ) { |
|
2913
|
193
|
100
|
|
|
|
|
if (n == 0) XSRETURN_UNDEF; |
|
2914
|
189
|
|
|
|
|
|
switch (ix) { |
|
2915
|
69
|
|
|
|
|
|
case 0: ret = nth_prime_power(n); break; |
|
2916
|
40
|
|
|
|
|
|
case 1: ret = nth_prime_power_upper(n); break; |
|
2917
|
40
|
|
|
|
|
|
case 2: ret = nth_prime_power_lower(n); break; |
|
2918
|
40
|
|
|
|
|
|
case 3: |
|
2919
|
40
|
|
|
|
|
|
default: ret = nth_prime_power_approx(n); break; |
|
2920
|
|
|
|
|
|
|
} |
|
2921
|
189
|
|
|
|
|
|
XSRETURN_UV(ret); |
|
2922
|
|
|
|
|
|
|
} |
|
2923
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
2924
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
2925
|
|
|
|
|
|
|
|
|
2926
|
|
|
|
|
|
|
void nth_perfect_power(IN SV* svn) |
|
2927
|
|
|
|
|
|
|
ALIAS: |
|
2928
|
|
|
|
|
|
|
nth_perfect_power_upper = 1 |
|
2929
|
|
|
|
|
|
|
nth_perfect_power_lower = 2 |
|
2930
|
|
|
|
|
|
|
nth_perfect_power_approx = 3 |
|
2931
|
|
|
|
|
|
|
PREINIT: |
|
2932
|
|
|
|
|
|
|
UV n, ret; |
|
2933
|
|
|
|
|
|
|
PPCODE: |
|
2934
|
181
|
50
|
|
|
|
|
if ( _validate_and_set(&n, aTHX_ svn, IFLAG_POS) && |
|
2935
|
181
|
100
|
|
|
|
|
n <= MPU_MAX_PERFECT_POW_IDX ) { |
|
2936
|
180
|
50
|
|
|
|
|
if (n == 0) XSRETURN_UNDEF; |
|
2937
|
180
|
|
|
|
|
|
switch (ix) { |
|
2938
|
63
|
|
|
|
|
|
case 0: ret = nth_perfect_power(n); break; |
|
2939
|
57
|
|
|
|
|
|
case 1: ret = nth_perfect_power_upper(n); break; |
|
2940
|
57
|
|
|
|
|
|
case 2: ret = nth_perfect_power_lower(n); break; |
|
2941
|
3
|
|
|
|
|
|
case 3: |
|
2942
|
3
|
|
|
|
|
|
default: ret = nth_perfect_power_approx(n); break; |
|
2943
|
|
|
|
|
|
|
} |
|
2944
|
180
|
|
|
|
|
|
XSRETURN_UV(ret); |
|
2945
|
|
|
|
|
|
|
} |
|
2946
|
1
|
|
|
|
|
|
DISPATCHPP(); |
|
2947
|
1
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
2948
|
1
|
|
|
|
|
|
XSRETURN(1); |
|
2949
|
|
|
|
|
|
|
|
|
2950
|
|
|
|
|
|
|
void nth_ramanujan_prime(IN SV* svn) |
|
2951
|
|
|
|
|
|
|
ALIAS: |
|
2952
|
|
|
|
|
|
|
nth_ramanujan_prime_upper = 1 |
|
2953
|
|
|
|
|
|
|
nth_ramanujan_prime_lower = 2 |
|
2954
|
|
|
|
|
|
|
nth_ramanujan_prime_approx = 3 |
|
2955
|
|
|
|
|
|
|
PREINIT: |
|
2956
|
|
|
|
|
|
|
UV n, ret; |
|
2957
|
|
|
|
|
|
|
PPCODE: |
|
2958
|
225
|
50
|
|
|
|
|
if ( _validate_and_set(&n, aTHX_ svn, IFLAG_POS) && |
|
2959
|
225
|
50
|
|
|
|
|
n <= MPU_MAX_RMJN_PRIME_IDX ) { |
|
2960
|
225
|
50
|
|
|
|
|
if (n == 0) XSRETURN_UNDEF; |
|
2961
|
225
|
|
|
|
|
|
switch (ix) { |
|
2962
|
75
|
|
|
|
|
|
case 0: ret = nth_ramanujan_prime(n); break; |
|
2963
|
74
|
|
|
|
|
|
case 1: ret = nth_ramanujan_prime_upper(n); break; |
|
2964
|
74
|
|
|
|
|
|
case 2: ret = nth_ramanujan_prime_lower(n); break; |
|
2965
|
2
|
|
|
|
|
|
case 3: |
|
2966
|
2
|
|
|
|
|
|
default: ret = nth_ramanujan_prime_approx(n); break; |
|
2967
|
|
|
|
|
|
|
} |
|
2968
|
225
|
|
|
|
|
|
XSRETURN_UV(ret); |
|
2969
|
|
|
|
|
|
|
} |
|
2970
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
2971
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
2972
|
|
|
|
|
|
|
|
|
2973
|
|
|
|
|
|
|
void nth_twin_prime(IN SV* svn) |
|
2974
|
|
|
|
|
|
|
ALIAS: |
|
2975
|
|
|
|
|
|
|
nth_twin_prime_approx = 1 |
|
2976
|
|
|
|
|
|
|
PREINIT: |
|
2977
|
|
|
|
|
|
|
UV n, ret; |
|
2978
|
|
|
|
|
|
|
PPCODE: |
|
2979
|
63
|
50
|
|
|
|
|
if ( _validate_and_set(&n, aTHX_ svn, IFLAG_POS) && |
|
2980
|
63
|
50
|
|
|
|
|
n <= MPU_MAX_TWIN_PRIME_IDX ) { |
|
2981
|
63
|
100
|
|
|
|
|
if (n == 0) XSRETURN_UNDEF; |
|
2982
|
62
|
100
|
|
|
|
|
switch (ix) { |
|
2983
|
53
|
|
|
|
|
|
case 0: ret = nth_twin_prime(n); break; |
|
2984
|
9
|
|
|
|
|
|
case 1: |
|
2985
|
9
|
|
|
|
|
|
default: ret = nth_twin_prime_approx(n); break; |
|
2986
|
|
|
|
|
|
|
} |
|
2987
|
62
|
|
|
|
|
|
XSRETURN_UV(ret); |
|
2988
|
|
|
|
|
|
|
} |
|
2989
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
2990
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
2991
|
|
|
|
|
|
|
|
|
2992
|
|
|
|
|
|
|
void nth_semiprime(IN SV* svn) |
|
2993
|
|
|
|
|
|
|
ALIAS: |
|
2994
|
|
|
|
|
|
|
nth_semiprime_approx = 1 |
|
2995
|
|
|
|
|
|
|
PREINIT: |
|
2996
|
|
|
|
|
|
|
UV n, ret; |
|
2997
|
|
|
|
|
|
|
PPCODE: |
|
2998
|
2677
|
50
|
|
|
|
|
if ( _validate_and_set(&n, aTHX_ svn, IFLAG_POS) && |
|
2999
|
2677
|
50
|
|
|
|
|
n <= MPU_MAX_SEMI_PRIME_IDX ) { |
|
3000
|
2677
|
100
|
|
|
|
|
if (n == 0) XSRETURN_UNDEF; |
|
3001
|
2676
|
100
|
|
|
|
|
switch (ix) { |
|
3002
|
2672
|
|
|
|
|
|
case 0: ret = nth_semiprime(n); break; |
|
3003
|
4
|
|
|
|
|
|
case 1: |
|
3004
|
4
|
|
|
|
|
|
default: ret = nth_semiprime_approx(n); break; |
|
3005
|
|
|
|
|
|
|
} |
|
3006
|
2676
|
|
|
|
|
|
XSRETURN_UV(ret); |
|
3007
|
|
|
|
|
|
|
} |
|
3008
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
3009
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
3010
|
|
|
|
|
|
|
|
|
3011
|
|
|
|
|
|
|
void nth_lucky(IN SV* svn) |
|
3012
|
|
|
|
|
|
|
ALIAS: |
|
3013
|
|
|
|
|
|
|
nth_lucky_upper = 1 |
|
3014
|
|
|
|
|
|
|
nth_lucky_lower = 2 |
|
3015
|
|
|
|
|
|
|
nth_lucky_approx = 3 |
|
3016
|
|
|
|
|
|
|
PREINIT: |
|
3017
|
|
|
|
|
|
|
UV n, ret; |
|
3018
|
|
|
|
|
|
|
PPCODE: |
|
3019
|
516
|
50
|
|
|
|
|
if ( _validate_and_set(&n, aTHX_ svn, IFLAG_POS) && |
|
3020
|
516
|
50
|
|
|
|
|
n <= MPU_MAX_LUCKY_IDX ) { |
|
3021
|
516
|
100
|
|
|
|
|
if (n == 0) XSRETURN_UNDEF; |
|
3022
|
512
|
|
|
|
|
|
switch (ix) { |
|
3023
|
164
|
|
|
|
|
|
case 0: ret = nth_lucky(n); break; |
|
3024
|
116
|
|
|
|
|
|
case 1: ret = nth_lucky_upper(n); break; |
|
3025
|
116
|
|
|
|
|
|
case 2: ret = nth_lucky_lower(n); break; |
|
3026
|
116
|
|
|
|
|
|
case 3: |
|
3027
|
116
|
|
|
|
|
|
default: ret = nth_lucky_approx(n); break; |
|
3028
|
|
|
|
|
|
|
} |
|
3029
|
512
|
|
|
|
|
|
XSRETURN_UV(ret); |
|
3030
|
|
|
|
|
|
|
} |
|
3031
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
3032
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
3033
|
|
|
|
|
|
|
|
|
3034
|
|
|
|
|
|
|
|
|
3035
|
|
|
|
|
|
|
void next_prime(IN SV* svn) |
|
3036
|
|
|
|
|
|
|
ALIAS: |
|
3037
|
|
|
|
|
|
|
prev_prime = 1 |
|
3038
|
|
|
|
|
|
|
PREINIT: |
|
3039
|
|
|
|
|
|
|
UV n, ret; |
|
3040
|
|
|
|
|
|
|
PPCODE: |
|
3041
|
12522
|
100
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS) |
|
3042
|
12484
|
100
|
|
|
|
|
&& !(ix == 0 && n >= MPU_MAX_PRIME)) { |
|
|
|
100
|
|
|
|
|
|
|
3043
|
12480
|
|
|
|
|
|
ret = 0; |
|
3044
|
12480
|
|
|
|
|
|
switch (ix) { |
|
3045
|
8731
|
|
|
|
|
|
case 0: ret = next_prime(n); break; |
|
3046
|
3749
|
|
|
|
|
|
case 1: ret = prev_prime(n); break; |
|
3047
|
0
|
|
|
|
|
|
default: break; |
|
3048
|
|
|
|
|
|
|
} |
|
3049
|
12480
|
100
|
|
|
|
|
if (ret == 0) XSRETURN_UNDEF; |
|
3050
|
12475
|
|
|
|
|
|
XSRETURN_UV(ret); |
|
3051
|
|
|
|
|
|
|
} |
|
3052
|
22
|
|
|
|
|
|
DISPATCHPP(); |
|
3053
|
21
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
3054
|
21
|
|
|
|
|
|
XSRETURN(1); |
|
3055
|
|
|
|
|
|
|
|
|
3056
|
|
|
|
|
|
|
void next_prime_power(IN SV* svn) |
|
3057
|
|
|
|
|
|
|
ALIAS: |
|
3058
|
|
|
|
|
|
|
prev_prime_power = 1 |
|
3059
|
|
|
|
|
|
|
PREINIT: |
|
3060
|
|
|
|
|
|
|
UV n, ret; |
|
3061
|
|
|
|
|
|
|
PPCODE: |
|
3062
|
110
|
50
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_ABS) |
|
3063
|
110
|
100
|
|
|
|
|
&& !(ix == 0 && n >= MPU_MAX_PRIME)) { |
|
|
|
50
|
|
|
|
|
|
|
3064
|
110
|
|
|
|
|
|
ret = 0; |
|
3065
|
110
|
|
|
|
|
|
switch (ix) { |
|
3066
|
54
|
|
|
|
|
|
case 0: ret = next_prime_power(n); break; |
|
3067
|
56
|
|
|
|
|
|
case 1: ret = prev_prime_power(n); break; |
|
3068
|
0
|
|
|
|
|
|
default: break; |
|
3069
|
|
|
|
|
|
|
} |
|
3070
|
110
|
100
|
|
|
|
|
if (ret == 0) XSRETURN_UNDEF; |
|
3071
|
106
|
|
|
|
|
|
XSRETURN_UV(ret); |
|
3072
|
|
|
|
|
|
|
} |
|
3073
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
3074
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
3075
|
|
|
|
|
|
|
|
|
3076
|
|
|
|
|
|
|
void next_perfect_power(IN SV* svn) |
|
3077
|
|
|
|
|
|
|
PREINIT: |
|
3078
|
|
|
|
|
|
|
UV n; |
|
3079
|
|
|
|
|
|
|
int status; |
|
3080
|
|
|
|
|
|
|
PPCODE: |
|
3081
|
67
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY); |
|
3082
|
67
|
100
|
|
|
|
|
if (status == 1) { |
|
3083
|
49
|
|
|
|
|
|
n = next_perfect_power(n); |
|
3084
|
49
|
100
|
|
|
|
|
if (n != 0) XSRETURN_UV(n); |
|
3085
|
18
|
100
|
|
|
|
|
} else if (status == -1) { /* next perfect power: negative n */ |
|
3086
|
17
|
|
|
|
|
|
n = next_perfect_power_neg(neg_iv(n)); |
|
3087
|
17
|
|
|
|
|
|
XSRETURN_IV(neg_iv(n)); |
|
3088
|
|
|
|
|
|
|
} |
|
3089
|
2
|
|
|
|
|
|
DISPATCHPP(); |
|
3090
|
2
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
3091
|
2
|
|
|
|
|
|
XSRETURN(1); |
|
3092
|
|
|
|
|
|
|
|
|
3093
|
|
|
|
|
|
|
void prev_perfect_power(IN SV* svn) |
|
3094
|
|
|
|
|
|
|
PREINIT: |
|
3095
|
|
|
|
|
|
|
UV n; |
|
3096
|
|
|
|
|
|
|
int status; |
|
3097
|
|
|
|
|
|
|
PPCODE: |
|
3098
|
72
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY); |
|
3099
|
72
|
100
|
|
|
|
|
if (status == 1) { |
|
3100
|
48
|
100
|
|
|
|
|
if (n == 0) XSRETURN_IV(-1); |
|
3101
|
45
|
|
|
|
|
|
n = prev_perfect_power(n); |
|
3102
|
45
|
|
|
|
|
|
XSRETURN_UV(n); |
|
3103
|
24
|
100
|
|
|
|
|
} else if (status == -1) { /* prev perfect power: negative n */ |
|
3104
|
17
|
|
|
|
|
|
n = prev_perfect_power_neg(neg_iv(n)); |
|
3105
|
17
|
50
|
|
|
|
|
if (n > 0 && n <= (UV)IV_MAX) |
|
|
|
100
|
|
|
|
|
|
|
3106
|
16
|
|
|
|
|
|
XSRETURN_IV(neg_iv(n)); |
|
3107
|
|
|
|
|
|
|
} |
|
3108
|
8
|
|
|
|
|
|
DISPATCHPP(); |
|
3109
|
8
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
3110
|
8
|
|
|
|
|
|
XSRETURN(1); |
|
3111
|
|
|
|
|
|
|
|
|
3112
|
|
|
|
|
|
|
void next_chen_prime(IN SV* svn) |
|
3113
|
|
|
|
|
|
|
PREINIT: |
|
3114
|
|
|
|
|
|
|
UV n, ret; |
|
3115
|
|
|
|
|
|
|
PPCODE: |
|
3116
|
36
|
50
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) { |
|
3117
|
36
|
|
|
|
|
|
ret = next_chen_prime(n); |
|
3118
|
36
|
50
|
|
|
|
|
if (ret != 0) XSRETURN_UV(ret); |
|
3119
|
|
|
|
|
|
|
} |
|
3120
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
3121
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
3122
|
|
|
|
|
|
|
|
|
3123
|
|
|
|
|
|
|
void urandomb(IN UV bits) |
|
3124
|
|
|
|
|
|
|
ALIAS: |
|
3125
|
|
|
|
|
|
|
random_ndigit_prime = 1 |
|
3126
|
|
|
|
|
|
|
random_semiprime = 2 |
|
3127
|
|
|
|
|
|
|
random_unrestricted_semiprime = 3 |
|
3128
|
|
|
|
|
|
|
random_safe_prime = 4 |
|
3129
|
|
|
|
|
|
|
random_nbit_prime = 5 |
|
3130
|
|
|
|
|
|
|
random_shawe_taylor_prime = 6 |
|
3131
|
|
|
|
|
|
|
random_maurer_prime = 7 |
|
3132
|
|
|
|
|
|
|
random_proven_prime = 8 |
|
3133
|
|
|
|
|
|
|
random_strong_prime = 9 |
|
3134
|
|
|
|
|
|
|
PREINIT: |
|
3135
|
|
|
|
|
|
|
UV res, minarg; |
|
3136
|
|
|
|
|
|
|
dMY_CXT; |
|
3137
|
|
|
|
|
|
|
void* cs; |
|
3138
|
|
|
|
|
|
|
PPCODE: |
|
3139
|
961
|
|
|
|
|
|
switch (ix) { |
|
3140
|
17
|
|
|
|
|
|
case 1: minarg = 1; break; |
|
3141
|
11
|
|
|
|
|
|
case 2: minarg = 4; break; |
|
3142
|
10
|
|
|
|
|
|
case 3: minarg = 3; break; |
|
3143
|
7
|
|
|
|
|
|
case 4: minarg = 3; break; |
|
3144
|
70
|
|
|
|
|
|
case 5: |
|
3145
|
|
|
|
|
|
|
case 6: |
|
3146
|
|
|
|
|
|
|
case 7: |
|
3147
|
70
|
|
|
|
|
|
case 8: minarg = 2; break; |
|
3148
|
2
|
|
|
|
|
|
case 9: minarg = 128; break; |
|
3149
|
844
|
|
|
|
|
|
default: minarg = 0; break; |
|
3150
|
|
|
|
|
|
|
} |
|
3151
|
961
|
100
|
|
|
|
|
if (minarg > 0 && bits < minarg) |
|
|
|
100
|
|
|
|
|
|
|
3152
|
8
|
|
|
|
|
|
croak("%s: input '%d' must be >= %d", SUBNAME, (int)bits, (int)minarg); |
|
3153
|
953
|
|
|
|
|
|
cs = MY_CXT.randcxt; |
|
3154
|
953
|
100
|
|
|
|
|
if (bits <= BITS_PER_WORD) { |
|
3155
|
920
|
|
|
|
|
|
switch (ix) { |
|
3156
|
820
|
|
|
|
|
|
case 0: res = urandomb(cs,bits); break; |
|
3157
|
16
|
|
|
|
|
|
case 1: res = random_ndigit_prime(cs,bits); break; |
|
3158
|
9
|
|
|
|
|
|
case 2: res = random_semiprime(cs,bits); break; |
|
3159
|
8
|
|
|
|
|
|
case 3: res = random_unrestricted_semiprime(cs,bits); break; |
|
3160
|
4
|
|
|
|
|
|
case 4: res = random_safe_prime(cs,bits); break; |
|
3161
|
63
|
|
|
|
|
|
case 5: |
|
3162
|
|
|
|
|
|
|
case 6: |
|
3163
|
|
|
|
|
|
|
case 7: |
|
3164
|
|
|
|
|
|
|
case 8: |
|
3165
|
|
|
|
|
|
|
case 9: |
|
3166
|
63
|
|
|
|
|
|
default: res = random_nbit_prime(cs,bits); break; |
|
3167
|
|
|
|
|
|
|
} |
|
3168
|
920
|
100
|
|
|
|
|
if (res || ix == 0) XSRETURN_UV(res); |
|
|
|
100
|
|
|
|
|
|
|
3169
|
|
|
|
|
|
|
} |
|
3170
|
36
|
100
|
|
|
|
|
DISPATCHPP_GMPONLYIF(ix != 1 || bits != uvmax_maxlen); |
|
|
|
100
|
|
|
|
|
|
|
3171
|
36
|
|
|
|
|
|
objectify_result(aTHX_ 0, ST(0)); |
|
3172
|
36
|
|
|
|
|
|
XSRETURN(1); |
|
3173
|
|
|
|
|
|
|
|
|
3174
|
|
|
|
|
|
|
void urandomm(IN SV* svn) |
|
3175
|
|
|
|
|
|
|
PREINIT: |
|
3176
|
|
|
|
|
|
|
UV n, ret; |
|
3177
|
|
|
|
|
|
|
PPCODE: |
|
3178
|
328
|
100
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) { |
|
3179
|
|
|
|
|
|
|
dMY_CXT; |
|
3180
|
305
|
|
|
|
|
|
ret = urandomm64(MY_CXT.randcxt, n); |
|
3181
|
305
|
|
|
|
|
|
XSRETURN_UV(ret); |
|
3182
|
|
|
|
|
|
|
} |
|
3183
|
23
|
|
|
|
|
|
DISPATCHPP(); |
|
3184
|
23
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
3185
|
23
|
|
|
|
|
|
XSRETURN(1); |
|
3186
|
|
|
|
|
|
|
|
|
3187
|
|
|
|
|
|
|
void pisano_period(IN SV* svn) |
|
3188
|
|
|
|
|
|
|
ALIAS: |
|
3189
|
|
|
|
|
|
|
partitions = 1 |
|
3190
|
|
|
|
|
|
|
consecutive_integer_lcm = 2 |
|
3191
|
|
|
|
|
|
|
PREINIT: |
|
3192
|
348
|
|
|
|
|
|
UV n, r = 0; |
|
3193
|
|
|
|
|
|
|
PPCODE: |
|
3194
|
348
|
100
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) { |
|
3195
|
346
|
|
|
|
|
|
switch (ix) { |
|
3196
|
187
|
|
|
|
|
|
case 0: r = pisano_period(n); break; |
|
3197
|
57
|
|
|
|
|
|
case 1: r = npartitions(n); break; |
|
3198
|
102
|
|
|
|
|
|
case 2: r = consecutive_integer_lcm(n); break; |
|
3199
|
0
|
|
|
|
|
|
default: break; |
|
3200
|
|
|
|
|
|
|
} |
|
3201
|
|
|
|
|
|
|
/* Returns 0 if n=0 or result overflows */ |
|
3202
|
346
|
100
|
|
|
|
|
if (r != 0 || n == 0) |
|
|
|
100
|
|
|
|
|
|
|
3203
|
286
|
|
|
|
|
|
XSRETURN_UV(r); |
|
3204
|
|
|
|
|
|
|
} |
|
3205
|
62
|
|
|
|
|
|
DISPATCHPP(); |
|
3206
|
62
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
3207
|
62
|
|
|
|
|
|
XSRETURN(1); |
|
3208
|
|
|
|
|
|
|
|
|
3209
|
|
|
|
|
|
|
void random_factored_integer(IN SV* svn) |
|
3210
|
|
|
|
|
|
|
PREINIT: |
|
3211
|
|
|
|
|
|
|
UV n; |
|
3212
|
|
|
|
|
|
|
PPCODE: |
|
3213
|
1
|
50
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS | IFLAG_NONZERO)) { |
|
3214
|
|
|
|
|
|
|
dMY_CXT; |
|
3215
|
|
|
|
|
|
|
int f, nf, flip; |
|
3216
|
|
|
|
|
|
|
UV r, F[MPU_MAX_FACTORS+1]; |
|
3217
|
1
|
|
|
|
|
|
AV* av = newAV(); |
|
3218
|
1
|
|
|
|
|
|
r = random_factored_integer(MY_CXT.randcxt, n, &nf, F); |
|
3219
|
1
|
|
|
|
|
|
flip = (F[0] >= F[nf-1]); /* Handle results in either sort order */ |
|
3220
|
4
|
100
|
|
|
|
|
for (f = 0; f < nf; f++) |
|
3221
|
3
|
50
|
|
|
|
|
av_push(av, newSVuv(F[flip ? nf-1-f : f])); |
|
3222
|
1
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSVuv( r ))); |
|
3223
|
1
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newRV_noinc( (SV*) av ))); |
|
3224
|
|
|
|
|
|
|
} else { |
|
3225
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
3226
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
3227
|
|
|
|
|
|
|
} |
|
3228
|
|
|
|
|
|
|
|
|
3229
|
|
|
|
|
|
|
|
|
3230
|
|
|
|
|
|
|
|
|
3231
|
|
|
|
|
|
|
void contfrac(IN SV* svnum, IN SV* svden) |
|
3232
|
|
|
|
|
|
|
PREINIT: |
|
3233
|
|
|
|
|
|
|
UV num, den; |
|
3234
|
|
|
|
|
|
|
int nstatus; |
|
3235
|
|
|
|
|
|
|
PPCODE: |
|
3236
|
53
|
|
|
|
|
|
nstatus = _validate_and_set(&num, aTHX_ svnum, IFLAG_ANY); |
|
3237
|
|
|
|
|
|
|
/* TODO: handle negative numerator */ |
|
3238
|
91
|
100
|
|
|
|
|
if (nstatus == 1 && _validate_and_set(&den, aTHX_ svden, IFLAG_POS | IFLAG_NONZERO)) { |
|
|
|
50
|
|
|
|
|
|
|
3239
|
|
|
|
|
|
|
UV *cf, rem; |
|
3240
|
38
|
|
|
|
|
|
int i, steps = contfrac(&cf, &rem, num, den); |
|
3241
|
38
|
50
|
|
|
|
|
EXTEND(SP, (EXTEND_TYPE)steps); |
|
|
|
50
|
|
|
|
|
|
|
3242
|
318
|
100
|
|
|
|
|
for (i = 0; i < steps; i++) |
|
3243
|
280
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv( cf[i] ))); |
|
3244
|
38
|
|
|
|
|
|
Safefree(cf); |
|
3245
|
|
|
|
|
|
|
} else { |
|
3246
|
15
|
|
|
|
|
|
DISPATCHPP(); |
|
3247
|
15
|
|
|
|
|
|
return; |
|
3248
|
|
|
|
|
|
|
} |
|
3249
|
|
|
|
|
|
|
|
|
3250
|
|
|
|
|
|
|
void from_contfrac(...) |
|
3251
|
|
|
|
|
|
|
PROTOTYPE: @ |
|
3252
|
|
|
|
|
|
|
PREINIT: |
|
3253
|
|
|
|
|
|
|
size_t i; |
|
3254
|
|
|
|
|
|
|
UV n, cfA0, cfA1, cfB0, cfB1, cfAn, cfBn; |
|
3255
|
|
|
|
|
|
|
int nstatus, overflow; |
|
3256
|
|
|
|
|
|
|
PPCODE: |
|
3257
|
53
|
|
|
|
|
|
nstatus = 1; |
|
3258
|
53
|
|
|
|
|
|
overflow = 0; |
|
3259
|
53
|
|
|
|
|
|
cfA0 = 1; cfA1 = 0; |
|
3260
|
53
|
|
|
|
|
|
cfB0 = 0; cfB1 = 1; |
|
3261
|
53
|
100
|
|
|
|
|
if (items > 0) { |
|
3262
|
52
|
|
|
|
|
|
nstatus = _validate_and_set(&n, aTHX_ ST(0), IFLAG_ANY); |
|
3263
|
|
|
|
|
|
|
/* TODO: handle negative n */ |
|
3264
|
52
|
|
|
|
|
|
cfA1 = n; |
|
3265
|
446
|
100
|
|
|
|
|
for (i = 1; nstatus == 1 && i < (size_t) items; i++) { |
|
|
|
100
|
|
|
|
|
|
|
3266
|
398
|
100
|
|
|
|
|
if (!_validate_and_set(&n, aTHX_ ST(i), IFLAG_POS | IFLAG_NONZERO)) |
|
3267
|
1
|
|
|
|
|
|
break; |
|
3268
|
|
|
|
|
|
|
/* check each step for overflow */ |
|
3269
|
397
|
100
|
|
|
|
|
overflow = (UV_MAX/n < cfA1) || (UV_MAX/n < cfB1); |
|
|
|
100
|
|
|
|
|
|
|
3270
|
397
|
100
|
|
|
|
|
if (overflow) break; |
|
3271
|
395
|
|
|
|
|
|
cfAn = n * cfA1; |
|
3272
|
395
|
|
|
|
|
|
cfBn = n * cfB1; |
|
3273
|
395
|
50
|
|
|
|
|
overflow = (UV_MAX-cfAn < cfA0) || (UV_MAX-cfBn < cfB0); |
|
|
|
100
|
|
|
|
|
|
|
3274
|
395
|
100
|
|
|
|
|
if (overflow) break; |
|
3275
|
394
|
|
|
|
|
|
cfAn = cfAn + cfA0; |
|
3276
|
394
|
|
|
|
|
|
cfBn = cfBn + cfB0; |
|
3277
|
394
|
|
|
|
|
|
cfA0 = cfA1; cfA1 = cfAn; |
|
3278
|
394
|
|
|
|
|
|
cfB0 = cfB1; cfB1 = cfBn; |
|
3279
|
|
|
|
|
|
|
} |
|
3280
|
52
|
100
|
|
|
|
|
if (i < (size_t) items) /* Covers overflow */ |
|
3281
|
13
|
|
|
|
|
|
nstatus = 0; |
|
3282
|
|
|
|
|
|
|
} |
|
3283
|
53
|
100
|
|
|
|
|
if (nstatus == 1) { |
|
3284
|
36
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSVuv( cfA1 ))); |
|
3285
|
36
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSVuv( cfB1 ))); |
|
3286
|
|
|
|
|
|
|
} else { |
|
3287
|
17
|
|
|
|
|
|
DISPATCHPP(); |
|
3288
|
|
|
|
|
|
|
} |
|
3289
|
53
|
|
|
|
|
|
XSRETURN(2); |
|
3290
|
|
|
|
|
|
|
|
|
3291
|
|
|
|
|
|
|
void next_calkin_wilf(IN SV* svnum, IN SV* svden) |
|
3292
|
|
|
|
|
|
|
ALIAS: |
|
3293
|
|
|
|
|
|
|
next_stern_brocot = 1 |
|
3294
|
|
|
|
|
|
|
PREINIT: |
|
3295
|
|
|
|
|
|
|
UV num, den; |
|
3296
|
|
|
|
|
|
|
int status; |
|
3297
|
|
|
|
|
|
|
PPCODE: |
|
3298
|
198
|
50
|
|
|
|
|
if (_validate_and_set(&num, aTHX_ svnum, IFLAG_POS | IFLAG_NONZERO) && _validate_and_set(&den, aTHX_ svden, IFLAG_POS | IFLAG_NONZERO)) { |
|
|
|
50
|
|
|
|
|
|
|
3299
|
198
|
|
|
|
|
|
switch (ix) { |
|
3300
|
99
|
|
|
|
|
|
case 0: status = next_calkin_wilf(&num, &den); break; |
|
3301
|
99
|
|
|
|
|
|
case 1: status = next_stern_brocot(&num, &den); break; |
|
3302
|
0
|
|
|
|
|
|
default: status = 0; break; |
|
3303
|
|
|
|
|
|
|
} |
|
3304
|
198
|
50
|
|
|
|
|
if (status) { |
|
3305
|
198
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSVuv( num ))); |
|
3306
|
198
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSVuv( den ))); |
|
3307
|
198
|
|
|
|
|
|
XSRETURN(2); |
|
3308
|
|
|
|
|
|
|
} |
|
3309
|
|
|
|
|
|
|
} |
|
3310
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
3311
|
0
|
|
|
|
|
|
XSRETURN(2); |
|
3312
|
|
|
|
|
|
|
|
|
3313
|
|
|
|
|
|
|
void calkin_wilf_n(IN SV* svnum, IN SV* svden) |
|
3314
|
|
|
|
|
|
|
ALIAS: |
|
3315
|
|
|
|
|
|
|
stern_brocot_n = 1 |
|
3316
|
|
|
|
|
|
|
PREINIT: |
|
3317
|
|
|
|
|
|
|
UV num, den, n; |
|
3318
|
|
|
|
|
|
|
PPCODE: |
|
3319
|
220
|
50
|
|
|
|
|
if (_validate_and_set(&num, aTHX_ svnum, IFLAG_POS | IFLAG_NONZERO) && _validate_and_set(&den, aTHX_ svden, IFLAG_POS | IFLAG_NONZERO)) { |
|
|
|
50
|
|
|
|
|
|
|
3320
|
220
|
|
|
|
|
|
switch (ix) { |
|
3321
|
110
|
|
|
|
|
|
case 0: n = calkin_wilf_n(num, den); break; |
|
3322
|
110
|
|
|
|
|
|
case 1: n = stern_brocot_n(num, den); break; |
|
3323
|
0
|
|
|
|
|
|
default: n = 0; break; |
|
3324
|
|
|
|
|
|
|
} |
|
3325
|
220
|
100
|
|
|
|
|
if (n) XSRETURN_UV(n); |
|
3326
|
|
|
|
|
|
|
} |
|
3327
|
6
|
|
|
|
|
|
DISPATCHPP(); |
|
3328
|
6
|
|
|
|
|
|
XSRETURN(1); |
|
3329
|
|
|
|
|
|
|
|
|
3330
|
|
|
|
|
|
|
void nth_calkin_wilf(IN SV* svn) |
|
3331
|
|
|
|
|
|
|
ALIAS: |
|
3332
|
|
|
|
|
|
|
nth_stern_brocot = 1 |
|
3333
|
|
|
|
|
|
|
PREINIT: |
|
3334
|
|
|
|
|
|
|
UV n, num, den; |
|
3335
|
|
|
|
|
|
|
int status; |
|
3336
|
|
|
|
|
|
|
PPCODE: |
|
3337
|
220
|
100
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS | IFLAG_NONZERO)) { |
|
3338
|
214
|
|
|
|
|
|
switch (ix) { |
|
3339
|
107
|
|
|
|
|
|
case 0: status = nth_calkin_wilf(&num, &den, n); break; |
|
3340
|
107
|
|
|
|
|
|
case 1: status = nth_stern_brocot(&num, &den, n); break; |
|
3341
|
0
|
|
|
|
|
|
default: status = 0; break; |
|
3342
|
|
|
|
|
|
|
} |
|
3343
|
214
|
50
|
|
|
|
|
if (status) { |
|
3344
|
214
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSVuv( num ))); |
|
3345
|
214
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSVuv( den ))); |
|
3346
|
214
|
|
|
|
|
|
XSRETURN(2); |
|
3347
|
|
|
|
|
|
|
} |
|
3348
|
|
|
|
|
|
|
} |
|
3349
|
6
|
|
|
|
|
|
DISPATCHPP(); |
|
3350
|
6
|
|
|
|
|
|
XSRETURN(2); |
|
3351
|
|
|
|
|
|
|
|
|
3352
|
|
|
|
|
|
|
void nth_stern_diatomic(IN SV* svn) |
|
3353
|
|
|
|
|
|
|
PREINIT: |
|
3354
|
|
|
|
|
|
|
UV n; |
|
3355
|
|
|
|
|
|
|
PPCODE: |
|
3356
|
340
|
50
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) |
|
3357
|
340
|
|
|
|
|
|
XSRETURN_UV(nth_stern_diatomic(n)); |
|
3358
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
3359
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
3360
|
|
|
|
|
|
|
|
|
3361
|
|
|
|
|
|
|
void farey(IN SV* svn, IN SV* svk = 0) |
|
3362
|
|
|
|
|
|
|
PREINIT: |
|
3363
|
|
|
|
|
|
|
UV n, k; |
|
3364
|
|
|
|
|
|
|
int wantsingle, kresult; |
|
3365
|
|
|
|
|
|
|
PPCODE: |
|
3366
|
151
|
|
|
|
|
|
wantsingle = svk != 0; |
|
3367
|
151
|
100
|
|
|
|
|
if (wantsingle) { |
|
3368
|
128
|
50
|
|
|
|
|
if (!_validate_and_set(&k, aTHX_ svk, IFLAG_POS)) |
|
3369
|
0
|
|
|
|
|
|
k = UV_MAX; |
|
3370
|
|
|
|
|
|
|
} |
|
3371
|
151
|
50
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS | IFLAG_NONZERO)) { |
|
3372
|
151
|
100
|
|
|
|
|
if (!wantsingle && GIMME_V != G_ARRAY) |
|
|
|
100
|
|
|
|
|
|
|
3373
|
13
|
|
|
|
|
|
XSRETURN_UV(farey_length(n)); |
|
3374
|
138
|
50
|
|
|
|
|
if (n <= UVCONST(4294967295)) { |
|
3375
|
138
|
100
|
|
|
|
|
if (wantsingle) { |
|
3376
|
|
|
|
|
|
|
uint32_t p, q; |
|
3377
|
128
|
|
|
|
|
|
kresult = kth_farey(n, k, &p, &q); |
|
3378
|
247
|
100
|
|
|
|
|
if (kresult == 0) XSRETURN_UNDEF; |
|
3379
|
119
|
50
|
|
|
|
|
if (kresult == 1) { |
|
3380
|
119
|
|
|
|
|
|
PUSH_2ELEM_AREF(p, q); |
|
3381
|
119
|
|
|
|
|
|
XSRETURN(1); |
|
3382
|
|
|
|
|
|
|
} |
|
3383
|
|
|
|
|
|
|
} else { |
|
3384
|
|
|
|
|
|
|
uint32_t *num, *den; |
|
3385
|
10
|
|
|
|
|
|
UV i, len = farey_array(n, &num, &den); |
|
3386
|
10
|
50
|
|
|
|
|
if (len > 0) { |
|
3387
|
10
|
50
|
|
|
|
|
EXTEND(SP, (EXTEND_TYPE)len); |
|
|
|
50
|
|
|
|
|
|
|
3388
|
124
|
100
|
|
|
|
|
for (i = 0; i < len; i++) |
|
3389
|
114
|
|
|
|
|
|
PUSH_2ELEM_AREF(num[i], den[i]); |
|
3390
|
10
|
|
|
|
|
|
Safefree(num); |
|
3391
|
10
|
|
|
|
|
|
Safefree(den); |
|
3392
|
10
|
|
|
|
|
|
XSRETURN(len); |
|
3393
|
|
|
|
|
|
|
} |
|
3394
|
|
|
|
|
|
|
} |
|
3395
|
|
|
|
|
|
|
} |
|
3396
|
|
|
|
|
|
|
} |
|
3397
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
3398
|
0
|
|
|
|
|
|
return; |
|
3399
|
|
|
|
|
|
|
|
|
3400
|
|
|
|
|
|
|
void next_farey(IN SV* svn, IN SV* svfrac) |
|
3401
|
|
|
|
|
|
|
ALIAS: |
|
3402
|
|
|
|
|
|
|
farey_rank = 1 |
|
3403
|
|
|
|
|
|
|
PREINIT: |
|
3404
|
|
|
|
|
|
|
SV **psvp, **psvq; |
|
3405
|
|
|
|
|
|
|
AV* av; |
|
3406
|
|
|
|
|
|
|
UV n, p64, q64; |
|
3407
|
|
|
|
|
|
|
uint32_t p, q; |
|
3408
|
|
|
|
|
|
|
int status; |
|
3409
|
|
|
|
|
|
|
PPCODE: |
|
3410
|
1009
|
50
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS | IFLAG_NONZERO) && |
|
3411
|
1009
|
50
|
|
|
|
|
n <= UVCONST(4294967295)) { |
|
3412
|
1009
|
50
|
|
|
|
|
CHECK_ARRAYREF(svfrac); |
|
|
|
50
|
|
|
|
|
|
|
3413
|
1009
|
|
|
|
|
|
av = (AV*) SvRV(svfrac); |
|
3414
|
1009
|
50
|
|
|
|
|
if (av_count(av) != 2) croak("%s: expected 2-element array reference", SUBNAME); |
|
3415
|
1009
|
|
|
|
|
|
psvp = av_fetch(av, 0, 0); |
|
3416
|
1009
|
|
|
|
|
|
psvq = av_fetch(av, 1, 0); |
|
3417
|
1009
|
|
|
|
|
|
status = 1; |
|
3418
|
1009
|
50
|
|
|
|
|
if (psvp == 0 || psvq == 0) |
|
|
|
50
|
|
|
|
|
|
|
3419
|
0
|
|
|
|
|
|
status = 0; |
|
3420
|
1009
|
50
|
|
|
|
|
if (status != 0) |
|
3421
|
1009
|
|
|
|
|
|
status = _validate_and_set(&p64, aTHX_ *psvp, IFLAG_POS); |
|
3422
|
1009
|
50
|
|
|
|
|
if (status != 0) |
|
3423
|
1009
|
|
|
|
|
|
status = _validate_and_set(&q64, aTHX_ *psvq, IFLAG_POS | IFLAG_NONZERO); |
|
3424
|
1009
|
50
|
|
|
|
|
if (status != 0 && p64 >= q64) { |
|
|
|
100
|
|
|
|
|
|
|
3425
|
22
|
100
|
|
|
|
|
if (ix == 0) XSRETURN_UNDEF; |
|
3426
|
11
|
|
|
|
|
|
else XSRETURN_UV(farey_length(n) - (p64 == q64)); |
|
3427
|
|
|
|
|
|
|
} |
|
3428
|
987
|
50
|
|
|
|
|
if (status != 0) { |
|
3429
|
987
|
|
|
|
|
|
p = p64; q = q64; |
|
3430
|
987
|
50
|
|
|
|
|
if (p != p64 || q != q64) |
|
|
|
50
|
|
|
|
|
|
|
3431
|
0
|
|
|
|
|
|
status = 0; /* We only do 32-bit here */ |
|
3432
|
|
|
|
|
|
|
} |
|
3433
|
987
|
50
|
|
|
|
|
if (status != 0) { |
|
3434
|
987
|
100
|
|
|
|
|
if (ix == 1) |
|
3435
|
110
|
|
|
|
|
|
XSRETURN_UV(farey_rank(n, p, q)); |
|
3436
|
|
|
|
|
|
|
else { |
|
3437
|
877
|
50
|
|
|
|
|
if (next_farey(n, &p, &q)) { |
|
3438
|
877
|
|
|
|
|
|
PUSH_2ELEM_AREF(p, q); |
|
3439
|
877
|
|
|
|
|
|
XSRETURN(1); |
|
3440
|
|
|
|
|
|
|
} |
|
3441
|
|
|
|
|
|
|
/* Possibly drop through */ |
|
3442
|
|
|
|
|
|
|
} |
|
3443
|
|
|
|
|
|
|
} |
|
3444
|
|
|
|
|
|
|
} |
|
3445
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
3446
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
3447
|
|
|
|
|
|
|
|
|
3448
|
|
|
|
|
|
|
|
|
3449
|
|
|
|
|
|
|
|
|
3450
|
|
|
|
|
|
|
void Pi(IN UV digits = 0) |
|
3451
|
|
|
|
|
|
|
PREINIT: |
|
3452
|
|
|
|
|
|
|
#ifdef USE_QUADMATH |
|
3453
|
|
|
|
|
|
|
const UV mantsize = FLT128_DIG; |
|
3454
|
|
|
|
|
|
|
const NV pival = 3.141592653589793238462643383279502884197169Q; |
|
3455
|
|
|
|
|
|
|
#elif defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE) |
|
3456
|
|
|
|
|
|
|
const UV mantsize = LDBL_DIG; |
|
3457
|
|
|
|
|
|
|
const NV pival = 3.141592653589793238462643383279502884197169L; |
|
3458
|
|
|
|
|
|
|
#else |
|
3459
|
1001
|
|
|
|
|
|
const UV mantsize = DBL_DIG; |
|
3460
|
1001
|
50
|
|
|
|
|
const NV pival = 3.141592653589793238462643383279502884197169; |
|
3461
|
|
|
|
|
|
|
#endif |
|
3462
|
|
|
|
|
|
|
PPCODE: |
|
3463
|
1001
|
100
|
|
|
|
|
if (digits == 0) { |
|
3464
|
1
|
|
|
|
|
|
XSRETURN_NV( pival ); |
|
3465
|
1000
|
100
|
|
|
|
|
} else if (digits <= mantsize) { |
|
3466
|
15
|
|
|
|
|
|
char* out = pidigits(digits); |
|
3467
|
15
|
|
|
|
|
|
NV pi = STRTONV(out); |
|
3468
|
15
|
|
|
|
|
|
Safefree(out); |
|
3469
|
15
|
|
|
|
|
|
XSRETURN_NV( pi ); |
|
3470
|
|
|
|
|
|
|
} else { |
|
3471
|
985
|
|
|
|
|
|
DISPATCHPP(); |
|
3472
|
985
|
|
|
|
|
|
XSRETURN(1); |
|
3473
|
|
|
|
|
|
|
} |
|
3474
|
|
|
|
|
|
|
|
|
3475
|
|
|
|
|
|
|
void bernfrac(IN SV* svn) |
|
3476
|
|
|
|
|
|
|
ALIAS: |
|
3477
|
|
|
|
|
|
|
harmfrac = 1 |
|
3478
|
|
|
|
|
|
|
PREINIT: |
|
3479
|
|
|
|
|
|
|
UV n; |
|
3480
|
|
|
|
|
|
|
PPCODE: |
|
3481
|
114
|
50
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS) != 0) { |
|
3482
|
114
|
100
|
|
|
|
|
if (ix == 0) { |
|
3483
|
|
|
|
|
|
|
IV num; UV den; |
|
3484
|
60
|
100
|
|
|
|
|
if (bernfrac(&num, &den, n)) { |
|
3485
|
41
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSViv( num ))); |
|
3486
|
41
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSVuv( den ))); |
|
3487
|
41
|
|
|
|
|
|
XSRETURN(2); |
|
3488
|
|
|
|
|
|
|
} |
|
3489
|
|
|
|
|
|
|
} else { |
|
3490
|
|
|
|
|
|
|
UV num, den; |
|
3491
|
54
|
100
|
|
|
|
|
if (harmfrac(&num, &den, n)) { |
|
3492
|
52
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSVuv( num ))); |
|
3493
|
52
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSVuv( den ))); |
|
3494
|
52
|
|
|
|
|
|
XSRETURN(2); |
|
3495
|
|
|
|
|
|
|
} |
|
3496
|
|
|
|
|
|
|
} |
|
3497
|
|
|
|
|
|
|
} |
|
3498
|
21
|
|
|
|
|
|
DISPATCHPP(); |
|
3499
|
63
|
50
|
|
|
|
|
OBJECTIFY_STACK(2); |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
3500
|
21
|
|
|
|
|
|
XSRETURN(2); |
|
3501
|
|
|
|
|
|
|
|
|
3502
|
|
|
|
|
|
|
void |
|
3503
|
|
|
|
|
|
|
_pidigits(IN int digits) |
|
3504
|
|
|
|
|
|
|
PREINIT: |
|
3505
|
|
|
|
|
|
|
char* out; |
|
3506
|
|
|
|
|
|
|
PPCODE: |
|
3507
|
972
|
50
|
|
|
|
|
if (digits <= 0) XSRETURN_EMPTY; |
|
3508
|
972
|
|
|
|
|
|
out = pidigits(digits); |
|
3509
|
972
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSVpvn(out, digits+1))); |
|
3510
|
972
|
|
|
|
|
|
Safefree(out); |
|
3511
|
|
|
|
|
|
|
|
|
3512
|
|
|
|
|
|
|
void inverse_totient(IN SV* svn) |
|
3513
|
|
|
|
|
|
|
PREINIT: |
|
3514
|
|
|
|
|
|
|
U32 gimme_v; |
|
3515
|
|
|
|
|
|
|
int status; |
|
3516
|
|
|
|
|
|
|
UV i, n, ntotients; |
|
3517
|
|
|
|
|
|
|
PPCODE: |
|
3518
|
114
|
|
|
|
|
|
gimme_v = GIMME_V; |
|
3519
|
114
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, IFLAG_POS); |
|
3520
|
114
|
50
|
|
|
|
|
if (status == 1) { |
|
3521
|
114
|
100
|
|
|
|
|
if (gimme_v == G_SCALAR) { |
|
3522
|
104
|
|
|
|
|
|
XSRETURN_UV( inverse_totient_count(n) ); |
|
3523
|
10
|
50
|
|
|
|
|
} else if (gimme_v == G_ARRAY) { |
|
3524
|
10
|
|
|
|
|
|
UV* tots = inverse_totient_list(&ntotients, n); |
|
3525
|
10
|
50
|
|
|
|
|
if (ntotients != UV_MAX) { |
|
3526
|
10
|
50
|
|
|
|
|
EXTEND(SP, (EXTEND_TYPE)ntotients); |
|
|
|
50
|
|
|
|
|
|
|
3527
|
55
|
100
|
|
|
|
|
for (i = 0; i < ntotients; i++) |
|
3528
|
45
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv( tots[i] ))); |
|
3529
|
10
|
|
|
|
|
|
Safefree(tots); |
|
3530
|
10
|
|
|
|
|
|
XSRETURN(ntotients); |
|
3531
|
|
|
|
|
|
|
} |
|
3532
|
|
|
|
|
|
|
} |
|
3533
|
|
|
|
|
|
|
} |
|
3534
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
3535
|
0
|
|
|
|
|
|
return; |
|
3536
|
|
|
|
|
|
|
|
|
3537
|
|
|
|
|
|
|
void |
|
3538
|
|
|
|
|
|
|
factor(IN SV* svn) |
|
3539
|
|
|
|
|
|
|
ALIAS: |
|
3540
|
|
|
|
|
|
|
factor_exp = 1 |
|
3541
|
|
|
|
|
|
|
PREINIT: |
|
3542
|
|
|
|
|
|
|
UV n; |
|
3543
|
|
|
|
|
|
|
uint32_t i; |
|
3544
|
|
|
|
|
|
|
U32 gimme_v; |
|
3545
|
|
|
|
|
|
|
int status; |
|
3546
|
|
|
|
|
|
|
PPCODE: |
|
3547
|
1749
|
|
|
|
|
|
gimme_v = GIMME_V; |
|
3548
|
1749
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, IFLAG_POS); |
|
3549
|
1749
|
100
|
|
|
|
|
if (status == 1) { |
|
3550
|
1618
|
100
|
|
|
|
|
if (ix == 0) { |
|
3551
|
|
|
|
|
|
|
UV factors[MPU_MAX_FACTORS]; |
|
3552
|
1031
|
|
|
|
|
|
uint32_t nfactors = factor(n, factors); |
|
3553
|
1031
|
100
|
|
|
|
|
if (gimme_v == G_SCALAR) |
|
3554
|
341
|
|
|
|
|
|
XSRETURN_UV(nfactors); |
|
3555
|
690
|
50
|
|
|
|
|
EXTEND(SP, (EXTEND_TYPE)nfactors); |
|
3556
|
2161
|
100
|
|
|
|
|
for (i = 0; i < nfactors; i++) |
|
3557
|
1471
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv( factors[i] ))); |
|
3558
|
|
|
|
|
|
|
} else { |
|
3559
|
587
|
|
|
|
|
|
factored_t nf = factorint(n); |
|
3560
|
587
|
100
|
|
|
|
|
if (gimme_v == G_SCALAR) |
|
3561
|
12
|
|
|
|
|
|
XSRETURN_UV(nf.nfactors); |
|
3562
|
575
|
50
|
|
|
|
|
EXTEND(SP, (EXTEND_TYPE)nf.nfactors); |
|
3563
|
1891
|
100
|
|
|
|
|
for (i = 0; i < nf.nfactors; i++) |
|
3564
|
1316
|
|
|
|
|
|
PUSH_2ELEM_AREF( nf.f[i], nf.e[i] ); |
|
3565
|
|
|
|
|
|
|
} |
|
3566
|
|
|
|
|
|
|
} else { |
|
3567
|
131
|
|
|
|
|
|
DISPATCHPP(); |
|
3568
|
131
|
|
|
|
|
|
return; |
|
3569
|
|
|
|
|
|
|
} |
|
3570
|
|
|
|
|
|
|
|
|
3571
|
|
|
|
|
|
|
void divisors(IN SV* svn, IN SV* svk = 0) |
|
3572
|
|
|
|
|
|
|
PREINIT: |
|
3573
|
|
|
|
|
|
|
int status; |
|
3574
|
|
|
|
|
|
|
UV n, k, i, ndivisors, *divs; |
|
3575
|
|
|
|
|
|
|
PPCODE: |
|
3576
|
981
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, IFLAG_POS); |
|
3577
|
981
|
|
|
|
|
|
k = n; |
|
3578
|
981
|
100
|
|
|
|
|
if (status == 1 && svk != 0) { |
|
|
|
100
|
|
|
|
|
|
|
3579
|
9
|
|
|
|
|
|
status = _validate_and_set(&k, aTHX_ svk, IFLAG_POS); |
|
3580
|
9
|
100
|
|
|
|
|
if (k > n) k = n; |
|
3581
|
|
|
|
|
|
|
} |
|
3582
|
981
|
100
|
|
|
|
|
if (status != 1) { |
|
3583
|
8
|
|
|
|
|
|
DISPATCHPP(); |
|
3584
|
8
|
|
|
|
|
|
return; |
|
3585
|
|
|
|
|
|
|
} |
|
3586
|
973
|
50
|
|
|
|
|
if (GIMME_V == G_VOID) { |
|
3587
|
|
|
|
|
|
|
/* Nothing */ |
|
3588
|
973
|
100
|
|
|
|
|
} else if (GIMME_V == G_SCALAR && k >= n) { |
|
|
|
50
|
|
|
|
|
|
|
3589
|
21
|
|
|
|
|
|
ndivisors = divisor_sum(n, 0); |
|
3590
|
21
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv( ndivisors ))); |
|
3591
|
|
|
|
|
|
|
} else { |
|
3592
|
952
|
|
|
|
|
|
divs = divisor_list(n, &ndivisors, k); |
|
3593
|
952
|
50
|
|
|
|
|
if (GIMME_V == G_SCALAR) { |
|
3594
|
0
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv( ndivisors ))); |
|
3595
|
|
|
|
|
|
|
} else { |
|
3596
|
952
|
50
|
|
|
|
|
EXTEND(SP, (EXTEND_TYPE)ndivisors); |
|
|
|
100
|
|
|
|
|
|
|
3597
|
6783
|
100
|
|
|
|
|
for (i = 0; i < ndivisors; i++) |
|
3598
|
5831
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv( divs[i] ))); |
|
3599
|
|
|
|
|
|
|
} |
|
3600
|
952
|
|
|
|
|
|
Safefree(divs); |
|
3601
|
|
|
|
|
|
|
} |
|
3602
|
|
|
|
|
|
|
|
|
3603
|
|
|
|
|
|
|
void |
|
3604
|
|
|
|
|
|
|
trial_factor(IN SV* svn, ...) |
|
3605
|
|
|
|
|
|
|
ALIAS: |
|
3606
|
|
|
|
|
|
|
fermat_factor = 1 |
|
3607
|
|
|
|
|
|
|
holf_factor = 2 |
|
3608
|
|
|
|
|
|
|
squfof_factor = 3 |
|
3609
|
|
|
|
|
|
|
lehman_factor = 4 |
|
3610
|
|
|
|
|
|
|
prho_factor = 5 |
|
3611
|
|
|
|
|
|
|
cheb_factor = 6 |
|
3612
|
|
|
|
|
|
|
pplus1_factor = 7 |
|
3613
|
|
|
|
|
|
|
pbrent_factor = 8 |
|
3614
|
|
|
|
|
|
|
pminus1_factor = 9 |
|
3615
|
|
|
|
|
|
|
ecm_factor = 10 |
|
3616
|
|
|
|
|
|
|
PREINIT: |
|
3617
|
|
|
|
|
|
|
UV n, arg1, arg2; |
|
3618
|
|
|
|
|
|
|
static const UV default_arg1[] = |
|
3619
|
|
|
|
|
|
|
{0, 64000000, 8000000, 4000000, 1, 4000000, 0, 200, 4000000, 1000000}; |
|
3620
|
|
|
|
|
|
|
/* Trial, Fermat, Holf, SQUFOF, Lmn, PRHO, Cheb, P+1, Brent, P-1 */ |
|
3621
|
|
|
|
|
|
|
PPCODE: |
|
3622
|
200
|
100
|
|
|
|
|
if (!_validate_and_set(&n, aTHX_ svn, IFLAG_POS) || ix == 10) { |
|
|
|
50
|
|
|
|
|
|
|
3623
|
87
|
|
|
|
|
|
DISPATCHPP(); |
|
3624
|
87
|
|
|
|
|
|
return; |
|
3625
|
|
|
|
|
|
|
} |
|
3626
|
113
|
50
|
|
|
|
|
if (n == 0) XSRETURN_UV(0); |
|
3627
|
|
|
|
|
|
|
/* Must read arguments before pushing anything */ |
|
3628
|
113
|
100
|
|
|
|
|
arg1 = (items >= 2) ? my_svuv(ST(1)) : default_arg1[ix]; |
|
3629
|
113
|
100
|
|
|
|
|
arg2 = (items >= 3) ? my_svuv(ST(2)) : 0; |
|
3630
|
|
|
|
|
|
|
/* Small factors */ |
|
3631
|
175
|
50
|
|
|
|
|
while ( (n% 2) == 0 ) { n /= 2; XPUSHs(sv_2mortal(newSVuv( 2 ))); } |
|
|
|
100
|
|
|
|
|
|
|
3632
|
173
|
50
|
|
|
|
|
while ( (n% 3) == 0 ) { n /= 3; XPUSHs(sv_2mortal(newSVuv( 3 ))); } |
|
|
|
100
|
|
|
|
|
|
|
3633
|
194
|
50
|
|
|
|
|
while ( (n% 5) == 0 ) { n /= 5; XPUSHs(sv_2mortal(newSVuv( 5 ))); } |
|
|
|
100
|
|
|
|
|
|
|
3634
|
113
|
100
|
|
|
|
|
if (n == 1) { /* done */ } |
|
3635
|
63
|
100
|
|
|
|
|
else if (is_prime(n)) { XPUSHs(sv_2mortal(newSVuv( n ))); } |
|
|
|
50
|
|
|
|
|
|
|
3636
|
|
|
|
|
|
|
else { |
|
3637
|
|
|
|
|
|
|
UV factors[MPU_MAX_FACTORS+1]; |
|
3638
|
30
|
|
|
|
|
|
int i, nfactors = 0; |
|
3639
|
30
|
|
|
|
|
|
switch (ix) { |
|
3640
|
6
|
|
|
|
|
|
case 0: nfactors = trial_factor (n, factors, 2, arg1); break; |
|
3641
|
2
|
|
|
|
|
|
case 1: nfactors = fermat_factor (n, factors, arg1); break; |
|
3642
|
3
|
|
|
|
|
|
case 2: nfactors = holf_factor (n, factors, arg1); break; |
|
3643
|
2
|
|
|
|
|
|
case 3: nfactors = squfof_factor (n, factors, arg1); break; |
|
3644
|
2
|
|
|
|
|
|
case 4: nfactors = lehman_factor (n, factors, arg1); break; |
|
3645
|
2
|
|
|
|
|
|
case 5: nfactors = prho_factor (n, factors, arg1); break; |
|
3646
|
3
|
|
|
|
|
|
case 6: nfactors = cheb_factor (n, factors, arg1, arg2); break; |
|
3647
|
2
|
|
|
|
|
|
case 7: nfactors = pplus1_factor (n, factors, arg1); break; |
|
3648
|
2
|
50
|
|
|
|
|
case 8: if (items < 3) arg2 = 1; |
|
3649
|
2
|
|
|
|
|
|
nfactors = pbrent_factor (n, factors, arg1, arg2); break; |
|
3650
|
6
|
|
|
|
|
|
case 9: |
|
3651
|
6
|
100
|
|
|
|
|
default: if (items < 3) arg2 = 10*arg1; |
|
3652
|
6
|
|
|
|
|
|
nfactors = pminus1_factor(n, factors, arg1, arg2); break; |
|
3653
|
|
|
|
|
|
|
} |
|
3654
|
30
|
50
|
|
|
|
|
EXTEND(SP, (EXTEND_TYPE)nfactors); |
|
|
|
50
|
|
|
|
|
|
|
3655
|
89
|
100
|
|
|
|
|
for (i = 0; i < nfactors; i++) |
|
3656
|
59
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv( factors[i] ))); |
|
3657
|
|
|
|
|
|
|
} |
|
3658
|
|
|
|
|
|
|
|
|
3659
|
|
|
|
|
|
|
|
|
3660
|
|
|
|
|
|
|
void |
|
3661
|
|
|
|
|
|
|
divisor_sum(IN SV* svn, ...) |
|
3662
|
|
|
|
|
|
|
PREINIT: |
|
3663
|
|
|
|
|
|
|
UV n, k, sigma; |
|
3664
|
|
|
|
|
|
|
PPCODE: |
|
3665
|
2420
|
100
|
|
|
|
|
if (items == 1) { |
|
3666
|
92
|
100
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) { |
|
3667
|
91
|
|
|
|
|
|
sigma = divisor_sum(n, 1); |
|
3668
|
91
|
100
|
|
|
|
|
if (n <= 1 || sigma != 0) |
|
|
|
50
|
|
|
|
|
|
|
3669
|
91
|
|
|
|
|
|
XSRETURN_UV(sigma); |
|
3670
|
|
|
|
|
|
|
} |
|
3671
|
|
|
|
|
|
|
} else { |
|
3672
|
2328
|
|
|
|
|
|
SV* svk = ST(1); |
|
3673
|
3740
|
100
|
|
|
|
|
if ( (!SvROK(svk) || (SvROK(svk) && SvTYPE(SvRV(svk)) != SVt_PVCV)) && |
|
|
|
50
|
|
|
|
|
|
|
3674
|
2820
|
50
|
|
|
|
|
_validate_and_set(&n, aTHX_ svn, IFLAG_POS) && |
|
3675
|
1408
|
|
|
|
|
|
_validate_and_set(&k, aTHX_ svk, IFLAG_POS) ) { |
|
3676
|
1408
|
|
|
|
|
|
sigma = divisor_sum(n, k); |
|
3677
|
1408
|
100
|
|
|
|
|
if (n <= 1 || sigma != 0) |
|
|
|
50
|
|
|
|
|
|
|
3678
|
1408
|
|
|
|
|
|
XSRETURN_UV(sigma); |
|
3679
|
|
|
|
|
|
|
} |
|
3680
|
|
|
|
|
|
|
} |
|
3681
|
921
|
|
|
|
|
|
DISPATCHPP(); |
|
3682
|
921
|
|
|
|
|
|
XSRETURN(1); |
|
3683
|
|
|
|
|
|
|
|
|
3684
|
|
|
|
|
|
|
void |
|
3685
|
|
|
|
|
|
|
jordan_totient(IN SV* sva, IN SV* svn) |
|
3686
|
|
|
|
|
|
|
ALIAS: |
|
3687
|
|
|
|
|
|
|
powersum = 1 |
|
3688
|
|
|
|
|
|
|
ramanujan_sum = 2 |
|
3689
|
|
|
|
|
|
|
legendre_phi = 3 |
|
3690
|
|
|
|
|
|
|
smooth_count = 4 |
|
3691
|
|
|
|
|
|
|
rough_count = 5 |
|
3692
|
|
|
|
|
|
|
PREINIT: |
|
3693
|
|
|
|
|
|
|
int astatus, nstatus; |
|
3694
|
|
|
|
|
|
|
UV a, n, ret; |
|
3695
|
|
|
|
|
|
|
PPCODE: |
|
3696
|
12290
|
|
|
|
|
|
astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_POS); |
|
3697
|
12290
|
|
|
|
|
|
nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_POS); |
|
3698
|
12290
|
100
|
|
|
|
|
if (astatus != 0 && nstatus != 0) { |
|
|
|
100
|
|
|
|
|
|
|
3699
|
12287
|
|
|
|
|
|
switch (ix) { |
|
3700
|
490
|
|
|
|
|
|
case 0: ret = jordan_totient(a, n); |
|
3701
|
490
|
100
|
|
|
|
|
if (ret == 0 && n > 1) |
|
|
|
50
|
|
|
|
|
|
|
3702
|
22
|
|
|
|
|
|
goto overflow; |
|
3703
|
468
|
|
|
|
|
|
break; |
|
3704
|
10801
|
|
|
|
|
|
case 1: ret = powersum(a, n); |
|
3705
|
10801
|
100
|
|
|
|
|
if (ret == 0 && a > 0) |
|
|
|
100
|
|
|
|
|
|
|
3706
|
12
|
|
|
|
|
|
goto overflow; |
|
3707
|
10789
|
|
|
|
|
|
break; |
|
3708
|
902
|
100
|
|
|
|
|
case 2: if (a < 1 || n < 1) XSRETURN_IV(0); |
|
|
|
100
|
|
|
|
|
|
|
3709
|
|
|
|
|
|
|
{ |
|
3710
|
900
|
|
|
|
|
|
UV g = a / gcd_ui(a,n); |
|
3711
|
900
|
|
|
|
|
|
int m = moebius(g); |
|
3712
|
900
|
100
|
|
|
|
|
if (m == 0 || a == g) RETURN_NPARITY(m); |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
3713
|
285
|
|
|
|
|
|
XSRETURN_IV( m * (totient(a) / totient(g)) ); |
|
3714
|
|
|
|
|
|
|
} |
|
3715
|
|
|
|
|
|
|
break; |
|
3716
|
18
|
|
|
|
|
|
case 3: ret = legendre_phi(a, n); break; |
|
3717
|
39
|
|
|
|
|
|
case 4: ret = debruijn_psi(a, n); break; |
|
3718
|
37
|
|
|
|
|
|
case 5: |
|
3719
|
37
|
|
|
|
|
|
default: ret = buchstab_phi(a, n); break; |
|
3720
|
|
|
|
|
|
|
} |
|
3721
|
11351
|
|
|
|
|
|
XSRETURN_UV(ret); |
|
3722
|
|
|
|
|
|
|
} |
|
3723
|
3
|
|
|
|
|
|
overflow: |
|
3724
|
37
|
|
|
|
|
|
DISPATCHPP(); |
|
3725
|
37
|
|
|
|
|
|
objectify_result(aTHX_ sva, ST(0)); |
|
3726
|
37
|
|
|
|
|
|
XSRETURN(1); |
|
3727
|
|
|
|
|
|
|
|
|
3728
|
|
|
|
|
|
|
void almost_prime_count(IN SV* svk, IN SV* svn) |
|
3729
|
|
|
|
|
|
|
ALIAS: |
|
3730
|
|
|
|
|
|
|
almost_prime_count_approx = 1 |
|
3731
|
|
|
|
|
|
|
almost_prime_count_lower = 2 |
|
3732
|
|
|
|
|
|
|
almost_prime_count_upper = 3 |
|
3733
|
|
|
|
|
|
|
omega_prime_count = 4 |
|
3734
|
|
|
|
|
|
|
PREINIT: |
|
3735
|
|
|
|
|
|
|
UV k, n, ret; |
|
3736
|
|
|
|
|
|
|
PPCODE: |
|
3737
|
214
|
|
|
|
|
|
if (_validate_and_set(&k, aTHX_ svk, IFLAG_ABS) && |
|
3738
|
107
|
|
|
|
|
|
_validate_and_set(&n, aTHX_ svn, IFLAG_ABS) && |
|
3739
|
97
|
50
|
|
|
|
|
k < BITS_PER_WORD) { |
|
3740
|
97
|
|
|
|
|
|
ret = 0; |
|
3741
|
97
|
|
|
|
|
|
switch (ix) { |
|
3742
|
33
|
|
|
|
|
|
case 0: ret = almost_prime_count(k, n); break; |
|
3743
|
6
|
|
|
|
|
|
case 1: ret = almost_prime_count_approx(k, n); break; |
|
3744
|
2
|
|
|
|
|
|
case 2: ret = almost_prime_count_lower(k, n); break; |
|
3745
|
2
|
|
|
|
|
|
case 3: ret = almost_prime_count_upper(k, n); break; |
|
3746
|
54
|
|
|
|
|
|
case 4: ret = omega_prime_count(k, n); break; |
|
3747
|
0
|
|
|
|
|
|
default: break; |
|
3748
|
|
|
|
|
|
|
} |
|
3749
|
97
|
|
|
|
|
|
XSRETURN_UV(ret); |
|
3750
|
|
|
|
|
|
|
} |
|
3751
|
10
|
|
|
|
|
|
DISPATCHPP(); |
|
3752
|
10
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
3753
|
10
|
|
|
|
|
|
XSRETURN(1); |
|
3754
|
|
|
|
|
|
|
|
|
3755
|
|
|
|
|
|
|
void nth_almost_prime(IN SV* svk, IN SV* svn) |
|
3756
|
|
|
|
|
|
|
ALIAS: |
|
3757
|
|
|
|
|
|
|
nth_almost_prime_approx = 1 |
|
3758
|
|
|
|
|
|
|
nth_almost_prime_lower = 2 |
|
3759
|
|
|
|
|
|
|
nth_almost_prime_upper = 3 |
|
3760
|
|
|
|
|
|
|
PREINIT: |
|
3761
|
|
|
|
|
|
|
UV k, n, max; |
|
3762
|
|
|
|
|
|
|
PPCODE: |
|
3763
|
48
|
|
|
|
|
|
if (_validate_and_set(&k, aTHX_ svk, IFLAG_ABS) && |
|
3764
|
24
|
|
|
|
|
|
_validate_and_set(&n, aTHX_ svn, IFLAG_ABS) && |
|
3765
|
24
|
100
|
|
|
|
|
k < BITS_PER_WORD) { |
|
3766
|
22
|
|
|
|
|
|
UV ret = 0; |
|
3767
|
22
|
50
|
|
|
|
|
if (n == 0 || (k == 0 && n > 1)) XSRETURN_UNDEF; |
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
3768
|
22
|
|
|
|
|
|
max = max_almost_prime_count(k); |
|
3769
|
22
|
50
|
|
|
|
|
if (max > 0 && n <= max) { |
|
|
|
100
|
|
|
|
|
|
|
3770
|
21
|
|
|
|
|
|
switch (ix) { |
|
3771
|
9
|
|
|
|
|
|
case 0: ret = nth_almost_prime(k, n); break; |
|
3772
|
8
|
|
|
|
|
|
case 1: ret = nth_almost_prime_approx(k, n); break; |
|
3773
|
2
|
|
|
|
|
|
case 2: ret = nth_almost_prime_lower(k, n); break; |
|
3774
|
2
|
|
|
|
|
|
case 3: ret = nth_almost_prime_upper(k, n); break; |
|
3775
|
|
|
|
|
|
|
} |
|
3776
|
21
|
50
|
|
|
|
|
if (ret != 0) XSRETURN_UV(ret); |
|
3777
|
|
|
|
|
|
|
} |
|
3778
|
|
|
|
|
|
|
} |
|
3779
|
3
|
|
|
|
|
|
DISPATCHPP(); |
|
3780
|
3
|
|
|
|
|
|
XSRETURN(1); |
|
3781
|
|
|
|
|
|
|
|
|
3782
|
|
|
|
|
|
|
void nth_omega_prime(IN SV* svk, IN SV* svn) |
|
3783
|
|
|
|
|
|
|
PREINIT: |
|
3784
|
|
|
|
|
|
|
UV k, n, max, ret; |
|
3785
|
|
|
|
|
|
|
PPCODE: |
|
3786
|
432
|
|
|
|
|
|
if (_validate_and_set(&k, aTHX_ svk, IFLAG_ABS) && |
|
3787
|
216
|
|
|
|
|
|
_validate_and_set(&n, aTHX_ svn, IFLAG_ABS) && |
|
3788
|
216
|
50
|
|
|
|
|
k < 16) { |
|
3789
|
216
|
100
|
|
|
|
|
if (n == 0 || (k == 0 && n > 1)) XSRETURN_UNDEF; |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
3790
|
202
|
|
|
|
|
|
max = max_omega_prime_count(k); |
|
3791
|
202
|
50
|
|
|
|
|
if (max > 0 && n <= max) { |
|
|
|
50
|
|
|
|
|
|
|
3792
|
202
|
|
|
|
|
|
ret = nth_omega_prime(k, n); |
|
3793
|
202
|
|
|
|
|
|
XSRETURN_UV(ret); |
|
3794
|
|
|
|
|
|
|
} |
|
3795
|
|
|
|
|
|
|
} |
|
3796
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
3797
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
3798
|
|
|
|
|
|
|
|
|
3799
|
|
|
|
|
|
|
|
|
3800
|
|
|
|
|
|
|
void powmod(IN SV* sva, IN SV* svg, IN SV* svn) |
|
3801
|
|
|
|
|
|
|
ALIAS: |
|
3802
|
|
|
|
|
|
|
rootmod = 1 |
|
3803
|
|
|
|
|
|
|
PREINIT: |
|
3804
|
|
|
|
|
|
|
int astatus, gstatus, nstatus, retundef; |
|
3805
|
|
|
|
|
|
|
UV a, g, n, ret; |
|
3806
|
|
|
|
|
|
|
PPCODE: |
|
3807
|
864
|
|
|
|
|
|
astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_ANY); |
|
3808
|
864
|
|
|
|
|
|
gstatus = _validate_and_set(&g, aTHX_ svg, IFLAG_ANY); |
|
3809
|
864
|
|
|
|
|
|
nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ABS); |
|
3810
|
864
|
100
|
|
|
|
|
if (astatus != 0 && gstatus != 0 && nstatus != 0) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
3811
|
527
|
100
|
|
|
|
|
if (n == 0) XSRETURN_UNDEF; |
|
3812
|
482
|
100
|
|
|
|
|
if (n == 1) XSRETURN_UV(0); |
|
3813
|
438
|
|
|
|
|
|
_mod_with(&a, astatus, n); |
|
3814
|
438
|
|
|
|
|
|
retundef = ret = 0; |
|
3815
|
438
|
100
|
|
|
|
|
if (ix == 0) { |
|
3816
|
328
|
|
|
|
|
|
retundef = !prep_pow_inv(&a,&g,gstatus,n); |
|
3817
|
328
|
100
|
|
|
|
|
if (!retundef) ret = powmod(a, g, n); |
|
3818
|
|
|
|
|
|
|
} else { |
|
3819
|
110
|
100
|
|
|
|
|
retundef = !(prep_pow_inv(&a,&g,gstatus,n) && rootmod(&ret,a,g,n)); |
|
|
|
100
|
|
|
|
|
|
|
3820
|
|
|
|
|
|
|
} |
|
3821
|
438
|
100
|
|
|
|
|
if (retundef) XSRETURN_UNDEF; |
|
3822
|
383
|
|
|
|
|
|
XSRETURN_UV(ret); |
|
3823
|
|
|
|
|
|
|
} |
|
3824
|
337
|
|
|
|
|
|
DISPATCHPP(); |
|
3825
|
337
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
3826
|
337
|
|
|
|
|
|
XSRETURN(1); |
|
3827
|
|
|
|
|
|
|
|
|
3828
|
|
|
|
|
|
|
void addmod(IN SV* sva, IN SV* svb, IN SV* svn) |
|
3829
|
|
|
|
|
|
|
ALIAS: |
|
3830
|
|
|
|
|
|
|
submod = 1 |
|
3831
|
|
|
|
|
|
|
mulmod = 2 |
|
3832
|
|
|
|
|
|
|
divmod = 3 |
|
3833
|
|
|
|
|
|
|
znlog = 4 |
|
3834
|
|
|
|
|
|
|
PREINIT: |
|
3835
|
|
|
|
|
|
|
int astatus, bstatus, nstatus, retundef; |
|
3836
|
|
|
|
|
|
|
UV a, b, n, ret; |
|
3837
|
|
|
|
|
|
|
PPCODE: |
|
3838
|
27559
|
|
|
|
|
|
astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_ANY); |
|
3839
|
27559
|
|
|
|
|
|
bstatus = _validate_and_set(&b, aTHX_ svb, IFLAG_ANY); |
|
3840
|
27559
|
|
|
|
|
|
nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ABS); |
|
3841
|
27559
|
100
|
|
|
|
|
if (astatus != 0 && bstatus != 0 && nstatus != 0) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
3842
|
14870
|
100
|
|
|
|
|
if (n == 0) XSRETURN_UNDEF; |
|
3843
|
14758
|
100
|
|
|
|
|
if (n == 1) XSRETURN_UV(0); |
|
3844
|
14644
|
|
|
|
|
|
_mod_with(&a, astatus, n); |
|
3845
|
14644
|
|
|
|
|
|
_mod_with(&b, bstatus, n); |
|
3846
|
14644
|
|
|
|
|
|
retundef = ret = 0; |
|
3847
|
14644
|
|
|
|
|
|
switch (ix) { |
|
3848
|
565
|
|
|
|
|
|
case 0: ret = addmod(a, b, n); break; |
|
3849
|
172
|
|
|
|
|
|
case 1: ret = submod(a, b, n); break; |
|
3850
|
13777
|
|
|
|
|
|
case 2: ret = mulmod(a, b, n); break; |
|
3851
|
108
|
|
|
|
|
|
case 3: b = modinverse(b, n); |
|
3852
|
108
|
100
|
|
|
|
|
if (b == 0) retundef = 1; |
|
3853
|
80
|
|
|
|
|
|
else ret = mulmod(a, b, n); |
|
3854
|
108
|
|
|
|
|
|
break; |
|
3855
|
22
|
|
|
|
|
|
case 4: ret = znlog(a, b, n); |
|
3856
|
22
|
100
|
|
|
|
|
if (ret == 0 && (b == 0 || a != 1)) retundef = 1; |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
3857
|
22
|
|
|
|
|
|
break; |
|
3858
|
0
|
|
|
|
|
|
default: break; |
|
3859
|
|
|
|
|
|
|
} |
|
3860
|
14644
|
100
|
|
|
|
|
if (retundef) XSRETURN_UNDEF; |
|
3861
|
14613
|
|
|
|
|
|
XSRETURN_UV(ret); |
|
3862
|
|
|
|
|
|
|
} |
|
3863
|
12689
|
|
|
|
|
|
DISPATCHPP(); |
|
3864
|
12689
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
3865
|
12689
|
|
|
|
|
|
XSRETURN(1); |
|
3866
|
|
|
|
|
|
|
|
|
3867
|
|
|
|
|
|
|
void muladdmod(IN SV* sva, IN SV* svb, IN SV* svc, IN SV* svn) |
|
3868
|
|
|
|
|
|
|
ALIAS: |
|
3869
|
|
|
|
|
|
|
mulsubmod = 1 |
|
3870
|
|
|
|
|
|
|
PREINIT: |
|
3871
|
|
|
|
|
|
|
int astatus, bstatus, cstatus, nstatus; |
|
3872
|
|
|
|
|
|
|
UV a, b, c, n, ret; |
|
3873
|
|
|
|
|
|
|
PPCODE: |
|
3874
|
45064
|
|
|
|
|
|
astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_ANY); |
|
3875
|
45064
|
|
|
|
|
|
bstatus = _validate_and_set(&b, aTHX_ svb, IFLAG_ANY); |
|
3876
|
45064
|
|
|
|
|
|
cstatus = _validate_and_set(&c, aTHX_ svc, IFLAG_ANY); |
|
3877
|
45064
|
|
|
|
|
|
nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ABS); |
|
3878
|
45064
|
100
|
|
|
|
|
if (astatus != 0 && bstatus != 0 && cstatus != 0 && nstatus != 0) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
3879
|
16774
|
50
|
|
|
|
|
if (n == 0) XSRETURN_UNDEF; |
|
3880
|
16774
|
50
|
|
|
|
|
if (n == 1) XSRETURN_UV(0); |
|
3881
|
16774
|
|
|
|
|
|
_mod_with(&a, astatus, n); |
|
3882
|
16774
|
|
|
|
|
|
_mod_with(&b, bstatus, n); |
|
3883
|
16774
|
|
|
|
|
|
_mod_with(&c, cstatus, n); |
|
3884
|
16774
|
100
|
|
|
|
|
ret = (ix==0) ? muladdmod(a,b,c,n) : mulsubmod(a,b,c,n); |
|
3885
|
16774
|
|
|
|
|
|
XSRETURN_UV(ret); |
|
3886
|
|
|
|
|
|
|
} |
|
3887
|
28290
|
|
|
|
|
|
DISPATCHPP(); |
|
3888
|
28290
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
3889
|
28290
|
|
|
|
|
|
XSRETURN(1); |
|
3890
|
|
|
|
|
|
|
|
|
3891
|
|
|
|
|
|
|
void binomialmod(IN SV* svn, IN SV* svk, IN SV* svm) |
|
3892
|
|
|
|
|
|
|
PREINIT: |
|
3893
|
|
|
|
|
|
|
int nstatus, kstatus, mstatus; |
|
3894
|
|
|
|
|
|
|
UV ret, n, k, m; |
|
3895
|
|
|
|
|
|
|
PPCODE: |
|
3896
|
22168
|
|
|
|
|
|
nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY); |
|
3897
|
22168
|
|
|
|
|
|
kstatus = _validate_and_set(&k, aTHX_ svk, IFLAG_ANY); |
|
3898
|
22168
|
|
|
|
|
|
mstatus = _validate_and_set(&m, aTHX_ svm, IFLAG_ABS); |
|
3899
|
22168
|
100
|
|
|
|
|
if (nstatus != 0 && kstatus != 0 && mstatus != 0) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
3900
|
22167
|
50
|
|
|
|
|
if (m == 0) XSRETURN_UNDEF; |
|
3901
|
22167
|
100
|
|
|
|
|
if (m == 1) XSRETURN_UV(0); |
|
3902
|
21347
|
100
|
|
|
|
|
if ( (nstatus == 1 && (kstatus == -1 || k > n)) || |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
3903
|
3
|
100
|
|
|
|
|
(nstatus ==-1 && (kstatus == -1 && k > n)) ) |
|
|
|
50
|
|
|
|
|
|
|
3904
|
3
|
|
|
|
|
|
XSRETURN_UV(0); |
|
3905
|
21344
|
100
|
|
|
|
|
if (kstatus == -1) k = n - k; |
|
3906
|
21344
|
100
|
|
|
|
|
if (nstatus == -1) n = neg_iv(n) + k - 1; |
|
3907
|
21344
|
50
|
|
|
|
|
if (binomialmod(&ret, n, k, m)) { |
|
3908
|
21344
|
100
|
|
|
|
|
if ((nstatus == -1) && (k & 1) && ret != 0) ret = m-ret; |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
3909
|
21344
|
|
|
|
|
|
XSRETURN_UV(ret); |
|
3910
|
|
|
|
|
|
|
} |
|
3911
|
|
|
|
|
|
|
} |
|
3912
|
1
|
|
|
|
|
|
DISPATCHPP(); |
|
3913
|
1
|
|
|
|
|
|
XSRETURN(1); |
|
3914
|
|
|
|
|
|
|
|
|
3915
|
|
|
|
|
|
|
void factorialmod(IN SV* sva, IN SV* svn) |
|
3916
|
|
|
|
|
|
|
PREINIT: |
|
3917
|
|
|
|
|
|
|
int astatus, nstatus; |
|
3918
|
|
|
|
|
|
|
UV a, n; |
|
3919
|
|
|
|
|
|
|
PPCODE: |
|
3920
|
825
|
|
|
|
|
|
astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_POS); |
|
3921
|
825
|
|
|
|
|
|
nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ABS); |
|
3922
|
825
|
100
|
|
|
|
|
if (astatus != 0 && nstatus != 0) { |
|
|
|
100
|
|
|
|
|
|
|
3923
|
823
|
50
|
|
|
|
|
if (n == 0) XSRETURN_UNDEF; |
|
3924
|
823
|
100
|
|
|
|
|
if (n == 1) XSRETURN_UV(0); |
|
3925
|
822
|
|
|
|
|
|
XSRETURN_UV( factorialmod(a, n) ); |
|
3926
|
|
|
|
|
|
|
} |
|
3927
|
2
|
|
|
|
|
|
DISPATCHPP_GMPONLYIF(astatus == 1); |
|
3928
|
2
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
3929
|
2
|
|
|
|
|
|
XSRETURN(1); |
|
3930
|
|
|
|
|
|
|
|
|
3931
|
|
|
|
|
|
|
void invmod(IN SV* sva, IN SV* svn) |
|
3932
|
|
|
|
|
|
|
ALIAS: |
|
3933
|
|
|
|
|
|
|
znorder = 1 |
|
3934
|
|
|
|
|
|
|
sqrtmod = 2 |
|
3935
|
|
|
|
|
|
|
negmod = 3 |
|
3936
|
|
|
|
|
|
|
PREINIT: |
|
3937
|
|
|
|
|
|
|
int astatus, nstatus; |
|
3938
|
|
|
|
|
|
|
UV a, n, r, retok; |
|
3939
|
|
|
|
|
|
|
PPCODE: |
|
3940
|
406
|
|
|
|
|
|
astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_ANY); |
|
3941
|
404
|
|
|
|
|
|
nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ABS); |
|
3942
|
403
|
100
|
|
|
|
|
if (astatus != 0 && nstatus != 0) { |
|
|
|
100
|
|
|
|
|
|
|
3943
|
269
|
100
|
|
|
|
|
if (n == 0) XSRETURN_UNDEF; |
|
3944
|
258
|
100
|
|
|
|
|
if (n == 1) XSRETURN_UV((ix==1) ? 1 : 0); /* znorder different */ |
|
3945
|
245
|
|
|
|
|
|
_mod_with(&a, astatus, n); |
|
3946
|
245
|
|
|
|
|
|
retok = r = 0; |
|
3947
|
245
|
|
|
|
|
|
switch (ix) { |
|
3948
|
162
|
|
|
|
|
|
case 0: retok = r = modinverse(a, n); break; |
|
3949
|
16
|
|
|
|
|
|
case 1: retok = r = znorder(a, n); break; |
|
3950
|
52
|
|
|
|
|
|
case 2: retok = sqrtmod(&r, a, n); break; |
|
3951
|
15
|
|
|
|
|
|
case 3: |
|
3952
|
15
|
|
|
|
|
|
default: retok = 1; r = negmod(a, n); break; |
|
3953
|
|
|
|
|
|
|
} |
|
3954
|
245
|
100
|
|
|
|
|
if (retok == 0) XSRETURN_UNDEF; |
|
3955
|
221
|
|
|
|
|
|
XSRETURN_UV(r); |
|
3956
|
|
|
|
|
|
|
} |
|
3957
|
134
|
|
|
|
|
|
DISPATCHPP(); |
|
3958
|
134
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
3959
|
134
|
|
|
|
|
|
XSRETURN(1); |
|
3960
|
|
|
|
|
|
|
|
|
3961
|
|
|
|
|
|
|
void allsqrtmod(IN SV* sva, IN SV* svn) |
|
3962
|
|
|
|
|
|
|
PREINIT: |
|
3963
|
|
|
|
|
|
|
int astatus, nstatus; |
|
3964
|
|
|
|
|
|
|
UV a, n, i, numr, *roots; |
|
3965
|
|
|
|
|
|
|
PPCODE: |
|
3966
|
38
|
|
|
|
|
|
astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_ANY); |
|
3967
|
38
|
|
|
|
|
|
nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ABS); |
|
3968
|
38
|
100
|
|
|
|
|
if (astatus != 0 && nstatus != 0) { |
|
|
|
50
|
|
|
|
|
|
|
3969
|
36
|
100
|
|
|
|
|
if (n == 0) XSRETURN_EMPTY; |
|
3970
|
34
|
|
|
|
|
|
_mod_with(&a, astatus, n); |
|
3971
|
34
|
|
|
|
|
|
roots = allsqrtmod(&numr, a, n); |
|
3972
|
34
|
100
|
|
|
|
|
if (roots != 0) { |
|
3973
|
27
|
50
|
|
|
|
|
if (GIMME_V != G_ARRAY) { |
|
3974
|
0
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv(numr))); |
|
3975
|
|
|
|
|
|
|
} else { |
|
3976
|
27
|
50
|
|
|
|
|
EXTEND(SP, (EXTEND_TYPE)numr); |
|
|
|
50
|
|
|
|
|
|
|
3977
|
107
|
100
|
|
|
|
|
for (i = 0; i < numr; i++) |
|
3978
|
80
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv(roots[i]))); |
|
3979
|
|
|
|
|
|
|
} |
|
3980
|
27
|
|
|
|
|
|
Safefree(roots); |
|
3981
|
|
|
|
|
|
|
} |
|
3982
|
|
|
|
|
|
|
} else { |
|
3983
|
2
|
|
|
|
|
|
DISPATCHPP(); |
|
3984
|
2
|
|
|
|
|
|
return; |
|
3985
|
|
|
|
|
|
|
} |
|
3986
|
|
|
|
|
|
|
|
|
3987
|
|
|
|
|
|
|
void allrootmod(IN SV* sva, IN SV* svg, IN SV* svn) |
|
3988
|
|
|
|
|
|
|
PREINIT: |
|
3989
|
|
|
|
|
|
|
int astatus, gstatus, nstatus; |
|
3990
|
|
|
|
|
|
|
UV a, g, n, i, numr, *roots; |
|
3991
|
|
|
|
|
|
|
PPCODE: |
|
3992
|
52
|
|
|
|
|
|
astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_ANY); |
|
3993
|
52
|
|
|
|
|
|
gstatus = _validate_and_set(&g, aTHX_ svg, IFLAG_ANY); |
|
3994
|
52
|
|
|
|
|
|
nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ABS); |
|
3995
|
52
|
100
|
|
|
|
|
if (astatus != 0 && gstatus != 0 && nstatus != 0) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
3996
|
50
|
100
|
|
|
|
|
if (n == 0) XSRETURN_EMPTY; |
|
3997
|
49
|
|
|
|
|
|
_mod_with(&a, astatus, n); |
|
3998
|
49
|
100
|
|
|
|
|
if (!prep_pow_inv(&a,&g,gstatus,n)) XSRETURN_EMPTY; |
|
3999
|
47
|
|
|
|
|
|
roots = allrootmod(&numr, a, g, n); |
|
4000
|
47
|
100
|
|
|
|
|
if (roots != 0) { |
|
4001
|
36
|
50
|
|
|
|
|
if (GIMME_V != G_ARRAY) { |
|
4002
|
0
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv(numr))); |
|
4003
|
|
|
|
|
|
|
} else { |
|
4004
|
36
|
50
|
|
|
|
|
EXTEND(SP, (EXTEND_TYPE)numr); |
|
|
|
50
|
|
|
|
|
|
|
4005
|
260
|
100
|
|
|
|
|
for (i = 0; i < numr; i++) |
|
4006
|
224
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv(roots[i]))); |
|
4007
|
|
|
|
|
|
|
} |
|
4008
|
36
|
|
|
|
|
|
Safefree(roots); |
|
4009
|
|
|
|
|
|
|
} |
|
4010
|
|
|
|
|
|
|
} else { |
|
4011
|
2
|
|
|
|
|
|
DISPATCHPP(); |
|
4012
|
2
|
|
|
|
|
|
return; |
|
4013
|
|
|
|
|
|
|
} |
|
4014
|
|
|
|
|
|
|
|
|
4015
|
|
|
|
|
|
|
void is_primitive_root(IN SV* sva, IN SV* svn) |
|
4016
|
|
|
|
|
|
|
PREINIT: |
|
4017
|
|
|
|
|
|
|
int astatus, nstatus; |
|
4018
|
|
|
|
|
|
|
UV a, n; |
|
4019
|
|
|
|
|
|
|
PPCODE: |
|
4020
|
39
|
|
|
|
|
|
astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_ANY); |
|
4021
|
39
|
|
|
|
|
|
nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ABS); |
|
4022
|
39
|
50
|
|
|
|
|
if (astatus != 0 && nstatus != 0) { |
|
|
|
100
|
|
|
|
|
|
|
4023
|
33
|
100
|
|
|
|
|
if (n == 0) XSRETURN_UNDEF; |
|
4024
|
32
|
|
|
|
|
|
_mod_with(&a, astatus, n); |
|
4025
|
32
|
50
|
|
|
|
|
RETURN_NPARITY( is_primitive_root(a,n,0) ); |
|
|
|
50
|
|
|
|
|
|
|
4026
|
|
|
|
|
|
|
} |
|
4027
|
6
|
|
|
|
|
|
DISPATCHPP(); |
|
4028
|
6
|
|
|
|
|
|
XSRETURN(1); |
|
4029
|
|
|
|
|
|
|
|
|
4030
|
|
|
|
|
|
|
void qnr(IN SV* svn) |
|
4031
|
|
|
|
|
|
|
ALIAS: |
|
4032
|
|
|
|
|
|
|
znprimroot = 1 |
|
4033
|
|
|
|
|
|
|
PREINIT: |
|
4034
|
|
|
|
|
|
|
UV n, r; |
|
4035
|
|
|
|
|
|
|
PPCODE: |
|
4036
|
71
|
100
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_ABS)) { |
|
4037
|
64
|
100
|
|
|
|
|
if (n == 0) XSRETURN_UNDEF; |
|
4038
|
63
|
100
|
|
|
|
|
if (ix == 0) { |
|
4039
|
35
|
|
|
|
|
|
r = qnr(n); |
|
4040
|
|
|
|
|
|
|
} else { |
|
4041
|
28
|
|
|
|
|
|
r = znprimroot(n); |
|
4042
|
28
|
100
|
|
|
|
|
if (r == 0 && n != 1) XSRETURN_UNDEF; |
|
|
|
100
|
|
|
|
|
|
|
4043
|
|
|
|
|
|
|
} |
|
4044
|
60
|
100
|
|
|
|
|
if (r < 100) RETURN_NPARITY(r); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
4045
|
3
|
|
|
|
|
|
else XSRETURN_UV(r); |
|
4046
|
|
|
|
|
|
|
} |
|
4047
|
7
|
|
|
|
|
|
DISPATCHPP(); |
|
4048
|
7
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
4049
|
7
|
|
|
|
|
|
XSRETURN(1); |
|
4050
|
|
|
|
|
|
|
|
|
4051
|
|
|
|
|
|
|
void |
|
4052
|
|
|
|
|
|
|
is_smooth(IN SV* svn, IN SV* svk) |
|
4053
|
|
|
|
|
|
|
ALIAS: |
|
4054
|
|
|
|
|
|
|
is_rough = 1 |
|
4055
|
|
|
|
|
|
|
PREINIT: |
|
4056
|
|
|
|
|
|
|
UV n, k; |
|
4057
|
|
|
|
|
|
|
PPCODE: |
|
4058
|
2374
|
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_ABS) && |
|
4059
|
1183
|
|
|
|
|
|
_validate_and_set(&k, aTHX_ svk, IFLAG_POS)) { |
|
4060
|
1183
|
100
|
|
|
|
|
RETURN_NPARITY( (ix == 0) ? is_smooth(n,k) : is_rough(n,k) ); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
4061
|
|
|
|
|
|
|
} |
|
4062
|
8
|
|
|
|
|
|
DISPATCHPP(); |
|
4063
|
8
|
|
|
|
|
|
XSRETURN(1); |
|
4064
|
|
|
|
|
|
|
|
|
4065
|
|
|
|
|
|
|
void |
|
4066
|
|
|
|
|
|
|
is_omega_prime(IN SV* svk, IN SV* svn) |
|
4067
|
|
|
|
|
|
|
ALIAS: |
|
4068
|
|
|
|
|
|
|
is_almost_prime = 1 |
|
4069
|
|
|
|
|
|
|
PREINIT: |
|
4070
|
|
|
|
|
|
|
UV n, k; |
|
4071
|
|
|
|
|
|
|
int nstatus, kstatus; |
|
4072
|
|
|
|
|
|
|
PPCODE: |
|
4073
|
11281
|
|
|
|
|
|
kstatus = _validate_and_set(&k, aTHX_ svk, IFLAG_POS); |
|
4074
|
11281
|
|
|
|
|
|
nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY); |
|
4075
|
11281
|
50
|
|
|
|
|
if (kstatus != 0 && nstatus != 0) { |
|
|
|
100
|
|
|
|
|
|
|
4076
|
11277
|
|
|
|
|
|
int res = (nstatus != 1) ? 0 |
|
4077
|
23169
|
50
|
|
|
|
|
: (ix == 0) ? is_omega_prime(k, n) |
|
4078
|
11892
|
100
|
|
|
|
|
: is_almost_prime(k, n); |
|
4079
|
11277
|
50
|
|
|
|
|
RETURN_NPARITY(res); |
|
|
|
50
|
|
|
|
|
|
|
4080
|
|
|
|
|
|
|
} |
|
4081
|
4
|
|
|
|
|
|
DISPATCHPP(); |
|
4082
|
4
|
|
|
|
|
|
XSRETURN(1); |
|
4083
|
|
|
|
|
|
|
|
|
4084
|
|
|
|
|
|
|
void is_divisible(IN SV* svn, IN SV* svd, ...) |
|
4085
|
|
|
|
|
|
|
PREINIT: |
|
4086
|
|
|
|
|
|
|
UV n, d, ret; |
|
4087
|
|
|
|
|
|
|
size_t i; |
|
4088
|
|
|
|
|
|
|
PPCODE: |
|
4089
|
901517
|
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_ABS) && |
|
4090
|
450336
|
|
|
|
|
|
_validate_and_set(&d, aTHX_ svd, IFLAG_ABS)) { |
|
4091
|
450335
|
|
|
|
|
|
int status = 1; |
|
4092
|
450335
|
100
|
|
|
|
|
ret = d==0 ? (n==0) : n % d == 0; |
|
4093
|
450344
|
100
|
|
|
|
|
for (i = 2; i < (size_t)items && !ret; i++) { |
|
|
|
50
|
|
|
|
|
|
|
4094
|
9
|
50
|
|
|
|
|
if ((status = _validate_and_set(&d, aTHX_ ST(i), IFLAG_ABS)) != 1) |
|
4095
|
0
|
|
|
|
|
|
break; |
|
4096
|
9
|
50
|
|
|
|
|
ret = d==0 ? (n==0) : n % d == 0; |
|
4097
|
|
|
|
|
|
|
} |
|
4098
|
450335
|
50
|
|
|
|
|
if (status == 1) RETURN_NPARITY(ret); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
4099
|
|
|
|
|
|
|
} |
|
4100
|
846
|
|
|
|
|
|
DISPATCHPP(); |
|
4101
|
846
|
|
|
|
|
|
XSRETURN(1); |
|
4102
|
|
|
|
|
|
|
|
|
4103
|
|
|
|
|
|
|
void is_congruent(IN SV* svn, IN SV* svc, IN SV* svd) |
|
4104
|
|
|
|
|
|
|
PREINIT: |
|
4105
|
|
|
|
|
|
|
UV n, c, d; |
|
4106
|
|
|
|
|
|
|
int nstatus, cstatus, dstatus; |
|
4107
|
|
|
|
|
|
|
PPCODE: |
|
4108
|
40054
|
|
|
|
|
|
nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY); |
|
4109
|
40054
|
|
|
|
|
|
cstatus = _validate_and_set(&c, aTHX_ svc, IFLAG_ANY); |
|
4110
|
40054
|
|
|
|
|
|
dstatus = _validate_and_set(&d, aTHX_ svd, IFLAG_ABS); |
|
4111
|
40054
|
100
|
|
|
|
|
if (nstatus != 0 && cstatus != 0 && dstatus != 0) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
4112
|
40048
|
100
|
|
|
|
|
if (d != 0) { |
|
4113
|
40010
|
|
|
|
|
|
_mod_with(&n, nstatus, d); |
|
4114
|
40010
|
|
|
|
|
|
_mod_with(&c, cstatus, d); |
|
4115
|
|
|
|
|
|
|
} |
|
4116
|
40048
|
50
|
|
|
|
|
RETURN_NPARITY( n == c ); |
|
|
|
50
|
|
|
|
|
|
|
4117
|
|
|
|
|
|
|
} |
|
4118
|
6
|
|
|
|
|
|
DISPATCHPP(); |
|
4119
|
6
|
|
|
|
|
|
XSRETURN(1); |
|
4120
|
|
|
|
|
|
|
|
|
4121
|
|
|
|
|
|
|
void valuation(IN SV* svn, IN SV* svk) |
|
4122
|
|
|
|
|
|
|
PREINIT: |
|
4123
|
|
|
|
|
|
|
UV n, k; |
|
4124
|
|
|
|
|
|
|
PPCODE: |
|
4125
|
309
|
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_ABS) && |
|
4126
|
134
|
|
|
|
|
|
_validate_and_set(&k, aTHX_ svk, IFLAG_POS)) { |
|
4127
|
134
|
50
|
|
|
|
|
if (k <= 1) croak("valuation: k must be > 1"); |
|
4128
|
134
|
100
|
|
|
|
|
if (n == 0) XSRETURN_UNDEF; |
|
4129
|
133
|
50
|
|
|
|
|
RETURN_NPARITY(valuation(n, k)); |
|
|
|
50
|
|
|
|
|
|
|
4130
|
|
|
|
|
|
|
} |
|
4131
|
41
|
|
|
|
|
|
DISPATCHPP(); |
|
4132
|
41
|
|
|
|
|
|
XSRETURN(1); |
|
4133
|
|
|
|
|
|
|
|
|
4134
|
|
|
|
|
|
|
void is_powerful(IN SV* svn, IN SV* svk = 0); |
|
4135
|
|
|
|
|
|
|
ALIAS: |
|
4136
|
|
|
|
|
|
|
powerful_count = 1 |
|
4137
|
|
|
|
|
|
|
sumpowerful = 2 |
|
4138
|
|
|
|
|
|
|
nth_powerful = 3 |
|
4139
|
|
|
|
|
|
|
PREINIT: |
|
4140
|
|
|
|
|
|
|
int nstatus; |
|
4141
|
1673
|
100
|
|
|
|
|
UV n, ret, k = 2; |
|
4142
|
|
|
|
|
|
|
PPCODE: |
|
4143
|
1673
|
|
|
|
|
|
nstatus = _validate_and_set(&n, aTHX_ svn, (ix < 3) ? IFLAG_ANY: IFLAG_POS); |
|
4144
|
1673
|
100
|
|
|
|
|
if (nstatus != 0 && (!svk || _validate_and_set(&k, aTHX_ svk, IFLAG_POS))) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
4145
|
1667
|
100
|
|
|
|
|
if (nstatus == -1) RETURN_NPARITY(0); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
4146
|
1612
|
100
|
|
|
|
|
if (ix == 0) RETURN_NPARITY( is_powerful(n, k) ); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
4147
|
379
|
100
|
|
|
|
|
if (ix == 1) XSRETURN_UV( powerful_count(n, k) ); |
|
4148
|
186
|
100
|
|
|
|
|
if (ix == 2) { |
|
4149
|
182
|
100
|
|
|
|
|
if (n == 0) XSRETURN_UV(0); |
|
4150
|
179
|
|
|
|
|
|
ret = sumpowerful(n, k); |
|
4151
|
|
|
|
|
|
|
} else { |
|
4152
|
4
|
100
|
|
|
|
|
if (n == 0) XSRETURN_UNDEF; |
|
4153
|
3
|
|
|
|
|
|
ret = nth_powerful(n, k); |
|
4154
|
|
|
|
|
|
|
} |
|
4155
|
|
|
|
|
|
|
/* ret=0: nth_powerful / sumpowerful result > UV_MAX, so go to PP/GMP */ |
|
4156
|
182
|
100
|
|
|
|
|
if (ret > 0) XSRETURN_UV(ret); |
|
4157
|
|
|
|
|
|
|
} |
|
4158
|
10
|
|
|
|
|
|
DISPATCHPP(); |
|
4159
|
10
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
4160
|
10
|
|
|
|
|
|
XSRETURN(1); |
|
4161
|
|
|
|
|
|
|
|
|
4162
|
|
|
|
|
|
|
|
|
4163
|
|
|
|
|
|
|
void kronecker(IN SV* sva, IN SV* svb) |
|
4164
|
|
|
|
|
|
|
PREINIT: |
|
4165
|
|
|
|
|
|
|
int astatus, bstatus; |
|
4166
|
|
|
|
|
|
|
UV a, b; |
|
4167
|
|
|
|
|
|
|
PPCODE: |
|
4168
|
484
|
|
|
|
|
|
astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_ANY); |
|
4169
|
484
|
|
|
|
|
|
bstatus = _validate_and_set(&b, aTHX_ svb, IFLAG_ANY); |
|
4170
|
484
|
100
|
|
|
|
|
if (astatus != 0 && bstatus != 0) { |
|
|
|
100
|
|
|
|
|
|
|
4171
|
|
|
|
|
|
|
int k; |
|
4172
|
166
|
100
|
|
|
|
|
if (bstatus == 1) |
|
4173
|
154
|
100
|
|
|
|
|
k = (astatus==1) ? kronecker_uu(a,b) : kronecker_su((IV)a,b); |
|
4174
|
|
|
|
|
|
|
else |
|
4175
|
12
|
100
|
|
|
|
|
k = (astatus==1) ? kronecker_uu(a,neg_iv(b)) : -kronecker_su((IV)a,neg_iv(b)); |
|
4176
|
166
|
50
|
|
|
|
|
RETURN_NPARITY( k ); |
|
|
|
50
|
|
|
|
|
|
|
4177
|
|
|
|
|
|
|
} |
|
4178
|
318
|
|
|
|
|
|
DISPATCHPP(); |
|
4179
|
318
|
|
|
|
|
|
XSRETURN(1); |
|
4180
|
|
|
|
|
|
|
|
|
4181
|
|
|
|
|
|
|
void is_qr(IN SV* sva, IN SV* svn) |
|
4182
|
|
|
|
|
|
|
PREINIT: |
|
4183
|
|
|
|
|
|
|
int astatus, nstatus; |
|
4184
|
|
|
|
|
|
|
UV a, n; |
|
4185
|
|
|
|
|
|
|
PPCODE: |
|
4186
|
103
|
|
|
|
|
|
astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_ANY); |
|
4187
|
103
|
|
|
|
|
|
nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ABS); |
|
4188
|
103
|
100
|
|
|
|
|
if (astatus != 0 && nstatus != 0) { |
|
|
|
50
|
|
|
|
|
|
|
4189
|
101
|
100
|
|
|
|
|
if (n == 0) XSRETURN_UNDEF; |
|
4190
|
100
|
100
|
|
|
|
|
if (n == 1) RETURN_NPARITY(1); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
4191
|
94
|
|
|
|
|
|
_mod_with(&a, astatus, n); |
|
4192
|
94
|
50
|
|
|
|
|
RETURN_NPARITY( is_qr(a,n) ); |
|
|
|
50
|
|
|
|
|
|
|
4193
|
|
|
|
|
|
|
} |
|
4194
|
2
|
|
|
|
|
|
DISPATCHPP(); |
|
4195
|
2
|
|
|
|
|
|
XSRETURN(1); |
|
4196
|
|
|
|
|
|
|
|
|
4197
|
|
|
|
|
|
|
void addint(IN SV* sva, IN SV* svb) |
|
4198
|
|
|
|
|
|
|
ALIAS: |
|
4199
|
|
|
|
|
|
|
subint = 1 |
|
4200
|
|
|
|
|
|
|
mulint = 2 |
|
4201
|
|
|
|
|
|
|
divint = 3 |
|
4202
|
|
|
|
|
|
|
modint = 4 |
|
4203
|
|
|
|
|
|
|
cdivint = 5 |
|
4204
|
|
|
|
|
|
|
powint = 7 |
|
4205
|
|
|
|
|
|
|
PREINIT: |
|
4206
|
|
|
|
|
|
|
int astatus, bstatus, overflow, postneg, nix, smask; |
|
4207
|
|
|
|
|
|
|
UV a, b, t, ret; |
|
4208
|
|
|
|
|
|
|
PPCODE: |
|
4209
|
822654
|
|
|
|
|
|
astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_ANY); |
|
4210
|
822654
|
100
|
|
|
|
|
bstatus = _validate_and_set(&b, aTHX_ svb, (ix == 7) ? IFLAG_POS : IFLAG_ANY); |
|
4211
|
|
|
|
|
|
|
|
|
4212
|
822654
|
100
|
|
|
|
|
if (astatus != 0 && bstatus != 0) { |
|
|
|
100
|
|
|
|
|
|
|
4213
|
|
|
|
|
|
|
/* We will try to do everything with non-negative integers, with overflow |
|
4214
|
|
|
|
|
|
|
* detection. This means some pre-processing and post-processing for |
|
4215
|
|
|
|
|
|
|
* negative inputs. */ |
|
4216
|
784845
|
|
|
|
|
|
nix = ix; /* So we can modify */ |
|
4217
|
784845
|
|
|
|
|
|
ret = overflow = postneg = 0; |
|
4218
|
784845
|
100
|
|
|
|
|
smask = ((astatus == -1) << 1) + (bstatus == -1); |
|
4219
|
|
|
|
|
|
|
/* smask=0: +a +b smask=1: +a -b smask=2: -a +b smask=3: -a -b */ |
|
4220
|
|
|
|
|
|
|
|
|
4221
|
784845
|
100
|
|
|
|
|
if (b == 0 && (ix==3 || ix==4 || ix==5)) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
4222
|
6
|
|
|
|
|
|
croak("%s: divide by zero", SUBNAME); |
|
4223
|
|
|
|
|
|
|
|
|
4224
|
784839
|
100
|
|
|
|
|
if (smask != 0) { /* Manipulate so all arguments are positive */ |
|
4225
|
273751
|
100
|
|
|
|
|
if (smask & 2) a = neg_iv(a); |
|
4226
|
273751
|
100
|
|
|
|
|
if (smask & 1) b = neg_iv(b); |
|
4227
|
|
|
|
|
|
|
|
|
4228
|
273751
|
100
|
|
|
|
|
if (ix == 0) { |
|
4229
|
239
|
|
|
|
|
|
switch (smask) { |
|
4230
|
53
|
|
|
|
|
|
case 1: nix=1; break; /* a - |b| */ |
|
4231
|
137
|
|
|
|
|
|
case 2: nix=1; t=a; a=b; b=t; break; /* b - |a| */ |
|
4232
|
49
|
|
|
|
|
|
case 3: postneg=1; break; /* -(|a| + |b|) */ |
|
4233
|
0
|
|
|
|
|
|
default: break; |
|
4234
|
|
|
|
|
|
|
} |
|
4235
|
273512
|
100
|
|
|
|
|
} else if (ix == 1) { |
|
4236
|
804
|
|
|
|
|
|
switch (smask) { |
|
4237
|
393
|
|
|
|
|
|
case 1: nix=0; break; /* a + |b| */ |
|
4238
|
393
|
|
|
|
|
|
case 2: nix=0; postneg=1; break; /* -(|a| + b) */ |
|
4239
|
18
|
|
|
|
|
|
case 3: t=a; a=b; b=t; break; /* |b| - |a| */ |
|
4240
|
0
|
|
|
|
|
|
default: break; |
|
4241
|
|
|
|
|
|
|
} |
|
4242
|
272708
|
100
|
|
|
|
|
} else if (ix == 2) { |
|
4243
|
516
|
100
|
|
|
|
|
switch (smask) { |
|
4244
|
500
|
|
|
|
|
|
case 1: |
|
4245
|
500
|
|
|
|
|
|
case 2: postneg = 1; break; |
|
4246
|
16
|
|
|
|
|
|
default: break; |
|
4247
|
|
|
|
|
|
|
} |
|
4248
|
272192
|
100
|
|
|
|
|
} else if (ix == 3) { |
|
4249
|
1059
|
100
|
|
|
|
|
switch (smask) { |
|
4250
|
1051
|
|
|
|
|
|
case 1: |
|
4251
|
1051
|
|
|
|
|
|
case 2: postneg = 1; nix = 5; break; |
|
4252
|
8
|
|
|
|
|
|
default: break; |
|
4253
|
|
|
|
|
|
|
} |
|
4254
|
271133
|
100
|
|
|
|
|
} else if (ix == 4) { |
|
4255
|
271093
|
|
|
|
|
|
switch (smask) { |
|
4256
|
90018
|
|
|
|
|
|
case 1: nix = 6; postneg = 1; break; |
|
4257
|
91059
|
|
|
|
|
|
case 2: nix = 6; break; |
|
4258
|
90016
|
|
|
|
|
|
case 3: postneg = 1; break; |
|
4259
|
0
|
|
|
|
|
|
default: break; |
|
4260
|
|
|
|
|
|
|
} |
|
4261
|
40
|
100
|
|
|
|
|
} else if (ix == 5) { |
|
4262
|
9
|
100
|
|
|
|
|
switch (smask) { |
|
4263
|
7
|
|
|
|
|
|
case 1: |
|
4264
|
7
|
|
|
|
|
|
case 2: postneg = 1; nix = 3; break; |
|
4265
|
2
|
|
|
|
|
|
default: break; |
|
4266
|
|
|
|
|
|
|
} |
|
4267
|
31
|
50
|
|
|
|
|
} else if (ix == 6) { |
|
4268
|
|
|
|
|
|
|
/* ix = 6 is cmodint */ |
|
4269
|
31
|
50
|
|
|
|
|
} else if (ix == 7) { |
|
4270
|
|
|
|
|
|
|
/* bstatus is never -1 for powint */ |
|
4271
|
31
|
|
|
|
|
|
postneg = (b & 1); |
|
4272
|
|
|
|
|
|
|
} |
|
4273
|
|
|
|
|
|
|
} |
|
4274
|
784839
|
|
|
|
|
|
switch (nix) { |
|
4275
|
8051
|
|
|
|
|
|
case 0: ret = a + b; /* addint */ |
|
4276
|
8051
|
|
|
|
|
|
overflow = UV_MAX-a < b; |
|
4277
|
8051
|
|
|
|
|
|
break; |
|
4278
|
834
|
|
|
|
|
|
case 1: ret = a - b; /* subint */ |
|
4279
|
834
|
100
|
|
|
|
|
if (b > a && (IV)ret < 0) XSRETURN_IV((IV)ret); |
|
|
|
100
|
|
|
|
|
|
|
4280
|
661
|
|
|
|
|
|
overflow = (b > a); |
|
4281
|
661
|
|
|
|
|
|
break; |
|
4282
|
105151
|
|
|
|
|
|
case 2: ret = a * b; /* mulint */ |
|
4283
|
105151
|
100
|
|
|
|
|
overflow = a > 0 && UV_MAX/a < b; |
|
|
|
100
|
|
|
|
|
|
|
4284
|
105151
|
|
|
|
|
|
break; |
|
4285
|
76957
|
|
|
|
|
|
case 3: ret = a / b; break; /* divint */ |
|
4286
|
311535
|
|
|
|
|
|
case 4: ret = a % b; break; /* modint */ |
|
4287
|
1062
|
|
|
|
|
|
case 5: ret = a / b + (a % b != 0); /* cdivint */ |
|
4288
|
1062
|
|
|
|
|
|
break; |
|
4289
|
181077
|
100
|
|
|
|
|
case 6: ret = (a%b) ? b-(a%b) : 0; /* cmodint */ |
|
4290
|
181077
|
|
|
|
|
|
break; |
|
4291
|
100172
|
|
|
|
|
|
case 7: |
|
4292
|
100172
|
|
|
|
|
|
default: ret = ipowsafe(a, b); |
|
4293
|
100172
|
100
|
|
|
|
|
overflow = (a > 1 && ret == UV_MAX); |
|
|
|
100
|
|
|
|
|
|
|
4294
|
100172
|
|
|
|
|
|
break; |
|
4295
|
|
|
|
|
|
|
} |
|
4296
|
784666
|
100
|
|
|
|
|
if (!overflow) { |
|
4297
|
772456
|
100
|
|
|
|
|
if (!postneg) |
|
4298
|
590417
|
|
|
|
|
|
XSRETURN_UV(ret); |
|
4299
|
182039
|
100
|
|
|
|
|
if (ret <= (UV)IV_MAX) |
|
4300
|
181987
|
|
|
|
|
|
XSRETURN_IV(neg_iv(ret)); |
|
4301
|
|
|
|
|
|
|
} |
|
4302
|
|
|
|
|
|
|
} |
|
4303
|
50071
|
|
|
|
|
|
DISPATCHPP(); |
|
4304
|
50071
|
|
|
|
|
|
objectify_result(aTHX_ sva, ST(0)); |
|
4305
|
50071
|
|
|
|
|
|
XSRETURN(1); |
|
4306
|
|
|
|
|
|
|
|
|
4307
|
|
|
|
|
|
|
void add1int(IN SV* svn) |
|
4308
|
|
|
|
|
|
|
ALIAS: |
|
4309
|
|
|
|
|
|
|
sub1int = 1 |
|
4310
|
|
|
|
|
|
|
PREINIT: |
|
4311
|
|
|
|
|
|
|
int status; |
|
4312
|
|
|
|
|
|
|
UV n; |
|
4313
|
|
|
|
|
|
|
PPCODE: |
|
4314
|
2149
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY); |
|
4315
|
2149
|
100
|
|
|
|
|
if (status == 1) { |
|
4316
|
454
|
100
|
|
|
|
|
if (ix == 1 && n == 0) XSRETURN_IV(-1); |
|
|
|
100
|
|
|
|
|
|
|
4317
|
448
|
100
|
|
|
|
|
if (ix == 1 || (ix == 0 && n < UV_MAX)) |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
4318
|
445
|
100
|
|
|
|
|
XSRETURN_UV( (ix==0) ? n+1 : n-1 ); |
|
4319
|
1695
|
100
|
|
|
|
|
} else if (status == -1) { |
|
4320
|
37
|
100
|
|
|
|
|
if (ix == 0 || (ix == 1 && (IV)n > IV_MIN)) |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
4321
|
37
|
100
|
|
|
|
|
XSRETURN_IV( (ix==0) ? (IV)n+1 : (IV)n-1 ); |
|
4322
|
|
|
|
|
|
|
} |
|
4323
|
1661
|
|
|
|
|
|
DISPATCHPP(); |
|
4324
|
1661
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
4325
|
1661
|
|
|
|
|
|
XSRETURN(1); |
|
4326
|
|
|
|
|
|
|
|
|
4327
|
|
|
|
|
|
|
void absint(IN SV* svn) |
|
4328
|
|
|
|
|
|
|
ALIAS: |
|
4329
|
|
|
|
|
|
|
negint = 1 |
|
4330
|
|
|
|
|
|
|
PREINIT: |
|
4331
|
|
|
|
|
|
|
UV n; |
|
4332
|
|
|
|
|
|
|
PPCODE: |
|
4333
|
2421
|
100
|
|
|
|
|
if (ix == 0) { |
|
4334
|
301
|
100
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_ABS)) |
|
4335
|
270
|
|
|
|
|
|
XSRETURN_UV(n); |
|
4336
|
|
|
|
|
|
|
} else { |
|
4337
|
2120
|
|
|
|
|
|
int status = _validate_and_set(&n, aTHX_ svn, IFLAG_IV); |
|
4338
|
2120
|
100
|
|
|
|
|
if (status == -1) XSRETURN_UV(neg_iv(n)); |
|
4339
|
1974
|
100
|
|
|
|
|
else if (status == 1) XSRETURN_IV(neg_iv(n)); |
|
4340
|
|
|
|
|
|
|
} |
|
4341
|
1570
|
|
|
|
|
|
DISPATCHPP(); |
|
4342
|
1570
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
4343
|
1570
|
|
|
|
|
|
XSRETURN(1); |
|
4344
|
|
|
|
|
|
|
|
|
4345
|
|
|
|
|
|
|
void signint(IN SV* svn) |
|
4346
|
|
|
|
|
|
|
ALIAS: |
|
4347
|
|
|
|
|
|
|
is_odd = 1 |
|
4348
|
|
|
|
|
|
|
is_even = 2 |
|
4349
|
|
|
|
|
|
|
PREINIT: |
|
4350
|
|
|
|
|
|
|
int status, sign, isodd; |
|
4351
|
|
|
|
|
|
|
UV n; |
|
4352
|
|
|
|
|
|
|
const char* s; |
|
4353
|
|
|
|
|
|
|
STRLEN len; |
|
4354
|
|
|
|
|
|
|
PPCODE: |
|
4355
|
2308
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY); |
|
4356
|
2308
|
100
|
|
|
|
|
if (status == 0) { /* Look at the string input */ |
|
4357
|
1584
|
|
|
|
|
|
s = SvPV(svn, len); |
|
4358
|
1584
|
50
|
|
|
|
|
if (len == 0 || s == 0) croak("%s: invalid non-empty input", SUBNAME); |
|
|
|
50
|
|
|
|
|
|
|
4359
|
1584
|
100
|
|
|
|
|
sign = (s[0] == '-') ? -1 : (s[0] == '0') ? 0 : 1; |
|
4360
|
1584
|
100
|
|
|
|
|
isodd = (s[len-1] == '1' || s[len-1] == '3' || s[len-1] == '5' || s[len-1] == '7' || s[len-1] == '9'); |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
4361
|
|
|
|
|
|
|
} else { |
|
4362
|
724
|
100
|
|
|
|
|
sign = (status == -1) ? -1 : (n == 0) ? 0 : 1; |
|
4363
|
724
|
|
|
|
|
|
isodd = n & 1; |
|
4364
|
|
|
|
|
|
|
} |
|
4365
|
2308
|
100
|
|
|
|
|
RETURN_NPARITY( (ix==0) ? sign : (ix==1) ? isodd : !isodd ); |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
4366
|
|
|
|
|
|
|
|
|
4367
|
|
|
|
|
|
|
void cmpint(IN SV* sva, IN SV* svb) |
|
4368
|
|
|
|
|
|
|
PREINIT: |
|
4369
|
290
|
|
|
|
|
|
int astatus, bstatus, ret = 0; |
|
4370
|
|
|
|
|
|
|
UV a, b; |
|
4371
|
|
|
|
|
|
|
PPCODE: |
|
4372
|
290
|
|
|
|
|
|
astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_ANY); |
|
4373
|
290
|
|
|
|
|
|
bstatus = _validate_and_set(&b, aTHX_ svb, IFLAG_ANY); |
|
4374
|
290
|
100
|
|
|
|
|
if (astatus != 0 && bstatus != 0) { |
|
|
|
100
|
|
|
|
|
|
|
4375
|
123
|
100
|
|
|
|
|
if (astatus > bstatus) ret = 1; |
|
4376
|
105
|
100
|
|
|
|
|
else if (astatus < bstatus) ret = -1; |
|
4377
|
80
|
100
|
|
|
|
|
else if (a == b) ret = 0; |
|
4378
|
62
|
100
|
|
|
|
|
else ret = ((astatus == 1 && a > b) || (astatus == -1 && (IV)a > (IV)b)) ? 1 : -1; |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
4379
|
|
|
|
|
|
|
} else { |
|
4380
|
|
|
|
|
|
|
STRLEN alen, blen; |
|
4381
|
|
|
|
|
|
|
char *aptr, *bptr; |
|
4382
|
167
|
|
|
|
|
|
aptr = SvPV(sva, alen); |
|
4383
|
167
|
|
|
|
|
|
bptr = SvPV(svb, blen); |
|
4384
|
167
|
|
|
|
|
|
ret = strnum_cmp(aptr, alen, bptr, blen); |
|
4385
|
|
|
|
|
|
|
} |
|
4386
|
290
|
50
|
|
|
|
|
RETURN_NPARITY(ret); |
|
|
|
50
|
|
|
|
|
|
|
4387
|
|
|
|
|
|
|
|
|
4388
|
|
|
|
|
|
|
void logint(IN SV* svn, IN UV k, IN SV* svret = 0) |
|
4389
|
|
|
|
|
|
|
ALIAS: |
|
4390
|
|
|
|
|
|
|
rootint = 1 |
|
4391
|
|
|
|
|
|
|
PREINIT: |
|
4392
|
|
|
|
|
|
|
UV n, root; |
|
4393
|
|
|
|
|
|
|
PPCODE: |
|
4394
|
35293
|
100
|
|
|
|
|
if (ix == 0 && k <= 1) croak("logint: base must be > 1"); |
|
|
|
100
|
|
|
|
|
|
|
4395
|
35291
|
100
|
|
|
|
|
if (ix == 1 && k <= 0) croak("rootint: k must be > 0"); |
|
|
|
100
|
|
|
|
|
|
|
4396
|
35290
|
100
|
|
|
|
|
if (svret != 0 && !SvROK(svret)) |
|
|
|
50
|
|
|
|
|
|
|
4397
|
0
|
|
|
|
|
|
croak("%s: third argument not a scalar reference",SUBNAME); |
|
4398
|
35290
|
100
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, ix == 0 ? IFLAG_POS | IFLAG_NONZERO : IFLAG_POS)) { |
|
|
|
100
|
|
|
|
|
|
|
4399
|
31300
|
100
|
|
|
|
|
root = (ix == 0) ? logint(n, k) : rootint(n, k); |
|
4400
|
31300
|
100
|
|
|
|
|
if (svret) sv_setuv(SvRV(svret), ix == 0 ? ipow(k,root) : ipow(root,k)); |
|
|
|
100
|
|
|
|
|
|
|
4401
|
31300
|
|
|
|
|
|
XSRETURN_UV(root); |
|
4402
|
|
|
|
|
|
|
} |
|
4403
|
3987
|
|
|
|
|
|
DISPATCHPP_GMPONLYIF(svret == 0); |
|
4404
|
3987
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
4405
|
3987
|
|
|
|
|
|
XSRETURN(1); |
|
4406
|
|
|
|
|
|
|
|
|
4407
|
|
|
|
|
|
|
void divrem(IN SV* sva, IN SV* svb) |
|
4408
|
|
|
|
|
|
|
ALIAS: |
|
4409
|
|
|
|
|
|
|
fdivrem = 1 |
|
4410
|
|
|
|
|
|
|
cdivrem = 2 |
|
4411
|
|
|
|
|
|
|
tdivrem = 3 |
|
4412
|
|
|
|
|
|
|
PREINIT: |
|
4413
|
|
|
|
|
|
|
int astatus, bstatus; |
|
4414
|
|
|
|
|
|
|
UV D, d; |
|
4415
|
|
|
|
|
|
|
IV iD, id; |
|
4416
|
|
|
|
|
|
|
PPCODE: |
|
4417
|
985
|
|
|
|
|
|
astatus = _validate_and_set(&D, aTHX_ sva, IFLAG_ANY); |
|
4418
|
985
|
|
|
|
|
|
bstatus = _validate_and_set(&d, aTHX_ svb, IFLAG_ANY); |
|
4419
|
985
|
100
|
|
|
|
|
if (astatus != 0 && bstatus != 0 && d == 0) |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
4420
|
8
|
|
|
|
|
|
croak("%s: divide by zero", SUBNAME); |
|
4421
|
977
|
100
|
|
|
|
|
if (astatus == 1 && bstatus == 1 && (ix != 2 || D % d == 0)) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
4422
|
681
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSVuv( D / d ))); |
|
4423
|
681
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSVuv( D % d ))); |
|
4424
|
681
|
|
|
|
|
|
XSRETURN(2); |
|
4425
|
296
|
100
|
|
|
|
|
} else if (ix == 2 && astatus == 1 && bstatus == 1 && d <= (UV)IV_MAX) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
4426
|
|
|
|
|
|
|
/* Exact division was handled above */ |
|
4427
|
8
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSVuv( D/d + 1 ))); |
|
4428
|
8
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSViv( ((IV)D%d) - d ))); |
|
4429
|
8
|
|
|
|
|
|
XSRETURN(2); |
|
4430
|
361
|
100
|
|
|
|
|
} else if (astatus != 0 && bstatus != 0 && |
|
4431
|
146
|
100
|
|
|
|
|
_validate_and_set((UV*)&iD, aTHX_ sva, IFLAG_IV) != 0 && |
|
4432
|
73
|
|
|
|
|
|
_validate_and_set((UV*)&id, aTHX_ svb, IFLAG_IV) != 0) { |
|
4433
|
|
|
|
|
|
|
/* Both values fit in an IV */ |
|
4434
|
|
|
|
|
|
|
IV q, r; |
|
4435
|
72
|
|
|
|
|
|
switch (ix) { |
|
4436
|
18
|
|
|
|
|
|
case 0: edivrem(&q, &r, iD, id); break; |
|
4437
|
21
|
|
|
|
|
|
case 1: fdivrem(&q, &r, iD, id); break; |
|
4438
|
18
|
|
|
|
|
|
case 2: cdivrem(&q, &r, iD, id); break; |
|
4439
|
15
|
|
|
|
|
|
case 3: |
|
4440
|
15
|
|
|
|
|
|
default: tdivrem(&q, &r, D, d); break; |
|
4441
|
|
|
|
|
|
|
} |
|
4442
|
72
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSViv( q ))); |
|
4443
|
72
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSViv( r ))); |
|
4444
|
72
|
|
|
|
|
|
XSRETURN(2); |
|
4445
|
|
|
|
|
|
|
} |
|
4446
|
216
|
|
|
|
|
|
DISPATCHPP(); |
|
4447
|
648
|
50
|
|
|
|
|
OBJECTIFY_STACK(2); |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
4448
|
216
|
|
|
|
|
|
XSRETURN(2); |
|
4449
|
|
|
|
|
|
|
|
|
4450
|
|
|
|
|
|
|
void lshiftint(IN SV* svn, IN SV* svk = 0) |
|
4451
|
|
|
|
|
|
|
ALIAS: |
|
4452
|
|
|
|
|
|
|
rshiftint = 1 |
|
4453
|
|
|
|
|
|
|
rashiftint = 2 |
|
4454
|
|
|
|
|
|
|
PREINIT: |
|
4455
|
|
|
|
|
|
|
int nstatus, kstatus, nix; |
|
4456
|
|
|
|
|
|
|
UV n, k, nk; |
|
4457
|
|
|
|
|
|
|
PPCODE: |
|
4458
|
4465
|
|
|
|
|
|
nix = ix; |
|
4459
|
4465
|
100
|
|
|
|
|
if (items == 1) { |
|
4460
|
2710
|
|
|
|
|
|
kstatus = 1; |
|
4461
|
2710
|
|
|
|
|
|
k = 1; |
|
4462
|
|
|
|
|
|
|
} else { |
|
4463
|
1755
|
|
|
|
|
|
kstatus = _validate_and_set(&k, aTHX_ svk, IFLAG_ANY); |
|
4464
|
1755
|
100
|
|
|
|
|
if (kstatus == -1) { |
|
4465
|
96
|
|
|
|
|
|
k = neg_iv(k); |
|
4466
|
96
|
|
|
|
|
|
nix = !ix; /* 0 => 1, 1 => 0, 2 => 0 */ |
|
4467
|
|
|
|
|
|
|
} |
|
4468
|
|
|
|
|
|
|
} |
|
4469
|
4465
|
50
|
|
|
|
|
if (kstatus != 0) { |
|
4470
|
4465
|
|
|
|
|
|
nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY); |
|
4471
|
4465
|
100
|
|
|
|
|
if (k == 0) |
|
4472
|
57
|
|
|
|
|
|
XSRETURN(1); |
|
4473
|
4408
|
100
|
|
|
|
|
if (nstatus != 0 && nix > 0 && k >= BITS_PER_WORD) /* Big right shift */ |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
4474
|
114
|
100
|
|
|
|
|
XSRETURN_IV(nstatus == -1 && nix==2 ? -1 : 0); |
|
|
|
100
|
|
|
|
|
|
|
4475
|
4294
|
100
|
|
|
|
|
if (nstatus == 1 && k < BITS_PER_WORD) { |
|
|
|
100
|
|
|
|
|
|
|
4476
|
954
|
100
|
|
|
|
|
if (nix > 0) XSRETURN_UV(n >> k); /* Right shift */ |
|
4477
|
389
|
100
|
|
|
|
|
if ( ((n << k) >> k) == n) XSRETURN_UV(n << k); /* Left shift */ |
|
4478
|
|
|
|
|
|
|
/* Fall through -- left shift needs more bits */ |
|
4479
|
3340
|
100
|
|
|
|
|
} else if (nstatus == -1 && nix > 0 && k < BITS_PER_WORD) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
4480
|
59
|
|
|
|
|
|
n = neg_iv(n); |
|
4481
|
59
|
|
|
|
|
|
nk = n >> k; |
|
4482
|
59
|
100
|
|
|
|
|
XSRETURN_IV( nix == 1 ? -nk : (nk<
|
|
|
|
100
|
|
|
|
|
|
|
4483
|
3281
|
100
|
|
|
|
|
} else if (nstatus == -1 && nix == 0 && k+1 < BITS_PER_WORD) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
4484
|
130
|
|
|
|
|
|
n = neg_iv(n); |
|
4485
|
130
|
|
|
|
|
|
nk = n << k; |
|
4486
|
130
|
100
|
|
|
|
|
if ((nk << 1) >> (k+1) == n) |
|
4487
|
125
|
|
|
|
|
|
XSRETURN_IV(-nk); |
|
4488
|
|
|
|
|
|
|
/* Fall through -- left shift needs more bits */ |
|
4489
|
|
|
|
|
|
|
} |
|
4490
|
|
|
|
|
|
|
} |
|
4491
|
3319
|
|
|
|
|
|
DISPATCHPP(); |
|
4492
|
3319
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
4493
|
3319
|
|
|
|
|
|
XSRETURN(1); |
|
4494
|
|
|
|
|
|
|
|
|
4495
|
|
|
|
|
|
|
void |
|
4496
|
|
|
|
|
|
|
gcdext(IN SV* sva, IN SV* svb) |
|
4497
|
|
|
|
|
|
|
PREINIT: |
|
4498
|
|
|
|
|
|
|
IV u, v, d, a, b; |
|
4499
|
|
|
|
|
|
|
PPCODE: |
|
4500
|
26
|
|
|
|
|
|
if (_validate_and_set((UV*)&a, aTHX_ sva, IFLAG_IV) && |
|
4501
|
12
|
|
|
|
|
|
_validate_and_set((UV*)&b, aTHX_ svb, IFLAG_IV)) { |
|
4502
|
12
|
|
|
|
|
|
d = gcdext(a, b, &u, &v, 0, 0); |
|
4503
|
12
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSViv( u ))); |
|
4504
|
12
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSViv( v ))); |
|
4505
|
12
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSViv( d ))); |
|
4506
|
|
|
|
|
|
|
} else { |
|
4507
|
2
|
|
|
|
|
|
DISPATCHPP(); |
|
4508
|
8
|
50
|
|
|
|
|
OBJECTIFY_STACK(3); |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
4509
|
2
|
|
|
|
|
|
XSRETURN(3); |
|
4510
|
|
|
|
|
|
|
} |
|
4511
|
|
|
|
|
|
|
|
|
4512
|
|
|
|
|
|
|
void |
|
4513
|
|
|
|
|
|
|
stirling(IN UV n, IN UV m, IN UV type = 1) |
|
4514
|
|
|
|
|
|
|
PPCODE: |
|
4515
|
894
|
100
|
|
|
|
|
if (type != 1 && type != 2 && type != 3) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
4516
|
1
|
|
|
|
|
|
croak("stirling: type must be 1, 2, or 3"); |
|
4517
|
893
|
100
|
|
|
|
|
if (n == m) |
|
4518
|
70
|
|
|
|
|
|
XSRETURN_UV(1); |
|
4519
|
823
|
100
|
|
|
|
|
else if (n == 0 || m == 0 || m > n) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
4520
|
123
|
|
|
|
|
|
XSRETURN_UV(0); |
|
4521
|
700
|
100
|
|
|
|
|
else if (type == 3) { |
|
4522
|
190
|
|
|
|
|
|
UV s = stirling3(n, m); |
|
4523
|
190
|
100
|
|
|
|
|
if (s != 0) XSRETURN_UV(s); |
|
4524
|
510
|
100
|
|
|
|
|
} else if (type == 2) { |
|
4525
|
318
|
|
|
|
|
|
IV s = stirling2(n, m); |
|
4526
|
318
|
100
|
|
|
|
|
if (s != 0) XSRETURN_IV(s); |
|
4527
|
192
|
50
|
|
|
|
|
} else if (type == 1) { |
|
4528
|
192
|
|
|
|
|
|
IV s = stirling1(n, m); |
|
4529
|
192
|
100
|
|
|
|
|
if (s != 0) XSRETURN_IV(s); |
|
4530
|
|
|
|
|
|
|
} |
|
4531
|
161
|
|
|
|
|
|
DISPATCHPP(); |
|
4532
|
161
|
|
|
|
|
|
objectify_result(aTHX_ 0, ST(0)); |
|
4533
|
161
|
|
|
|
|
|
XSRETURN(1); |
|
4534
|
|
|
|
|
|
|
|
|
4535
|
|
|
|
|
|
|
NV |
|
4536
|
|
|
|
|
|
|
_XS_ExponentialIntegral(IN SV* x) |
|
4537
|
|
|
|
|
|
|
ALIAS: |
|
4538
|
|
|
|
|
|
|
_XS_LogarithmicIntegral = 1 |
|
4539
|
|
|
|
|
|
|
_XS_RiemannZeta = 2 |
|
4540
|
|
|
|
|
|
|
_XS_RiemannR = 3 |
|
4541
|
|
|
|
|
|
|
_XS_LambertW = 4 |
|
4542
|
|
|
|
|
|
|
PREINIT: |
|
4543
|
|
|
|
|
|
|
NV nv, ret; |
|
4544
|
|
|
|
|
|
|
CODE: |
|
4545
|
108
|
50
|
|
|
|
|
nv = !SvROK(x) ? SvNV(x) : STRTONV(SvPV_nolen(x)); |
|
4546
|
108
|
|
|
|
|
|
switch (ix) { |
|
4547
|
19
|
|
|
|
|
|
case 0: ret = Ei(nv); break; |
|
4548
|
65
|
|
|
|
|
|
case 1: ret = Li(nv); break; |
|
4549
|
6
|
|
|
|
|
|
case 2: ret = (NV) ld_riemann_zeta(nv); break; |
|
4550
|
9
|
|
|
|
|
|
case 3: ret = (NV) RiemannR(nv,0); break; |
|
4551
|
9
|
|
|
|
|
|
case 4: |
|
4552
|
9
|
|
|
|
|
|
default:ret = lambertw(nv); break; |
|
4553
|
|
|
|
|
|
|
} |
|
4554
|
108
|
100
|
|
|
|
|
RETVAL = ret; |
|
4555
|
|
|
|
|
|
|
OUTPUT: |
|
4556
|
|
|
|
|
|
|
RETVAL |
|
4557
|
|
|
|
|
|
|
|
|
4558
|
|
|
|
|
|
|
|
|
4559
|
|
|
|
|
|
|
void euler_phi(IN SV* svlo, IN SV* svhi = 0) |
|
4560
|
|
|
|
|
|
|
ALIAS: |
|
4561
|
|
|
|
|
|
|
moebius = 1 |
|
4562
|
|
|
|
|
|
|
PREINIT: |
|
4563
|
|
|
|
|
|
|
UV lo, hi; |
|
4564
|
|
|
|
|
|
|
int lostatus, histatus; |
|
4565
|
|
|
|
|
|
|
uint32_t mask; |
|
4566
|
|
|
|
|
|
|
PPCODE: |
|
4567
|
28364
|
100
|
|
|
|
|
mask = (ix == 1 && items == 1) ? IFLAG_ABS : IFLAG_ANY; |
|
|
|
100
|
|
|
|
|
|
|
4568
|
28364
|
|
|
|
|
|
lostatus = _validate_and_set(&lo, aTHX_ svlo, mask); |
|
4569
|
28364
|
100
|
|
|
|
|
if (svhi == 0 && lostatus != 0) { |
|
|
|
100
|
|
|
|
|
|
|
4570
|
28297
|
100
|
|
|
|
|
if (ix == 0) XSRETURN_UV( (lostatus == -1) ? 0 : totient(lo) ); |
|
|
|
100
|
|
|
|
|
|
|
4571
|
28223
|
50
|
|
|
|
|
else RETURN_NPARITY( moebius(lo) ); |
|
|
|
50
|
|
|
|
|
|
|
4572
|
|
|
|
|
|
|
} |
|
4573
|
67
|
100
|
|
|
|
|
histatus = (svhi == 0) ? 0 : _validate_and_set(&hi, aTHX_ svhi, IFLAG_ANY); |
|
4574
|
|
|
|
|
|
|
/* - If range is larger than MAX_EXTEND, reduce it to fit. |
|
4575
|
|
|
|
|
|
|
* Arguably we should croak as invalid input. |
|
4576
|
|
|
|
|
|
|
* - If range includes UV_MAX, pull it off and handle separately. |
|
4577
|
|
|
|
|
|
|
* This makes count never underflow (e.g. lo=0,hi=max, hi-lo+1 => 0) |
|
4578
|
|
|
|
|
|
|
* It also simplifies loop overflow logic in the range function. |
|
4579
|
|
|
|
|
|
|
*/ |
|
4580
|
107
|
100
|
|
|
|
|
if (lostatus == 1 && histatus == 1) { |
|
|
|
100
|
|
|
|
|
|
|
4581
|
|
|
|
|
|
|
UV i, count; |
|
4582
|
41
|
|
|
|
|
|
int appendmax = (hi == UV_MAX); |
|
4583
|
41
|
100
|
|
|
|
|
if (lo > hi) XSRETURN(0); |
|
4584
|
|
|
|
|
|
|
|
|
4585
|
40
|
100
|
|
|
|
|
if (appendmax) hi--; |
|
4586
|
|
|
|
|
|
|
if ((hi-lo+1) > MAX_EXTEND) hi = lo + MAX_EXTEND - 1; |
|
4587
|
40
|
|
|
|
|
|
count = hi-lo+1; |
|
4588
|
40
|
50
|
|
|
|
|
if (count > 0) { |
|
4589
|
40
|
50
|
|
|
|
|
EXTEND(SP, (EXTEND_TYPE)count); |
|
|
|
100
|
|
|
|
|
|
|
4590
|
40
|
100
|
|
|
|
|
if (ix == 0) { |
|
4591
|
14
|
100
|
|
|
|
|
UV arrlo = (lo < 100) ? 0 : lo; |
|
4592
|
14
|
|
|
|
|
|
UV *totients = range_totient(arrlo, hi); |
|
4593
|
385
|
100
|
|
|
|
|
for (i = 0; i < count; i++) |
|
4594
|
371
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv(totients[i+lo-arrlo]))); |
|
4595
|
14
|
|
|
|
|
|
Safefree(totients); |
|
4596
|
|
|
|
|
|
|
} else { |
|
4597
|
26
|
|
|
|
|
|
signed char* mu = range_moebius(lo, hi); |
|
4598
|
|
|
|
|
|
|
dMY_CXT; |
|
4599
|
27562
|
100
|
|
|
|
|
for (i = 0; i < count; i++) |
|
4600
|
27536
|
50
|
|
|
|
|
PUSH_NPARITY(mu[i]); |
|
|
|
50
|
|
|
|
|
|
|
4601
|
26
|
|
|
|
|
|
Safefree(mu); |
|
4602
|
|
|
|
|
|
|
} |
|
4603
|
|
|
|
|
|
|
} |
|
4604
|
40
|
100
|
|
|
|
|
if (appendmax) { |
|
4605
|
2
|
50
|
|
|
|
|
EXTEND(SP, 1); |
|
4606
|
2
|
100
|
|
|
|
|
if (ix == 0) { |
|
4607
|
1
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv(totient(UV_MAX)))); |
|
4608
|
|
|
|
|
|
|
} else { |
|
4609
|
|
|
|
|
|
|
dMY_CXT; |
|
4610
|
1
|
50
|
|
|
|
|
PUSH_NPARITY(-1); /* moebius of 2^32-1, 2^64-1, 2^128-1 => -1 */ |
|
|
|
50
|
|
|
|
|
|
|
4611
|
|
|
|
|
|
|
} |
|
4612
|
|
|
|
|
|
|
} |
|
4613
|
|
|
|
|
|
|
} else { |
|
4614
|
26
|
|
|
|
|
|
DISPATCHPP(); |
|
4615
|
26
|
|
|
|
|
|
return; |
|
4616
|
|
|
|
|
|
|
} |
|
4617
|
|
|
|
|
|
|
|
|
4618
|
|
|
|
|
|
|
void sqrtint(IN SV* svn) |
|
4619
|
|
|
|
|
|
|
ALIAS: |
|
4620
|
|
|
|
|
|
|
carmichael_lambda = 1 |
|
4621
|
|
|
|
|
|
|
exp_mangoldt = 2 |
|
4622
|
|
|
|
|
|
|
PREINIT: |
|
4623
|
|
|
|
|
|
|
UV n, r; |
|
4624
|
|
|
|
|
|
|
PPCODE: |
|
4625
|
65715
|
100
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) { |
|
4626
|
65668
|
|
|
|
|
|
r = 0; |
|
4627
|
65668
|
|
|
|
|
|
switch (ix) { |
|
4628
|
65447
|
|
|
|
|
|
case 0: r = isqrt(n); break; |
|
4629
|
201
|
|
|
|
|
|
case 1: r = carmichael_lambda(n); break; |
|
4630
|
20
|
|
|
|
|
|
case 2: r = exp_mangoldt(n); break; |
|
4631
|
0
|
|
|
|
|
|
default: break; |
|
4632
|
|
|
|
|
|
|
} |
|
4633
|
65668
|
|
|
|
|
|
XSRETURN_UV(r); |
|
4634
|
|
|
|
|
|
|
} |
|
4635
|
46
|
|
|
|
|
|
DISPATCHPP(); |
|
4636
|
46
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
4637
|
46
|
|
|
|
|
|
XSRETURN(1); |
|
4638
|
|
|
|
|
|
|
|
|
4639
|
|
|
|
|
|
|
void prime_omega(IN SV* svn) |
|
4640
|
|
|
|
|
|
|
ALIAS: |
|
4641
|
|
|
|
|
|
|
prime_bigomega = 1 |
|
4642
|
|
|
|
|
|
|
hammingweight = 2 |
|
4643
|
|
|
|
|
|
|
is_square_free = 3 |
|
4644
|
|
|
|
|
|
|
PREINIT: |
|
4645
|
|
|
|
|
|
|
UV n, ret; |
|
4646
|
|
|
|
|
|
|
PPCODE: |
|
4647
|
37173
|
100
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_ABS)) { |
|
4648
|
37150
|
|
|
|
|
|
ret = 0; |
|
4649
|
37150
|
|
|
|
|
|
switch (ix) { |
|
4650
|
14
|
|
|
|
|
|
case 0: ret = prime_omega(n); break; |
|
4651
|
14
|
|
|
|
|
|
case 1: ret = prime_bigomega(n); break; |
|
4652
|
11
|
|
|
|
|
|
case 2: ret = popcnt(n); break; |
|
4653
|
37111
|
|
|
|
|
|
case 3: ret = is_square_free(n); break; |
|
4654
|
0
|
|
|
|
|
|
default: break; |
|
4655
|
|
|
|
|
|
|
} |
|
4656
|
37150
|
50
|
|
|
|
|
RETURN_NPARITY(ret); |
|
|
|
50
|
|
|
|
|
|
|
4657
|
|
|
|
|
|
|
} |
|
4658
|
23
|
100
|
|
|
|
|
if (ix == 2 && _XS_get_callgmp() < 47) { |
|
|
|
50
|
|
|
|
|
|
|
4659
|
3
|
|
|
|
|
|
char* ptr; STRLEN len; ptr = SvPV(svn, len); |
|
4660
|
3
|
|
|
|
|
|
XSRETURN_UV(mpu_popcount_string(ptr, len)); |
|
4661
|
|
|
|
|
|
|
} |
|
4662
|
20
|
|
|
|
|
|
DISPATCHPP(); |
|
4663
|
20
|
|
|
|
|
|
XSRETURN(1); |
|
4664
|
|
|
|
|
|
|
|
|
4665
|
|
|
|
|
|
|
void factorial(IN SV* svn) |
|
4666
|
|
|
|
|
|
|
ALIAS: |
|
4667
|
|
|
|
|
|
|
subfactorial = 1 |
|
4668
|
|
|
|
|
|
|
fubini = 2 |
|
4669
|
|
|
|
|
|
|
primorial = 3 |
|
4670
|
|
|
|
|
|
|
pn_primorial = 4 |
|
4671
|
|
|
|
|
|
|
sumtotient = 5 |
|
4672
|
|
|
|
|
|
|
PREINIT: |
|
4673
|
|
|
|
|
|
|
UV n, r; |
|
4674
|
|
|
|
|
|
|
PPCODE: |
|
4675
|
1322
|
50
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) { |
|
4676
|
1320
|
|
|
|
|
|
r = 0; |
|
4677
|
1320
|
|
|
|
|
|
switch(ix) { |
|
4678
|
1161
|
|
|
|
|
|
case 0: r = factorial(n); break; |
|
4679
|
25
|
|
|
|
|
|
case 1: r = subfactorial(n); break; |
|
4680
|
24
|
|
|
|
|
|
case 2: r = fubini(n); break; |
|
4681
|
62
|
|
|
|
|
|
case 3: r = primorial(n); break; |
|
4682
|
35
|
|
|
|
|
|
case 4: r = pn_primorial(n); break; |
|
4683
|
13
|
|
|
|
|
|
case 5: r = sumtotient(n); break; |
|
4684
|
0
|
|
|
|
|
|
default: break; |
|
4685
|
|
|
|
|
|
|
} |
|
4686
|
1320
|
100
|
|
|
|
|
if (n == 0 || r > 0) XSRETURN_UV(r); |
|
|
|
100
|
|
|
|
|
|
|
4687
|
418
|
50
|
|
|
|
|
if (ix == 5) { /* Probably an overflow, try 128-bit. */ |
|
4688
|
|
|
|
|
|
|
UV hicount, count; |
|
4689
|
0
|
|
|
|
|
|
int retok = sumtotient128(n, &hicount, &count); |
|
4690
|
0
|
0
|
|
|
|
|
if (retok == 1 && hicount > 0) |
|
|
|
0
|
|
|
|
|
|
|
4691
|
0
|
|
|
|
|
|
RETURN_128(hicount, count); |
|
4692
|
0
|
0
|
|
|
|
|
if (retok == 1) |
|
4693
|
0
|
|
|
|
|
|
XSRETURN_UV(count); |
|
4694
|
|
|
|
|
|
|
} |
|
4695
|
|
|
|
|
|
|
} |
|
4696
|
418
|
|
|
|
|
|
DISPATCHPP(); |
|
4697
|
418
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
4698
|
418
|
|
|
|
|
|
XSRETURN(1); |
|
4699
|
|
|
|
|
|
|
|
|
4700
|
|
|
|
|
|
|
void binomial(IN SV* svn, IN SV* svk) |
|
4701
|
|
|
|
|
|
|
PREINIT: |
|
4702
|
|
|
|
|
|
|
int nstatus, kstatus; |
|
4703
|
|
|
|
|
|
|
UV n, k, ret; |
|
4704
|
|
|
|
|
|
|
PPCODE: |
|
4705
|
3578
|
|
|
|
|
|
nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY); |
|
4706
|
3578
|
|
|
|
|
|
kstatus = _validate_and_set(&k, aTHX_ svk, IFLAG_ANY); |
|
4707
|
3578
|
100
|
|
|
|
|
if (nstatus != 0 && kstatus != 0) { |
|
|
|
50
|
|
|
|
|
|
|
4708
|
3568
|
100
|
|
|
|
|
if ( (nstatus == 1 && (kstatus == -1 || k > n)) || |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
4709
|
367
|
100
|
|
|
|
|
(nstatus ==-1 && (kstatus == -1 && k > n)) ) |
|
|
|
100
|
|
|
|
|
|
|
4710
|
241
|
|
|
|
|
|
XSRETURN_UV(0); |
|
4711
|
3327
|
100
|
|
|
|
|
if (kstatus == -1) |
|
4712
|
81
|
|
|
|
|
|
k = n - k; /* n<0,k<=n: (-1)^(n-k) * binomial(-k-1,n-k) */ |
|
4713
|
3327
|
100
|
|
|
|
|
if (nstatus == -1) { |
|
4714
|
310
|
|
|
|
|
|
ret = binomial( neg_iv(n)+k-1, k ); |
|
4715
|
310
|
100
|
|
|
|
|
if (ret > 0 && ret <= (UV)IV_MAX) |
|
|
|
50
|
|
|
|
|
|
|
4716
|
245
|
100
|
|
|
|
|
XSRETURN_IV( (IV)ret * ((k&1) ? -1 : 1) ); |
|
4717
|
3017
|
50
|
|
|
|
|
} else if (nstatus == 1) { |
|
4718
|
3017
|
|
|
|
|
|
ret = binomial(n, k); |
|
4719
|
3017
|
100
|
|
|
|
|
if (ret != 0) XSRETURN_UV(ret); |
|
4720
|
|
|
|
|
|
|
} |
|
4721
|
|
|
|
|
|
|
} |
|
4722
|
192
|
100
|
|
|
|
|
DISPATCHPP_GMPONLYIF(nstatus == 1 && kstatus != 0); |
|
|
|
50
|
|
|
|
|
|
|
4723
|
192
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
4724
|
192
|
|
|
|
|
|
XSRETURN(1); |
|
4725
|
|
|
|
|
|
|
|
|
4726
|
|
|
|
|
|
|
void falling_factorial(IN SV* svn, IN SV* svk) |
|
4727
|
|
|
|
|
|
|
ALIAS: |
|
4728
|
|
|
|
|
|
|
rising_factorial = 1 |
|
4729
|
|
|
|
|
|
|
PREINIT: |
|
4730
|
|
|
|
|
|
|
int nstatus, kstatus; |
|
4731
|
|
|
|
|
|
|
UV n, k; |
|
4732
|
|
|
|
|
|
|
PPCODE: |
|
4733
|
482
|
|
|
|
|
|
nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY | IFLAG_IV); |
|
4734
|
482
|
|
|
|
|
|
kstatus = _validate_and_set(&k, aTHX_ svk, IFLAG_POS); |
|
4735
|
486
|
100
|
|
|
|
|
if (nstatus == 1 && kstatus == 1) { |
|
|
|
50
|
|
|
|
|
|
|
4736
|
252
|
100
|
|
|
|
|
UV ret = (ix==0) ? falling_factorial(n,k) : rising_factorial(n,k); |
|
4737
|
252
|
100
|
|
|
|
|
if (ret != UV_MAX) XSRETURN_UV(ret); |
|
4738
|
230
|
100
|
|
|
|
|
} else if (nstatus == -1 && kstatus == 1) { |
|
|
|
50
|
|
|
|
|
|
|
4739
|
220
|
|
|
|
|
|
IV in = (IV)n; |
|
4740
|
220
|
100
|
|
|
|
|
IV ret = (ix==0) ? falling_factorial_s(in,k) : rising_factorial_s(in,k); |
|
4741
|
220
|
50
|
|
|
|
|
if (ret != IV_MAX) XSRETURN_IV(ret); |
|
4742
|
|
|
|
|
|
|
} |
|
4743
|
14
|
|
|
|
|
|
DISPATCHPP(); |
|
4744
|
14
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
4745
|
14
|
|
|
|
|
|
XSRETURN(1); |
|
4746
|
|
|
|
|
|
|
|
|
4747
|
|
|
|
|
|
|
void mertens(IN SV* svn) |
|
4748
|
|
|
|
|
|
|
ALIAS: |
|
4749
|
|
|
|
|
|
|
liouville = 1 |
|
4750
|
|
|
|
|
|
|
sumliouville = 2 |
|
4751
|
|
|
|
|
|
|
is_pillai = 3 |
|
4752
|
|
|
|
|
|
|
is_congruent_number = 4 |
|
4753
|
|
|
|
|
|
|
hclassno = 5 |
|
4754
|
|
|
|
|
|
|
ramanujan_tau = 6 |
|
4755
|
|
|
|
|
|
|
PREINIT: |
|
4756
|
|
|
|
|
|
|
UV n; |
|
4757
|
|
|
|
|
|
|
int status; |
|
4758
|
|
|
|
|
|
|
PPCODE: |
|
4759
|
1458
|
100
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, (ix < 5) ? IFLAG_POS : IFLAG_ANY); |
|
4760
|
1458
|
100
|
|
|
|
|
if (status == -1) |
|
4761
|
1
|
|
|
|
|
|
XSRETURN_IV(0); |
|
4762
|
1457
|
100
|
|
|
|
|
if (status == 1) { |
|
4763
|
1455
|
|
|
|
|
|
IV r = 0; |
|
4764
|
1455
|
|
|
|
|
|
switch(ix) { |
|
4765
|
52
|
|
|
|
|
|
case 0: r = mertens(n); break; |
|
4766
|
60
|
|
|
|
|
|
case 1: r = liouville(n); break; |
|
4767
|
57
|
|
|
|
|
|
case 2: r = sumliouville(n); break; |
|
4768
|
993
|
|
|
|
|
|
case 3: r = pillai_v(n); break; |
|
4769
|
210
|
|
|
|
|
|
case 4: r = is_congruent_number(n); break; |
|
4770
|
73
|
|
|
|
|
|
case 5: r = hclassno(n); break; |
|
4771
|
10
|
|
|
|
|
|
case 6: r = ramanujan_tau(n); |
|
4772
|
10
|
100
|
|
|
|
|
if (r == 0 && n != 0) |
|
|
|
100
|
|
|
|
|
|
|
4773
|
4
|
|
|
|
|
|
status = 0; |
|
4774
|
10
|
|
|
|
|
|
break; |
|
4775
|
0
|
|
|
|
|
|
default: break; |
|
4776
|
|
|
|
|
|
|
} |
|
4777
|
1455
|
100
|
|
|
|
|
if (status != 0) RETURN_NPARITY(r); |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
4778
|
|
|
|
|
|
|
} |
|
4779
|
6
|
|
|
|
|
|
DISPATCHPP(); |
|
4780
|
6
|
|
|
|
|
|
objectify_result(aTHX_ svn, ST(0)); |
|
4781
|
6
|
|
|
|
|
|
XSRETURN(1); |
|
4782
|
|
|
|
|
|
|
|
|
4783
|
|
|
|
|
|
|
int _is_congruent_number_filter(IN UV n) |
|
4784
|
|
|
|
|
|
|
CODE: |
|
4785
|
247
|
|
|
|
|
|
RETVAL = is_congruent_number_filter(n); |
|
4786
|
|
|
|
|
|
|
OUTPUT: |
|
4787
|
|
|
|
|
|
|
RETVAL |
|
4788
|
|
|
|
|
|
|
|
|
4789
|
|
|
|
|
|
|
bool _is_congruent_number_tunnell(IN UV n) |
|
4790
|
|
|
|
|
|
|
CODE: |
|
4791
|
200
|
|
|
|
|
|
RETVAL = is_congruent_number_tunnell(n); |
|
4792
|
|
|
|
|
|
|
OUTPUT: |
|
4793
|
|
|
|
|
|
|
RETVAL |
|
4794
|
|
|
|
|
|
|
|
|
4795
|
|
|
|
|
|
|
void chebyshev_theta(IN SV* svn) |
|
4796
|
|
|
|
|
|
|
ALIAS: |
|
4797
|
|
|
|
|
|
|
chebyshev_psi = 1 |
|
4798
|
|
|
|
|
|
|
PREINIT: |
|
4799
|
|
|
|
|
|
|
UV n; |
|
4800
|
|
|
|
|
|
|
PPCODE: |
|
4801
|
19
|
50
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) { |
|
4802
|
19
|
100
|
|
|
|
|
NV r = (ix==0) ? chebyshev_theta(n) : chebyshev_psi(n); |
|
4803
|
19
|
|
|
|
|
|
XSRETURN_NV(r); |
|
4804
|
|
|
|
|
|
|
} |
|
4805
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
4806
|
|
|
|
|
|
|
/* Result is FP */ |
|
4807
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
4808
|
|
|
|
|
|
|
|
|
4809
|
|
|
|
|
|
|
|
|
4810
|
|
|
|
|
|
|
#define RETURN_SET_REF(s) /* Return sorted set values */ \ |
|
4811
|
|
|
|
|
|
|
{ \ |
|
4812
|
|
|
|
|
|
|
UV *sdata; \ |
|
4813
|
|
|
|
|
|
|
unsigned long slen = iset_size(s); \ |
|
4814
|
|
|
|
|
|
|
int sign = iset_sign(s); \ |
|
4815
|
|
|
|
|
|
|
New(0, sdata, slen, UV); \ |
|
4816
|
|
|
|
|
|
|
iset_allvals(s, sdata); \ |
|
4817
|
|
|
|
|
|
|
iset_destroy(&s); \ |
|
4818
|
|
|
|
|
|
|
RETURN_LIST_REF( slen, sdata, sign ); \ |
|
4819
|
|
|
|
|
|
|
} |
|
4820
|
|
|
|
|
|
|
#define RETURN_EMPTY_SET_REF() RETURN_EMPTY_LIST_REF() |
|
4821
|
|
|
|
|
|
|
|
|
4822
|
|
|
|
|
|
|
void sumset(IN SV* sva, IN SV* svb = 0) |
|
4823
|
|
|
|
|
|
|
PROTOTYPE: $;$ |
|
4824
|
|
|
|
|
|
|
PREINIT: |
|
4825
|
|
|
|
|
|
|
int atype, btype, stype, sign; |
|
4826
|
|
|
|
|
|
|
UV *ra, *rb; |
|
4827
|
|
|
|
|
|
|
size_t alen, blen, i, j; |
|
4828
|
|
|
|
|
|
|
iset_t s; |
|
4829
|
|
|
|
|
|
|
PPCODE: |
|
4830
|
31
|
|
|
|
|
|
atype = arrayref_to_int_array(aTHX_ &alen, &ra, 1, sva, "sumset arg 1"); |
|
4831
|
31
|
100
|
|
|
|
|
if (svb == 0 || atype == IARR_TYPE_BAD) { |
|
|
|
50
|
|
|
|
|
|
|
4832
|
7
|
|
|
|
|
|
rb = ra; |
|
4833
|
7
|
|
|
|
|
|
blen = alen; |
|
4834
|
7
|
|
|
|
|
|
btype = atype; |
|
4835
|
|
|
|
|
|
|
} else { |
|
4836
|
24
|
|
|
|
|
|
btype = arrayref_to_int_array(aTHX_ &blen, &rb, 1, svb, "sumset arg 2"); |
|
4837
|
|
|
|
|
|
|
} |
|
4838
|
31
|
100
|
|
|
|
|
if (alen == 0 || blen == 0) { |
|
|
|
100
|
|
|
|
|
|
|
4839
|
2
|
50
|
|
|
|
|
if (rb != ra) Safefree(rb); |
|
4840
|
2
|
|
|
|
|
|
Safefree(ra); |
|
4841
|
2
|
|
|
|
|
|
RETURN_EMPTY_SET_REF(); |
|
4842
|
|
|
|
|
|
|
} |
|
4843
|
29
|
50
|
|
|
|
|
if (atype == IARR_TYPE_BAD || btype == IARR_TYPE_BAD) |
|
|
|
100
|
|
|
|
|
|
|
4844
|
1
|
|
|
|
|
|
stype = IARR_TYPE_BAD; |
|
4845
|
|
|
|
|
|
|
else |
|
4846
|
28
|
|
|
|
|
|
stype = type_of_sumset(atype, btype, ra[0],ra[alen-1], rb[0],rb[blen-1]); |
|
4847
|
29
|
100
|
|
|
|
|
if (stype == IARR_TYPE_BAD) { |
|
4848
|
11
|
50
|
|
|
|
|
if (rb != ra) Safefree(rb); |
|
4849
|
11
|
|
|
|
|
|
Safefree(ra); |
|
4850
|
11
|
|
|
|
|
|
DISPATCHPP(); |
|
4851
|
11
|
|
|
|
|
|
XSRETURN(1); |
|
4852
|
|
|
|
|
|
|
} |
|
4853
|
18
|
50
|
|
|
|
|
sign = IARR_TYPE_TO_STATUS(stype); |
|
|
|
100
|
|
|
|
|
|
|
4854
|
|
|
|
|
|
|
/* Sumset */ |
|
4855
|
18
|
|
|
|
|
|
s = iset_create( 10UL * (alen+blen) ); |
|
4856
|
143
|
100
|
|
|
|
|
for (i = 0; i < alen; i++) |
|
4857
|
2801
|
100
|
|
|
|
|
for (j = 0; j < blen; j++) |
|
4858
|
2676
|
|
|
|
|
|
iset_add(&s, ra[i]+rb[j], sign); |
|
4859
|
18
|
100
|
|
|
|
|
if (rb != ra) Safefree(rb); |
|
4860
|
18
|
|
|
|
|
|
Safefree(ra); |
|
4861
|
467
|
50
|
|
|
|
|
RETURN_SET_REF(s); |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
4862
|
|
|
|
|
|
|
|
|
4863
|
|
|
|
|
|
|
void setbinop(IN SV* block, IN SV* sva, IN SV* svb = 0) |
|
4864
|
|
|
|
|
|
|
PROTOTYPE: &$;$ |
|
4865
|
|
|
|
|
|
|
PREINIT: |
|
4866
|
|
|
|
|
|
|
int atype, btype; |
|
4867
|
|
|
|
|
|
|
UV *ra, *rb; |
|
4868
|
|
|
|
|
|
|
Size_t alen, blen; |
|
4869
|
|
|
|
|
|
|
CODE: |
|
4870
|
|
|
|
|
|
|
/* Must be CODE and not PPCODE */ |
|
4871
|
|
|
|
|
|
|
#if PERL_VERSION_GE(5,10,1) |
|
4872
|
26
|
|
|
|
|
|
atype = arrayref_to_int_array(aTHX_ &alen, &ra, 1, sva, "setbinop arg 1"); |
|
4873
|
26
|
100
|
|
|
|
|
if (svb == 0 || atype == IARR_TYPE_BAD) { |
|
|
|
50
|
|
|
|
|
|
|
4874
|
3
|
|
|
|
|
|
rb = ra; |
|
4875
|
3
|
|
|
|
|
|
blen = alen; |
|
4876
|
3
|
|
|
|
|
|
btype = atype; |
|
4877
|
|
|
|
|
|
|
} else { |
|
4878
|
23
|
|
|
|
|
|
btype = arrayref_to_int_array(aTHX_ &blen, &rb, 1, svb, "setbinop arg 2"); |
|
4879
|
|
|
|
|
|
|
} |
|
4880
|
26
|
100
|
|
|
|
|
if (alen == 0 || blen == 0) { |
|
|
|
50
|
|
|
|
|
|
|
4881
|
1
|
50
|
|
|
|
|
if (rb != ra) Safefree(rb); |
|
4882
|
1
|
|
|
|
|
|
Safefree(ra); |
|
4883
|
1
|
|
|
|
|
|
RETURN_EMPTY_SET_REF(); |
|
4884
|
|
|
|
|
|
|
} |
|
4885
|
25
|
50
|
|
|
|
|
if (atype != IARR_TYPE_BAD && btype != IARR_TYPE_BAD) { |
|
|
|
50
|
|
|
|
|
|
|
4886
|
|
|
|
|
|
|
iset_t s; |
|
4887
|
|
|
|
|
|
|
Size_t i, j; |
|
4888
|
|
|
|
|
|
|
GV *agv, *bgv; |
|
4889
|
|
|
|
|
|
|
SV *asv, *bsv; |
|
4890
|
|
|
|
|
|
|
UV ret; |
|
4891
|
|
|
|
|
|
|
CV *subcv; |
|
4892
|
25
|
|
|
|
|
|
int status = 0; |
|
4893
|
|
|
|
|
|
|
|
|
4894
|
25
|
50
|
|
|
|
|
SETSUBREF(subcv, block); |
|
4895
|
|
|
|
|
|
|
|
|
4896
|
25
|
|
|
|
|
|
agv = gv_fetchpv("a", GV_ADD, SVt_PV); |
|
4897
|
25
|
|
|
|
|
|
bgv = gv_fetchpv("b", GV_ADD, SVt_PV); |
|
4898
|
25
|
|
|
|
|
|
SAVESPTR(GvSV(agv)); |
|
4899
|
25
|
|
|
|
|
|
SAVESPTR(GvSV(bgv)); |
|
4900
|
25
|
|
|
|
|
|
asv = NEWSVINT(0,0); |
|
4901
|
25
|
|
|
|
|
|
bsv = NEWSVINT(0,0); |
|
4902
|
25
|
|
|
|
|
|
GvSV(agv) = asv; |
|
4903
|
25
|
|
|
|
|
|
GvSV(bgv) = bsv; |
|
4904
|
25
|
|
|
|
|
|
s = iset_create( 4UL * ((size_t)alen + (size_t)blen + 2) ); |
|
4905
|
|
|
|
|
|
|
#ifdef dMULTICALL |
|
4906
|
25
|
50
|
|
|
|
|
if (!CvISXSUB(subcv)) { |
|
4907
|
|
|
|
|
|
|
dMULTICALL; |
|
4908
|
25
|
|
|
|
|
|
I32 gimme = G_SCALAR; |
|
4909
|
25
|
|
|
|
|
|
DECL_MULTICALL_SCOPE(subcv); |
|
4910
|
25
|
50
|
|
|
|
|
PUSH_MULTICALL(subcv); |
|
4911
|
90
|
100
|
|
|
|
|
for (i = 0; i < alen; i++) { |
|
4912
|
300
|
100
|
|
|
|
|
for (j = 0; j < blen; j++) { |
|
4913
|
235
|
100
|
|
|
|
|
FASTSETSVINT(asv, atype == IARR_TYPE_POS, ra[i]); |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
4914
|
235
|
100
|
|
|
|
|
FASTSETSVINT(bsv, btype == IARR_TYPE_POS, rb[j]); |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
4915
|
235
|
50
|
|
|
|
|
SCOPED_MULTICALL; |
|
|
|
50
|
|
|
|
|
|
|
4916
|
235
|
|
|
|
|
|
status = _validate_and_set(&ret, aTHX_ *PL_stack_sp, IFLAG_ANY); |
|
4917
|
235
|
100
|
|
|
|
|
if (status != 0) iset_add(&s, ret, status); |
|
4918
|
235
|
100
|
|
|
|
|
if (status == 0 || iset_is_invalid(s)) break; |
|
|
|
100
|
|
|
|
|
|
|
4919
|
|
|
|
|
|
|
} |
|
4920
|
70
|
100
|
|
|
|
|
if (j < blen) break; |
|
4921
|
|
|
|
|
|
|
} |
|
4922
|
|
|
|
|
|
|
FIX_MULTICALL_REFCOUNT; |
|
4923
|
25
|
50
|
|
|
|
|
POP_MULTICALL; |
|
4924
|
|
|
|
|
|
|
} |
|
4925
|
|
|
|
|
|
|
else |
|
4926
|
|
|
|
|
|
|
#endif |
|
4927
|
|
|
|
|
|
|
{ |
|
4928
|
0
|
0
|
|
|
|
|
for (i = 0; i < alen; i++) { |
|
4929
|
0
|
0
|
|
|
|
|
for (j = 0; j < blen; j++) { |
|
4930
|
0
|
|
|
|
|
|
dSP; |
|
4931
|
0
|
0
|
|
|
|
|
FASTSETSVINT(asv, atype == IARR_TYPE_POS, ra[i]); |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
4932
|
0
|
0
|
|
|
|
|
FASTSETSVINT(bsv, btype == IARR_TYPE_POS, rb[j]); |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
4933
|
0
|
0
|
|
|
|
|
PUSHMARK(SP); |
|
4934
|
0
|
|
|
|
|
|
call_sv((SV*)subcv, G_SCALAR); |
|
4935
|
0
|
|
|
|
|
|
status = _validate_and_set(&ret, aTHX_ *PL_stack_sp, IFLAG_ANY); |
|
4936
|
0
|
0
|
|
|
|
|
if (status != 0) iset_add(&s, ret, status); |
|
4937
|
0
|
0
|
|
|
|
|
if (status == 0 || iset_is_invalid(s)) break; |
|
|
|
0
|
|
|
|
|
|
|
4938
|
|
|
|
|
|
|
} |
|
4939
|
0
|
0
|
|
|
|
|
if (j < blen) break; |
|
4940
|
|
|
|
|
|
|
} |
|
4941
|
|
|
|
|
|
|
} |
|
4942
|
|
|
|
|
|
|
/* asv and bsv are going to be freed with agv and bgv. */ |
|
4943
|
25
|
100
|
|
|
|
|
if (status != 0 && !iset_is_invalid(s)) { |
|
|
|
100
|
|
|
|
|
|
|
4944
|
20
|
100
|
|
|
|
|
if (rb != ra) Safefree(rb); |
|
4945
|
20
|
|
|
|
|
|
Safefree(ra); |
|
4946
|
176
|
50
|
|
|
|
|
RETURN_SET_REF(s); |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
4947
|
|
|
|
|
|
|
} |
|
4948
|
5
|
|
|
|
|
|
iset_destroy(&s); |
|
4949
|
|
|
|
|
|
|
} |
|
4950
|
5
|
50
|
|
|
|
|
if (rb != ra) Safefree(rb); |
|
4951
|
5
|
|
|
|
|
|
Safefree(ra); |
|
4952
|
|
|
|
|
|
|
#endif |
|
4953
|
5
|
|
|
|
|
|
DISPATCHPP(); |
|
4954
|
5
|
|
|
|
|
|
XSRETURN(1); |
|
4955
|
|
|
|
|
|
|
|
|
4956
|
|
|
|
|
|
|
void setunion(IN SV* sva, IN SV* svb) |
|
4957
|
|
|
|
|
|
|
PROTOTYPE: $$ |
|
4958
|
|
|
|
|
|
|
ALIAS: |
|
4959
|
|
|
|
|
|
|
setintersect = 1 |
|
4960
|
|
|
|
|
|
|
setminus = 2 |
|
4961
|
|
|
|
|
|
|
setdelta = 3 |
|
4962
|
|
|
|
|
|
|
PREINIT: |
|
4963
|
|
|
|
|
|
|
int atype, btype; |
|
4964
|
|
|
|
|
|
|
UV *ra, *rb; |
|
4965
|
|
|
|
|
|
|
size_t alen, blen; |
|
4966
|
|
|
|
|
|
|
PPCODE: |
|
4967
|
|
|
|
|
|
|
/* Fast path: both inputs are arrayrefs of native non-negative sorted |
|
4968
|
|
|
|
|
|
|
* unique integers. Merge SV* directly with SvREFCNT_inc, skipping |
|
4969
|
|
|
|
|
|
|
* intermediate UV array allocations and per-element newSVuv calls. */ |
|
4970
|
|
|
|
|
|
|
{ |
|
4971
|
|
|
|
|
|
|
size_t fa, fb; |
|
4972
|
56
|
|
|
|
|
|
SV **aa = _check_sorted_nonneg_arrayref(aTHX_ sva, &fa); |
|
4973
|
56
|
100
|
|
|
|
|
SV **bb = aa ? _check_sorted_nonneg_arrayref(aTHX_ svb, &fb) : NULL; |
|
4974
|
56
|
100
|
|
|
|
|
if (aa && bb) { |
|
|
|
100
|
|
|
|
|
|
|
4975
|
8
|
100
|
|
|
|
|
int inc_eq = (ix == 0 || ix == 1); /* union, intersect */ |
|
|
|
100
|
|
|
|
|
|
|
4976
|
8
|
|
|
|
|
|
int inc_lt = (ix != 1); /* union, minus, delta */ |
|
4977
|
8
|
100
|
|
|
|
|
int inc_gt = (ix == 0 || ix == 3); /* union, delta */ |
|
|
|
100
|
|
|
|
|
|
|
4978
|
8
|
100
|
|
|
|
|
size_t maxlen = (ix == 1) ? (fa < fb ? fa : fb) : fa + fb; |
|
4979
|
8
|
|
|
|
|
|
AV *res = newAV(); |
|
4980
|
8
|
|
|
|
|
|
size_t rlen = 0, ia = 0, ib = 0; |
|
4981
|
8
|
|
|
|
|
|
av_extend(res, (SSize_t)maxlen - 1); |
|
4982
|
8
|
|
|
|
|
|
SV **ar = AvARRAY(res); |
|
4983
|
32
|
100
|
|
|
|
|
while (ia < fa && ib < fb) { |
|
|
|
50
|
|
|
|
|
|
|
4984
|
24
|
|
|
|
|
|
UV va = SvUVX(aa[ia]), vb = SvUVX(bb[ib]); |
|
4985
|
24
|
100
|
|
|
|
|
if (va==vb) {if (inc_eq) ar[rlen++]=SvREFCNT_inc(aa[ia]); ia++; ib++;} |
|
|
|
100
|
|
|
|
|
|
|
4986
|
12
|
50
|
|
|
|
|
else if (va< vb) {if (inc_lt) ar[rlen++]=SvREFCNT_inc(aa[ia]); ia++;} |
|
|
|
100
|
|
|
|
|
|
|
4987
|
0
|
0
|
|
|
|
|
else {if (inc_gt) ar[rlen++]=SvREFCNT_inc(bb[ib]); ib++;} |
|
4988
|
|
|
|
|
|
|
} |
|
4989
|
8
|
100
|
|
|
|
|
if (inc_lt) while (ia < fa) ar[rlen++] = SvREFCNT_inc(aa[ia++]); |
|
|
|
50
|
|
|
|
|
|
|
4990
|
16
|
100
|
|
|
|
|
if (inc_gt) while (ib < fb) ar[rlen++] = SvREFCNT_inc(bb[ib++]); |
|
|
|
100
|
|
|
|
|
|
|
4991
|
8
|
|
|
|
|
|
AvFILLp(res) = (SSize_t)rlen - 1; |
|
4992
|
8
|
|
|
|
|
|
ST(0) = sv_2mortal(newRV_noinc((SV*)res)); |
|
4993
|
8
|
|
|
|
|
|
XSRETURN(1); |
|
4994
|
|
|
|
|
|
|
} |
|
4995
|
|
|
|
|
|
|
} |
|
4996
|
|
|
|
|
|
|
/* Get the integers and ensure they are sorted unique integers first. */ |
|
4997
|
48
|
|
|
|
|
|
atype = arrayref_to_int_array(aTHX_ &alen, &ra, 1, sva, SUBNAME); |
|
4998
|
48
|
|
|
|
|
|
btype = arrayref_to_int_array(aTHX_ &blen, &rb, 1, svb, SUBNAME); |
|
4999
|
|
|
|
|
|
|
|
|
5000
|
48
|
100
|
|
|
|
|
if (CAN_COMBINE_IARR_TYPES(atype,btype)) { |
|
5001
|
30
|
|
|
|
|
|
UV *r = 0; |
|
5002
|
30
|
|
|
|
|
|
size_t rlen = 0, ia = 0, ib = 0; |
|
5003
|
30
|
100
|
|
|
|
|
int pcmp = (atype == IARR_TYPE_NEG || btype == IARR_TYPE_NEG) ? 0 : 1; |
|
|
|
100
|
|
|
|
|
|
|
5004
|
|
|
|
|
|
|
|
|
5005
|
30
|
100
|
|
|
|
|
if (ix == 0) { /* union */ |
|
5006
|
8
|
50
|
|
|
|
|
New(0, r, alen + blen, UV); |
|
5007
|
40
|
100
|
|
|
|
|
while (ia < alen && ib < blen) { |
|
|
|
100
|
|
|
|
|
|
|
5008
|
32
|
100
|
|
|
|
|
if (ra[ia] == rb[ib]) { |
|
5009
|
9
|
|
|
|
|
|
r[rlen++] = ra[ia]; |
|
5010
|
9
|
|
|
|
|
|
ia++; ib++; |
|
5011
|
|
|
|
|
|
|
} else { |
|
5012
|
23
|
100
|
|
|
|
|
if (SIGNED_CMP_LT(pcmp, ra[ia], rb[ib])) r[rlen++] = ra[ia++]; |
|
|
|
100
|
|
|
|
|
|
|
5013
|
8
|
|
|
|
|
|
else r[rlen++] = rb[ib++]; |
|
5014
|
|
|
|
|
|
|
} |
|
5015
|
|
|
|
|
|
|
} |
|
5016
|
8
|
100
|
|
|
|
|
if (ia < alen) { Copy(ra+ia, r+rlen, alen-ia, UV); rlen += alen-ia; } |
|
|
|
50
|
|
|
|
|
|
|
5017
|
8
|
100
|
|
|
|
|
if (ib < blen) { Copy(rb+ib, r+rlen, blen-ib, UV); rlen += blen-ib; } |
|
|
|
50
|
|
|
|
|
|
|
5018
|
22
|
100
|
|
|
|
|
} else if (ix == 1) { /* intersect */ |
|
5019
|
7
|
50
|
|
|
|
|
New(0, r, (alen < blen) ? alen : blen, UV); |
|
5020
|
34
|
100
|
|
|
|
|
while (ia < alen && ib < blen) { |
|
|
|
100
|
|
|
|
|
|
|
5021
|
27
|
100
|
|
|
|
|
if (ra[ia] == rb[ib]) { |
|
5022
|
9
|
|
|
|
|
|
r[rlen++] = ra[ia]; |
|
5023
|
9
|
|
|
|
|
|
ia++; ib++; |
|
5024
|
|
|
|
|
|
|
} else { |
|
5025
|
18
|
100
|
|
|
|
|
if (SIGNED_CMP_LT(pcmp, ra[ia], rb[ib])) ia++; |
|
|
|
100
|
|
|
|
|
|
|
5026
|
6
|
|
|
|
|
|
else ib++; |
|
5027
|
|
|
|
|
|
|
} |
|
5028
|
|
|
|
|
|
|
} |
|
5029
|
15
|
100
|
|
|
|
|
} else if (ix == 2) { /* minus (difference) */ |
|
5030
|
7
|
50
|
|
|
|
|
New(0, r, alen, UV); |
|
5031
|
34
|
100
|
|
|
|
|
while (ia < alen && ib < blen) { |
|
|
|
100
|
|
|
|
|
|
|
5032
|
27
|
100
|
|
|
|
|
if (ra[ia] == rb[ib]) { |
|
5033
|
9
|
|
|
|
|
|
ia++; ib++; |
|
5034
|
|
|
|
|
|
|
} else { |
|
5035
|
18
|
100
|
|
|
|
|
if (SIGNED_CMP_LT(pcmp, ra[ia], rb[ib])) r[rlen++] = ra[ia++]; |
|
|
|
100
|
|
|
|
|
|
|
5036
|
6
|
|
|
|
|
|
else ib++; |
|
5037
|
|
|
|
|
|
|
} |
|
5038
|
|
|
|
|
|
|
} |
|
5039
|
7
|
100
|
|
|
|
|
if (ia < alen) { Copy(ra+ia, r+rlen, alen-ia, UV); rlen += alen-ia; } |
|
|
|
50
|
|
|
|
|
|
|
5040
|
8
|
50
|
|
|
|
|
} else if (ix == 3) { /* delta (symmetric difference) */ |
|
5041
|
8
|
50
|
|
|
|
|
New(0, r, alen + blen, UV); |
|
5042
|
39
|
100
|
|
|
|
|
while (ia < alen && ib < blen) { |
|
|
|
100
|
|
|
|
|
|
|
5043
|
31
|
100
|
|
|
|
|
if (ra[ia] == rb[ib]) { |
|
5044
|
11
|
|
|
|
|
|
ia++; ib++; |
|
5045
|
|
|
|
|
|
|
} else { |
|
5046
|
20
|
100
|
|
|
|
|
if (SIGNED_CMP_LT(pcmp, ra[ia], rb[ib])) r[rlen++] = ra[ia++]; |
|
|
|
100
|
|
|
|
|
|
|
5047
|
6
|
|
|
|
|
|
else r[rlen++] = rb[ib++]; |
|
5048
|
|
|
|
|
|
|
} |
|
5049
|
|
|
|
|
|
|
} |
|
5050
|
8
|
100
|
|
|
|
|
if (ia < alen) { Copy(ra+ia, r+rlen, alen-ia, UV); rlen += alen-ia; } |
|
|
|
50
|
|
|
|
|
|
|
5051
|
8
|
100
|
|
|
|
|
if (ib < blen) { Copy(rb+ib, r+rlen, blen-ib, UV); rlen += blen-ib; } |
|
|
|
50
|
|
|
|
|
|
|
5052
|
|
|
|
|
|
|
} |
|
5053
|
30
|
|
|
|
|
|
Safefree(ra); |
|
5054
|
30
|
|
|
|
|
|
Safefree(rb); |
|
5055
|
135
|
100
|
|
|
|
|
RETURN_LIST_REF(rlen, r, pcmp); |
|
|
|
100
|
|
|
|
|
|
|
5056
|
|
|
|
|
|
|
} |
|
5057
|
|
|
|
|
|
|
/* if (atype != IARR_TYPE_BAD && btype != IARR_TYPE_BAD) { .. isets .. } */ |
|
5058
|
18
|
|
|
|
|
|
Safefree(ra); |
|
5059
|
18
|
|
|
|
|
|
Safefree(rb); |
|
5060
|
18
|
|
|
|
|
|
DISPATCHPP(); |
|
5061
|
18
|
|
|
|
|
|
XSRETURN(1); |
|
5062
|
|
|
|
|
|
|
|
|
5063
|
|
|
|
|
|
|
void set_is_disjoint(IN SV* sva, IN SV* svb) |
|
5064
|
|
|
|
|
|
|
PROTOTYPE: $$ |
|
5065
|
|
|
|
|
|
|
ALIAS: |
|
5066
|
|
|
|
|
|
|
set_is_equal = 1 |
|
5067
|
|
|
|
|
|
|
set_is_subset = 2 |
|
5068
|
|
|
|
|
|
|
set_is_proper_subset = 3 |
|
5069
|
|
|
|
|
|
|
set_is_superset = 4 |
|
5070
|
|
|
|
|
|
|
set_is_proper_superset = 5 |
|
5071
|
|
|
|
|
|
|
set_is_proper_intersection = 6 |
|
5072
|
|
|
|
|
|
|
PREINIT: |
|
5073
|
|
|
|
|
|
|
int atype, btype, ret; |
|
5074
|
|
|
|
|
|
|
UV *ra, *rb; |
|
5075
|
|
|
|
|
|
|
size_t alen, blen, inalen, inblen; |
|
5076
|
|
|
|
|
|
|
PPCODE: |
|
5077
|
|
|
|
|
|
|
/* If one set is much smaller than the other, it would be faster using |
|
5078
|
|
|
|
|
|
|
* is_in_set(). We'll keep things simple and slurp in both sets. */ |
|
5079
|
|
|
|
|
|
|
|
|
5080
|
|
|
|
|
|
|
/* THIS ASSUMES THE INPUT LISTS HAVE NO DUPLICATES */ |
|
5081
|
90
|
|
|
|
|
|
inalen = inblen = 0; |
|
5082
|
90
|
50
|
|
|
|
|
if (SvROK(sva) && SvTYPE(SvRV(sva)) == SVt_PVAV && SvROK(svb) && SvTYPE(SvRV(svb)) == SVt_PVAV) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
5083
|
|
|
|
|
|
|
/* Shortcut on length if we can to skip intersection. */ |
|
5084
|
90
|
|
|
|
|
|
inalen = av_count((AV*) SvRV(sva)); |
|
5085
|
90
|
|
|
|
|
|
inblen = av_count((AV*) SvRV(svb)); |
|
5086
|
90
|
100
|
|
|
|
|
if ( (ix == 1 && inalen != inblen) || |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
5087
|
85
|
100
|
|
|
|
|
(ix == 2 && inalen < inblen) || (ix == 3 && inalen <= inblen) || |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
5088
|
78
|
100
|
|
|
|
|
(ix == 4 && inalen > inblen) || (ix == 5 && inalen >= inblen) ) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
5089
|
19
|
50
|
|
|
|
|
RETURN_NPARITY(0); |
|
|
|
50
|
|
|
|
|
|
|
5090
|
|
|
|
|
|
|
} |
|
5091
|
|
|
|
|
|
|
|
|
5092
|
|
|
|
|
|
|
/* Get the integers as sorted arrays of IV or UV */ |
|
5093
|
71
|
|
|
|
|
|
atype = arrayref_to_int_array(aTHX_ &alen, &ra, 1, sva, SUBNAME); |
|
5094
|
71
|
|
|
|
|
|
btype = arrayref_to_int_array(aTHX_ &blen, &rb, 1, svb, SUBNAME); |
|
5095
|
|
|
|
|
|
|
|
|
5096
|
71
|
100
|
|
|
|
|
if (CAN_COMBINE_IARR_TYPES(atype,btype)) { |
|
5097
|
57
|
|
|
|
|
|
size_t rlen = 0, ia = 0, ib = 0; |
|
5098
|
57
|
100
|
|
|
|
|
int pcmp = (atype == IARR_TYPE_NEG || btype == IARR_TYPE_NEG) ? 0 : 1; |
|
|
|
100
|
|
|
|
|
|
|
5099
|
|
|
|
|
|
|
|
|
5100
|
338
|
100
|
|
|
|
|
while (ia < alen && ib < blen) { |
|
|
|
100
|
|
|
|
|
|
|
5101
|
281
|
100
|
|
|
|
|
if (ra[ia] == rb[ib]) { |
|
5102
|
207
|
|
|
|
|
|
rlen++; |
|
5103
|
207
|
|
|
|
|
|
ia++; ib++; |
|
5104
|
|
|
|
|
|
|
} else { |
|
5105
|
74
|
100
|
|
|
|
|
if (SIGNED_CMP_LT(pcmp, ra[ia], rb[ib])) ia++; |
|
|
|
100
|
|
|
|
|
|
|
5106
|
30
|
|
|
|
|
|
else ib++; |
|
5107
|
|
|
|
|
|
|
} |
|
5108
|
|
|
|
|
|
|
} |
|
5109
|
57
|
|
|
|
|
|
Safefree(ra); |
|
5110
|
57
|
|
|
|
|
|
Safefree(rb); |
|
5111
|
57
|
|
|
|
|
|
ret = 0; |
|
5112
|
57
|
|
|
|
|
|
switch (ix) { |
|
5113
|
8
|
100
|
|
|
|
|
case 0: if (rlen == 0) ret = 1; break; |
|
5114
|
4
|
50
|
|
|
|
|
case 1: if (alen == blen && rlen == blen) ret = 1; break; |
|
|
|
100
|
|
|
|
|
|
|
5115
|
23
|
50
|
|
|
|
|
case 2: if (alen >= blen && rlen == blen) ret = 1; break; |
|
|
|
100
|
|
|
|
|
|
|
5116
|
3
|
50
|
|
|
|
|
case 3: if (alen > blen && rlen == blen) ret = 1; break; |
|
|
|
100
|
|
|
|
|
|
|
5117
|
7
|
50
|
|
|
|
|
case 4: if (alen <= blen && rlen == alen) ret = 1; break; |
|
|
|
100
|
|
|
|
|
|
|
5118
|
3
|
50
|
|
|
|
|
case 5: if (alen < blen && rlen == alen) ret = 1; break; |
|
|
|
100
|
|
|
|
|
|
|
5119
|
9
|
|
|
|
|
|
case 6: |
|
5120
|
9
|
100
|
|
|
|
|
default:if (rlen > 0 && rlen < alen && rlen < blen) ret = 1; break; |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
5121
|
|
|
|
|
|
|
} |
|
5122
|
57
|
50
|
|
|
|
|
RETURN_NPARITY(ret); |
|
|
|
50
|
|
|
|
|
|
|
5123
|
|
|
|
|
|
|
} |
|
5124
|
14
|
|
|
|
|
|
Safefree(ra); |
|
5125
|
14
|
|
|
|
|
|
Safefree(rb); |
|
5126
|
14
|
|
|
|
|
|
DISPATCHPP(); |
|
5127
|
14
|
|
|
|
|
|
XSRETURN(1); |
|
5128
|
|
|
|
|
|
|
|
|
5129
|
|
|
|
|
|
|
void setcontains(IN SV* sva, ...) |
|
5130
|
|
|
|
|
|
|
ALIAS: |
|
5131
|
|
|
|
|
|
|
setcontainsany = 1 |
|
5132
|
|
|
|
|
|
|
PROTOTYPE: $@ |
|
5133
|
|
|
|
|
|
|
PREINIT: |
|
5134
|
|
|
|
|
|
|
UV b; |
|
5135
|
|
|
|
|
|
|
AV *ava; |
|
5136
|
|
|
|
|
|
|
int bstatus, subset, findall; |
|
5137
|
|
|
|
|
|
|
Size_t alen, blen, i; |
|
5138
|
|
|
|
|
|
|
DECL_ARREF(arb); |
|
5139
|
|
|
|
|
|
|
PPCODE: |
|
5140
|
52
|
50
|
|
|
|
|
CHECK_ARRAYREF(sva); /* First argument is a set as array ref */ |
|
|
|
50
|
|
|
|
|
|
|
5141
|
52
|
|
|
|
|
|
ava = (AV*) SvRV(sva); |
|
5142
|
52
|
|
|
|
|
|
alen = av_count(ava); |
|
5143
|
52
|
50
|
|
|
|
|
if (items < 2) RETURN_NPARITY(1); |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
5144
|
52
|
50
|
|
|
|
|
if (SvMAGICAL(ava) || !AvREAL(ava)) { /* Punt these to Perl */ |
|
|
|
50
|
|
|
|
|
|
|
5145
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
5146
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
5147
|
|
|
|
|
|
|
} |
|
5148
|
52
|
|
|
|
|
|
findall = ix == 0 ? 1 : 0; |
|
5149
|
85
|
100
|
|
|
|
|
if (items == 2 && SvROK(ST(1)) && SvTYPE(SvRV(ST(1))) == SVt_PVAV) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
5150
|
|
|
|
|
|
|
set_data_t svcache; |
|
5151
|
33
|
50
|
|
|
|
|
USE_ARREF(arb, ST(1), SUBNAME, AR_READ); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
5152
|
|
|
|
|
|
|
/* If setcontainsany and B is bigger than A, swap them for performance. */ |
|
5153
|
33
|
100
|
|
|
|
|
if (ix == 1 && len_arb > alen && svarr_arb != 0) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
5154
|
1
|
|
|
|
|
|
ava = avp_arb; |
|
5155
|
1
|
|
|
|
|
|
alen = len_arb; |
|
5156
|
1
|
50
|
|
|
|
|
USE_ARREF(arb, ST(0), SUBNAME, AR_READ); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
5157
|
|
|
|
|
|
|
} |
|
5158
|
33
|
|
|
|
|
|
blen = len_arb; |
|
5159
|
33
|
100
|
|
|
|
|
subset = ix == 0 && blen > alen ? 0 : findall; |
|
|
|
100
|
|
|
|
|
|
|
5160
|
33
|
|
|
|
|
|
_sc_clear_cache(&svcache); |
|
5161
|
|
|
|
|
|
|
/* setcontains: if we find anything that is NOT in SETA, return 0 |
|
5162
|
|
|
|
|
|
|
* setcontainsany: if we find anything that IS in SETA, return 1 */ |
|
5163
|
88
|
100
|
|
|
|
|
for (i = 0; i < blen && subset == findall; i++) { |
|
|
|
100
|
|
|
|
|
|
|
5164
|
55
|
|
|
|
|
|
bstatus = _validate_and_set(&b, aTHX_ FETCH_ARREF(arb,i), IFLAG_ANY); |
|
5165
|
55
|
|
|
|
|
|
subset = is_in_set(aTHX_ ava, &svcache, bstatus, b); |
|
5166
|
|
|
|
|
|
|
} |
|
5167
|
|
|
|
|
|
|
} else { |
|
5168
|
|
|
|
|
|
|
UV *rb; |
|
5169
|
19
|
|
|
|
|
|
int btype = array_to_int_array(aTHX_ &blen, &rb, 1, &ST(1), items-1); |
|
5170
|
19
|
100
|
|
|
|
|
bstatus = IARR_TYPE_TO_STATUS(btype); |
|
|
|
100
|
|
|
|
|
|
|
5171
|
19
|
100
|
|
|
|
|
subset = bstatus == 0 ? -1 : ix == 0 && blen > alen ? 0 : findall; |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
5172
|
19
|
50
|
|
|
|
|
if (blen <= 4) { |
|
5173
|
36
|
100
|
|
|
|
|
for (i = 0; i < blen && subset == findall; i++) |
|
|
|
100
|
|
|
|
|
|
|
5174
|
17
|
|
|
|
|
|
subset = is_in_set(aTHX_ ava, 0, bstatus, rb[i]); |
|
5175
|
|
|
|
|
|
|
} else { |
|
5176
|
|
|
|
|
|
|
set_data_t svcache; |
|
5177
|
0
|
|
|
|
|
|
_sc_clear_cache(&svcache); |
|
5178
|
0
|
0
|
|
|
|
|
for (i = 0; i < blen && subset == findall; i++) |
|
|
|
0
|
|
|
|
|
|
|
5179
|
0
|
|
|
|
|
|
subset = is_in_set(aTHX_ ava, &svcache, bstatus, rb[i]); |
|
5180
|
|
|
|
|
|
|
} |
|
5181
|
19
|
|
|
|
|
|
Safefree(rb); |
|
5182
|
|
|
|
|
|
|
} |
|
5183
|
52
|
100
|
|
|
|
|
if (subset != -1) |
|
5184
|
40
|
50
|
|
|
|
|
RETURN_NPARITY(subset); |
|
|
|
50
|
|
|
|
|
|
|
5185
|
12
|
|
|
|
|
|
DISPATCHPP(); |
|
5186
|
12
|
|
|
|
|
|
XSRETURN(1); |
|
5187
|
|
|
|
|
|
|
|
|
5188
|
|
|
|
|
|
|
void setinsert(IN SV* sva, ...) |
|
5189
|
|
|
|
|
|
|
PROTOTYPE: $@ |
|
5190
|
|
|
|
|
|
|
PREINIT: |
|
5191
|
|
|
|
|
|
|
AV *ava; |
|
5192
|
|
|
|
|
|
|
Size_t alen, blen, i; |
|
5193
|
|
|
|
|
|
|
UV *rb; |
|
5194
|
|
|
|
|
|
|
int btype, bstatus; |
|
5195
|
|
|
|
|
|
|
PPCODE: |
|
5196
|
40
|
50
|
|
|
|
|
CHECK_ARRAYREF(sva); /* First argument is a set as array ref */ |
|
|
|
50
|
|
|
|
|
|
|
5197
|
40
|
|
|
|
|
|
ava = (AV*) SvRV(sva); |
|
5198
|
40
|
|
|
|
|
|
alen = av_count(ava); |
|
5199
|
40
|
100
|
|
|
|
|
if (items < 2) |
|
5200
|
2
|
50
|
|
|
|
|
RETURN_NPARITY(0); |
|
|
|
50
|
|
|
|
|
|
|
5201
|
38
|
50
|
|
|
|
|
CHECK_AV_NOT_READONLY(ava); /* We intend to modify it */ |
|
5202
|
38
|
50
|
|
|
|
|
if (SvMAGICAL(ava) || !AvREAL(ava)) { /* Punt these to Perl */ |
|
|
|
50
|
|
|
|
|
|
|
5203
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
5204
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
5205
|
|
|
|
|
|
|
} |
|
5206
|
|
|
|
|
|
|
|
|
5207
|
38
|
100
|
|
|
|
|
if (SvROK(ST(1)) && SvTYPE(SvRV(ST(1))) == SVt_PVAV) { |
|
|
|
50
|
|
|
|
|
|
|
5208
|
13
|
50
|
|
|
|
|
if (items != 2) |
|
5209
|
0
|
|
|
|
|
|
croak("setinsert: expected integer list or single array reference"); |
|
5210
|
13
|
|
|
|
|
|
btype = arrayref_to_int_array(aTHX_ &blen, &rb, 1, ST(1), "setinsert"); |
|
5211
|
|
|
|
|
|
|
} else { |
|
5212
|
25
|
|
|
|
|
|
btype = array_to_int_array(aTHX_ &blen, &rb, 1, &ST(1), items-1); |
|
5213
|
|
|
|
|
|
|
} |
|
5214
|
38
|
100
|
|
|
|
|
bstatus = IARR_TYPE_TO_STATUS(btype); |
|
|
|
100
|
|
|
|
|
|
|
5215
|
|
|
|
|
|
|
|
|
5216
|
38
|
100
|
|
|
|
|
if (bstatus != 0 && blen <= 4) { |
|
|
|
100
|
|
|
|
|
|
|
5217
|
34
|
|
|
|
|
|
int res = 0; |
|
5218
|
34
|
|
|
|
|
|
size_t nins = 0; |
|
5219
|
78
|
50
|
|
|
|
|
for (i = 0; res >= 0 && i < blen; i++) { |
|
|
|
100
|
|
|
|
|
|
|
5220
|
44
|
|
|
|
|
|
res = ins_into_set(aTHX_ ava, bstatus, rb[i]); |
|
5221
|
44
|
|
|
|
|
|
nins += (res > 0); |
|
5222
|
|
|
|
|
|
|
} |
|
5223
|
34
|
50
|
|
|
|
|
if (res >= 0) { Safefree(rb); RETURN_NPARITY(nins); } |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
5224
|
4
|
100
|
|
|
|
|
} else if (bstatus != 0) { |
|
5225
|
|
|
|
|
|
|
size_t nbeg, nmid, nend, nmidcheck; |
|
5226
|
|
|
|
|
|
|
int alostatus, ahistatus; |
|
5227
|
|
|
|
|
|
|
UV alo, ahi; |
|
5228
|
|
|
|
|
|
|
set_data_t svcache; |
|
5229
|
|
|
|
|
|
|
|
|
5230
|
|
|
|
|
|
|
/* 1. ava is empty. push everything and we're done. */ |
|
5231
|
3
|
50
|
|
|
|
|
if (alen == 0) { |
|
5232
|
0
|
|
|
|
|
|
av_extend(ava, blen); |
|
5233
|
0
|
0
|
|
|
|
|
for (i = 0; i < blen; i++) |
|
5234
|
0
|
0
|
|
|
|
|
av_push(ava, NEWSVINT(bstatus, rb[i])); |
|
5235
|
0
|
|
|
|
|
|
Safefree(rb); |
|
5236
|
3
|
0
|
|
|
|
|
RETURN_NPARITY(blen); |
|
|
|
0
|
|
|
|
|
|
|
5237
|
|
|
|
|
|
|
} |
|
5238
|
3
|
|
|
|
|
|
_sc_clear_cache(&svcache); |
|
5239
|
|
|
|
|
|
|
/* Get hi and lo values of set. */ |
|
5240
|
3
|
50
|
|
|
|
|
if (_sc_set_lohi(aTHX_ AvARRAY(ava), &svcache, 0, alen-1, &alostatus, &ahistatus, &alo, &ahi) >= 0) { |
|
5241
|
3
|
50
|
|
|
|
|
if (_sign_cmp(alostatus,alo,ahistatus,ahi) > 0) |
|
5242
|
0
|
|
|
|
|
|
croak("%s: expected numerically ascending sorted input", SUBNAME); |
|
5243
|
|
|
|
|
|
|
/* Both lo/hi are not bigint, so there are no bigints in the set. */ |
|
5244
|
3
|
|
|
|
|
|
nbeg = nend = nmid = 0; |
|
5245
|
|
|
|
|
|
|
/* 1. Find out how many elements go in front. */ |
|
5246
|
10
|
50
|
|
|
|
|
while (nbeg < blen && _sign_cmp(bstatus,rb[nbeg],alostatus,alo) < 0) |
|
|
|
100
|
|
|
|
|
|
|
5247
|
7
|
|
|
|
|
|
nbeg++; |
|
5248
|
|
|
|
|
|
|
/* 2. Find out how many elements go at the end. */ |
|
5249
|
509
|
100
|
|
|
|
|
while (nend < blen-nbeg && _sign_cmp(bstatus,rb[blen-1-nend],ahistatus,ahi) > 0) |
|
|
|
100
|
|
|
|
|
|
|
5250
|
506
|
|
|
|
|
|
nend++; |
|
5251
|
|
|
|
|
|
|
/* 3. In-place insert everything in the middle. */ |
|
5252
|
3
|
|
|
|
|
|
nmidcheck = blen - nbeg - nend; |
|
5253
|
3
|
100
|
|
|
|
|
if (nmidcheck > 0) { |
|
5254
|
|
|
|
|
|
|
size_t *insert_idx; |
|
5255
|
|
|
|
|
|
|
SV **insert_sv; |
|
5256
|
2
|
50
|
|
|
|
|
New(0, insert_idx, nmidcheck, size_t); |
|
5257
|
2
|
50
|
|
|
|
|
New(0, insert_sv, nmidcheck, SV*); |
|
5258
|
17
|
50
|
|
|
|
|
for (i = nbeg; bstatus != 0 && i < blen-nend; i++) { |
|
|
|
100
|
|
|
|
|
|
|
5259
|
15
|
|
|
|
|
|
int index = insert_index_in_set(aTHX_ ava,&svcache,bstatus,rb[i]); |
|
5260
|
15
|
50
|
|
|
|
|
if (index < 0) |
|
5261
|
0
|
|
|
|
|
|
croak("%s: expected sorted input, found bigint value in interior", SUBNAME); |
|
5262
|
15
|
100
|
|
|
|
|
if (index > 0) { |
|
5263
|
4
|
50
|
|
|
|
|
insert_sv[nmid] = NEWSVINT(bstatus,rb[i]);/* Value to insert */ |
|
5264
|
4
|
|
|
|
|
|
insert_idx[nmid] = index-1; /* Where to insert */ |
|
5265
|
4
|
|
|
|
|
|
nmid++; |
|
5266
|
|
|
|
|
|
|
} |
|
5267
|
|
|
|
|
|
|
} |
|
5268
|
2
|
|
|
|
|
|
av_extend(ava, alen + nmid + nbeg + nend); |
|
5269
|
2
|
100
|
|
|
|
|
if (nmid > 0) { |
|
5270
|
|
|
|
|
|
|
SV** arr; |
|
5271
|
1
|
|
|
|
|
|
unsigned long index_lastorig = alen-1; |
|
5272
|
1
|
|
|
|
|
|
unsigned long index_moveto = index_lastorig + nmid; |
|
5273
|
|
|
|
|
|
|
|
|
5274
|
|
|
|
|
|
|
/* Push new values on end so Perl calculates array correctly. */ |
|
5275
|
5
|
100
|
|
|
|
|
for (i = 0; i < nmid; i++) |
|
5276
|
4
|
|
|
|
|
|
av_push(ava, insert_sv[i]); |
|
5277
|
1
|
|
|
|
|
|
arr = AvARRAY(ava); |
|
5278
|
|
|
|
|
|
|
/* SV* pointer manipulation to insert new values in place. */ |
|
5279
|
5
|
100
|
|
|
|
|
for (i = 0; i < nmid; i++) { |
|
5280
|
4
|
|
|
|
|
|
size_t j = nmid-1-i; |
|
5281
|
4
|
|
|
|
|
|
size_t idx = insert_idx[j]; |
|
5282
|
4
|
|
|
|
|
|
size_t nmove = index_lastorig - idx + 1; |
|
5283
|
4
|
100
|
|
|
|
|
if (nmove > 0) { |
|
5284
|
2
|
|
|
|
|
|
size_t moveto = index_moveto - nmove + 1; |
|
5285
|
2
|
|
|
|
|
|
memmove(arr+moveto, arr+idx, sizeof(SV*) * nmove); |
|
5286
|
2
|
|
|
|
|
|
index_lastorig -= nmove; |
|
5287
|
2
|
|
|
|
|
|
index_moveto -= nmove; |
|
5288
|
|
|
|
|
|
|
} |
|
5289
|
4
|
|
|
|
|
|
arr[index_moveto--] = insert_sv[j]; |
|
5290
|
|
|
|
|
|
|
} |
|
5291
|
|
|
|
|
|
|
} |
|
5292
|
2
|
|
|
|
|
|
Safefree(insert_sv); |
|
5293
|
2
|
|
|
|
|
|
Safefree(insert_idx); |
|
5294
|
|
|
|
|
|
|
} |
|
5295
|
|
|
|
|
|
|
/* 4. Insert at front */ |
|
5296
|
3
|
100
|
|
|
|
|
if (nbeg > 0) { |
|
5297
|
2
|
|
|
|
|
|
av_unshift(ava, nbeg); |
|
5298
|
9
|
100
|
|
|
|
|
for (i = 0; i < nbeg; i++) |
|
5299
|
7
|
100
|
|
|
|
|
av_store(ava, i, NEWSVINT(bstatus, rb[i])); |
|
5300
|
|
|
|
|
|
|
} |
|
5301
|
|
|
|
|
|
|
/* 5. Push onto back */ |
|
5302
|
3
|
50
|
|
|
|
|
if (nend > 0) { |
|
5303
|
509
|
100
|
|
|
|
|
for (i = 0; i < nend; i++) |
|
5304
|
506
|
100
|
|
|
|
|
av_push(ava, NEWSVINT(bstatus, rb[blen-nend+i])); |
|
5305
|
|
|
|
|
|
|
} |
|
5306
|
3
|
|
|
|
|
|
Safefree(rb); |
|
5307
|
3
|
50
|
|
|
|
|
RETURN_NPARITY(nbeg+nmid+nend); |
|
|
|
100
|
|
|
|
|
|
|
5308
|
|
|
|
|
|
|
} |
|
5309
|
|
|
|
|
|
|
} |
|
5310
|
1
|
|
|
|
|
|
Safefree(rb); |
|
5311
|
1
|
|
|
|
|
|
DISPATCHPP(); |
|
5312
|
1
|
|
|
|
|
|
XSRETURN(1); |
|
5313
|
|
|
|
|
|
|
|
|
5314
|
|
|
|
|
|
|
void setremove(IN SV* sva, ...) |
|
5315
|
|
|
|
|
|
|
PROTOTYPE: $@ |
|
5316
|
|
|
|
|
|
|
PREINIT: |
|
5317
|
|
|
|
|
|
|
AV *ava; |
|
5318
|
|
|
|
|
|
|
Size_t alen, blen, i; |
|
5319
|
|
|
|
|
|
|
UV *rb; |
|
5320
|
|
|
|
|
|
|
int btype, bstatus; |
|
5321
|
|
|
|
|
|
|
PPCODE: |
|
5322
|
12
|
50
|
|
|
|
|
CHECK_ARRAYREF(sva); /* First argument is a set as array ref */ |
|
|
|
50
|
|
|
|
|
|
|
5323
|
12
|
|
|
|
|
|
ava = (AV*) SvRV(sva); |
|
5324
|
12
|
|
|
|
|
|
alen = av_count(ava); |
|
5325
|
12
|
100
|
|
|
|
|
if (alen == 0 || items < 2) |
|
|
|
50
|
|
|
|
|
|
|
5326
|
2
|
50
|
|
|
|
|
RETURN_NPARITY(0); |
|
|
|
50
|
|
|
|
|
|
|
5327
|
10
|
50
|
|
|
|
|
CHECK_AV_NOT_READONLY(ava); /* We intend to modify it */ |
|
5328
|
10
|
50
|
|
|
|
|
if (SvMAGICAL(ava) || !AvREAL(ava)) { /* Punt these to Perl */ |
|
|
|
50
|
|
|
|
|
|
|
5329
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
5330
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
5331
|
|
|
|
|
|
|
} |
|
5332
|
10
|
100
|
|
|
|
|
if (SvROK(ST(1)) && SvTYPE(SvRV(ST(1))) == SVt_PVAV) { |
|
|
|
50
|
|
|
|
|
|
|
5333
|
7
|
50
|
|
|
|
|
if (items != 2) |
|
5334
|
0
|
|
|
|
|
|
croak("setremove: expected integer list or single array reference"); |
|
5335
|
7
|
|
|
|
|
|
btype = arrayref_to_int_array(aTHX_ &blen, &rb, 1, ST(1), "setremove"); |
|
5336
|
|
|
|
|
|
|
} else { |
|
5337
|
3
|
|
|
|
|
|
btype = array_to_int_array(aTHX_ &blen, &rb, 1, &ST(1), items-1); |
|
5338
|
|
|
|
|
|
|
} |
|
5339
|
10
|
50
|
|
|
|
|
if (btype != IARR_TYPE_BAD) { |
|
5340
|
10
|
50
|
|
|
|
|
bstatus = IARR_TYPE_TO_STATUS(btype); |
|
|
|
100
|
|
|
|
|
|
|
5341
|
10
|
50
|
|
|
|
|
if (blen <= 5 || alen <= 20) { /* SIMPLE DELETE LOOP */ |
|
|
|
0
|
|
|
|
|
|
|
5342
|
10
|
|
|
|
|
|
int res = 0; |
|
5343
|
10
|
|
|
|
|
|
size_t ndel = 0; |
|
5344
|
25
|
50
|
|
|
|
|
for (i = 0; res >= 0 && i < blen; i++) { |
|
|
|
100
|
|
|
|
|
|
|
5345
|
15
|
|
|
|
|
|
res = del_from_set(aTHX_ ava, bstatus, rb[i]); |
|
5346
|
15
|
100
|
|
|
|
|
if (res > 0) ndel++; |
|
5347
|
|
|
|
|
|
|
} |
|
5348
|
10
|
50
|
|
|
|
|
if (res >= 0) { Safefree(rb); RETURN_NPARITY(ndel); } |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
5349
|
0
|
0
|
|
|
|
|
} else if (blen < 500 || (blen*100) < alen) { /* ONE PASS DELETE */ |
|
|
|
0
|
|
|
|
|
|
|
5350
|
0
|
|
|
|
|
|
Size_t *del_idx, ndel = 0; |
|
5351
|
|
|
|
|
|
|
set_data_t svcache; |
|
5352
|
0
|
|
|
|
|
|
_sc_clear_cache(&svcache); |
|
5353
|
|
|
|
|
|
|
/* Create index list to remove */ |
|
5354
|
0
|
0
|
|
|
|
|
New(0, del_idx, blen, Size_t); |
|
5355
|
0
|
0
|
|
|
|
|
for (i = 0; i < blen; i++) { |
|
5356
|
0
|
|
|
|
|
|
int index = index_in_set(aTHX_ ava, &svcache, bstatus, rb[i]); |
|
5357
|
0
|
0
|
|
|
|
|
if (index < 0) |
|
5358
|
0
|
|
|
|
|
|
croak("%s: expected sorted input, found bigint value in interior", SUBNAME); |
|
5359
|
0
|
0
|
|
|
|
|
if (index > 0) |
|
5360
|
0
|
|
|
|
|
|
del_idx[ndel++] = index-1; |
|
5361
|
|
|
|
|
|
|
} |
|
5362
|
0
|
|
|
|
|
|
Safefree(rb); |
|
5363
|
0
|
0
|
|
|
|
|
if (ndel > 0) { |
|
5364
|
0
|
|
|
|
|
|
SV **arr = AvARRAY(ava); |
|
5365
|
0
|
|
|
|
|
|
size_t to = del_idx[0]; |
|
5366
|
0
|
0
|
|
|
|
|
for (i = 0; i < ndel; i++) { |
|
5367
|
0
|
|
|
|
|
|
size_t idx = del_idx[i]; |
|
5368
|
0
|
|
|
|
|
|
size_t beg = idx+1; |
|
5369
|
0
|
0
|
|
|
|
|
size_t len = (i+1) >= ndel ? alen-beg : del_idx[i+1]-beg; |
|
5370
|
0
|
|
|
|
|
|
SvREFCNT_dec_NN(arr[idx]); |
|
5371
|
0
|
0
|
|
|
|
|
if (len > 0) { |
|
5372
|
0
|
|
|
|
|
|
memmove(arr+to, arr+beg, sizeof(SV*) * len); |
|
5373
|
0
|
|
|
|
|
|
to += len; |
|
5374
|
|
|
|
|
|
|
} |
|
5375
|
|
|
|
|
|
|
} |
|
5376
|
0
|
0
|
|
|
|
|
Zero(arr + alen - ndel, ndel, SV*); |
|
5377
|
0
|
|
|
|
|
|
av_fill(ava, alen-ndel-1); |
|
5378
|
|
|
|
|
|
|
} |
|
5379
|
0
|
|
|
|
|
|
Safefree(del_idx); |
|
5380
|
0
|
0
|
|
|
|
|
RETURN_NPARITY(ndel); |
|
|
|
0
|
|
|
|
|
|
|
5381
|
|
|
|
|
|
|
} else { /* CLEAR AND GREP */ |
|
5382
|
0
|
|
|
|
|
|
int atype, astatus, del_complete = 0; |
|
5383
|
0
|
|
|
|
|
|
UV *ra = 0; |
|
5384
|
0
|
|
|
|
|
|
atype = arrayref_to_int_array(aTHX_ &alen, &ra, 1, sva, SUBNAME); |
|
5385
|
0
|
0
|
|
|
|
|
if (CAN_COMBINE_IARR_TYPES(atype,btype)) { |
|
5386
|
0
|
|
|
|
|
|
size_t ia = 0, ib = 0; |
|
5387
|
0
|
0
|
|
|
|
|
int pcmp = (atype == IARR_TYPE_NEG || btype == IARR_TYPE_NEG) ? 0 : 1; |
|
|
|
0
|
|
|
|
|
|
|
5388
|
|
|
|
|
|
|
|
|
5389
|
0
|
0
|
|
|
|
|
astatus = IARR_TYPE_TO_STATUS(atype); |
|
|
|
0
|
|
|
|
|
|
|
5390
|
0
|
|
|
|
|
|
av_clear(ava); |
|
5391
|
0
|
0
|
|
|
|
|
while (ia < alen && ib < blen) { |
|
|
|
0
|
|
|
|
|
|
|
5392
|
0
|
0
|
|
|
|
|
if (ra[ia] == rb[ib]) { |
|
5393
|
0
|
|
|
|
|
|
ia++; ib++; |
|
5394
|
|
|
|
|
|
|
} else { |
|
5395
|
0
|
0
|
|
|
|
|
if (SIGNED_CMP_LT(pcmp, ra[ia], rb[ib])) av_push(ava, NEWSVINT(astatus, ra[ia++])); |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
5396
|
0
|
|
|
|
|
|
else ib++; |
|
5397
|
|
|
|
|
|
|
} |
|
5398
|
|
|
|
|
|
|
} |
|
5399
|
0
|
0
|
|
|
|
|
while (ia < alen) av_push(ava, NEWSVINT(astatus, ra[ia++])); |
|
|
|
0
|
|
|
|
|
|
|
5400
|
0
|
|
|
|
|
|
del_complete = 1; |
|
5401
|
|
|
|
|
|
|
} |
|
5402
|
0
|
|
|
|
|
|
Safefree(ra); |
|
5403
|
0
|
|
|
|
|
|
Safefree(rb); |
|
5404
|
0
|
0
|
|
|
|
|
if (del_complete) RETURN_NPARITY(alen - av_count(ava)); |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
5405
|
|
|
|
|
|
|
} |
|
5406
|
|
|
|
|
|
|
} |
|
5407
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
5408
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
5409
|
|
|
|
|
|
|
|
|
5410
|
|
|
|
|
|
|
|
|
5411
|
|
|
|
|
|
|
void setinvert(IN SV* sva, ...) |
|
5412
|
|
|
|
|
|
|
PROTOTYPE: $@ |
|
5413
|
|
|
|
|
|
|
PREINIT: |
|
5414
|
|
|
|
|
|
|
AV *ava; |
|
5415
|
|
|
|
|
|
|
Size_t alen, blen, i; |
|
5416
|
|
|
|
|
|
|
UV *rb; |
|
5417
|
|
|
|
|
|
|
int btype, bstatus; |
|
5418
|
|
|
|
|
|
|
PPCODE: |
|
5419
|
12
|
50
|
|
|
|
|
CHECK_ARRAYREF(sva); |
|
|
|
50
|
|
|
|
|
|
|
5420
|
12
|
|
|
|
|
|
ava = (AV*) SvRV(sva); |
|
5421
|
12
|
|
|
|
|
|
alen = av_count(ava); |
|
5422
|
12
|
100
|
|
|
|
|
if (items < 2) |
|
5423
|
2
|
50
|
|
|
|
|
RETURN_NPARITY(0); |
|
|
|
50
|
|
|
|
|
|
|
5424
|
10
|
50
|
|
|
|
|
CHECK_AV_NOT_READONLY(ava); |
|
5425
|
10
|
50
|
|
|
|
|
if (SvMAGICAL(ava) || !AvREAL(ava)) { |
|
|
|
50
|
|
|
|
|
|
|
5426
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
5427
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
5428
|
|
|
|
|
|
|
} |
|
5429
|
10
|
100
|
|
|
|
|
if (SvROK(ST(1)) && SvTYPE(SvRV(ST(1))) == SVt_PVAV) { |
|
|
|
50
|
|
|
|
|
|
|
5430
|
5
|
50
|
|
|
|
|
if (items != 2) |
|
5431
|
0
|
|
|
|
|
|
croak("setinvert: expected integer list or single array reference"); |
|
5432
|
5
|
|
|
|
|
|
btype = arrayref_to_int_array(aTHX_ &blen, &rb, 1, ST(1), "setinvert"); |
|
5433
|
|
|
|
|
|
|
} else { |
|
5434
|
5
|
|
|
|
|
|
btype = array_to_int_array(aTHX_ &blen, &rb, 1, &ST(1), items-1); |
|
5435
|
|
|
|
|
|
|
} |
|
5436
|
10
|
50
|
|
|
|
|
if (btype != IARR_TYPE_BAD) { |
|
5437
|
10
|
100
|
|
|
|
|
if (blen == 0) { |
|
5438
|
2
|
|
|
|
|
|
Safefree(rb); |
|
5439
|
2
|
50
|
|
|
|
|
RETURN_NPARITY(0); |
|
|
|
50
|
|
|
|
|
|
|
5440
|
|
|
|
|
|
|
} |
|
5441
|
8
|
50
|
|
|
|
|
bstatus = IARR_TYPE_TO_STATUS(btype); |
|
|
|
100
|
|
|
|
|
|
|
5442
|
8
|
50
|
|
|
|
|
if (blen <= 4 || alen <= 20) { /* SIMPLE TOGGLE LOOP */ |
|
|
|
0
|
|
|
|
|
|
|
5443
|
8
|
|
|
|
|
|
IV ndelta = 0; |
|
5444
|
8
|
|
|
|
|
|
int res = 0; |
|
5445
|
26
|
50
|
|
|
|
|
for (i = 0; res >= 0 && i < blen; i++) { |
|
|
|
100
|
|
|
|
|
|
|
5446
|
18
|
|
|
|
|
|
res = del_from_set(aTHX_ ava, bstatus, rb[i]); |
|
5447
|
18
|
100
|
|
|
|
|
if (res > 0) { ndelta--; } /* found and removed */ |
|
5448
|
5
|
50
|
|
|
|
|
else if (res == 0) { /* not found, insert */ |
|
5449
|
5
|
|
|
|
|
|
res = ins_into_set(aTHX_ ava, bstatus, rb[i]); |
|
5450
|
5
|
50
|
|
|
|
|
if (res > 0) ndelta++; |
|
5451
|
|
|
|
|
|
|
} |
|
5452
|
|
|
|
|
|
|
} |
|
5453
|
8
|
50
|
|
|
|
|
if (res >= 0) { |
|
5454
|
8
|
|
|
|
|
|
Safefree(rb); |
|
5455
|
8
|
|
|
|
|
|
ST(0) = sv_2mortal(newSViv(ndelta)); |
|
5456
|
8
|
|
|
|
|
|
XSRETURN(1); |
|
5457
|
|
|
|
|
|
|
} |
|
5458
|
|
|
|
|
|
|
} else { /* MERGE-STYLE SYMMETRIC DIFFERENCE */ |
|
5459
|
0
|
|
|
|
|
|
int atype, astatus, done = 0; |
|
5460
|
0
|
|
|
|
|
|
UV *ra = 0; |
|
5461
|
0
|
|
|
|
|
|
Size_t old_alen = alen; |
|
5462
|
0
|
|
|
|
|
|
atype = arrayref_to_int_array(aTHX_ &alen, &ra, 1, sva, SUBNAME); |
|
5463
|
0
|
0
|
|
|
|
|
if (CAN_COMBINE_IARR_TYPES(atype, btype)) { |
|
5464
|
0
|
|
|
|
|
|
size_t ia = 0, ib = 0; |
|
5465
|
0
|
0
|
|
|
|
|
int pcmp = (atype == IARR_TYPE_NEG || btype == IARR_TYPE_NEG) ? 0 : 1; |
|
|
|
0
|
|
|
|
|
|
|
5466
|
0
|
0
|
|
|
|
|
astatus = IARR_TYPE_TO_STATUS(atype); |
|
|
|
0
|
|
|
|
|
|
|
5467
|
0
|
|
|
|
|
|
av_clear(ava); |
|
5468
|
0
|
0
|
|
|
|
|
while (ia < alen && ib < blen) { |
|
|
|
0
|
|
|
|
|
|
|
5469
|
0
|
0
|
|
|
|
|
if (ra[ia] == rb[ib]) { ia++; ib++; } |
|
5470
|
0
|
0
|
|
|
|
|
else if (SIGNED_CMP_LT(pcmp, ra[ia], rb[ib])) av_push(ava, NEWSVINT(astatus, ra[ia++])); |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
5471
|
0
|
0
|
|
|
|
|
else av_push(ava, NEWSVINT(bstatus, rb[ib++])); |
|
5472
|
|
|
|
|
|
|
} |
|
5473
|
0
|
0
|
|
|
|
|
while (ia < alen) av_push(ava, NEWSVINT(astatus, ra[ia++])); |
|
|
|
0
|
|
|
|
|
|
|
5474
|
0
|
0
|
|
|
|
|
while (ib < blen) av_push(ava, NEWSVINT(bstatus, rb[ib++])); |
|
|
|
0
|
|
|
|
|
|
|
5475
|
0
|
|
|
|
|
|
done = 1; |
|
5476
|
|
|
|
|
|
|
} |
|
5477
|
0
|
|
|
|
|
|
Safefree(ra); |
|
5478
|
0
|
0
|
|
|
|
|
if (done) { |
|
5479
|
0
|
|
|
|
|
|
Safefree(rb); |
|
5480
|
0
|
|
|
|
|
|
ST(0) = sv_2mortal(newSViv((IV)av_count(ava) - (IV)old_alen)); |
|
5481
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
5482
|
|
|
|
|
|
|
} |
|
5483
|
|
|
|
|
|
|
} |
|
5484
|
|
|
|
|
|
|
} |
|
5485
|
0
|
|
|
|
|
|
Safefree(rb); |
|
5486
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
5487
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
5488
|
|
|
|
|
|
|
|
|
5489
|
|
|
|
|
|
|
|
|
5490
|
|
|
|
|
|
|
void is_sidon_set(IN SV* sva) |
|
5491
|
|
|
|
|
|
|
PROTOTYPE: $ |
|
5492
|
|
|
|
|
|
|
PREINIT: |
|
5493
|
|
|
|
|
|
|
int itype, is_sidon; |
|
5494
|
|
|
|
|
|
|
size_t len, i, j; |
|
5495
|
|
|
|
|
|
|
UV *data; |
|
5496
|
|
|
|
|
|
|
iset_t s; |
|
5497
|
|
|
|
|
|
|
PPCODE: |
|
5498
|
19
|
|
|
|
|
|
itype = arrayref_to_int_array(aTHX_ &len, &data, 1, sva,"is_sidon_set"); |
|
5499
|
19
|
100
|
|
|
|
|
if (itype == IARR_TYPE_NEG) { /* All elements must be non-negative. */ |
|
5500
|
3
|
|
|
|
|
|
Safefree(data); |
|
5501
|
3
|
50
|
|
|
|
|
RETURN_NPARITY(0); |
|
|
|
50
|
|
|
|
|
|
|
5502
|
|
|
|
|
|
|
} |
|
5503
|
|
|
|
|
|
|
/* If any bigints or we cannot add the values in 64-bits, call PP. */ |
|
5504
|
16
|
50
|
|
|
|
|
if (itype == IARR_TYPE_BAD || itype == IARR_TYPE_POS) { |
|
|
|
100
|
|
|
|
|
|
|
5505
|
1
|
|
|
|
|
|
Safefree(data); |
|
5506
|
1
|
|
|
|
|
|
DISPATCHPP(); |
|
5507
|
1
|
|
|
|
|
|
XSRETURN(1); |
|
5508
|
|
|
|
|
|
|
} |
|
5509
|
|
|
|
|
|
|
/* Check if the set is a Sidon set. */ |
|
5510
|
15
|
|
|
|
|
|
is_sidon = 1; |
|
5511
|
15
|
|
|
|
|
|
s = iset_create( 20UL * len ); |
|
5512
|
128
|
100
|
|
|
|
|
for (i = 0; i < len && is_sidon; i++) |
|
|
|
100
|
|
|
|
|
|
|
5513
|
2397
|
100
|
|
|
|
|
for (j = i; j < len; j++) |
|
5514
|
2288
|
100
|
|
|
|
|
if (!iset_add(&s, data[i] + data[j], 1)) |
|
5515
|
4
|
|
|
|
|
|
{ is_sidon = 0; break; } |
|
5516
|
15
|
|
|
|
|
|
Safefree(data); |
|
5517
|
15
|
|
|
|
|
|
iset_destroy(&s); |
|
5518
|
15
|
50
|
|
|
|
|
RETURN_NPARITY(is_sidon); |
|
|
|
50
|
|
|
|
|
|
|
5519
|
|
|
|
|
|
|
|
|
5520
|
|
|
|
|
|
|
void is_sumfree_set(IN SV* sva) |
|
5521
|
|
|
|
|
|
|
PROTOTYPE: $ |
|
5522
|
|
|
|
|
|
|
PREINIT: |
|
5523
|
|
|
|
|
|
|
UV *data; |
|
5524
|
|
|
|
|
|
|
size_t len, i, j; |
|
5525
|
|
|
|
|
|
|
int itype; |
|
5526
|
|
|
|
|
|
|
bool is_sumfree; |
|
5527
|
|
|
|
|
|
|
PPCODE: |
|
5528
|
35
|
|
|
|
|
|
itype = arrayref_to_int_array(aTHX_ &len, &data,1,sva,"is_sumfree_set"); |
|
5529
|
35
|
50
|
|
|
|
|
if (itype != IARR_TYPE_BAD && len <= 1) { /* Degenerate cases: len 0 or 1 */ |
|
|
|
100
|
|
|
|
|
|
|
5530
|
5
|
100
|
|
|
|
|
is_sumfree = len == 0 || data[0] != 0; |
|
|
|
100
|
|
|
|
|
|
|
5531
|
5
|
|
|
|
|
|
Safefree(data); |
|
5532
|
5
|
50
|
|
|
|
|
RETURN_NPARITY(is_sumfree); |
|
|
|
50
|
|
|
|
|
|
|
5533
|
|
|
|
|
|
|
} |
|
5534
|
|
|
|
|
|
|
/* Check for IV overflow on sum */ |
|
5535
|
30
|
100
|
|
|
|
|
if (itype == IARR_TYPE_NEG) { |
|
5536
|
9
|
|
|
|
|
|
IV min = data[0], max = data[len-1]; /* Array is sorted */ |
|
5537
|
9
|
100
|
|
|
|
|
if (min < IV_MIN/2 || max > IV_MAX/2) itype = IARR_TYPE_BAD; |
|
|
|
50
|
|
|
|
|
|
|
5538
|
|
|
|
|
|
|
} |
|
5539
|
30
|
|
|
|
|
|
is_sumfree = 1; |
|
5540
|
30
|
100
|
|
|
|
|
if (itype == IARR_TYPE_ANY) { |
|
5541
|
71
|
100
|
|
|
|
|
for (i = 0; i < len && is_sumfree; i++) |
|
|
|
100
|
|
|
|
|
|
|
5542
|
168
|
100
|
|
|
|
|
for (j = i; j < len; j++) |
|
5543
|
126
|
100
|
|
|
|
|
if (is_in_sorted_uv_array(data[i]+data[j], data, len)) |
|
5544
|
9
|
|
|
|
|
|
{ is_sumfree = 0; break; } |
|
5545
|
10
|
100
|
|
|
|
|
} else if (itype == IARR_TYPE_NEG) { |
|
5546
|
24
|
100
|
|
|
|
|
for (i = 0; i < len && is_sumfree; i++) |
|
|
|
100
|
|
|
|
|
|
|
5547
|
48
|
100
|
|
|
|
|
for (j = i; j < len; j++) |
|
5548
|
35
|
100
|
|
|
|
|
if (is_in_sorted_iv_array((IV)data[i]+(IV)data[j], (IV*)data, len)) |
|
5549
|
3
|
|
|
|
|
|
{ is_sumfree = 0; break; } |
|
5550
|
|
|
|
|
|
|
} |
|
5551
|
30
|
|
|
|
|
|
Safefree(data); |
|
5552
|
|
|
|
|
|
|
|
|
5553
|
30
|
100
|
|
|
|
|
if (itype == IARR_TYPE_ANY || itype == IARR_TYPE_NEG) |
|
|
|
100
|
|
|
|
|
|
|
5554
|
28
|
50
|
|
|
|
|
RETURN_NPARITY(is_sumfree); |
|
|
|
50
|
|
|
|
|
|
|
5555
|
|
|
|
|
|
|
|
|
5556
|
|
|
|
|
|
|
/* We're here because one of: |
|
5557
|
|
|
|
|
|
|
* 1) itype is TYPE_BAD because there were bigints. |
|
5558
|
|
|
|
|
|
|
* 2) itype is TYPE_BAD because summed IVs would overflow. |
|
5559
|
|
|
|
|
|
|
* 3) itype is TYPE_POS. |
|
5560
|
|
|
|
|
|
|
* At least one element is >= 2^63, so we would overflow on sum. |
|
5561
|
|
|
|
|
|
|
*/ |
|
5562
|
2
|
|
|
|
|
|
DISPATCHPP(); |
|
5563
|
2
|
|
|
|
|
|
XSRETURN(1); |
|
5564
|
|
|
|
|
|
|
|
|
5565
|
|
|
|
|
|
|
void toset(...) |
|
5566
|
|
|
|
|
|
|
PROTOTYPE: @ |
|
5567
|
|
|
|
|
|
|
PREINIT: |
|
5568
|
|
|
|
|
|
|
int type; |
|
5569
|
|
|
|
|
|
|
size_t len; |
|
5570
|
|
|
|
|
|
|
UV *L; |
|
5571
|
|
|
|
|
|
|
PPCODE: |
|
5572
|
77
|
100
|
|
|
|
|
if (items == 0) RETURN_EMPTY_SET_REF(); |
|
5573
|
73
|
|
|
|
|
|
type = array_to_int_array(aTHX_ &len, &L, 1, &ST(0), items); |
|
5574
|
73
|
100
|
|
|
|
|
if (type != IARR_TYPE_BAD) |
|
5575
|
299
|
100
|
|
|
|
|
RETURN_LIST_REF(len, L, type != IARR_TYPE_NEG); |
|
|
|
100
|
|
|
|
|
|
|
5576
|
32
|
|
|
|
|
|
Safefree(L); |
|
5577
|
32
|
|
|
|
|
|
DISPATCHPP(); |
|
5578
|
32
|
|
|
|
|
|
XSRETURN(1); |
|
5579
|
|
|
|
|
|
|
|
|
5580
|
|
|
|
|
|
|
|
|
5581
|
|
|
|
|
|
|
void vecsort(...) |
|
5582
|
|
|
|
|
|
|
PROTOTYPE: @ |
|
5583
|
|
|
|
|
|
|
PREINIT: |
|
5584
|
|
|
|
|
|
|
int type; |
|
5585
|
|
|
|
|
|
|
size_t len; |
|
5586
|
|
|
|
|
|
|
UV *L; |
|
5587
|
|
|
|
|
|
|
PPCODE: |
|
5588
|
87
|
100
|
|
|
|
|
if (items == 0) |
|
5589
|
1
|
|
|
|
|
|
XSRETURN_EMPTY; |
|
5590
|
86
|
100
|
|
|
|
|
if (SvROK(ST(0)) && SvTYPE(SvRV(ST(0))) == SVt_PVAV) { |
|
|
|
100
|
|
|
|
|
|
|
5591
|
9
|
50
|
|
|
|
|
if (items != 1) |
|
5592
|
0
|
|
|
|
|
|
croak("vecsort: expected integer list or single array reference"); |
|
5593
|
9
|
|
|
|
|
|
type = arrayref_to_int_array(aTHX_ &len, &L, 0, ST(0), "vecsort"); |
|
5594
|
|
|
|
|
|
|
} else { |
|
5595
|
77
|
|
|
|
|
|
type = array_to_int_array(aTHX_ &len, &L, 0, &ST(0), items); |
|
5596
|
|
|
|
|
|
|
} |
|
5597
|
86
|
100
|
|
|
|
|
if (GIMME_V != G_ARRAY) /* In scalar context, return number of elements */ |
|
5598
|
3
|
|
|
|
|
|
XSRETURN_UV(len); |
|
5599
|
83
|
100
|
|
|
|
|
if (type == IARR_TYPE_ANY || type == IARR_TYPE_POS) { |
|
|
|
100
|
|
|
|
|
|
|
5600
|
62
|
|
|
|
|
|
sort_uv_array(L, len); |
|
5601
|
21
|
100
|
|
|
|
|
} else if (type == IARR_TYPE_NEG) { |
|
5602
|
1
|
|
|
|
|
|
sort_iv_array((IV*)L, len); |
|
5603
|
|
|
|
|
|
|
} else { |
|
5604
|
20
|
|
|
|
|
|
Safefree(L); |
|
5605
|
20
|
|
|
|
|
|
DISPATCHPP(); |
|
5606
|
20
|
|
|
|
|
|
return; |
|
5607
|
|
|
|
|
|
|
} |
|
5608
|
451
|
50
|
|
|
|
|
RETURN_LIST_VALS( len, L, (type != IARR_TYPE_NEG) ); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
5609
|
|
|
|
|
|
|
|
|
5610
|
|
|
|
|
|
|
void vecsorti(IN SV* sva) |
|
5611
|
|
|
|
|
|
|
PROTOTYPE: $ |
|
5612
|
|
|
|
|
|
|
PREINIT: |
|
5613
|
|
|
|
|
|
|
int type; |
|
5614
|
|
|
|
|
|
|
size_t i, len; |
|
5615
|
|
|
|
|
|
|
UV *L; |
|
5616
|
|
|
|
|
|
|
SV **arr; |
|
5617
|
|
|
|
|
|
|
AV *ava; |
|
5618
|
|
|
|
|
|
|
PPCODE: |
|
5619
|
32
|
50
|
|
|
|
|
CHECK_ARRAYREF(sva); |
|
|
|
50
|
|
|
|
|
|
|
5620
|
32
|
|
|
|
|
|
ava = (AV*) SvRV(sva); |
|
5621
|
32
|
50
|
|
|
|
|
CHECK_AV_NOT_READONLY(ava); /* We intend to modify it */ |
|
5622
|
32
|
50
|
|
|
|
|
if (SvMAGICAL(ava) || !AvREAL(ava)) { /* Punt these to Perl */ |
|
|
|
50
|
|
|
|
|
|
|
5623
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
5624
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
5625
|
|
|
|
|
|
|
} |
|
5626
|
32
|
|
|
|
|
|
type = arrayref_to_int_array(aTHX_ &len, &L, 0, sva, "vecsorti"); |
|
5627
|
|
|
|
|
|
|
/* If we really wanted to optimize small values, the reading function |
|
5628
|
|
|
|
|
|
|
* could create a mask like: |
|
5629
|
|
|
|
|
|
|
* mask |= (istatus == 1) ? n : (n ^ (n<<1)); |
|
5630
|
|
|
|
|
|
|
* then we know if the input is 8-bit, 16-bit, 32-bit, etc. |
|
5631
|
|
|
|
|
|
|
*/ |
|
5632
|
32
|
100
|
|
|
|
|
if (type == IARR_TYPE_ANY || type == IARR_TYPE_POS) { |
|
|
|
100
|
|
|
|
|
|
|
5633
|
7
|
|
|
|
|
|
sort_uv_array(L, len); |
|
5634
|
25
|
50
|
|
|
|
|
} else if (type == IARR_TYPE_NEG) { |
|
5635
|
0
|
|
|
|
|
|
sort_iv_array((IV*)L, len); |
|
5636
|
|
|
|
|
|
|
} else { |
|
5637
|
25
|
|
|
|
|
|
Safefree(L); |
|
5638
|
25
|
|
|
|
|
|
DISPATCHPP(); |
|
5639
|
25
|
|
|
|
|
|
XSRETURN(1); |
|
5640
|
|
|
|
|
|
|
} |
|
5641
|
7
|
|
|
|
|
|
arr = AvARRAY(ava); |
|
5642
|
25
|
100
|
|
|
|
|
for (i = 0; i < len; i++) |
|
5643
|
18
|
100
|
|
|
|
|
FASTSETSVINT(arr[i], type == IARR_TYPE_POS, L[i]); |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
5644
|
7
|
|
|
|
|
|
Safefree(L); |
|
5645
|
7
|
|
|
|
|
|
XSRETURN(1); |
|
5646
|
|
|
|
|
|
|
|
|
5647
|
|
|
|
|
|
|
|
|
5648
|
|
|
|
|
|
|
void numtoperm(IN UV n, IN SV* svk) |
|
5649
|
|
|
|
|
|
|
PREINIT: |
|
5650
|
|
|
|
|
|
|
UV k; |
|
5651
|
|
|
|
|
|
|
int i, S[32]; |
|
5652
|
|
|
|
|
|
|
PPCODE: |
|
5653
|
6
|
100
|
|
|
|
|
if (n == 0) |
|
5654
|
1
|
|
|
|
|
|
XSRETURN_EMPTY; |
|
5655
|
5
|
50
|
|
|
|
|
if (n < 32 && _validate_and_set(&k, aTHX_ svk, IFLAG_ABS) == 1) { |
|
|
|
50
|
|
|
|
|
|
|
5656
|
5
|
50
|
|
|
|
|
if (num_to_perm(k, n, S)) { |
|
5657
|
|
|
|
|
|
|
dMY_CXT; |
|
5658
|
5
|
50
|
|
|
|
|
EXTEND(SP, (EXTEND_TYPE)n); |
|
|
|
50
|
|
|
|
|
|
|
5659
|
50
|
100
|
|
|
|
|
for (i = 0; i < (int)n; i++) |
|
5660
|
45
|
50
|
|
|
|
|
PUSH_NPARITY( S[i] ); |
|
|
|
50
|
|
|
|
|
|
|
5661
|
5
|
|
|
|
|
|
XSRETURN(n); |
|
5662
|
|
|
|
|
|
|
} |
|
5663
|
|
|
|
|
|
|
} |
|
5664
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
5665
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
5666
|
|
|
|
|
|
|
|
|
5667
|
|
|
|
|
|
|
void permtonum(IN SV* svp) |
|
5668
|
|
|
|
|
|
|
PREINIT: |
|
5669
|
|
|
|
|
|
|
UV val, num; |
|
5670
|
|
|
|
|
|
|
Size_t i, plen; |
|
5671
|
|
|
|
|
|
|
DECL_ARREF(avp); |
|
5672
|
|
|
|
|
|
|
PPCODE: |
|
5673
|
6
|
50
|
|
|
|
|
USE_ARREF(avp, svp, SUBNAME, AR_READ); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
5674
|
6
|
|
|
|
|
|
plen = len_avp; |
|
5675
|
6
|
100
|
|
|
|
|
if (plen <= 20) { |
|
5676
|
5
|
|
|
|
|
|
int V[21], A[21] = {0}; |
|
5677
|
47
|
100
|
|
|
|
|
for (i = 0; i < plen; i++) { |
|
5678
|
42
|
|
|
|
|
|
SV *iv = FETCH_ARREF(avp,i); |
|
5679
|
42
|
50
|
|
|
|
|
if (_validate_and_set(&val, aTHX_ iv, IFLAG_POS) != 1) |
|
5680
|
0
|
|
|
|
|
|
break; |
|
5681
|
42
|
50
|
|
|
|
|
if (val >= plen || A[val] != 0) break; |
|
|
|
50
|
|
|
|
|
|
|
5682
|
42
|
|
|
|
|
|
A[val] = i+1; |
|
5683
|
42
|
|
|
|
|
|
V[i] = val; |
|
5684
|
|
|
|
|
|
|
} |
|
5685
|
5
|
50
|
|
|
|
|
if (i >= plen && perm_to_num(plen, V, &num)) |
|
|
|
100
|
|
|
|
|
|
|
5686
|
4
|
|
|
|
|
|
XSRETURN_UV(num); |
|
5687
|
|
|
|
|
|
|
} |
|
5688
|
2
|
|
|
|
|
|
DISPATCHPP(); |
|
5689
|
2
|
|
|
|
|
|
objectify_result(aTHX_ svp, ST(0)); |
|
5690
|
2
|
|
|
|
|
|
XSRETURN(1); |
|
5691
|
|
|
|
|
|
|
|
|
5692
|
|
|
|
|
|
|
void randperm(IN UV n, IN UV k = 0) |
|
5693
|
|
|
|
|
|
|
PREINIT: |
|
5694
|
|
|
|
|
|
|
UV i, *S; |
|
5695
|
|
|
|
|
|
|
dMY_CXT; |
|
5696
|
|
|
|
|
|
|
PPCODE: |
|
5697
|
75
|
100
|
|
|
|
|
if (items == 1) k = n; |
|
5698
|
75
|
100
|
|
|
|
|
if (k > n) k = n; |
|
5699
|
75
|
100
|
|
|
|
|
if (k == 0) XSRETURN_EMPTY; |
|
5700
|
73
|
50
|
|
|
|
|
New(0, S, k, UV); |
|
5701
|
73
|
|
|
|
|
|
randperm(MY_CXT.randcxt, n, k, S); |
|
5702
|
73
|
50
|
|
|
|
|
EXTEND(SP, (EXTEND_TYPE)k); |
|
|
|
50
|
|
|
|
|
|
|
5703
|
662
|
100
|
|
|
|
|
for (i = 0; i < k; i++) { |
|
5704
|
589
|
100
|
|
|
|
|
if (n < 2*CINTS) PUSH_NPARITY(S[i]); |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
5705
|
106
|
|
|
|
|
|
else PUSHs(sv_2mortal(newSVuv(S[i]))); |
|
5706
|
|
|
|
|
|
|
} |
|
5707
|
73
|
|
|
|
|
|
Safefree(S); |
|
5708
|
|
|
|
|
|
|
|
|
5709
|
|
|
|
|
|
|
void shuffle(...) |
|
5710
|
|
|
|
|
|
|
PROTOTYPE: @ |
|
5711
|
|
|
|
|
|
|
PREINIT: |
|
5712
|
|
|
|
|
|
|
SSize_t i, j; |
|
5713
|
|
|
|
|
|
|
void* randcxt; |
|
5714
|
|
|
|
|
|
|
dMY_CXT; |
|
5715
|
|
|
|
|
|
|
PPCODE: |
|
5716
|
31
|
100
|
|
|
|
|
if (items == 0) |
|
5717
|
1
|
|
|
|
|
|
XSRETURN_EMPTY; |
|
5718
|
713
|
100
|
|
|
|
|
for (i = 0, randcxt = MY_CXT.randcxt; i < items-1; i++) { |
|
5719
|
683
|
|
|
|
|
|
j = urandomm64(randcxt, items-i); |
|
5720
|
683
|
|
|
|
|
|
{ SV* t = ST(i); ST(i) = ST(i+j); ST(i+j) = t; } |
|
5721
|
|
|
|
|
|
|
} |
|
5722
|
30
|
|
|
|
|
|
XSRETURN(items); |
|
5723
|
|
|
|
|
|
|
|
|
5724
|
|
|
|
|
|
|
void vecsample(IN SV* svk, ...) |
|
5725
|
|
|
|
|
|
|
PROTOTYPE: $@ |
|
5726
|
|
|
|
|
|
|
PREINIT: |
|
5727
|
|
|
|
|
|
|
void *randcxt; |
|
5728
|
|
|
|
|
|
|
UV k; |
|
5729
|
|
|
|
|
|
|
Size_t nitems, i; |
|
5730
|
|
|
|
|
|
|
dMY_CXT; |
|
5731
|
|
|
|
|
|
|
PPCODE: |
|
5732
|
28
|
100
|
|
|
|
|
if (items == 1) |
|
5733
|
6
|
|
|
|
|
|
XSRETURN_EMPTY; |
|
5734
|
22
|
|
|
|
|
|
randcxt = MY_CXT.randcxt; |
|
5735
|
|
|
|
|
|
|
/* |
|
5736
|
|
|
|
|
|
|
* Fisher-Yates shuffle with first 'k' selections returned. |
|
5737
|
|
|
|
|
|
|
* |
|
5738
|
|
|
|
|
|
|
* There is only one algorithm here, no shortcuts other than |
|
5739
|
|
|
|
|
|
|
* detecting an empty list. |
|
5740
|
|
|
|
|
|
|
* |
|
5741
|
|
|
|
|
|
|
* With a list input, the input is on the stack ST(1),ST(2),... |
|
5742
|
|
|
|
|
|
|
* We move the last item to ST(0) then shuffle 'k' iterations. |
|
5743
|
|
|
|
|
|
|
* |
|
5744
|
|
|
|
|
|
|
* With an array reference input, we cannot modify the input at all. |
|
5745
|
|
|
|
|
|
|
* We create an index array and shuffle using that. Remembering to |
|
5746
|
|
|
|
|
|
|
* act like the last item is at the front so we match the list results. |
|
5747
|
|
|
|
|
|
|
* We optimize by pushing each selection onto the return stack as |
|
5748
|
|
|
|
|
|
|
* we find it rather than pushing them all at the end with another loop. |
|
5749
|
|
|
|
|
|
|
*/ |
|
5750
|
22
|
100
|
|
|
|
|
if (items > 2 || !SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
5751
|
|
|
|
|
|
|
/* Standard form, where we are given an array of items */ |
|
5752
|
7
|
|
|
|
|
|
nitems = items-1; |
|
5753
|
7
|
50
|
|
|
|
|
if (_validate_and_set(&k, aTHX_ svk, IFLAG_POS) == 0 || k > nitems) |
|
|
|
50
|
|
|
|
|
|
|
5754
|
0
|
|
|
|
|
|
k = nitems; |
|
5755
|
7
|
|
|
|
|
|
ST(0) = ST(items-1); /* Move last value to the first stack entry. */ |
|
5756
|
10019
|
100
|
|
|
|
|
for (i = 0; i < k; i++) { |
|
5757
|
10012
|
|
|
|
|
|
uint32_t j = urandomm32(randcxt, nitems-i); |
|
5758
|
10012
|
|
|
|
|
|
{ SV* t = ST(i); ST(i) = ST(i+j); ST(i+j) = t; } |
|
5759
|
|
|
|
|
|
|
} |
|
5760
|
|
|
|
|
|
|
} else { /* We are given a single array reference. Select from it. */ |
|
5761
|
|
|
|
|
|
|
DECL_ARREF(avp); |
|
5762
|
15
|
50
|
|
|
|
|
USE_ARREF(avp, ST(1), SUBNAME, AR_READ); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
5763
|
15
|
|
|
|
|
|
nitems = len_avp; |
|
5764
|
|
|
|
|
|
|
|
|
5765
|
15
|
50
|
|
|
|
|
if (_validate_and_set(&k, aTHX_ svk, IFLAG_POS) == 0 || k > nitems) |
|
|
|
100
|
|
|
|
|
|
|
5766
|
3
|
|
|
|
|
|
k = nitems; |
|
5767
|
15
|
100
|
|
|
|
|
if (k == 0) |
|
5768
|
3
|
|
|
|
|
|
XSRETURN_EMPTY; |
|
5769
|
12
|
50
|
|
|
|
|
if (nitems < 65536) { |
|
5770
|
|
|
|
|
|
|
uint16_t *I; |
|
5771
|
12
|
50
|
|
|
|
|
New(0, I, nitems, uint16_t); |
|
5772
|
85
|
100
|
|
|
|
|
I[0] = nitems-1; for (i = 1; i < nitems; i++) I[i] = i-1; |
|
5773
|
12
|
50
|
|
|
|
|
EXTEND(SP, (EXTEND_TYPE)k); |
|
|
|
50
|
|
|
|
|
|
|
5774
|
42
|
100
|
|
|
|
|
for (i = 0; i < k; i++) { |
|
5775
|
30
|
|
|
|
|
|
uint32_t j = urandomm32(randcxt, nitems-i); |
|
5776
|
30
|
|
|
|
|
|
uint16_t t = I[i+j]; I[i+j] = I[i]; |
|
5777
|
30
|
|
|
|
|
|
PUSHs(FETCH_ARREF(avp,t)); |
|
5778
|
|
|
|
|
|
|
} |
|
5779
|
12
|
|
|
|
|
|
Safefree(I); |
|
5780
|
|
|
|
|
|
|
} else { |
|
5781
|
|
|
|
|
|
|
size_t *I; |
|
5782
|
0
|
0
|
|
|
|
|
New(0, I, nitems, size_t); |
|
5783
|
0
|
0
|
|
|
|
|
I[0] = nitems-1; for (i = 1; i < nitems; i++) I[i] = i-1; |
|
5784
|
0
|
0
|
|
|
|
|
EXTEND(SP, (EXTEND_TYPE)k); |
|
|
|
0
|
|
|
|
|
|
|
5785
|
0
|
0
|
|
|
|
|
for (i = 0; i < k; i++) { |
|
5786
|
0
|
|
|
|
|
|
size_t j = urandomm64(randcxt, nitems-i); |
|
5787
|
0
|
|
|
|
|
|
size_t t = I[i+j]; I[i+j] = I[i]; |
|
5788
|
0
|
|
|
|
|
|
PUSHs(FETCH_ARREF(avp,t)); |
|
5789
|
|
|
|
|
|
|
} |
|
5790
|
0
|
|
|
|
|
|
Safefree(I); |
|
5791
|
|
|
|
|
|
|
} |
|
5792
|
|
|
|
|
|
|
} |
|
5793
|
19
|
|
|
|
|
|
XSRETURN(k); |
|
5794
|
|
|
|
|
|
|
|
|
5795
|
|
|
|
|
|
|
void is_happy(SV* svn, UV base = 10, UV k = 2) |
|
5796
|
|
|
|
|
|
|
PREINIT: |
|
5797
|
|
|
|
|
|
|
UV n, sum; |
|
5798
|
|
|
|
|
|
|
int h, status; |
|
5799
|
|
|
|
|
|
|
PPCODE: |
|
5800
|
4974
|
50
|
|
|
|
|
if (base < 2 || base > 36) croak("is_happy: invalid base %"UVuf, base); |
|
|
|
50
|
|
|
|
|
|
|
5801
|
4974
|
50
|
|
|
|
|
if (k > 10) croak("is_happy: invalid exponent %"UVuf, k); |
|
5802
|
4974
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, IFLAG_POS); |
|
5803
|
4974
|
100
|
|
|
|
|
if (status == 0 && base == 10) { /* String op to reduce into range. */ |
|
|
|
50
|
|
|
|
|
|
|
5804
|
|
|
|
|
|
|
STRLEN i, len; |
|
5805
|
14
|
|
|
|
|
|
const char* s = SvPV(svn, len); |
|
5806
|
14
|
50
|
|
|
|
|
if (len <= UV_MAX/ipow(9,k)) { |
|
5807
|
1316
|
100
|
|
|
|
|
for (sum = 0, i = 0; i < len; i++) |
|
5808
|
1302
|
|
|
|
|
|
sum += ipow(s[i]-'0',k); |
|
5809
|
14
|
|
|
|
|
|
h = happy_height(sum, base, k); |
|
5810
|
14
|
50
|
|
|
|
|
RETURN_NPARITY( (h>0) ? h+1 : 0); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
5811
|
|
|
|
|
|
|
} |
|
5812
|
|
|
|
|
|
|
} |
|
5813
|
4960
|
50
|
|
|
|
|
if (status != 0) |
|
5814
|
4960
|
50
|
|
|
|
|
RETURN_NPARITY(happy_height(n, base, k)); |
|
|
|
50
|
|
|
|
|
|
|
5815
|
0
|
|
|
|
|
|
DISPATCHPP(); |
|
5816
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
5817
|
|
|
|
|
|
|
|
|
5818
|
|
|
|
|
|
|
void |
|
5819
|
|
|
|
|
|
|
sumdigits(SV* svn, UV ibase = 255) |
|
5820
|
|
|
|
|
|
|
PREINIT: |
|
5821
|
|
|
|
|
|
|
UV base, sum; |
|
5822
|
|
|
|
|
|
|
STRLEN i, len; |
|
5823
|
|
|
|
|
|
|
const char* s; |
|
5824
|
|
|
|
|
|
|
PPCODE: |
|
5825
|
1007
|
50
|
|
|
|
|
base = (ibase == 255) ? 10 : ibase; |
|
5826
|
1007
|
50
|
|
|
|
|
if (base < 2 || base > 36) croak("sumdigits: invalid base %"UVuf, base); |
|
|
|
50
|
|
|
|
|
|
|
5827
|
1007
|
|
|
|
|
|
sum = 0; |
|
5828
|
|
|
|
|
|
|
/* faster for integer input in base 10 */ |
|
5829
|
1007
|
50
|
|
|
|
|
if (base == 10 && SVNUMTEST(svn) && (SvIsUV(svn) || SvIVX(svn) >= 0)) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
5830
|
1001
|
|
|
|
|
|
UV n, t = my_svuv(svn); |
|
5831
|
3894
|
100
|
|
|
|
|
while ((n=t)) { |
|
5832
|
2893
|
|
|
|
|
|
t = n / base; |
|
5833
|
2893
|
|
|
|
|
|
sum += n - base*t; |
|
5834
|
|
|
|
|
|
|
} |
|
5835
|
1001
|
|
|
|
|
|
XSRETURN_UV(sum); |
|
5836
|
|
|
|
|
|
|
} |
|
5837
|
6
|
|
|
|
|
|
s = SvPV(svn, len); |
|
5838
|
|
|
|
|
|
|
/* If no base given and input is 0x... or 0b..., select base. */ |
|
5839
|
6
|
50
|
|
|
|
|
if (ibase == 255 && len > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'b')){ |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
5840
|
1
|
50
|
|
|
|
|
base = (s[1] == 'x') ? 16 : 2; |
|
5841
|
1
|
|
|
|
|
|
s += 2; |
|
5842
|
1
|
|
|
|
|
|
len -= 2; |
|
5843
|
|
|
|
|
|
|
} |
|
5844
|
38296
|
100
|
|
|
|
|
for (i = 0; i < len; i++) { |
|
5845
|
38290
|
|
|
|
|
|
UV d = 0; |
|
5846
|
38290
|
|
|
|
|
|
const char c = s[i]; |
|
5847
|
38290
|
100
|
|
|
|
|
if (c >= '0' && c <= '9') { d = c - '0'; } |
|
|
|
100
|
|
|
|
|
|
|
5848
|
5
|
100
|
|
|
|
|
else if (c >= 'a' && c <= 'z') { d = c - 'a' + 10; } |
|
|
|
50
|
|
|
|
|
|
|
5849
|
4
|
100
|
|
|
|
|
else if (c >= 'A' && c <= 'Z') { d = c - 'A' + 10; } |
|
|
|
50
|
|
|
|
|
|
|
5850
|
38290
|
50
|
|
|
|
|
if (d < base) |
|
5851
|
38290
|
|
|
|
|
|
sum += d; |
|
5852
|
|
|
|
|
|
|
} |
|
5853
|
6
|
|
|
|
|
|
XSRETURN_UV(sum); |
|
5854
|
|
|
|
|
|
|
|
|
5855
|
|
|
|
|
|
|
void todigits(SV* svn, int base=10, int length=-1) |
|
5856
|
|
|
|
|
|
|
ALIAS: |
|
5857
|
|
|
|
|
|
|
todigitstring = 1 |
|
5858
|
|
|
|
|
|
|
fromdigits = 2 |
|
5859
|
|
|
|
|
|
|
PREINIT: |
|
5860
|
|
|
|
|
|
|
int i, status; |
|
5861
|
|
|
|
|
|
|
UV n; |
|
5862
|
|
|
|
|
|
|
char *str; |
|
5863
|
|
|
|
|
|
|
PPCODE: |
|
5864
|
293
|
50
|
|
|
|
|
if (base < 2) croak("%s: invalid base: %d", SUBNAME, base); |
|
5865
|
293
|
|
|
|
|
|
status = 0; |
|
5866
|
293
|
100
|
|
|
|
|
if (ix == 0 || ix == 1) { |
|
|
|
100
|
|
|
|
|
|
|
5867
|
262
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ svn, IFLAG_ABS); |
|
5868
|
|
|
|
|
|
|
} |
|
5869
|
|
|
|
|
|
|
/* todigits with native input */ |
|
5870
|
293
|
100
|
|
|
|
|
if (ix == 0 && status != 0 && length < 128) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
5871
|
|
|
|
|
|
|
int digits[128]; |
|
5872
|
158
|
|
|
|
|
|
IV len = to_digit_array(digits, n, base, length); |
|
5873
|
158
|
50
|
|
|
|
|
if (len >= 0) { |
|
5874
|
|
|
|
|
|
|
dMY_CXT; |
|
5875
|
158
|
50
|
|
|
|
|
EXTEND(SP, (EXTEND_TYPE)len); |
|
|
|
50
|
|
|
|
|
|
|
5876
|
3901
|
100
|
|
|
|
|
for (i = 0; i < len; i++) |
|
5877
|
3743
|
50
|
|
|
|
|
PUSH_NPARITY( digits[len-i-1] ); |
|
|
|
50
|
|
|
|
|
|
|
5878
|
158
|
|
|
|
|
|
XSRETURN(len); |
|
5879
|
|
|
|
|
|
|
} |
|
5880
|
|
|
|
|
|
|
} |
|
5881
|
|
|
|
|
|
|
/* todigitstring with native input */ |
|
5882
|
135
|
100
|
|
|
|
|
if (ix == 1 && status != 0 && length < 128) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
5883
|
|
|
|
|
|
|
char s[128+1]; |
|
5884
|
5
|
|
|
|
|
|
IV len = to_digit_string(s, n, base, length); |
|
5885
|
5
|
50
|
|
|
|
|
if (len >= 0) { |
|
5886
|
5
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSVpv(s, len))); |
|
5887
|
5
|
|
|
|
|
|
XSRETURN(1); |
|
5888
|
|
|
|
|
|
|
} |
|
5889
|
|
|
|
|
|
|
} |
|
5890
|
|
|
|
|
|
|
/* todigits or todigitstring base 10 (large size) */ |
|
5891
|
130
|
100
|
|
|
|
|
if ((ix == 0 || ix == 1) && base == 10 && length < 0) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
5892
|
|
|
|
|
|
|
STRLEN len; |
|
5893
|
1
|
|
|
|
|
|
str = SvPV(svn, len); |
|
5894
|
1
|
50
|
|
|
|
|
if (ix == 1) { |
|
5895
|
0
|
0
|
|
|
|
|
XPUSHs(sv_2mortal(newSVpv(str, len))); |
|
5896
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
5897
|
|
|
|
|
|
|
} |
|
5898
|
1
|
50
|
|
|
|
|
if (len == 1 && str[0] == '0') XSRETURN(0); |
|
|
|
0
|
|
|
|
|
|
|
5899
|
|
|
|
|
|
|
{ |
|
5900
|
|
|
|
|
|
|
dMY_CXT; |
|
5901
|
1
|
50
|
|
|
|
|
EXTEND(SP, (EXTEND_TYPE)len); |
|
|
|
50
|
|
|
|
|
|
|
5902
|
46
|
100
|
|
|
|
|
for (i = 0; i < (int)len; i++) |
|
5903
|
45
|
50
|
|
|
|
|
PUSH_NPARITY(str[i]-'0'); |
|
|
|
50
|
|
|
|
|
|
|
5904
|
|
|
|
|
|
|
} |
|
5905
|
1
|
|
|
|
|
|
XSRETURN(len); |
|
5906
|
|
|
|
|
|
|
} |
|
5907
|
129
|
100
|
|
|
|
|
if (ix == 2) { /* fromdigits */ |
|
5908
|
31
|
100
|
|
|
|
|
if (!SvROK(svn)) { /* string */ |
|
5909
|
17
|
100
|
|
|
|
|
if (from_digit_string(&n, SvPV_nolen(svn), base)) { |
|
5910
|
6
|
|
|
|
|
|
XSRETURN_UV(n); |
|
5911
|
|
|
|
|
|
|
} |
|
5912
|
14
|
50
|
|
|
|
|
} else if (!_is_sv_bigint(aTHX_ svn)) { /* array ref of digits */ |
|
5913
|
14
|
|
|
|
|
|
UV* r = 0; |
|
5914
|
14
|
|
|
|
|
|
int len = arrayref_to_digit_array(aTHX_ &r, (AV*) SvRV(svn), base); |
|
5915
|
14
|
100
|
|
|
|
|
if (from_digit_to_UV(&n, r, len, base)) { |
|
5916
|
13
|
|
|
|
|
|
Safefree(r); |
|
5917
|
14
|
|
|
|
|
|
XSRETURN_UV(n); |
|
5918
|
1
|
50
|
|
|
|
|
} else if (from_digit_to_str(&str, r, len, base)){ |
|
5919
|
1
|
|
|
|
|
|
Safefree(r); |
|
5920
|
1
|
50
|
|
|
|
|
XPUSHs( sv_to_bigint(aTHX_ sv_2mortal(newSVpv(str,0))) ); |
|
5921
|
1
|
|
|
|
|
|
Safefree(str); |
|
5922
|
1
|
|
|
|
|
|
XSRETURN(1); |
|
5923
|
|
|
|
|
|
|
} |
|
5924
|
0
|
|
|
|
|
|
Safefree(r); |
|
5925
|
|
|
|
|
|
|
} |
|
5926
|
|
|
|
|
|
|
} |
|
5927
|
109
|
|
|
|
|
|
DISPATCHPP(); |
|
5928
|
109
|
100
|
|
|
|
|
if (ix == 2) objectify_result(aTHX_ 0, ST(0)); |
|
5929
|
109
|
|
|
|
|
|
return; |
|
5930
|
|
|
|
|
|
|
|
|
5931
|
|
|
|
|
|
|
void tozeckendorf(SV* svn) |
|
5932
|
|
|
|
|
|
|
PREINIT: |
|
5933
|
|
|
|
|
|
|
UV n; |
|
5934
|
|
|
|
|
|
|
PPCODE: |
|
5935
|
28
|
100
|
|
|
|
|
if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) { |
|
5936
|
27
|
|
|
|
|
|
char *str = to_zeckendorf(n); |
|
5937
|
27
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSVpv(str, 0))); |
|
5938
|
27
|
|
|
|
|
|
Safefree(str); |
|
5939
|
27
|
|
|
|
|
|
XSRETURN(1); |
|
5940
|
|
|
|
|
|
|
} |
|
5941
|
1
|
|
|
|
|
|
DISPATCHPP(); |
|
5942
|
1
|
|
|
|
|
|
XSRETURN(1); |
|
5943
|
|
|
|
|
|
|
|
|
5944
|
|
|
|
|
|
|
void fromzeckendorf(IN char* str) |
|
5945
|
|
|
|
|
|
|
PREINIT: |
|
5946
|
|
|
|
|
|
|
int status; |
|
5947
|
|
|
|
|
|
|
PPCODE: |
|
5948
|
27
|
|
|
|
|
|
status = validate_zeckendorf(str); |
|
5949
|
27
|
50
|
|
|
|
|
if (status == 0) |
|
5950
|
0
|
|
|
|
|
|
croak("fromzeckendorf: expected binary string"); |
|
5951
|
27
|
50
|
|
|
|
|
if (status == -1) |
|
5952
|
0
|
|
|
|
|
|
croak("fromzeckendorf: expected binary string in canonical Zeckendorf form"); |
|
5953
|
27
|
100
|
|
|
|
|
if (status == 1) |
|
5954
|
26
|
|
|
|
|
|
XSRETURN_UV(from_zeckendorf(str)); |
|
5955
|
1
|
|
|
|
|
|
DISPATCHPP(); |
|
5956
|
1
|
|
|
|
|
|
XSRETURN(1); |
|
5957
|
|
|
|
|
|
|
|
|
5958
|
|
|
|
|
|
|
void |
|
5959
|
|
|
|
|
|
|
lastfor() |
|
5960
|
|
|
|
|
|
|
PREINIT: |
|
5961
|
|
|
|
|
|
|
dMY_CXT; |
|
5962
|
|
|
|
|
|
|
PPCODE: |
|
5963
|
|
|
|
|
|
|
/* printf("last for with count = %u\n", MY_CXT.forcount); */ |
|
5964
|
90
|
50
|
|
|
|
|
if (MY_CXT.forcount == 0) croak("lastfor called outside a loop"); |
|
5965
|
90
|
|
|
|
|
|
MY_CXT.forexit = 1; |
|
5966
|
|
|
|
|
|
|
/* In some ideal world this would also act like a last */ |
|
5967
|
90
|
|
|
|
|
|
return; |
|
5968
|
|
|
|
|
|
|
|
|
5969
|
|
|
|
|
|
|
#define START_FORCOUNT \ |
|
5970
|
|
|
|
|
|
|
do { \ |
|
5971
|
|
|
|
|
|
|
oldforloop = ++MY_CXT.forcount; \ |
|
5972
|
|
|
|
|
|
|
oldforexit = MY_CXT.forexit; \ |
|
5973
|
|
|
|
|
|
|
forexit = &MY_CXT.forexit; \ |
|
5974
|
|
|
|
|
|
|
*forexit = 0; \ |
|
5975
|
|
|
|
|
|
|
} while(0) |
|
5976
|
|
|
|
|
|
|
|
|
5977
|
|
|
|
|
|
|
#define CHECK_FORCOUNT \ |
|
5978
|
|
|
|
|
|
|
if (*forexit) break; |
|
5979
|
|
|
|
|
|
|
|
|
5980
|
|
|
|
|
|
|
#define END_FORCOUNT \ |
|
5981
|
|
|
|
|
|
|
do { \ |
|
5982
|
|
|
|
|
|
|
/* Put back outer loop's exit request, if any. */ \ |
|
5983
|
|
|
|
|
|
|
*forexit = oldforexit; \ |
|
5984
|
|
|
|
|
|
|
/* Ensure loops are nested and not woven. */ \ |
|
5985
|
|
|
|
|
|
|
if (MY_CXT.forcount-- != oldforloop) croak("for loop mismatch"); \ |
|
5986
|
|
|
|
|
|
|
} while (0) |
|
5987
|
|
|
|
|
|
|
|
|
5988
|
|
|
|
|
|
|
#define DECL_FORCOUNT \ |
|
5989
|
|
|
|
|
|
|
uint16_t oldforloop; \ |
|
5990
|
|
|
|
|
|
|
char oldforexit; \ |
|
5991
|
|
|
|
|
|
|
char *forexit |
|
5992
|
|
|
|
|
|
|
|
|
5993
|
|
|
|
|
|
|
void |
|
5994
|
|
|
|
|
|
|
forprimes (SV* block, IN SV* svbeg, IN SV* svend = 0) |
|
5995
|
|
|
|
|
|
|
PROTOTYPE: &$;$ |
|
5996
|
|
|
|
|
|
|
PREINIT: |
|
5997
|
|
|
|
|
|
|
SV* svarg; |
|
5998
|
|
|
|
|
|
|
CV *subcv; |
|
5999
|
|
|
|
|
|
|
unsigned char* segment; |
|
6000
|
|
|
|
|
|
|
UV beg, end, seg_base, seg_low, seg_high; |
|
6001
|
|
|
|
|
|
|
DECL_FORCOUNT; |
|
6002
|
|
|
|
|
|
|
dMY_CXT; |
|
6003
|
|
|
|
|
|
|
PPCODE: |
|
6004
|
79
|
50
|
|
|
|
|
SETSUBREF(subcv, block); |
|
6005
|
|
|
|
|
|
|
|
|
6006
|
79
|
100
|
|
|
|
|
if (!_validate_and_set(&beg, aTHX_ svbeg, IFLAG_POS) || |
|
|
|
100
|
|
|
|
|
|
|
6007
|
35
|
50
|
|
|
|
|
(svend && !_validate_and_set(&end, aTHX_ svend, IFLAG_POS))) { |
|
6008
|
2
|
|
|
|
|
|
DISPATCH_VOIDPP(); |
|
6009
|
2
|
|
|
|
|
|
XSRETURN(0); |
|
6010
|
|
|
|
|
|
|
} |
|
6011
|
69
|
100
|
|
|
|
|
if (!svend) { end = beg; beg = 2; } |
|
6012
|
|
|
|
|
|
|
|
|
6013
|
69
|
|
|
|
|
|
START_FORCOUNT; |
|
6014
|
69
|
|
|
|
|
|
SAVESPTR(GvSV(PL_defgv)); |
|
6015
|
69
|
|
|
|
|
|
svarg = newSVuv(beg); |
|
6016
|
69
|
|
|
|
|
|
GvSV(PL_defgv) = svarg; |
|
6017
|
|
|
|
|
|
|
/* Handle early part */ |
|
6018
|
|
|
|
|
|
|
#if USE_MULTICALL |
|
6019
|
69
|
50
|
|
|
|
|
if (!CvISXSUB(subcv) && beg <= end) { |
|
|
|
100
|
|
|
|
|
|
|
6020
|
|
|
|
|
|
|
dMULTICALL; |
|
6021
|
68
|
|
|
|
|
|
I32 gimme = G_VOID; |
|
6022
|
68
|
|
|
|
|
|
DECL_MULTICALL_SCOPE(subcv); |
|
6023
|
68
|
50
|
|
|
|
|
PUSH_MULTICALL(subcv); |
|
6024
|
68
|
100
|
|
|
|
|
if (beg < 6) { |
|
6025
|
47
|
100
|
|
|
|
|
beg = (beg <= 2) ? 2 : (beg <= 3) ? 3 : 5; |
|
|
|
100
|
|
|
|
|
|
|
6026
|
168
|
100
|
|
|
|
|
for ( ; beg < 6 && beg <= end; beg += 1+(beg>2) ) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
6027
|
122
|
100
|
|
|
|
|
CHECK_FORCOUNT; |
|
6028
|
121
|
|
|
|
|
|
sv_setuv(svarg, beg); |
|
6029
|
121
|
50
|
|
|
|
|
SCOPED_MULTICALL; |
|
|
|
50
|
|
|
|
|
|
|
6030
|
|
|
|
|
|
|
} |
|
6031
|
|
|
|
|
|
|
} |
|
6032
|
68
|
100
|
|
|
|
|
if (beg <= end) { |
|
6033
|
60
|
|
|
|
|
|
if ( |
|
6034
|
|
|
|
|
|
|
#if BITS_PER_WORD == 64 |
|
6035
|
60
|
50
|
|
|
|
|
(beg >= UVCONST( 100000000000000) && end-beg < 100000) || |
|
|
|
0
|
|
|
|
|
|
|
6036
|
60
|
50
|
|
|
|
|
(beg >= UVCONST( 10000000000000) && end-beg < 40000) || |
|
|
|
0
|
|
|
|
|
|
|
6037
|
60
|
50
|
|
|
|
|
(beg >= UVCONST( 1000000000000) && end-beg < 17000) || |
|
|
|
0
|
|
|
|
|
|
|
6038
|
|
|
|
|
|
|
#endif |
|
6039
|
60
|
100
|
|
|
|
|
((end-beg) < 500) ) { /* MULTICALL next prime */ |
|
6040
|
306
|
100
|
|
|
|
|
for (beg = next_prime(beg-1); beg <= end && beg != 0; beg = next_prime(beg)) { |
|
|
|
50
|
|
|
|
|
|
|
6041
|
274
|
100
|
|
|
|
|
CHECK_FORCOUNT; |
|
6042
|
273
|
|
|
|
|
|
sv_setuv(svarg, beg); |
|
6043
|
273
|
50
|
|
|
|
|
SCOPED_MULTICALL; |
|
|
|
50
|
|
|
|
|
|
|
6044
|
|
|
|
|
|
|
} |
|
6045
|
|
|
|
|
|
|
} else { /* MULTICALL segment sieve */ |
|
6046
|
27
|
|
|
|
|
|
void* ctx = start_segment_primes(beg, end, &segment); |
|
6047
|
29
|
100
|
|
|
|
|
while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) { |
|
6048
|
27
|
50
|
|
|
|
|
int crossuv = (seg_high > IV_MAX) && !SvIsUV(svarg); |
|
|
|
0
|
|
|
|
|
|
|
6049
|
1310
|
50
|
|
|
|
|
START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_base, seg_low, seg_high ) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
6050
|
1261
|
100
|
|
|
|
|
CHECK_FORCOUNT; |
|
6051
|
|
|
|
|
|
|
/* sv_setuv(svarg, p); */ |
|
6052
|
1147
|
100
|
|
|
|
|
if (SvTYPE(svarg) != SVt_IV) { sv_setuv(svarg, p); } |
|
6053
|
982
|
50
|
|
|
|
|
else if (crossuv && p > IV_MAX) { sv_setuv(svarg, p); crossuv=0; } |
|
|
|
0
|
|
|
|
|
|
|
6054
|
982
|
|
|
|
|
|
else { SvUV_set(svarg, p); } |
|
6055
|
1147
|
50
|
|
|
|
|
SCOPED_MULTICALL; |
|
|
|
50
|
|
|
|
|
|
|
6056
|
133
|
|
|
|
|
|
END_DO_FOR_EACH_SIEVE_PRIME |
|
6057
|
27
|
100
|
|
|
|
|
CHECK_FORCOUNT; |
|
6058
|
|
|
|
|
|
|
} |
|
6059
|
27
|
|
|
|
|
|
end_segment_primes(ctx); |
|
6060
|
|
|
|
|
|
|
} |
|
6061
|
|
|
|
|
|
|
} |
|
6062
|
|
|
|
|
|
|
FIX_MULTICALL_REFCOUNT; |
|
6063
|
68
|
50
|
|
|
|
|
POP_MULTICALL; |
|
6064
|
|
|
|
|
|
|
} |
|
6065
|
|
|
|
|
|
|
else |
|
6066
|
|
|
|
|
|
|
#endif |
|
6067
|
|
|
|
|
|
|
{ |
|
6068
|
1
|
50
|
|
|
|
|
if (beg < 6) { |
|
6069
|
1
|
50
|
|
|
|
|
beg = (beg <= 2) ? 2 : (beg <= 3) ? 3 : 5; |
|
|
|
0
|
|
|
|
|
|
|
6070
|
1
|
0
|
|
|
|
|
for ( ; beg < 6 && beg <= end; beg += 1+(beg>2) ) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
6071
|
0
|
|
|
|
|
|
sv_setuv(svarg, beg); |
|
6072
|
0
|
0
|
|
|
|
|
PUSHMARK(SP); PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN; |
|
6073
|
0
|
0
|
|
|
|
|
CHECK_FORCOUNT; |
|
6074
|
|
|
|
|
|
|
} |
|
6075
|
|
|
|
|
|
|
} |
|
6076
|
1
|
50
|
|
|
|
|
if (beg <= end) { /* NO-MULTICALL segment sieve */ |
|
6077
|
0
|
|
|
|
|
|
void* ctx = start_segment_primes(beg, end, &segment); |
|
6078
|
0
|
0
|
|
|
|
|
while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) { |
|
6079
|
0
|
0
|
|
|
|
|
START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_base, seg_low, seg_high ) |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
6080
|
0
|
0
|
|
|
|
|
CHECK_FORCOUNT; |
|
6081
|
0
|
|
|
|
|
|
sv_setuv(svarg, p); |
|
6082
|
0
|
0
|
|
|
|
|
PUSHMARK(SP); PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN; |
|
6083
|
0
|
|
|
|
|
|
END_DO_FOR_EACH_SIEVE_PRIME |
|
6084
|
0
|
0
|
|
|
|
|
CHECK_FORCOUNT; |
|
6085
|
|
|
|
|
|
|
} |
|
6086
|
0
|
|
|
|
|
|
end_segment_primes(ctx); |
|
6087
|
|
|
|
|
|
|
} |
|
6088
|
|
|
|
|
|
|
} |
|
6089
|
69
|
|
|
|
|
|
SvREFCNT_dec(svarg); |
|
6090
|
69
|
50
|
|
|
|
|
END_FORCOUNT; |
|
6091
|
|
|
|
|
|
|
|
|
6092
|
|
|
|
|
|
|
#define FORCOMPTEST(ix,n) \ |
|
6093
|
|
|
|
|
|
|
( (ix==1) || (ix==0 && n&1) ) |
|
6094
|
|
|
|
|
|
|
|
|
6095
|
|
|
|
|
|
|
void |
|
6096
|
|
|
|
|
|
|
foroddcomposites (SV* block, IN SV* svbeg, IN SV* svend = 0) |
|
6097
|
|
|
|
|
|
|
ALIAS: |
|
6098
|
|
|
|
|
|
|
forcomposites = 1 |
|
6099
|
|
|
|
|
|
|
PROTOTYPE: &$;$ |
|
6100
|
|
|
|
|
|
|
PREINIT: |
|
6101
|
|
|
|
|
|
|
UV beg, end; |
|
6102
|
|
|
|
|
|
|
SV* svarg; /* We use svarg to prevent clobbering $_ outside the block */ |
|
6103
|
|
|
|
|
|
|
CV *subcv; |
|
6104
|
|
|
|
|
|
|
DECL_FORCOUNT; |
|
6105
|
|
|
|
|
|
|
dMY_CXT; |
|
6106
|
|
|
|
|
|
|
PPCODE: |
|
6107
|
61
|
50
|
|
|
|
|
SETSUBREF(subcv, block); |
|
6108
|
|
|
|
|
|
|
|
|
6109
|
61
|
100
|
|
|
|
|
if (!_validate_and_set(&beg, aTHX_ svbeg, IFLAG_POS) || |
|
|
|
100
|
|
|
|
|
|
|
6110
|
2
|
50
|
|
|
|
|
(svend && !_validate_and_set(&end, aTHX_ svend, IFLAG_POS))) { |
|
6111
|
2
|
|
|
|
|
|
DISPATCH_VOIDPP(); |
|
6112
|
2
|
|
|
|
|
|
XSRETURN(0); |
|
6113
|
|
|
|
|
|
|
} |
|
6114
|
59
|
100
|
|
|
|
|
if (!svend) { end = beg; beg = ix ? 4 : 9; } |
|
|
|
100
|
|
|
|
|
|
|
6115
|
|
|
|
|
|
|
|
|
6116
|
59
|
|
|
|
|
|
START_FORCOUNT; |
|
6117
|
59
|
|
|
|
|
|
SAVESPTR(GvSV(PL_defgv)); |
|
6118
|
59
|
|
|
|
|
|
svarg = newSVuv(0); |
|
6119
|
59
|
|
|
|
|
|
GvSV(PL_defgv) = svarg; |
|
6120
|
|
|
|
|
|
|
#if USE_MULTICALL |
|
6121
|
59
|
50
|
|
|
|
|
if (!CvISXSUB(subcv) && end >= beg) { |
|
|
|
100
|
|
|
|
|
|
|
6122
|
|
|
|
|
|
|
unsigned char* segment; |
|
6123
|
|
|
|
|
|
|
UV seg_base, seg_low, seg_high, c, cbeg, cend, cinc, prevprime, nextprime; |
|
6124
|
|
|
|
|
|
|
void* ctx; |
|
6125
|
|
|
|
|
|
|
dMULTICALL; |
|
6126
|
57
|
|
|
|
|
|
I32 gimme = G_VOID; |
|
6127
|
57
|
|
|
|
|
|
DECL_MULTICALL_SCOPE(subcv); |
|
6128
|
57
|
50
|
|
|
|
|
PUSH_MULTICALL(subcv); |
|
6129
|
57
|
50
|
|
|
|
|
if (beg >= MPU_MAX_PRIME || |
|
6130
|
|
|
|
|
|
|
#if BITS_PER_WORD == 64 |
|
6131
|
57
|
50
|
|
|
|
|
(beg >= UVCONST( 100000000000000) && end-beg < 120000) || |
|
|
|
0
|
|
|
|
|
|
|
6132
|
57
|
50
|
|
|
|
|
(beg >= UVCONST( 10000000000000) && end-beg < 50000) || |
|
|
|
0
|
|
|
|
|
|
|
6133
|
57
|
50
|
|
|
|
|
(beg >= UVCONST( 1000000000000) && end-beg < 20000) || |
|
|
|
0
|
|
|
|
|
|
|
6134
|
|
|
|
|
|
|
#endif |
|
6135
|
57
|
100
|
|
|
|
|
end-beg < 1000 ) { |
|
6136
|
55
|
|
|
|
|
|
beg = (beg <= 4) ? 3 : beg-1; |
|
6137
|
55
|
|
|
|
|
|
nextprime = next_prime(beg); |
|
6138
|
3933
|
100
|
|
|
|
|
while (beg++ < end) { |
|
6139
|
3928
|
100
|
|
|
|
|
if (beg == nextprime) |
|
6140
|
907
|
|
|
|
|
|
nextprime = next_prime(beg); |
|
6141
|
3021
|
100
|
|
|
|
|
else if (FORCOMPTEST(ix,beg)) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
6142
|
1716
|
|
|
|
|
|
sv_setuv(svarg, beg); |
|
6143
|
1716
|
50
|
|
|
|
|
SCOPED_MULTICALL; |
|
|
|
50
|
|
|
|
|
|
|
6144
|
|
|
|
|
|
|
} |
|
6145
|
3928
|
100
|
|
|
|
|
CHECK_FORCOUNT; |
|
6146
|
|
|
|
|
|
|
} |
|
6147
|
|
|
|
|
|
|
} else { |
|
6148
|
2
|
100
|
|
|
|
|
if (!ix) { |
|
6149
|
1
|
50
|
|
|
|
|
if (beg < 8) beg = 8; |
|
6150
|
1
|
50
|
|
|
|
|
} else if (beg <= 4) { /* sieve starts at 7, so handle this here */ |
|
6151
|
1
|
|
|
|
|
|
sv_setuv(svarg, 4); |
|
6152
|
1
|
50
|
|
|
|
|
SCOPED_MULTICALL; |
|
|
|
50
|
|
|
|
|
|
|
6153
|
1
|
|
|
|
|
|
beg = 6; |
|
6154
|
|
|
|
|
|
|
} |
|
6155
|
|
|
|
|
|
|
/* Find the two primes that bound their interval. */ |
|
6156
|
|
|
|
|
|
|
/* beg must be < max_prime, and end >= max_prime is special. */ |
|
6157
|
2
|
|
|
|
|
|
prevprime = prev_prime(beg); |
|
6158
|
2
|
50
|
|
|
|
|
nextprime = (end >= MPU_MAX_PRIME) ? MPU_MAX_PRIME : next_prime(end); |
|
6159
|
2
|
|
|
|
|
|
ctx = start_segment_primes(beg, nextprime, &segment); |
|
6160
|
4
|
100
|
|
|
|
|
while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) { |
|
6161
|
2
|
50
|
|
|
|
|
int crossuv = (seg_high > IV_MAX) && !SvIsUV(svarg); |
|
|
|
0
|
|
|
|
|
|
|
6162
|
9083
|
50
|
|
|
|
|
START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_base, seg_low, seg_high ) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
6163
|
8726
|
|
|
|
|
|
cbeg = prevprime+1; |
|
6164
|
8726
|
100
|
|
|
|
|
if (cbeg < beg) |
|
6165
|
1
|
50
|
|
|
|
|
cbeg = beg - (ix == 0 && (beg % 2)); |
|
|
|
50
|
|
|
|
|
|
|
6166
|
8726
|
|
|
|
|
|
prevprime = p; |
|
6167
|
8726
|
100
|
|
|
|
|
cend = prevprime-1; if (cend > end) cend = end; |
|
6168
|
|
|
|
|
|
|
/* If ix=0, skip evens by starting 1 farther and skipping by 2 */ |
|
6169
|
8726
|
100
|
|
|
|
|
cinc = 1 + (ix==0); |
|
6170
|
36294
|
100
|
|
|
|
|
for (c = cbeg + (ix==0); c <= cend; c += cinc) { |
|
6171
|
29528
|
100
|
|
|
|
|
CHECK_FORCOUNT; |
|
6172
|
27568
|
50
|
|
|
|
|
if (SvTYPE(svarg) != SVt_IV) { sv_setuv(svarg,c); } |
|
6173
|
27568
|
50
|
|
|
|
|
else if (crossuv && c > IV_MAX) { sv_setuv(svarg,c); crossuv=0;} |
|
|
|
0
|
|
|
|
|
|
|
6174
|
27568
|
|
|
|
|
|
else { SvUV_set(svarg,c); } |
|
6175
|
27568
|
50
|
|
|
|
|
SCOPED_MULTICALL; |
|
|
|
50
|
|
|
|
|
|
|
6176
|
|
|
|
|
|
|
} |
|
6177
|
354
|
|
|
|
|
|
END_DO_FOR_EACH_SIEVE_PRIME |
|
6178
|
|
|
|
|
|
|
} |
|
6179
|
2
|
|
|
|
|
|
end_segment_primes(ctx); |
|
6180
|
2
|
50
|
|
|
|
|
if (end > nextprime) /* Complete the case where end > max_prime */ |
|
6181
|
0
|
0
|
|
|
|
|
while (nextprime++ < end) |
|
6182
|
0
|
0
|
|
|
|
|
if (FORCOMPTEST(ix,nextprime)) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
6183
|
0
|
0
|
|
|
|
|
CHECK_FORCOUNT; |
|
6184
|
0
|
|
|
|
|
|
sv_setuv(svarg, nextprime); |
|
6185
|
0
|
0
|
|
|
|
|
SCOPED_MULTICALL; |
|
|
|
0
|
|
|
|
|
|
|
6186
|
|
|
|
|
|
|
} |
|
6187
|
|
|
|
|
|
|
} |
|
6188
|
|
|
|
|
|
|
FIX_MULTICALL_REFCOUNT; |
|
6189
|
57
|
50
|
|
|
|
|
POP_MULTICALL; |
|
6190
|
|
|
|
|
|
|
} |
|
6191
|
|
|
|
|
|
|
else |
|
6192
|
|
|
|
|
|
|
#endif |
|
6193
|
2
|
50
|
|
|
|
|
if (beg <= end) { |
|
6194
|
0
|
|
|
|
|
|
beg = (beg <= 4) ? 3 : beg-1; |
|
6195
|
0
|
0
|
|
|
|
|
while (beg++ < end) { |
|
6196
|
0
|
0
|
|
|
|
|
if (FORCOMPTEST(ix,beg) && !is_prob_prime(beg)) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
6197
|
0
|
|
|
|
|
|
sv_setuv(svarg, beg); |
|
6198
|
0
|
0
|
|
|
|
|
PUSHMARK(SP); PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN; |
|
6199
|
0
|
0
|
|
|
|
|
CHECK_FORCOUNT; |
|
6200
|
|
|
|
|
|
|
} |
|
6201
|
|
|
|
|
|
|
} |
|
6202
|
|
|
|
|
|
|
} |
|
6203
|
59
|
|
|
|
|
|
SvREFCNT_dec(svarg); |
|
6204
|
59
|
50
|
|
|
|
|
END_FORCOUNT; |
|
6205
|
|
|
|
|
|
|
|
|
6206
|
|
|
|
|
|
|
void |
|
6207
|
|
|
|
|
|
|
forsemiprimes (SV* block, IN SV* svbeg, IN SV* svend = 0) |
|
6208
|
|
|
|
|
|
|
PROTOTYPE: &$;$ |
|
6209
|
|
|
|
|
|
|
PREINIT: |
|
6210
|
|
|
|
|
|
|
UV beg, end; |
|
6211
|
|
|
|
|
|
|
SV* svarg; /* We use svarg to prevent clobbering $_ outside the block */ |
|
6212
|
|
|
|
|
|
|
CV *subcv; |
|
6213
|
|
|
|
|
|
|
DECL_FORCOUNT; |
|
6214
|
|
|
|
|
|
|
dMY_CXT; |
|
6215
|
|
|
|
|
|
|
PPCODE: |
|
6216
|
2
|
50
|
|
|
|
|
SETSUBREF(subcv, block); |
|
6217
|
|
|
|
|
|
|
|
|
6218
|
2
|
100
|
|
|
|
|
if (!_validate_and_set(&beg, aTHX_ svbeg, IFLAG_POS) || |
|
|
|
50
|
|
|
|
|
|
|
6219
|
0
|
0
|
|
|
|
|
(svend && !_validate_and_set(&end, aTHX_ svend, IFLAG_POS))) { |
|
6220
|
1
|
|
|
|
|
|
DISPATCH_VOIDPP(); |
|
6221
|
1
|
|
|
|
|
|
XSRETURN(0); |
|
6222
|
|
|
|
|
|
|
} |
|
6223
|
1
|
50
|
|
|
|
|
if (!svend) { end = beg; beg = 4; } |
|
6224
|
|
|
|
|
|
|
|
|
6225
|
1
|
50
|
|
|
|
|
if (beg < 4) beg = 4; |
|
6226
|
1
|
50
|
|
|
|
|
if (end > MPU_MAX_SEMI_PRIME) end = MPU_MAX_SEMI_PRIME; |
|
6227
|
|
|
|
|
|
|
|
|
6228
|
1
|
|
|
|
|
|
START_FORCOUNT; |
|
6229
|
1
|
|
|
|
|
|
SAVESPTR(GvSV(PL_defgv)); |
|
6230
|
1
|
|
|
|
|
|
svarg = newSVuv(0); |
|
6231
|
1
|
|
|
|
|
|
GvSV(PL_defgv) = svarg; |
|
6232
|
|
|
|
|
|
|
#if USE_MULTICALL |
|
6233
|
1
|
50
|
|
|
|
|
if (!CvISXSUB(subcv) && end >= beg) { |
|
|
|
50
|
|
|
|
|
|
|
6234
|
|
|
|
|
|
|
UV c, seg_beg, seg_end, *S, count; |
|
6235
|
|
|
|
|
|
|
dMULTICALL; |
|
6236
|
1
|
|
|
|
|
|
I32 gimme = G_VOID; |
|
6237
|
1
|
|
|
|
|
|
DECL_MULTICALL_SCOPE(subcv); |
|
6238
|
1
|
50
|
|
|
|
|
PUSH_MULTICALL(subcv); |
|
6239
|
1
|
50
|
|
|
|
|
if (beg >= MPU_MAX_SEMI_PRIME || |
|
6240
|
|
|
|
|
|
|
#if BITS_PER_WORD == 64 |
|
6241
|
1
|
50
|
|
|
|
|
(beg >= UVCONST(10000000000000000000) && end-beg < 1400000) || |
|
|
|
0
|
|
|
|
|
|
|
6242
|
1
|
50
|
|
|
|
|
(beg >= UVCONST( 1000000000000000000) && end-beg < 950000) || |
|
|
|
0
|
|
|
|
|
|
|
6243
|
1
|
50
|
|
|
|
|
(beg >= UVCONST( 100000000000000000) && end-beg < 440000) || |
|
|
|
0
|
|
|
|
|
|
|
6244
|
1
|
50
|
|
|
|
|
(beg >= UVCONST( 10000000000000000) && end-beg < 240000) || |
|
|
|
0
|
|
|
|
|
|
|
6245
|
1
|
50
|
|
|
|
|
(beg >= UVCONST( 1000000000000000) && end-beg < 65000) || |
|
|
|
0
|
|
|
|
|
|
|
6246
|
1
|
50
|
|
|
|
|
(beg >= UVCONST( 100000000000000) && end-beg < 29000) || |
|
|
|
0
|
|
|
|
|
|
|
6247
|
1
|
50
|
|
|
|
|
(beg >= UVCONST( 10000000000000) && end-beg < 11000) || |
|
|
|
0
|
|
|
|
|
|
|
6248
|
1
|
50
|
|
|
|
|
(beg >= UVCONST( 1000000000000) && end-beg < 5000) || |
|
|
|
0
|
|
|
|
|
|
|
6249
|
|
|
|
|
|
|
#endif |
|
6250
|
1
|
50
|
|
|
|
|
end-beg < 200 ) { |
|
6251
|
0
|
0
|
|
|
|
|
for (c = beg; c <= end && c >= beg; c++) { |
|
|
|
0
|
|
|
|
|
|
|
6252
|
0
|
0
|
|
|
|
|
if (is_semiprime(c)) { |
|
6253
|
0
|
|
|
|
|
|
sv_setuv(svarg, c); |
|
6254
|
0
|
0
|
|
|
|
|
SCOPED_MULTICALL; |
|
|
|
0
|
|
|
|
|
|
|
6255
|
|
|
|
|
|
|
} |
|
6256
|
0
|
0
|
|
|
|
|
CHECK_FORCOUNT; |
|
6257
|
|
|
|
|
|
|
} |
|
6258
|
|
|
|
|
|
|
} else { |
|
6259
|
2
|
100
|
|
|
|
|
while (beg < end) { |
|
6260
|
1
|
|
|
|
|
|
seg_beg = beg; |
|
6261
|
1
|
|
|
|
|
|
seg_end = end; |
|
6262
|
1
|
50
|
|
|
|
|
if ((seg_end - seg_beg) > 50000000) seg_end = seg_beg + 50000000 - 1; |
|
6263
|
1
|
|
|
|
|
|
count = range_semiprime_sieve(&S, seg_beg, seg_end); |
|
6264
|
300
|
100
|
|
|
|
|
for (c = 0; c < count; c++) { |
|
6265
|
299
|
|
|
|
|
|
sv_setuv(svarg, S[c]); |
|
6266
|
299
|
50
|
|
|
|
|
SCOPED_MULTICALL; |
|
|
|
50
|
|
|
|
|
|
|
6267
|
299
|
50
|
|
|
|
|
CHECK_FORCOUNT; |
|
6268
|
|
|
|
|
|
|
} |
|
6269
|
1
|
|
|
|
|
|
Safefree(S); |
|
6270
|
1
|
|
|
|
|
|
beg = seg_end+1; |
|
6271
|
1
|
50
|
|
|
|
|
CHECK_FORCOUNT; |
|
6272
|
|
|
|
|
|
|
} |
|
6273
|
|
|
|
|
|
|
} |
|
6274
|
|
|
|
|
|
|
FIX_MULTICALL_REFCOUNT; |
|
6275
|
1
|
50
|
|
|
|
|
POP_MULTICALL; |
|
6276
|
|
|
|
|
|
|
} |
|
6277
|
|
|
|
|
|
|
else |
|
6278
|
|
|
|
|
|
|
#endif |
|
6279
|
0
|
0
|
|
|
|
|
if (beg <= end) { |
|
6280
|
0
|
|
|
|
|
|
beg = (beg <= 4) ? 3 : beg-1; |
|
6281
|
0
|
0
|
|
|
|
|
while (beg++ < end) { |
|
6282
|
0
|
0
|
|
|
|
|
if (is_semiprime(beg)) { |
|
6283
|
0
|
|
|
|
|
|
sv_setuv(svarg, beg); |
|
6284
|
0
|
0
|
|
|
|
|
PUSHMARK(SP); PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN; |
|
6285
|
0
|
0
|
|
|
|
|
CHECK_FORCOUNT; |
|
6286
|
|
|
|
|
|
|
} |
|
6287
|
|
|
|
|
|
|
} |
|
6288
|
|
|
|
|
|
|
} |
|
6289
|
1
|
|
|
|
|
|
SvREFCNT_dec(svarg); |
|
6290
|
1
|
50
|
|
|
|
|
END_FORCOUNT; |
|
6291
|
|
|
|
|
|
|
|
|
6292
|
|
|
|
|
|
|
void |
|
6293
|
|
|
|
|
|
|
foralmostprimes (SV* block, IN UV k, IN SV* svbeg, IN SV* svend = 0) |
|
6294
|
|
|
|
|
|
|
PROTOTYPE: &$$;$ |
|
6295
|
|
|
|
|
|
|
PREINIT: |
|
6296
|
|
|
|
|
|
|
UV c, beg, end, shiftres; |
|
6297
|
|
|
|
|
|
|
SV* svarg; /* We use svarg to prevent clobbering $_ outside the block */ |
|
6298
|
|
|
|
|
|
|
CV *subcv; |
|
6299
|
|
|
|
|
|
|
DECL_FORCOUNT; |
|
6300
|
|
|
|
|
|
|
dMY_CXT; |
|
6301
|
|
|
|
|
|
|
PPCODE: |
|
6302
|
12
|
50
|
|
|
|
|
SETSUBREF(subcv, block); |
|
6303
|
|
|
|
|
|
|
|
|
6304
|
12
|
100
|
|
|
|
|
if (!_validate_and_set(&beg, aTHX_ svbeg, IFLAG_POS) || |
|
|
|
100
|
|
|
|
|
|
|
6305
|
1
|
50
|
|
|
|
|
(svend && !_validate_and_set(&end, aTHX_ svend, IFLAG_POS))) { |
|
6306
|
1
|
|
|
|
|
|
DISPATCH_VOIDPP(); |
|
6307
|
1
|
|
|
|
|
|
XSRETURN(0); |
|
6308
|
|
|
|
|
|
|
} |
|
6309
|
11
|
100
|
|
|
|
|
if (!svend) { end = beg; beg = 1; } |
|
6310
|
|
|
|
|
|
|
|
|
6311
|
|
|
|
|
|
|
/* If k is over 63 but the beg/end points are UVs, then we're empty. */ |
|
6312
|
11
|
100
|
|
|
|
|
if (k == 0 || k >= BITS_PER_WORD) XSRETURN(0); |
|
|
|
50
|
|
|
|
|
|
|
6313
|
|
|
|
|
|
|
|
|
6314
|
10
|
50
|
|
|
|
|
if (beg < (UVCONST(1) << k)) beg = UVCONST(1) << k; |
|
6315
|
10
|
50
|
|
|
|
|
if (end > max_nth_almost_prime(k)) end = max_nth_almost_prime(k); |
|
6316
|
10
|
100
|
|
|
|
|
if (beg > end) XSRETURN(0); |
|
6317
|
|
|
|
|
|
|
|
|
6318
|
|
|
|
|
|
|
/* We might be able to reduce the k value. */ |
|
6319
|
9
|
|
|
|
|
|
shiftres = 0; |
|
6320
|
9
|
50
|
|
|
|
|
if (k > MPU_MAX_POW3) |
|
6321
|
0
|
|
|
|
|
|
shiftres = k - MPU_MAX_POW3; |
|
6322
|
24
|
100
|
|
|
|
|
while ((k-shiftres) > 1 && (end >> shiftres) < ipow(3, k - shiftres)) |
|
|
|
100
|
|
|
|
|
|
|
6323
|
15
|
|
|
|
|
|
shiftres++; |
|
6324
|
9
|
|
|
|
|
|
beg = (beg >> shiftres) + (((beg >> shiftres) << shiftres) < beg); |
|
6325
|
9
|
|
|
|
|
|
end = end >> shiftres; |
|
6326
|
9
|
|
|
|
|
|
k -= shiftres; |
|
6327
|
|
|
|
|
|
|
/* k <= 40 (64-bit) or 20 (32-bit). */ |
|
6328
|
|
|
|
|
|
|
|
|
6329
|
9
|
|
|
|
|
|
START_FORCOUNT; |
|
6330
|
9
|
|
|
|
|
|
SAVESPTR(GvSV(PL_defgv)); |
|
6331
|
9
|
|
|
|
|
|
svarg = newSVuv(0); |
|
6332
|
9
|
|
|
|
|
|
GvSV(PL_defgv) = svarg; |
|
6333
|
|
|
|
|
|
|
#if USE_MULTICALL |
|
6334
|
9
|
50
|
|
|
|
|
if (!CvISXSUB(subcv) && end >= beg) { |
|
|
|
50
|
|
|
|
|
|
|
6335
|
9
|
|
|
|
|
|
UV seg_beg, seg_end, *S, count, k3 = ipow(3,k); |
|
6336
|
|
|
|
|
|
|
dMULTICALL; |
|
6337
|
9
|
|
|
|
|
|
I32 gimme = G_VOID; |
|
6338
|
9
|
|
|
|
|
|
DECL_MULTICALL_SCOPE(subcv); |
|
6339
|
9
|
50
|
|
|
|
|
PUSH_MULTICALL(subcv); |
|
6340
|
18
|
100
|
|
|
|
|
while (beg <= end) { |
|
6341
|
|
|
|
|
|
|
/* TODO: Tuning this better would be nice */ |
|
6342
|
9
|
|
|
|
|
|
UV ssize = 65536 * 256; |
|
6343
|
9
|
|
|
|
|
|
seg_beg = beg; |
|
6344
|
9
|
|
|
|
|
|
seg_end = end; |
|
6345
|
9
|
50
|
|
|
|
|
if (k > 12) ssize *= 16; |
|
6346
|
9
|
50
|
|
|
|
|
if (k > 18 || seg_beg > 9*k3) ssize *= 4; |
|
|
|
50
|
|
|
|
|
|
|
6347
|
9
|
50
|
|
|
|
|
if (k > 24 || seg_beg > 81*k3) ssize *= 3; |
|
|
|
50
|
|
|
|
|
|
|
6348
|
9
|
50
|
|
|
|
|
if ((seg_end - seg_beg) > ssize) seg_end = seg_beg + ssize - 1; |
|
6349
|
9
|
|
|
|
|
|
count = generate_almost_primes(&S, k, seg_beg, seg_end); |
|
6350
|
1008
|
100
|
|
|
|
|
for (c = 0; c < count; c++) { |
|
6351
|
999
|
|
|
|
|
|
sv_setuv(svarg, S[c] << shiftres); |
|
6352
|
999
|
50
|
|
|
|
|
SCOPED_MULTICALL; |
|
|
|
50
|
|
|
|
|
|
|
6353
|
999
|
50
|
|
|
|
|
CHECK_FORCOUNT; |
|
6354
|
|
|
|
|
|
|
} |
|
6355
|
9
|
|
|
|
|
|
Safefree(S); |
|
6356
|
9
|
50
|
|
|
|
|
if (seg_end == UV_MAX) break; |
|
6357
|
9
|
|
|
|
|
|
beg = seg_end+1; |
|
6358
|
9
|
50
|
|
|
|
|
CHECK_FORCOUNT; |
|
6359
|
|
|
|
|
|
|
} |
|
6360
|
|
|
|
|
|
|
FIX_MULTICALL_REFCOUNT; |
|
6361
|
9
|
50
|
|
|
|
|
POP_MULTICALL; |
|
6362
|
|
|
|
|
|
|
} |
|
6363
|
|
|
|
|
|
|
else |
|
6364
|
|
|
|
|
|
|
#endif |
|
6365
|
0
|
0
|
|
|
|
|
if (beg <= end) { |
|
6366
|
0
|
0
|
|
|
|
|
for (c = beg; c <= end && c >= beg; c++) { |
|
|
|
0
|
|
|
|
|
|
|
6367
|
0
|
0
|
|
|
|
|
if (is_almost_prime(k,c)) { |
|
6368
|
0
|
|
|
|
|
|
sv_setuv(svarg, c << shiftres); |
|
6369
|
0
|
0
|
|
|
|
|
PUSHMARK(SP); PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN; |
|
6370
|
0
|
0
|
|
|
|
|
CHECK_FORCOUNT; |
|
6371
|
|
|
|
|
|
|
} |
|
6372
|
|
|
|
|
|
|
} |
|
6373
|
|
|
|
|
|
|
} |
|
6374
|
9
|
|
|
|
|
|
SvREFCNT_dec(svarg); |
|
6375
|
9
|
50
|
|
|
|
|
END_FORCOUNT; |
|
6376
|
|
|
|
|
|
|
|
|
6377
|
|
|
|
|
|
|
void |
|
6378
|
|
|
|
|
|
|
fordivisors (SV* block, IN SV* svn) |
|
6379
|
|
|
|
|
|
|
PROTOTYPE: &$ |
|
6380
|
|
|
|
|
|
|
PREINIT: |
|
6381
|
|
|
|
|
|
|
UV i, n, ndivisors; |
|
6382
|
|
|
|
|
|
|
UV *divs; |
|
6383
|
|
|
|
|
|
|
SV* svarg; /* We use svarg to prevent clobbering $_ outside the block */ |
|
6384
|
|
|
|
|
|
|
CV *subcv; |
|
6385
|
|
|
|
|
|
|
DECL_FORCOUNT; |
|
6386
|
|
|
|
|
|
|
dMY_CXT; |
|
6387
|
|
|
|
|
|
|
PPCODE: |
|
6388
|
72
|
50
|
|
|
|
|
SETSUBREF(subcv, block); |
|
6389
|
|
|
|
|
|
|
|
|
6390
|
72
|
100
|
|
|
|
|
if (!_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) { |
|
6391
|
1
|
|
|
|
|
|
DISPATCH_VOIDPP(); |
|
6392
|
1
|
|
|
|
|
|
XSRETURN(0); |
|
6393
|
|
|
|
|
|
|
} |
|
6394
|
|
|
|
|
|
|
|
|
6395
|
71
|
|
|
|
|
|
divs = divisor_list(n, &ndivisors, UV_MAX); |
|
6396
|
|
|
|
|
|
|
|
|
6397
|
71
|
|
|
|
|
|
START_FORCOUNT; |
|
6398
|
71
|
|
|
|
|
|
SAVESPTR(GvSV(PL_defgv)); |
|
6399
|
71
|
|
|
|
|
|
svarg = newSVuv(0); |
|
6400
|
71
|
|
|
|
|
|
GvSV(PL_defgv) = svarg; |
|
6401
|
|
|
|
|
|
|
#if USE_MULTICALL |
|
6402
|
71
|
50
|
|
|
|
|
if (!CvISXSUB(subcv)) { |
|
6403
|
|
|
|
|
|
|
dMULTICALL; |
|
6404
|
71
|
|
|
|
|
|
I32 gimme = G_VOID; |
|
6405
|
71
|
|
|
|
|
|
DECL_MULTICALL_SCOPE(subcv); |
|
6406
|
71
|
50
|
|
|
|
|
PUSH_MULTICALL(subcv); |
|
6407
|
336
|
100
|
|
|
|
|
for (i = 0; i < ndivisors; i++) { |
|
6408
|
272
|
|
|
|
|
|
sv_setuv(svarg, divs[i]); |
|
6409
|
272
|
50
|
|
|
|
|
SCOPED_MULTICALL; |
|
|
|
50
|
|
|
|
|
|
|
6410
|
272
|
100
|
|
|
|
|
CHECK_FORCOUNT; |
|
6411
|
|
|
|
|
|
|
} |
|
6412
|
|
|
|
|
|
|
FIX_MULTICALL_REFCOUNT; |
|
6413
|
71
|
50
|
|
|
|
|
POP_MULTICALL; |
|
6414
|
|
|
|
|
|
|
} |
|
6415
|
|
|
|
|
|
|
else |
|
6416
|
|
|
|
|
|
|
#endif |
|
6417
|
|
|
|
|
|
|
{ |
|
6418
|
0
|
0
|
|
|
|
|
for (i = 0; i < ndivisors; i++) { |
|
6419
|
0
|
|
|
|
|
|
sv_setuv(svarg, divs[i]); |
|
6420
|
0
|
0
|
|
|
|
|
PUSHMARK(SP); PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN; |
|
6421
|
0
|
0
|
|
|
|
|
CHECK_FORCOUNT; |
|
6422
|
|
|
|
|
|
|
} |
|
6423
|
|
|
|
|
|
|
} |
|
6424
|
71
|
|
|
|
|
|
SvREFCNT_dec(svarg); |
|
6425
|
71
|
|
|
|
|
|
Safefree(divs); |
|
6426
|
71
|
50
|
|
|
|
|
END_FORCOUNT; |
|
6427
|
|
|
|
|
|
|
|
|
6428
|
|
|
|
|
|
|
void |
|
6429
|
|
|
|
|
|
|
forpart (SV* block, IN SV* svn, IN SV* svh = 0) |
|
6430
|
|
|
|
|
|
|
ALIAS: |
|
6431
|
|
|
|
|
|
|
forcomp = 1 |
|
6432
|
|
|
|
|
|
|
PROTOTYPE: &$;$ |
|
6433
|
|
|
|
|
|
|
PREINIT: |
|
6434
|
|
|
|
|
|
|
UV i, n, amin, amax, nmin, nmax; |
|
6435
|
|
|
|
|
|
|
int primeq; |
|
6436
|
|
|
|
|
|
|
CV *subcv; |
|
6437
|
|
|
|
|
|
|
SV** svals; |
|
6438
|
|
|
|
|
|
|
DECL_FORCOUNT; |
|
6439
|
|
|
|
|
|
|
dMY_CXT; |
|
6440
|
|
|
|
|
|
|
PPCODE: |
|
6441
|
44
|
50
|
|
|
|
|
SETSUBREF(subcv, block); |
|
6442
|
44
|
50
|
|
|
|
|
if (!_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) { |
|
6443
|
0
|
|
|
|
|
|
DISPATCH_VOIDPP(); |
|
6444
|
0
|
|
|
|
|
|
XSRETURN(0); |
|
6445
|
|
|
|
|
|
|
} |
|
6446
|
44
|
50
|
|
|
|
|
if (n > (UV_MAX-2)) croak("%s: argument overflow", SUBNAME); |
|
6447
|
|
|
|
|
|
|
|
|
6448
|
44
|
50
|
|
|
|
|
New(0, svals, n+1, SV*); |
|
6449
|
782
|
100
|
|
|
|
|
for (i = 0; i <= n; i++) { |
|
6450
|
738
|
|
|
|
|
|
svals[i] = newSVuv(i); |
|
6451
|
738
|
|
|
|
|
|
SvREADONLY_on(svals[i]); |
|
6452
|
|
|
|
|
|
|
} |
|
6453
|
|
|
|
|
|
|
|
|
6454
|
44
|
|
|
|
|
|
amin = 1; amax = n; nmin = 1; nmax = n; primeq = -1; |
|
6455
|
44
|
100
|
|
|
|
|
if (svh != 0) { |
|
6456
|
|
|
|
|
|
|
HV* rhash; |
|
6457
|
|
|
|
|
|
|
SV** svp; |
|
6458
|
16
|
50
|
|
|
|
|
if (!SvROK(svh) || SvTYPE(SvRV(svh)) != SVt_PVHV) |
|
|
|
50
|
|
|
|
|
|
|
6459
|
0
|
|
|
|
|
|
croak("%s: expected hash reference", SUBNAME); |
|
6460
|
16
|
|
|
|
|
|
rhash = (HV*) SvRV(svh); |
|
6461
|
16
|
100
|
|
|
|
|
if ((svp = hv_fetchs(rhash, "n", 0)) != NULL) |
|
6462
|
8
|
|
|
|
|
|
{ nmin = my_svuv(*svp); nmax = nmin; } |
|
6463
|
16
|
100
|
|
|
|
|
if ((svp = hv_fetchs(rhash, "amin", 0)) != NULL) amin = my_svuv(*svp); |
|
6464
|
16
|
100
|
|
|
|
|
if ((svp = hv_fetchs(rhash, "amax", 0)) != NULL) amax = my_svuv(*svp); |
|
6465
|
16
|
100
|
|
|
|
|
if ((svp = hv_fetchs(rhash, "nmin", 0)) != NULL) nmin = my_svuv(*svp); |
|
6466
|
16
|
100
|
|
|
|
|
if ((svp = hv_fetchs(rhash, "nmax", 0)) != NULL) nmax = my_svuv(*svp); |
|
6467
|
16
|
100
|
|
|
|
|
if ((svp = hv_fetchs(rhash, "prime",0)) != NULL) primeq=my_svuv(*svp); |
|
6468
|
|
|
|
|
|
|
|
|
6469
|
16
|
50
|
|
|
|
|
if (amin < 1) amin = 1; |
|
6470
|
16
|
50
|
|
|
|
|
if (amax > n) amax = n; |
|
6471
|
16
|
50
|
|
|
|
|
if (nmin < 1) nmin = 1; |
|
6472
|
16
|
50
|
|
|
|
|
if (nmax > n) nmax = n; |
|
6473
|
16
|
100
|
|
|
|
|
if (primeq != 0 && primeq != -1) primeq = 1; /* -1, 0, or 1 */ |
|
|
|
100
|
|
|
|
|
|
|
6474
|
|
|
|
|
|
|
} |
|
6475
|
|
|
|
|
|
|
|
|
6476
|
44
|
100
|
|
|
|
|
if (primeq == 1) { |
|
6477
|
2
|
|
|
|
|
|
UV prev = prev_prime(amax+1); |
|
6478
|
2
|
100
|
|
|
|
|
UV next = amin <= 2 ? 2 : next_prime(amin-1); |
|
6479
|
2
|
50
|
|
|
|
|
if (amin < next) amin = next; |
|
6480
|
2
|
50
|
|
|
|
|
if (amax > prev) amax = prev; |
|
6481
|
|
|
|
|
|
|
} |
|
6482
|
|
|
|
|
|
|
|
|
6483
|
44
|
100
|
|
|
|
|
if (n==0 && nmin <= 1) { |
|
|
|
50
|
|
|
|
|
|
|
6484
|
|
|
|
|
|
|
/* Nothing */ |
|
6485
|
2
|
50
|
|
|
|
|
PUSHMARK(SP); PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN; |
|
6486
|
|
|
|
|
|
|
} |
|
6487
|
44
|
100
|
|
|
|
|
if (n >= nmin && nmin <= nmax && amin <= amax && nmax > 0 && amax > 0) |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
6488
|
|
|
|
|
|
|
{ /* RuleAsc algorithm from Kelleher and O'Sullivan 2009/2014) */ |
|
6489
|
|
|
|
|
|
|
UV *a, k, x, y, r; |
|
6490
|
41
|
50
|
|
|
|
|
New(0, a, n+1, UV); |
|
6491
|
41
|
|
|
|
|
|
k = 1; |
|
6492
|
41
|
|
|
|
|
|
a[0] = amin-1; |
|
6493
|
41
|
|
|
|
|
|
a[1] = n-amin+1; |
|
6494
|
41
|
|
|
|
|
|
START_FORCOUNT; |
|
6495
|
16008
|
100
|
|
|
|
|
while (k != 0) { |
|
6496
|
15981
|
|
|
|
|
|
x = a[k-1]+1; |
|
6497
|
15981
|
|
|
|
|
|
y = a[k]-1; |
|
6498
|
15981
|
|
|
|
|
|
k--; |
|
6499
|
15981
|
100
|
|
|
|
|
r = (ix == 0) ? x : 1; |
|
6500
|
36483
|
100
|
|
|
|
|
while (r <= y) { |
|
6501
|
20502
|
|
|
|
|
|
a[k++] = x; |
|
6502
|
20502
|
|
|
|
|
|
x = r; |
|
6503
|
20502
|
|
|
|
|
|
y -= x; |
|
6504
|
|
|
|
|
|
|
} |
|
6505
|
15981
|
|
|
|
|
|
a[k] = x + y; |
|
6506
|
|
|
|
|
|
|
|
|
6507
|
|
|
|
|
|
|
/* ------ length restrictions ------ */ |
|
6508
|
20529
|
100
|
|
|
|
|
while (k+1 > nmax) { /* Skip range if over max size */ |
|
6509
|
4548
|
|
|
|
|
|
a[k-1] += a[k]; |
|
6510
|
4548
|
|
|
|
|
|
k--; |
|
6511
|
|
|
|
|
|
|
} |
|
6512
|
|
|
|
|
|
|
/* Look into: quick skip over nmin range */ |
|
6513
|
15981
|
100
|
|
|
|
|
if (k+1 < nmin) { /* Skip if not over min size */ |
|
6514
|
3617
|
100
|
|
|
|
|
if (a[0] >= n-nmin+1 && a[k] > 1) break; /* early exit check */ |
|
|
|
50
|
|
|
|
|
|
|
6515
|
3608
|
|
|
|
|
|
continue; |
|
6516
|
|
|
|
|
|
|
} |
|
6517
|
|
|
|
|
|
|
|
|
6518
|
|
|
|
|
|
|
/* ------ value restrictions ------ */ |
|
6519
|
12364
|
100
|
|
|
|
|
if (amin > 1 || amax < n) { |
|
|
|
100
|
|
|
|
|
|
|
6520
|
|
|
|
|
|
|
/* Lexical order allows us to start at amin, and exit early */ |
|
6521
|
3452
|
100
|
|
|
|
|
if (a[0] > amax) break; |
|
6522
|
|
|
|
|
|
|
|
|
6523
|
3449
|
100
|
|
|
|
|
if (ix == 0) { /* value restrictions for partitions */ |
|
6524
|
3428
|
100
|
|
|
|
|
if (a[k] > amax) continue; |
|
6525
|
|
|
|
|
|
|
} else { /* restrictions for compositions */ |
|
6526
|
|
|
|
|
|
|
/* TODO: maybe skip forward? */ |
|
6527
|
58
|
100
|
|
|
|
|
for (i = 0; i <= k; i++) |
|
6528
|
51
|
100
|
|
|
|
|
if (a[i] < amin || a[i] > amax) |
|
|
|
100
|
|
|
|
|
|
|
6529
|
|
|
|
|
|
|
break; |
|
6530
|
21
|
100
|
|
|
|
|
if (i <= k) continue; |
|
6531
|
|
|
|
|
|
|
} |
|
6532
|
|
|
|
|
|
|
} |
|
6533
|
11769
|
100
|
|
|
|
|
if (primeq != -1) { |
|
6534
|
3791
|
100
|
|
|
|
|
for (i = 0; i <= k; i++) if (is_prime(a[i]) != primeq) break; |
|
|
|
100
|
|
|
|
|
|
|
6535
|
2602
|
100
|
|
|
|
|
if (i <= k) continue; |
|
6536
|
|
|
|
|
|
|
} |
|
6537
|
|
|
|
|
|
|
|
|
6538
|
9259
|
50
|
|
|
|
|
PUSHMARK(SP); EXTEND(SP, (EXTEND_TYPE)k+1); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
6539
|
85795
|
100
|
|
|
|
|
for (i = 0; i <= k; i++) { PUSHs(svals[a[i]]); } |
|
6540
|
9259
|
|
|
|
|
|
PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN; |
|
6541
|
9259
|
100
|
|
|
|
|
CHECK_FORCOUNT; |
|
6542
|
|
|
|
|
|
|
} |
|
6543
|
41
|
|
|
|
|
|
Safefree(a); |
|
6544
|
41
|
50
|
|
|
|
|
END_FORCOUNT; |
|
6545
|
|
|
|
|
|
|
} |
|
6546
|
782
|
100
|
|
|
|
|
for (i = 0; i <= n; i++) |
|
6547
|
738
|
|
|
|
|
|
SvREFCNT_dec(svals[i]); |
|
6548
|
44
|
|
|
|
|
|
Safefree(svals); |
|
6549
|
|
|
|
|
|
|
|
|
6550
|
|
|
|
|
|
|
void |
|
6551
|
|
|
|
|
|
|
forcomb (SV* block, IN SV* svn, IN SV* svk = 0) |
|
6552
|
|
|
|
|
|
|
ALIAS: |
|
6553
|
|
|
|
|
|
|
forperm = 1 |
|
6554
|
|
|
|
|
|
|
forderange = 2 |
|
6555
|
|
|
|
|
|
|
PROTOTYPE: &$;$ |
|
6556
|
|
|
|
|
|
|
PREINIT: |
|
6557
|
|
|
|
|
|
|
UV i, n, k, begk, endk; |
|
6558
|
|
|
|
|
|
|
CV *subcv; |
|
6559
|
|
|
|
|
|
|
SV** svals; |
|
6560
|
|
|
|
|
|
|
UV* cm; |
|
6561
|
|
|
|
|
|
|
DECL_FORCOUNT; |
|
6562
|
|
|
|
|
|
|
dMY_CXT; |
|
6563
|
|
|
|
|
|
|
PPCODE: |
|
6564
|
34
|
50
|
|
|
|
|
SETSUBREF(subcv, block); |
|
6565
|
34
|
100
|
|
|
|
|
if (ix > 0 && svk != 0) |
|
|
|
50
|
|
|
|
|
|
|
6566
|
0
|
|
|
|
|
|
croak("%s: too many arguments", SUBNAME); |
|
6567
|
|
|
|
|
|
|
|
|
6568
|
34
|
50
|
|
|
|
|
if (!_validate_and_set(&n, aTHX_ svn, IFLAG_POS) || |
|
|
|
100
|
|
|
|
|
|
|
6569
|
17
|
50
|
|
|
|
|
(svk && !_validate_and_set(&k, aTHX_ svk, IFLAG_POS))) { |
|
6570
|
0
|
|
|
|
|
|
DISPATCH_VOIDPP(); |
|
6571
|
0
|
|
|
|
|
|
XSRETURN(0); |
|
6572
|
|
|
|
|
|
|
} |
|
6573
|
|
|
|
|
|
|
|
|
6574
|
34
|
100
|
|
|
|
|
if (svk == 0) { |
|
6575
|
17
|
100
|
|
|
|
|
begk = (ix == 0) ? 0 : n; |
|
6576
|
17
|
|
|
|
|
|
endk = n; |
|
6577
|
|
|
|
|
|
|
} else { |
|
6578
|
17
|
|
|
|
|
|
begk = endk = k; |
|
6579
|
17
|
100
|
|
|
|
|
if (begk > n) |
|
6580
|
1
|
|
|
|
|
|
XSRETURN(0); |
|
6581
|
|
|
|
|
|
|
} |
|
6582
|
|
|
|
|
|
|
|
|
6583
|
33
|
50
|
|
|
|
|
New(0, svals, n, SV*); |
|
6584
|
167
|
100
|
|
|
|
|
for (i = 0; i < n; i++) { |
|
6585
|
134
|
|
|
|
|
|
svals[i] = newSVuv(i); |
|
6586
|
134
|
|
|
|
|
|
SvREADONLY_on(svals[i]); |
|
6587
|
|
|
|
|
|
|
} |
|
6588
|
33
|
50
|
|
|
|
|
New(0, cm, endk+1, UV); |
|
6589
|
|
|
|
|
|
|
|
|
6590
|
33
|
|
|
|
|
|
START_FORCOUNT; |
|
6591
|
|
|
|
|
|
|
#if USE_MULTICALL |
|
6592
|
33
|
50
|
|
|
|
|
if (!CvISXSUB(subcv)) { |
|
6593
|
|
|
|
|
|
|
dMULTICALL; |
|
6594
|
33
|
|
|
|
|
|
I32 gimme = G_VOID; |
|
6595
|
33
|
|
|
|
|
|
DECL_MULTICALL_SCOPE(subcv); |
|
6596
|
33
|
|
|
|
|
|
AV *av = save_ary(PL_defgv); |
|
6597
|
33
|
|
|
|
|
|
AvREAL_off(av); |
|
6598
|
33
|
50
|
|
|
|
|
PUSH_MULTICALL(subcv); |
|
6599
|
69
|
100
|
|
|
|
|
for (k = begk; k <= endk; k++) { |
|
6600
|
39
|
|
|
|
|
|
_comb_init(cm, k, ix == 2); |
|
6601
|
|
|
|
|
|
|
while (1) { |
|
6602
|
22537
|
100
|
|
|
|
|
if (ix < 2 || k != 1) { |
|
|
|
100
|
|
|
|
|
|
|
6603
|
|
|
|
|
|
|
IV j; |
|
6604
|
22536
|
|
|
|
|
|
av_extend(av, k-1); |
|
6605
|
22536
|
|
|
|
|
|
av_fill(av, k-1); |
|
6606
|
303801
|
100
|
|
|
|
|
for (j = k-1; j >= 0; j--) |
|
6607
|
281265
|
|
|
|
|
|
AvARRAY(av)[j] = svals[ cm[k-j-1]-1 ]; |
|
6608
|
22536
|
50
|
|
|
|
|
SCOPED_MULTICALL; |
|
|
|
50
|
|
|
|
|
|
|
6609
|
|
|
|
|
|
|
} |
|
6610
|
22537
|
100
|
|
|
|
|
CHECK_FORCOUNT; |
|
6611
|
22534
|
100
|
|
|
|
|
if (_comb_iterate(cm, k, n, ix)) break; |
|
6612
|
|
|
|
|
|
|
} |
|
6613
|
39
|
100
|
|
|
|
|
CHECK_FORCOUNT; |
|
6614
|
|
|
|
|
|
|
} |
|
6615
|
|
|
|
|
|
|
FIX_MULTICALL_REFCOUNT; |
|
6616
|
33
|
50
|
|
|
|
|
POP_MULTICALL; |
|
6617
|
|
|
|
|
|
|
} else |
|
6618
|
|
|
|
|
|
|
#endif |
|
6619
|
|
|
|
|
|
|
{ |
|
6620
|
0
|
0
|
|
|
|
|
for (k = begk; k <= endk; k++) { |
|
6621
|
0
|
|
|
|
|
|
_comb_init(cm, k, ix == 2); |
|
6622
|
|
|
|
|
|
|
while (1) { |
|
6623
|
0
|
0
|
|
|
|
|
if (ix < 2 || k != 1) { |
|
|
|
0
|
|
|
|
|
|
|
6624
|
0
|
0
|
|
|
|
|
PUSHMARK(SP); EXTEND(SP, (EXTEND_TYPE)k); |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
6625
|
0
|
0
|
|
|
|
|
for (i = 0; i < k; i++) { PUSHs(svals[ cm[k-i-1]-1 ]); } |
|
6626
|
0
|
|
|
|
|
|
PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN; |
|
6627
|
|
|
|
|
|
|
} |
|
6628
|
0
|
0
|
|
|
|
|
CHECK_FORCOUNT; |
|
6629
|
0
|
0
|
|
|
|
|
if (_comb_iterate(cm, k, n, ix)) break; |
|
6630
|
|
|
|
|
|
|
} |
|
6631
|
0
|
0
|
|
|
|
|
CHECK_FORCOUNT; |
|
6632
|
|
|
|
|
|
|
} |
|
6633
|
|
|
|
|
|
|
} |
|
6634
|
|
|
|
|
|
|
|
|
6635
|
33
|
|
|
|
|
|
Safefree(cm); |
|
6636
|
167
|
100
|
|
|
|
|
for (i = 0; i < n; i++) |
|
6637
|
134
|
|
|
|
|
|
SvREFCNT_dec(svals[i]); |
|
6638
|
33
|
|
|
|
|
|
Safefree(svals); |
|
6639
|
33
|
50
|
|
|
|
|
END_FORCOUNT; |
|
6640
|
|
|
|
|
|
|
|
|
6641
|
|
|
|
|
|
|
void forsetproduct (SV* block, ...) |
|
6642
|
|
|
|
|
|
|
PROTOTYPE: &@ |
|
6643
|
|
|
|
|
|
|
PREINIT: |
|
6644
|
|
|
|
|
|
|
SSize_t narrays, i, j, *arlen, *arcnt; |
|
6645
|
|
|
|
|
|
|
SV ***arsvs; |
|
6646
|
|
|
|
|
|
|
CV *subcv; |
|
6647
|
|
|
|
|
|
|
DECL_FORCOUNT; |
|
6648
|
|
|
|
|
|
|
dMY_CXT; |
|
6649
|
|
|
|
|
|
|
PPCODE: |
|
6650
|
9
|
50
|
|
|
|
|
SETSUBREF(subcv, block); |
|
6651
|
|
|
|
|
|
|
|
|
6652
|
9
|
|
|
|
|
|
narrays = items-1; |
|
6653
|
9
|
100
|
|
|
|
|
if (narrays < 1) XSRETURN(0); |
|
6654
|
|
|
|
|
|
|
|
|
6655
|
22
|
100
|
|
|
|
|
for (i = 1; i <= narrays; i++) { |
|
6656
|
17
|
50
|
|
|
|
|
SvGETMAGIC(ST(i)); |
|
|
|
0
|
|
|
|
|
|
|
6657
|
17
|
100
|
|
|
|
|
CHECK_ARRAYREF(ST(i)); |
|
|
|
50
|
|
|
|
|
|
|
6658
|
16
|
100
|
|
|
|
|
if (av_count((AV *)SvRV(ST(i))) == 0) |
|
6659
|
2
|
|
|
|
|
|
XSRETURN(0); |
|
6660
|
|
|
|
|
|
|
} |
|
6661
|
|
|
|
|
|
|
|
|
6662
|
5
|
50
|
|
|
|
|
Newz(0, arcnt, narrays, SSize_t); |
|
6663
|
5
|
50
|
|
|
|
|
New(0, arlen, narrays, SSize_t); |
|
6664
|
5
|
50
|
|
|
|
|
New(0, arsvs, narrays, SV**); |
|
6665
|
|
|
|
|
|
|
/* Make local copies of the SV pointers. Allows magic/tied inputs. */ |
|
6666
|
17
|
100
|
|
|
|
|
for (i = 0; i < narrays; i++) { |
|
6667
|
|
|
|
|
|
|
DECL_ARREF(inav); |
|
6668
|
12
|
50
|
|
|
|
|
USE_ARREF(inav, ST(i+1), SUBNAME, AR_READ); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
6669
|
12
|
|
|
|
|
|
arlen[i] = len_inav; |
|
6670
|
12
|
50
|
|
|
|
|
New(0, arsvs[i], len_inav, SV*); |
|
6671
|
35
|
100
|
|
|
|
|
for (j = 0; j < (SSize_t)len_inav; j++) { |
|
6672
|
23
|
|
|
|
|
|
SV* v = FETCH_ARREF(inav,j); |
|
6673
|
23
|
50
|
|
|
|
|
arsvs[i][j] = v ? v : &PL_sv_undef; |
|
6674
|
|
|
|
|
|
|
} |
|
6675
|
|
|
|
|
|
|
} |
|
6676
|
5
|
|
|
|
|
|
START_FORCOUNT; |
|
6677
|
|
|
|
|
|
|
#if USE_MULTICALL |
|
6678
|
5
|
50
|
|
|
|
|
if (!CvISXSUB(subcv)) { |
|
6679
|
|
|
|
|
|
|
dMULTICALL; |
|
6680
|
|
|
|
|
|
|
SV **arr; |
|
6681
|
5
|
|
|
|
|
|
I32 gimme = G_VOID; |
|
6682
|
5
|
|
|
|
|
|
DECL_MULTICALL_SCOPE(subcv); |
|
6683
|
5
|
|
|
|
|
|
AV *av = save_ary(PL_defgv); |
|
6684
|
5
|
|
|
|
|
|
AvREAL_off(av); |
|
6685
|
5
|
50
|
|
|
|
|
PUSH_MULTICALL(subcv); |
|
6686
|
|
|
|
|
|
|
do { |
|
6687
|
22
|
|
|
|
|
|
av_fill(av, narrays-1); |
|
6688
|
22
|
|
|
|
|
|
arr = AvARRAY(av); |
|
6689
|
66
|
100
|
|
|
|
|
for (i = narrays-1; i >= 0; i--) /* Faster to fill backwards */ |
|
6690
|
44
|
|
|
|
|
|
arr[i] = arsvs[i][arcnt[i]]; |
|
6691
|
22
|
50
|
|
|
|
|
SCOPED_MULTICALL; |
|
|
|
50
|
|
|
|
|
|
|
6692
|
22
|
50
|
|
|
|
|
CHECK_FORCOUNT; |
|
6693
|
37
|
100
|
|
|
|
|
for (i = narrays-1; i >= 0; i--) { |
|
6694
|
32
|
100
|
|
|
|
|
if (++arcnt[i] >= arlen[i]) arcnt[i] = 0; |
|
6695
|
17
|
|
|
|
|
|
else break; |
|
6696
|
|
|
|
|
|
|
} |
|
6697
|
22
|
100
|
|
|
|
|
} while (i >= 0); |
|
6698
|
|
|
|
|
|
|
FIX_MULTICALL_REFCOUNT; |
|
6699
|
5
|
50
|
|
|
|
|
POP_MULTICALL; |
|
6700
|
|
|
|
|
|
|
} |
|
6701
|
|
|
|
|
|
|
else |
|
6702
|
|
|
|
|
|
|
#endif |
|
6703
|
|
|
|
|
|
|
do { |
|
6704
|
0
|
0
|
|
|
|
|
PUSHMARK(SP); EXTEND(SP, (EXTEND_TYPE)narrays); |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
6705
|
0
|
0
|
|
|
|
|
for (i = 0; i < narrays; i++) { PUSHs(arsvs[i][arcnt[i]]); } |
|
6706
|
0
|
|
|
|
|
|
PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN; |
|
6707
|
0
|
0
|
|
|
|
|
CHECK_FORCOUNT; |
|
6708
|
0
|
0
|
|
|
|
|
for (i = narrays-1; i >= 0; i--) { |
|
6709
|
0
|
0
|
|
|
|
|
if (++arcnt[i] >= arlen[i]) arcnt[i] = 0; |
|
6710
|
0
|
|
|
|
|
|
else break; |
|
6711
|
|
|
|
|
|
|
} |
|
6712
|
0
|
0
|
|
|
|
|
} while (i >= 0); |
|
6713
|
|
|
|
|
|
|
|
|
6714
|
17
|
100
|
|
|
|
|
for (i = 0; i < narrays; i++) |
|
6715
|
12
|
|
|
|
|
|
Safefree(arsvs[i]); |
|
6716
|
5
|
|
|
|
|
|
Safefree(arsvs); |
|
6717
|
5
|
|
|
|
|
|
Safefree(arlen); |
|
6718
|
5
|
|
|
|
|
|
Safefree(arcnt); |
|
6719
|
5
|
50
|
|
|
|
|
END_FORCOUNT; |
|
6720
|
|
|
|
|
|
|
|
|
6721
|
|
|
|
|
|
|
void |
|
6722
|
|
|
|
|
|
|
forfactored (SV* block, IN SV* svbeg, IN SV* svend = 0) |
|
6723
|
|
|
|
|
|
|
ALIAS: |
|
6724
|
|
|
|
|
|
|
forsquarefree = 1 |
|
6725
|
|
|
|
|
|
|
PROTOTYPE: &$;$ |
|
6726
|
|
|
|
|
|
|
PREINIT: |
|
6727
|
|
|
|
|
|
|
UV beg, end, n, *factors; |
|
6728
|
|
|
|
|
|
|
int i, nfactors, maxfactors; |
|
6729
|
|
|
|
|
|
|
factor_range_context_t fctx; |
|
6730
|
|
|
|
|
|
|
SV* svarg; /* We use svarg to prevent clobbering $_ outside the block */ |
|
6731
|
|
|
|
|
|
|
CV *subcv; |
|
6732
|
|
|
|
|
|
|
SV* svals[64]; |
|
6733
|
|
|
|
|
|
|
DECL_FORCOUNT; |
|
6734
|
|
|
|
|
|
|
dMY_CXT; |
|
6735
|
|
|
|
|
|
|
PPCODE: |
|
6736
|
14
|
50
|
|
|
|
|
SETSUBREF(subcv, block); |
|
6737
|
|
|
|
|
|
|
|
|
6738
|
14
|
100
|
|
|
|
|
if (!_validate_and_set(&beg, aTHX_ svbeg, IFLAG_POS) || |
|
|
|
100
|
|
|
|
|
|
|
6739
|
6
|
50
|
|
|
|
|
(svend && !_validate_and_set(&end, aTHX_ svend, IFLAG_POS))) { |
|
6740
|
4
|
|
|
|
|
|
DISPATCH_VOIDPP(); |
|
6741
|
4
|
|
|
|
|
|
XSRETURN(0); |
|
6742
|
|
|
|
|
|
|
} |
|
6743
|
10
|
100
|
|
|
|
|
if (!svend) { end = beg; beg = 1; } |
|
6744
|
10
|
100
|
|
|
|
|
if (beg < 1) beg = 1; |
|
6745
|
10
|
100
|
|
|
|
|
if (beg > end) XSRETURN(0); |
|
6746
|
|
|
|
|
|
|
|
|
6747
|
77
|
100
|
|
|
|
|
for (maxfactors = 0, n = end >> 1; n; n >>= 1) |
|
6748
|
69
|
|
|
|
|
|
maxfactors++; |
|
6749
|
77
|
100
|
|
|
|
|
for (i = 0; i < maxfactors; i++) { |
|
6750
|
69
|
|
|
|
|
|
svals[i] = newSVuv(UV_MAX); |
|
6751
|
69
|
|
|
|
|
|
SvREADONLY_on(svals[i]); |
|
6752
|
|
|
|
|
|
|
} |
|
6753
|
|
|
|
|
|
|
|
|
6754
|
8
|
|
|
|
|
|
START_FORCOUNT; |
|
6755
|
8
|
|
|
|
|
|
SAVESPTR(GvSV(PL_defgv)); |
|
6756
|
8
|
|
|
|
|
|
svarg = newSVuv(0); |
|
6757
|
8
|
|
|
|
|
|
GvSV(PL_defgv) = svarg; |
|
6758
|
8
|
100
|
|
|
|
|
if (beg <= 1) { |
|
6759
|
6
|
|
|
|
|
|
sv_setuv(svarg, 1); |
|
6760
|
6
|
50
|
|
|
|
|
PUSHMARK(SP); PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN; |
|
6761
|
6
|
|
|
|
|
|
beg = 2; |
|
6762
|
|
|
|
|
|
|
} |
|
6763
|
8
|
|
|
|
|
|
fctx = factor_range_init(beg, end, ix); |
|
6764
|
|
|
|
|
|
|
#if USE_MULTICALL |
|
6765
|
8
|
50
|
|
|
|
|
if (!CvISXSUB(subcv)) { |
|
6766
|
|
|
|
|
|
|
dMULTICALL; |
|
6767
|
8
|
|
|
|
|
|
I32 gimme = G_VOID; |
|
6768
|
8
|
|
|
|
|
|
DECL_MULTICALL_SCOPE(subcv); |
|
6769
|
8
|
|
|
|
|
|
AV *av = save_ary(PL_defgv); |
|
6770
|
8
|
|
|
|
|
|
AvREAL_off(av); |
|
6771
|
8
|
50
|
|
|
|
|
PUSH_MULTICALL(subcv); |
|
6772
|
2995
|
100
|
|
|
|
|
for (n = 0; n < end-beg+1; n++) { |
|
6773
|
2987
|
50
|
|
|
|
|
CHECK_FORCOUNT; |
|
6774
|
2987
|
|
|
|
|
|
nfactors = factor_range_next(&fctx); |
|
6775
|
2987
|
100
|
|
|
|
|
if (nfactors > 0) { |
|
6776
|
1863
|
|
|
|
|
|
sv_setuv(svarg, fctx.n); |
|
6777
|
1863
|
|
|
|
|
|
factors = fctx.factors; |
|
6778
|
1863
|
|
|
|
|
|
av_extend(av, nfactors-1); |
|
6779
|
1863
|
|
|
|
|
|
av_fill(av, nfactors-1); |
|
6780
|
6499
|
100
|
|
|
|
|
for (i = nfactors-1; i >= 0; i--) { |
|
6781
|
4636
|
|
|
|
|
|
SV* sv = svals[i]; |
|
6782
|
4636
|
|
|
|
|
|
SvREADONLY_off(sv); |
|
6783
|
4636
|
|
|
|
|
|
sv_setuv(sv, factors[i]); |
|
6784
|
4636
|
|
|
|
|
|
SvREADONLY_on(sv); |
|
6785
|
4636
|
|
|
|
|
|
AvARRAY(av)[i] = sv; |
|
6786
|
|
|
|
|
|
|
} |
|
6787
|
1863
|
50
|
|
|
|
|
SCOPED_MULTICALL; |
|
|
|
50
|
|
|
|
|
|
|
6788
|
|
|
|
|
|
|
} |
|
6789
|
|
|
|
|
|
|
} |
|
6790
|
|
|
|
|
|
|
FIX_MULTICALL_REFCOUNT; |
|
6791
|
8
|
50
|
|
|
|
|
POP_MULTICALL; |
|
6792
|
|
|
|
|
|
|
} |
|
6793
|
|
|
|
|
|
|
else |
|
6794
|
|
|
|
|
|
|
#endif |
|
6795
|
0
|
0
|
|
|
|
|
for (n = 0; n < end-beg+1; n++) { |
|
6796
|
0
|
0
|
|
|
|
|
CHECK_FORCOUNT; |
|
6797
|
0
|
|
|
|
|
|
nfactors = factor_range_next(&fctx); |
|
6798
|
0
|
0
|
|
|
|
|
if (nfactors > 0) { |
|
6799
|
0
|
0
|
|
|
|
|
PUSHMARK(SP); EXTEND(SP, (EXTEND_TYPE)nfactors); |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
6800
|
0
|
|
|
|
|
|
sv_setuv(svarg, fctx.n); |
|
6801
|
0
|
|
|
|
|
|
factors = fctx.factors; |
|
6802
|
0
|
0
|
|
|
|
|
for (i = 0; i < nfactors; i++) { |
|
6803
|
0
|
|
|
|
|
|
SV* sv = svals[i]; |
|
6804
|
0
|
|
|
|
|
|
SvREADONLY_off(sv); |
|
6805
|
0
|
|
|
|
|
|
sv_setuv(sv, factors[i]); |
|
6806
|
0
|
|
|
|
|
|
SvREADONLY_on(sv); |
|
6807
|
0
|
|
|
|
|
|
PUSHs(sv); |
|
6808
|
|
|
|
|
|
|
} |
|
6809
|
0
|
|
|
|
|
|
PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN; |
|
6810
|
|
|
|
|
|
|
} |
|
6811
|
|
|
|
|
|
|
} |
|
6812
|
8
|
|
|
|
|
|
factor_range_destroy(&fctx); |
|
6813
|
8
|
|
|
|
|
|
SvREFCNT_dec(svarg); |
|
6814
|
77
|
100
|
|
|
|
|
for (i = 0; i < maxfactors; i++) |
|
6815
|
69
|
|
|
|
|
|
SvREFCNT_dec(svals[i]); |
|
6816
|
8
|
50
|
|
|
|
|
END_FORCOUNT; |
|
6817
|
|
|
|
|
|
|
|
|
6818
|
|
|
|
|
|
|
void forsquarefreeint(SV* block, IN SV* svbeg, IN SV* svend = 0) |
|
6819
|
|
|
|
|
|
|
PROTOTYPE: &$;$ |
|
6820
|
|
|
|
|
|
|
PREINIT: |
|
6821
|
|
|
|
|
|
|
UV beg, end, i; |
|
6822
|
|
|
|
|
|
|
unsigned char* isf; |
|
6823
|
|
|
|
|
|
|
SV* svarg; /* We use svarg to prevent clobbering $_ outside the block */ |
|
6824
|
|
|
|
|
|
|
CV *subcv; |
|
6825
|
|
|
|
|
|
|
DECL_FORCOUNT; |
|
6826
|
|
|
|
|
|
|
dMY_CXT; |
|
6827
|
|
|
|
|
|
|
PPCODE: |
|
6828
|
5
|
50
|
|
|
|
|
SETSUBREF(subcv, block); |
|
6829
|
|
|
|
|
|
|
|
|
6830
|
5
|
100
|
|
|
|
|
if (!_validate_and_set(&beg, aTHX_ svbeg, IFLAG_POS) || |
|
|
|
100
|
|
|
|
|
|
|
6831
|
3
|
50
|
|
|
|
|
(svend && !_validate_and_set(&end, aTHX_ svend, IFLAG_POS))) { |
|
6832
|
1
|
|
|
|
|
|
DISPATCH_VOIDPP(); |
|
6833
|
1
|
|
|
|
|
|
XSRETURN(0); |
|
6834
|
|
|
|
|
|
|
} |
|
6835
|
4
|
100
|
|
|
|
|
if (!svend) { end = beg; beg = 1; } |
|
6836
|
4
|
100
|
|
|
|
|
if (beg < 1) beg = 1; |
|
6837
|
4
|
100
|
|
|
|
|
if (beg > end) XSRETURN(0); |
|
6838
|
|
|
|
|
|
|
|
|
6839
|
3
|
|
|
|
|
|
START_FORCOUNT; |
|
6840
|
3
|
|
|
|
|
|
SAVESPTR(GvSV(PL_defgv)); |
|
6841
|
3
|
|
|
|
|
|
svarg = newSVuv(0); |
|
6842
|
3
|
|
|
|
|
|
GvSV(PL_defgv) = svarg; |
|
6843
|
3
|
100
|
|
|
|
|
if (beg <= 1) { |
|
6844
|
2
|
|
|
|
|
|
sv_setuv(svarg, 1); |
|
6845
|
2
|
50
|
|
|
|
|
PUSHMARK(SP); PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN; |
|
6846
|
2
|
|
|
|
|
|
beg = 2; |
|
6847
|
|
|
|
|
|
|
} |
|
6848
|
5
|
100
|
|
|
|
|
while (beg <= end) { |
|
6849
|
2
|
|
|
|
|
|
UV seglo = beg, seghi = end; |
|
6850
|
2
|
50
|
|
|
|
|
if (seghi-seglo > (65536*256)) |
|
6851
|
0
|
|
|
|
|
|
seghi = seglo + 65536*256 - 1; |
|
6852
|
2
|
|
|
|
|
|
isf = range_issquarefree(seglo, seghi); |
|
6853
|
|
|
|
|
|
|
#if USE_MULTICALL |
|
6854
|
2
|
50
|
|
|
|
|
if (!CvISXSUB(subcv)) { |
|
6855
|
|
|
|
|
|
|
dMULTICALL; |
|
6856
|
2
|
|
|
|
|
|
I32 gimme = G_VOID; |
|
6857
|
2
|
|
|
|
|
|
DECL_MULTICALL_SCOPE(subcv); |
|
6858
|
2
|
50
|
|
|
|
|
PUSH_MULTICALL(subcv); |
|
6859
|
109057
|
100
|
|
|
|
|
for (i = 0; i < seghi-seglo+1; i++) { |
|
6860
|
109055
|
50
|
|
|
|
|
CHECK_FORCOUNT; |
|
6861
|
109055
|
100
|
|
|
|
|
if (isf[i]) { |
|
6862
|
66306
|
|
|
|
|
|
sv_setuv(svarg, seglo+i); |
|
6863
|
66306
|
50
|
|
|
|
|
SCOPED_MULTICALL; |
|
|
|
50
|
|
|
|
|
|
|
6864
|
|
|
|
|
|
|
} |
|
6865
|
|
|
|
|
|
|
} |
|
6866
|
|
|
|
|
|
|
FIX_MULTICALL_REFCOUNT; |
|
6867
|
2
|
50
|
|
|
|
|
POP_MULTICALL; |
|
6868
|
|
|
|
|
|
|
} |
|
6869
|
|
|
|
|
|
|
else |
|
6870
|
|
|
|
|
|
|
#endif |
|
6871
|
0
|
0
|
|
|
|
|
for (i = 0; i < seghi-seglo+1; i++) { |
|
6872
|
0
|
0
|
|
|
|
|
CHECK_FORCOUNT; |
|
6873
|
0
|
0
|
|
|
|
|
if (isf[i]) { |
|
6874
|
0
|
|
|
|
|
|
sv_setuv(svarg, seglo+i); |
|
6875
|
0
|
0
|
|
|
|
|
PUSHMARK(SP); PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN; |
|
6876
|
|
|
|
|
|
|
} |
|
6877
|
|
|
|
|
|
|
} |
|
6878
|
2
|
|
|
|
|
|
Safefree(isf); |
|
6879
|
2
|
50
|
|
|
|
|
if (seghi == UV_MAX) break; |
|
6880
|
2
|
|
|
|
|
|
beg = seghi+1; |
|
6881
|
2
|
50
|
|
|
|
|
CHECK_FORCOUNT; |
|
6882
|
|
|
|
|
|
|
} |
|
6883
|
3
|
|
|
|
|
|
SvREFCNT_dec(svarg); |
|
6884
|
3
|
50
|
|
|
|
|
END_FORCOUNT; |
|
6885
|
|
|
|
|
|
|
|
|
6886
|
|
|
|
|
|
|
void |
|
6887
|
|
|
|
|
|
|
vecreduce(SV* block, ...) |
|
6888
|
|
|
|
|
|
|
PROTOTYPE: &@ |
|
6889
|
|
|
|
|
|
|
CODE: |
|
6890
|
|
|
|
|
|
|
{ /* This is basically reduce from List::Util. Try to maintain compat. */ |
|
6891
|
4
|
|
|
|
|
|
SV *ret = sv_newmortal(); |
|
6892
|
|
|
|
|
|
|
SSize_t i; |
|
6893
|
|
|
|
|
|
|
GV *agv,*bgv; |
|
6894
|
4
|
|
|
|
|
|
SV **args = &PL_stack_base[ax]; |
|
6895
|
|
|
|
|
|
|
CV *subcv; |
|
6896
|
|
|
|
|
|
|
|
|
6897
|
4
|
50
|
|
|
|
|
SETSUBREF(subcv, block); |
|
6898
|
4
|
100
|
|
|
|
|
if (items <= 1) XSRETURN_UNDEF; |
|
6899
|
|
|
|
|
|
|
|
|
6900
|
3
|
|
|
|
|
|
agv = gv_fetchpv("a", GV_ADD, SVt_PV); |
|
6901
|
3
|
|
|
|
|
|
bgv = gv_fetchpv("b", GV_ADD, SVt_PV); |
|
6902
|
3
|
|
|
|
|
|
SAVESPTR(GvSV(agv)); |
|
6903
|
3
|
|
|
|
|
|
SAVESPTR(GvSV(bgv)); |
|
6904
|
3
|
|
|
|
|
|
GvSV(agv) = ret; |
|
6905
|
3
|
50
|
|
|
|
|
SvSetMagicSV(ret, args[1]); |
|
|
|
50
|
|
|
|
|
|
|
6906
|
|
|
|
|
|
|
#ifdef dMULTICALL |
|
6907
|
3
|
50
|
|
|
|
|
if (!CvISXSUB(subcv)) { |
|
6908
|
|
|
|
|
|
|
dMULTICALL; |
|
6909
|
3
|
|
|
|
|
|
I32 gimme = G_SCALAR; |
|
6910
|
3
|
|
|
|
|
|
DECL_MULTICALL_SCOPE(subcv); |
|
6911
|
3
|
50
|
|
|
|
|
PUSH_MULTICALL(subcv); |
|
6912
|
7
|
100
|
|
|
|
|
for (i = 2; i < items; i++) { |
|
6913
|
4
|
|
|
|
|
|
GvSV(bgv) = args[i]; |
|
6914
|
4
|
50
|
|
|
|
|
SCOPED_MULTICALL; |
|
|
|
50
|
|
|
|
|
|
|
6915
|
4
|
50
|
|
|
|
|
SvSetMagicSV(ret, *PL_stack_sp); |
|
|
|
50
|
|
|
|
|
|
|
6916
|
|
|
|
|
|
|
} |
|
6917
|
|
|
|
|
|
|
FIX_MULTICALL_REFCOUNT; |
|
6918
|
3
|
50
|
|
|
|
|
POP_MULTICALL; |
|
6919
|
|
|
|
|
|
|
} |
|
6920
|
|
|
|
|
|
|
else |
|
6921
|
|
|
|
|
|
|
#endif |
|
6922
|
|
|
|
|
|
|
{ |
|
6923
|
0
|
0
|
|
|
|
|
for (i = 2; i < items; i++) { |
|
6924
|
0
|
|
|
|
|
|
dSP; |
|
6925
|
0
|
|
|
|
|
|
GvSV(bgv) = args[i]; |
|
6926
|
0
|
0
|
|
|
|
|
PUSHMARK(SP); |
|
6927
|
0
|
|
|
|
|
|
call_sv((SV*)subcv, G_SCALAR); |
|
6928
|
0
|
0
|
|
|
|
|
SvSetMagicSV(ret, *PL_stack_sp); |
|
|
|
0
|
|
|
|
|
|
|
6929
|
|
|
|
|
|
|
} |
|
6930
|
|
|
|
|
|
|
} |
|
6931
|
3
|
|
|
|
|
|
ST(0) = ret; |
|
6932
|
3
|
|
|
|
|
|
XSRETURN(1); |
|
6933
|
|
|
|
|
|
|
} |
|
6934
|
|
|
|
|
|
|
|
|
6935
|
|
|
|
|
|
|
void |
|
6936
|
|
|
|
|
|
|
vecslide(SV* block, ...) |
|
6937
|
|
|
|
|
|
|
PROTOTYPE: &@ |
|
6938
|
|
|
|
|
|
|
CODE: |
|
6939
|
|
|
|
|
|
|
{ /* Similar to slide from List::MoreUtils. */ |
|
6940
|
|
|
|
|
|
|
SSize_t i; |
|
6941
|
5
|
|
|
|
|
|
SV **args = &PL_stack_base[ax]; |
|
6942
|
|
|
|
|
|
|
CV *subcv; |
|
6943
|
|
|
|
|
|
|
SV **retsvarr; /* Store results */ |
|
6944
|
|
|
|
|
|
|
|
|
6945
|
5
|
50
|
|
|
|
|
SETSUBREF(subcv, block); |
|
6946
|
5
|
100
|
|
|
|
|
if (items <= 2) XSRETURN_EMPTY; |
|
6947
|
|
|
|
|
|
|
|
|
6948
|
3
|
|
|
|
|
|
New(0, retsvarr, items-2, SV*); |
|
6949
|
|
|
|
|
|
|
|
|
6950
|
3
|
|
|
|
|
|
SAVEGENERICSV(plAgv); |
|
6951
|
3
|
|
|
|
|
|
SAVEGENERICSV(plBgv); |
|
6952
|
3
|
|
|
|
|
|
plAgv = MUTABLE_GV(SvREFCNT_inc(gv_fetchpvs("a",GV_ADD|GV_NOTQUAL,SVt_PV))); |
|
6953
|
3
|
|
|
|
|
|
plBgv = MUTABLE_GV(SvREFCNT_inc(gv_fetchpvs("b",GV_ADD|GV_NOTQUAL,SVt_PV))); |
|
6954
|
3
|
|
|
|
|
|
save_gp(plAgv, 0); |
|
6955
|
3
|
|
|
|
|
|
save_gp(plBgv, 0); |
|
6956
|
3
|
|
|
|
|
|
GvINTRO_off(plAgv); |
|
6957
|
3
|
|
|
|
|
|
GvINTRO_off(plBgv); |
|
6958
|
3
|
|
|
|
|
|
SAVEGENERICSV(GvSV(plAgv)); SvREFCNT_inc(GvSV(plAgv)); |
|
6959
|
3
|
|
|
|
|
|
SAVEGENERICSV(GvSV(plBgv)); SvREFCNT_inc(GvSV(plBgv)); |
|
6960
|
|
|
|
|
|
|
#ifdef dMULTICALL |
|
6961
|
3
|
50
|
|
|
|
|
if (!CvISXSUB(subcv)) { |
|
6962
|
|
|
|
|
|
|
dMULTICALL; |
|
6963
|
3
|
|
|
|
|
|
I32 gimme = G_SCALAR; |
|
6964
|
3
|
|
|
|
|
|
DECL_MULTICALL_SCOPE(subcv); |
|
6965
|
3
|
50
|
|
|
|
|
PUSH_MULTICALL(subcv); |
|
6966
|
12
|
100
|
|
|
|
|
for (i = 1; i < items-1; i++) { |
|
6967
|
9
|
|
|
|
|
|
SV *olda = GvSV(plAgv), *oldb = GvSV(plBgv); |
|
6968
|
9
|
|
|
|
|
|
GvSV(plAgv) = SvREFCNT_inc_simple_NN(args[i]); |
|
6969
|
9
|
|
|
|
|
|
GvSV(plBgv) = SvREFCNT_inc_simple_NN(args[i+1]); |
|
6970
|
9
|
|
|
|
|
|
SvREFCNT_dec(olda); SvREFCNT_dec(oldb); |
|
6971
|
9
|
100
|
|
|
|
|
SCOPED_MULTICALL; |
|
|
|
100
|
|
|
|
|
|
|
6972
|
9
|
|
|
|
|
|
retsvarr[i-1] = newSVsv(*PL_stack_sp); |
|
6973
|
|
|
|
|
|
|
} |
|
6974
|
|
|
|
|
|
|
FIX_MULTICALL_REFCOUNT; |
|
6975
|
3
|
50
|
|
|
|
|
POP_MULTICALL; |
|
6976
|
|
|
|
|
|
|
} |
|
6977
|
|
|
|
|
|
|
else |
|
6978
|
|
|
|
|
|
|
#endif |
|
6979
|
|
|
|
|
|
|
{ |
|
6980
|
0
|
0
|
|
|
|
|
for (i = 1; i < items-1; i++) { |
|
6981
|
|
|
|
|
|
|
SV *olda, *oldb; |
|
6982
|
0
|
|
|
|
|
|
dSP; |
|
6983
|
0
|
|
|
|
|
|
olda = GvSV(plAgv); oldb = GvSV(plBgv); |
|
6984
|
0
|
|
|
|
|
|
GvSV(plAgv) = SvREFCNT_inc_simple_NN(args[i]); |
|
6985
|
0
|
|
|
|
|
|
GvSV(plBgv) = SvREFCNT_inc_simple_NN(args[i+1]); |
|
6986
|
0
|
|
|
|
|
|
SvREFCNT_dec(olda); SvREFCNT_dec(oldb); |
|
6987
|
0
|
0
|
|
|
|
|
PUSHMARK(SP); |
|
6988
|
0
|
|
|
|
|
|
call_sv((SV*)subcv, G_SCALAR); |
|
6989
|
0
|
|
|
|
|
|
retsvarr[i-1] = newSVsv(*PL_stack_sp); |
|
6990
|
|
|
|
|
|
|
} |
|
6991
|
|
|
|
|
|
|
} |
|
6992
|
12
|
100
|
|
|
|
|
for (i = 0; i < items-2; i++) |
|
6993
|
9
|
|
|
|
|
|
{ ST(i) = sv_2mortal(retsvarr[i]); retsvarr[i]=0; } |
|
6994
|
3
|
|
|
|
|
|
Safefree(retsvarr); |
|
6995
|
3
|
|
|
|
|
|
XSRETURN(items-2); |
|
6996
|
|
|
|
|
|
|
} |
|
6997
|
|
|
|
|
|
|
|
|
6998
|
|
|
|
|
|
|
void |
|
6999
|
|
|
|
|
|
|
vecnone(SV* block, ...) |
|
7000
|
|
|
|
|
|
|
ALIAS: |
|
7001
|
|
|
|
|
|
|
vecall = 1 |
|
7002
|
|
|
|
|
|
|
vecany = 2 |
|
7003
|
|
|
|
|
|
|
vecnotall = 3 |
|
7004
|
|
|
|
|
|
|
vecfirst = 4 |
|
7005
|
|
|
|
|
|
|
vecfirstidx = 6 |
|
7006
|
|
|
|
|
|
|
PROTOTYPE: &@ |
|
7007
|
|
|
|
|
|
|
PPCODE: |
|
7008
|
|
|
|
|
|
|
{ /* This is very similar to List::Util. Try to maintain compat. */ |
|
7009
|
961
|
|
|
|
|
|
int ret_true = !(ix & 2); /* return true at end of loop for none/all; false for any/notall */ |
|
7010
|
961
|
|
|
|
|
|
int invert = (ix & 1); /* invert block test for all/notall */ |
|
7011
|
|
|
|
|
|
|
SSize_t index; |
|
7012
|
961
|
|
|
|
|
|
SV **args = &PL_stack_base[ax]; |
|
7013
|
|
|
|
|
|
|
CV *subcv; |
|
7014
|
|
|
|
|
|
|
|
|
7015
|
961
|
50
|
|
|
|
|
SETSUBREF(subcv, block); |
|
7016
|
|
|
|
|
|
|
|
|
7017
|
961
|
|
|
|
|
|
SAVESPTR(GvSV(PL_defgv)); |
|
7018
|
|
|
|
|
|
|
#ifdef dMULTICALL |
|
7019
|
961
|
50
|
|
|
|
|
if (!CvISXSUB(subcv)) { |
|
7020
|
|
|
|
|
|
|
dMULTICALL; |
|
7021
|
961
|
|
|
|
|
|
I32 gimme = G_SCALAR; |
|
7022
|
961
|
|
|
|
|
|
DECL_MULTICALL_SCOPE(subcv); |
|
7023
|
961
|
50
|
|
|
|
|
PUSH_MULTICALL(subcv); |
|
7024
|
6957
|
100
|
|
|
|
|
for (index = 1; index < items; index++) { |
|
7025
|
6583
|
|
|
|
|
|
GvSV(PL_defgv) = args[index]; |
|
7026
|
6583
|
100
|
|
|
|
|
SCOPED_MULTICALL; |
|
|
|
100
|
|
|
|
|
|
|
7027
|
6583
|
100
|
|
|
|
|
if (SvTRUEx(*PL_stack_sp) ^ invert) |
|
7028
|
587
|
|
|
|
|
|
break; |
|
7029
|
|
|
|
|
|
|
} |
|
7030
|
|
|
|
|
|
|
FIX_MULTICALL_REFCOUNT; |
|
7031
|
961
|
50
|
|
|
|
|
POP_MULTICALL; |
|
7032
|
|
|
|
|
|
|
} |
|
7033
|
|
|
|
|
|
|
else |
|
7034
|
|
|
|
|
|
|
#endif |
|
7035
|
|
|
|
|
|
|
{ |
|
7036
|
0
|
0
|
|
|
|
|
for (index = 1; index < items; index++) { |
|
7037
|
0
|
|
|
|
|
|
dSP; |
|
7038
|
0
|
|
|
|
|
|
GvSV(PL_defgv) = args[index]; |
|
7039
|
0
|
0
|
|
|
|
|
PUSHMARK(SP); |
|
7040
|
0
|
|
|
|
|
|
call_sv((SV*)subcv, G_SCALAR); |
|
7041
|
0
|
0
|
|
|
|
|
if (SvTRUEx(*PL_stack_sp) ^ invert) |
|
7042
|
0
|
|
|
|
|
|
break; |
|
7043
|
|
|
|
|
|
|
} |
|
7044
|
|
|
|
|
|
|
} |
|
7045
|
|
|
|
|
|
|
|
|
7046
|
961
|
100
|
|
|
|
|
if (ix == 4) { |
|
7047
|
5
|
100
|
|
|
|
|
if (index == items) |
|
7048
|
2
|
|
|
|
|
|
XSRETURN_UNDEF; |
|
7049
|
3
|
|
|
|
|
|
ST(0) = ST(index); |
|
7050
|
3
|
|
|
|
|
|
XSRETURN(1); |
|
7051
|
|
|
|
|
|
|
} |
|
7052
|
956
|
100
|
|
|
|
|
if (ix == 6) { |
|
7053
|
5
|
100
|
|
|
|
|
if (index == items) |
|
7054
|
2
|
|
|
|
|
|
XSRETURN_IV(-1); |
|
7055
|
3
|
|
|
|
|
|
XSRETURN_UV(index-1); |
|
7056
|
|
|
|
|
|
|
} |
|
7057
|
|
|
|
|
|
|
|
|
7058
|
951
|
100
|
|
|
|
|
if (index != items) /* We exited the loop early */ |
|
7059
|
581
|
|
|
|
|
|
ret_true = !ret_true; |
|
7060
|
|
|
|
|
|
|
|
|
7061
|
951
|
100
|
|
|
|
|
if (ret_true) XSRETURN_YES; |
|
7062
|
585
|
|
|
|
|
|
else XSRETURN_NO; |
|
7063
|
|
|
|
|
|
|
} |
|
7064
|
|
|
|
|
|
|
|
|
7065
|
|
|
|
|
|
|
void vecuniq(...) |
|
7066
|
|
|
|
|
|
|
PROTOTYPE: @ |
|
7067
|
|
|
|
|
|
|
PREINIT: |
|
7068
|
|
|
|
|
|
|
iset_t s; |
|
7069
|
|
|
|
|
|
|
int status, retvals; |
|
7070
|
|
|
|
|
|
|
SSize_t j; |
|
7071
|
|
|
|
|
|
|
UV n; |
|
7072
|
|
|
|
|
|
|
unsigned long sz, nret; |
|
7073
|
|
|
|
|
|
|
PPCODE: |
|
7074
|
7
|
100
|
|
|
|
|
retvals = (GIMME_V != G_SCALAR && GIMME_V != G_VOID); |
|
|
|
50
|
|
|
|
|
|
|
7075
|
7
|
|
|
|
|
|
s = iset_create((size_t)items); |
|
7076
|
93
|
100
|
|
|
|
|
for (status = 1, nret = 0, j = 0; j < items; j++) { |
|
7077
|
86
|
|
|
|
|
|
status = _validate_and_set(&n, aTHX_ ST(j), IFLAG_ANY); |
|
7078
|
86
|
50
|
|
|
|
|
if (status == 0) break; |
|
7079
|
86
|
100
|
|
|
|
|
if (iset_add(&s, n, status) == 0) |
|
7080
|
48
|
|
|
|
|
|
continue; |
|
7081
|
38
|
50
|
|
|
|
|
if (iset_sign(s) == 0) { status = 0; break; } |
|
7082
|
38
|
100
|
|
|
|
|
if (retvals) { |
|
7083
|
28
|
100
|
|
|
|
|
PUSHs(sv_2mortal(NEWSVINT(status,n))); |
|
7084
|
28
|
|
|
|
|
|
nret++; |
|
7085
|
|
|
|
|
|
|
} |
|
7086
|
|
|
|
|
|
|
} |
|
7087
|
7
|
|
|
|
|
|
sz = iset_size(s); |
|
7088
|
7
|
|
|
|
|
|
iset_destroy(&s); |
|
7089
|
7
|
50
|
|
|
|
|
if (status != 0 && retvals) { |
|
|
|
100
|
|
|
|
|
|
|
7090
|
6
|
50
|
|
|
|
|
if (nret != sz)croak("vecuniq: iset %lu items, pushed %lu items",sz,nret); |
|
7091
|
6
|
|
|
|
|
|
XSRETURN(nret); |
|
7092
|
1
|
50
|
|
|
|
|
} else if (status != 0) { |
|
7093
|
1
|
|
|
|
|
|
ST(0) = sv_2mortal(newSVuv(sz)); |
|
7094
|
1
|
|
|
|
|
|
XSRETURN(1); |
|
7095
|
|
|
|
|
|
|
} else { |
|
7096
|
|
|
|
|
|
|
/* This is 100% from List::MoreUtils::XS by Parseval and Rehsack */ |
|
7097
|
|
|
|
|
|
|
I32 i; |
|
7098
|
0
|
|
|
|
|
|
IV count = 0, seen_undef = 0; |
|
7099
|
0
|
|
|
|
|
|
HV *hv = newHV(); |
|
7100
|
0
|
|
|
|
|
|
SV **args = &PL_stack_base[ax]; |
|
7101
|
0
|
|
|
|
|
|
SV *tmp = sv_newmortal(); |
|
7102
|
0
|
|
|
|
|
|
sv_2mortal(newRV_noinc((SV*)hv)); |
|
7103
|
|
|
|
|
|
|
|
|
7104
|
0
|
0
|
|
|
|
|
if (GIMME_V == G_SCALAR) { /* don't build return list if not needed */ |
|
7105
|
0
|
0
|
|
|
|
|
for (i = 0; i < items; i++) { |
|
7106
|
0
|
0
|
|
|
|
|
SvGETMAGIC(args[i]); |
|
|
|
0
|
|
|
|
|
|
|
7107
|
0
|
0
|
|
|
|
|
if (SvOK(args[i])) { |
|
7108
|
0
|
|
|
|
|
|
sv_setsv_nomg(tmp, args[i]); |
|
7109
|
0
|
0
|
|
|
|
|
if (!hv_exists_ent(hv, tmp, 0)) { |
|
7110
|
0
|
|
|
|
|
|
++count; |
|
7111
|
0
|
|
|
|
|
|
hv_store_ent(hv, tmp, &PL_sv_yes, 0); |
|
7112
|
|
|
|
|
|
|
} |
|
7113
|
0
|
0
|
|
|
|
|
} else if (0 == seen_undef++) |
|
7114
|
0
|
|
|
|
|
|
++count; |
|
7115
|
|
|
|
|
|
|
} |
|
7116
|
0
|
|
|
|
|
|
ST(0) = sv_2mortal(newSVuv(count)); |
|
7117
|
0
|
|
|
|
|
|
XSRETURN(1); |
|
7118
|
|
|
|
|
|
|
} |
|
7119
|
|
|
|
|
|
|
/* list context: populate SP with mortal copies */ |
|
7120
|
0
|
0
|
|
|
|
|
for (i = 0; i < items; i++) { |
|
7121
|
0
|
0
|
|
|
|
|
SvGETMAGIC(args[i]); |
|
|
|
0
|
|
|
|
|
|
|
7122
|
0
|
0
|
|
|
|
|
if (SvOK(args[i])) { |
|
7123
|
0
|
0
|
|
|
|
|
SvSetSV_nosteal(tmp, args[i]); |
|
7124
|
0
|
0
|
|
|
|
|
if (!hv_exists_ent(hv, tmp, 0)) { |
|
7125
|
0
|
|
|
|
|
|
args[count++] = args[i]; |
|
7126
|
0
|
|
|
|
|
|
hv_store_ent(hv, tmp, &PL_sv_yes, 0); |
|
7127
|
|
|
|
|
|
|
} |
|
7128
|
0
|
0
|
|
|
|
|
} else if (0 == seen_undef++) |
|
7129
|
0
|
|
|
|
|
|
args[count++] = args[i]; |
|
7130
|
|
|
|
|
|
|
} |
|
7131
|
0
|
|
|
|
|
|
XSRETURN(count); |
|
7132
|
|
|
|
|
|
|
} |
|
7133
|
|
|
|
|
|
|
|
|
7134
|
|
|
|
|
|
|
void vecfreq(...) |
|
7135
|
|
|
|
|
|
|
PROTOTYPE: @ |
|
7136
|
|
|
|
|
|
|
PREINIT: |
|
7137
|
|
|
|
|
|
|
int itype; |
|
7138
|
|
|
|
|
|
|
size_t len, i, retlen; |
|
7139
|
|
|
|
|
|
|
UV *L, count; |
|
7140
|
|
|
|
|
|
|
PPCODE: |
|
7141
|
14
|
100
|
|
|
|
|
if (items == 0) { |
|
7142
|
2
|
100
|
|
|
|
|
if (GIMME_V == G_SCALAR) XSRETURN_UV(0); |
|
7143
|
1
|
|
|
|
|
|
else XSRETURN_EMPTY; |
|
7144
|
|
|
|
|
|
|
} |
|
7145
|
|
|
|
|
|
|
/* Try to read native integers. Bail to PP if something else. */ |
|
7146
|
12
|
|
|
|
|
|
len = (size_t) items; |
|
7147
|
12
|
50
|
|
|
|
|
New(0, L, len, UV); |
|
7148
|
12
|
|
|
|
|
|
itype = IARR_TYPE_ANY; |
|
7149
|
48
|
100
|
|
|
|
|
for (i = 0; i < len && itype != IARR_TYPE_BAD && SVNUMTEST(ST(i)); i++) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
7150
|
36
|
|
|
|
|
|
IV n = SvIVX(ST(i)); |
|
7151
|
36
|
100
|
|
|
|
|
if (n < 0) { |
|
7152
|
8
|
100
|
|
|
|
|
if (SvIsUV(ST(i))) itype |= IARR_TYPE_POS; |
|
7153
|
7
|
|
|
|
|
|
else itype |= IARR_TYPE_NEG; |
|
7154
|
|
|
|
|
|
|
} |
|
7155
|
36
|
|
|
|
|
|
L[i] = n; |
|
7156
|
|
|
|
|
|
|
} |
|
7157
|
12
|
100
|
|
|
|
|
if (i < len || itype == IARR_TYPE_BAD) { |
|
|
|
100
|
|
|
|
|
|
|
7158
|
4
|
|
|
|
|
|
Safefree(L); |
|
7159
|
4
|
|
|
|
|
|
DISPATCHPP(); |
|
7160
|
4
|
|
|
|
|
|
return; |
|
7161
|
|
|
|
|
|
|
} |
|
7162
|
8
|
100
|
|
|
|
|
if (itype == IARR_TYPE_NEG) |
|
7163
|
4
|
|
|
|
|
|
sort_iv_array((IV*)L, len); |
|
7164
|
|
|
|
|
|
|
else |
|
7165
|
4
|
|
|
|
|
|
sort_uv_array(L, len); |
|
7166
|
|
|
|
|
|
|
/* 2. Walk the sorted integers */ |
|
7167
|
8
|
100
|
|
|
|
|
if (GIMME_V == G_SCALAR) { |
|
7168
|
4
|
|
|
|
|
|
count = 0; |
|
7169
|
17
|
100
|
|
|
|
|
for (i = 1; i < len; i++) |
|
7170
|
13
|
100
|
|
|
|
|
if (L[i] != L[i-1]) |
|
7171
|
7
|
|
|
|
|
|
count++; |
|
7172
|
4
|
|
|
|
|
|
ST(0) = sv_2mortal(newSVuv(count+1)); |
|
7173
|
4
|
|
|
|
|
|
retlen = 1; |
|
7174
|
|
|
|
|
|
|
} else { |
|
7175
|
4
|
100
|
|
|
|
|
int sign = itype == IARR_TYPE_NEG ? -1 : 1; |
|
7176
|
4
|
50
|
|
|
|
|
EXTEND(SP, (EXTEND_TYPE)len*2); |
|
|
|
50
|
|
|
|
|
|
|
7177
|
4
|
|
|
|
|
|
retlen = 0; |
|
7178
|
4
|
|
|
|
|
|
count = 1; |
|
7179
|
17
|
100
|
|
|
|
|
for (i = 1; i < len; i++) { |
|
7180
|
13
|
100
|
|
|
|
|
if (L[i] == L[i-1]) { count++; continue; } |
|
7181
|
7
|
50
|
|
|
|
|
PUSHs(sv_2mortal(NEWSVINT(sign,L[i-1]))); /* key */ |
|
7182
|
7
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv(count))); /* val */ |
|
7183
|
7
|
|
|
|
|
|
retlen += 2; |
|
7184
|
7
|
|
|
|
|
|
count = 1; |
|
7185
|
|
|
|
|
|
|
} |
|
7186
|
4
|
100
|
|
|
|
|
PUSHs(sv_2mortal(NEWSVINT(sign,L[i-1]))); /* key */ |
|
7187
|
4
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVuv(count))); /* val */ |
|
7188
|
4
|
|
|
|
|
|
retlen += 2; |
|
7189
|
|
|
|
|
|
|
} |
|
7190
|
8
|
|
|
|
|
|
Safefree(L); |
|
7191
|
8
|
|
|
|
|
|
XSRETURN(retlen); |
|
7192
|
|
|
|
|
|
|
|
|
7193
|
|
|
|
|
|
|
void vecsingleton(...) |
|
7194
|
|
|
|
|
|
|
PROTOTYPE: @ |
|
7195
|
|
|
|
|
|
|
PREINIT: |
|
7196
|
|
|
|
|
|
|
int itype; |
|
7197
|
|
|
|
|
|
|
size_t len, i, retlen, count; |
|
7198
|
|
|
|
|
|
|
UV *L; |
|
7199
|
|
|
|
|
|
|
iset_t seen, dups; |
|
7200
|
|
|
|
|
|
|
PPCODE: |
|
7201
|
8
|
100
|
|
|
|
|
if (items == 0) { |
|
7202
|
1
|
50
|
|
|
|
|
if (GIMME_V == G_SCALAR) XSRETURN_UV(0); |
|
7203
|
1
|
|
|
|
|
|
else XSRETURN_EMPTY; |
|
7204
|
|
|
|
|
|
|
} |
|
7205
|
|
|
|
|
|
|
/* Try to read native integers. Bail to PP if something else. */ |
|
7206
|
7
|
|
|
|
|
|
len = (size_t) items; |
|
7207
|
7
|
50
|
|
|
|
|
New(0, L, len, UV); |
|
7208
|
7
|
|
|
|
|
|
seen = iset_create(len); |
|
7209
|
7
|
|
|
|
|
|
dups = iset_create(len>>1); |
|
7210
|
7
|
|
|
|
|
|
itype = IARR_TYPE_ANY; |
|
7211
|
55
|
100
|
|
|
|
|
for (i = 0; i < len && itype != IARR_TYPE_BAD && SVNUMTEST(ST(i)); i++) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
7212
|
48
|
|
|
|
|
|
IV n = SvIVX(ST(i)); |
|
7213
|
48
|
|
|
|
|
|
int sign = 1; |
|
7214
|
48
|
100
|
|
|
|
|
if (n < 0) { |
|
7215
|
2
|
50
|
|
|
|
|
if (SvIsUV(ST(i))) itype |= IARR_TYPE_POS; |
|
7216
|
2
|
|
|
|
|
|
else { itype |= IARR_TYPE_NEG; sign = -1; } |
|
7217
|
|
|
|
|
|
|
} |
|
7218
|
48
|
|
|
|
|
|
L[i] = n; |
|
7219
|
48
|
100
|
|
|
|
|
if (!iset_add(&seen, n, sign)) |
|
7220
|
22
|
|
|
|
|
|
iset_add(&dups, n, sign); |
|
7221
|
|
|
|
|
|
|
} |
|
7222
|
7
|
50
|
|
|
|
|
if (iset_is_invalid(seen)) itype = IARR_TYPE_BAD; /* Poison the type */ |
|
7223
|
7
|
|
|
|
|
|
iset_destroy(&seen); |
|
7224
|
7
|
100
|
|
|
|
|
if (i < len || itype == IARR_TYPE_BAD) { |
|
|
|
50
|
|
|
|
|
|
|
7225
|
4
|
|
|
|
|
|
iset_destroy(&dups); |
|
7226
|
4
|
|
|
|
|
|
Safefree(L); |
|
7227
|
4
|
|
|
|
|
|
DISPATCHPP(); |
|
7228
|
4
|
|
|
|
|
|
return; |
|
7229
|
|
|
|
|
|
|
} |
|
7230
|
3
|
100
|
|
|
|
|
if (GIMME_V != G_ARRAY) { |
|
7231
|
24
|
100
|
|
|
|
|
for (i = 0, count = 0; i < len; i++) |
|
7232
|
23
|
100
|
|
|
|
|
if (!iset_contains(dups, L[i])) |
|
7233
|
2
|
|
|
|
|
|
count++; |
|
7234
|
1
|
|
|
|
|
|
ST(0) = sv_2mortal(newSVuv(count)); |
|
7235
|
1
|
|
|
|
|
|
retlen = 1; |
|
7236
|
|
|
|
|
|
|
} else { |
|
7237
|
26
|
100
|
|
|
|
|
for (i = 0, retlen = 0; i < len; i++) |
|
7238
|
24
|
100
|
|
|
|
|
if (!iset_contains(dups, L[i])) |
|
7239
|
3
|
|
|
|
|
|
ST(retlen++) = ST(i); |
|
7240
|
|
|
|
|
|
|
} |
|
7241
|
3
|
|
|
|
|
|
iset_destroy(&dups); |
|
7242
|
3
|
|
|
|
|
|
Safefree(L); |
|
7243
|
3
|
|
|
|
|
|
XSRETURN(retlen); |