Math-Prime-Util
view release on metacpan or search on metacpan
A[val] = i+1;
V[i] = val;
}
if (i >= plen && perm_to_num(plen, V, &num))
XSRETURN_UV(num);
}
DISPATCHPP();
objectify_result(aTHX_ svp, ST(0));
XSRETURN(1);
void randperm(IN UV n, IN UV k = 0)
PREINIT:
UV i, *S;
dMY_CXT;
PPCODE:
if (items == 1) k = n;
if (k > n) k = n;
if (k == 0) XSRETURN_EMPTY;
New(0, S, k, UV);
randperm(MY_CXT.randcxt, n, k, S);
EXTEND(SP, (EXTEND_TYPE)k);
for (i = 0; i < k; i++) {
if (n < 2*CINTS) PUSH_NPARITY(S[i]);
else PUSHs(sv_2mortal(newSVuv(S[i])));
}
Safefree(S);
void shuffle(...)
PROTOTYPE: @
PREINIT:
SSize_t i, j;
void* randcxt;
dMY_CXT;
PPCODE:
if (items == 0)
XSRETURN_EMPTY;
for (i = 0, randcxt = MY_CXT.randcxt; i < items-1; i++) {
j = urandomm64(randcxt, items-i);
{ SV* t = ST(i); ST(i) = ST(i+j); ST(i+j) = t; }
}
XSRETURN(items);
void vecsample(IN SV* svk, ...)
PROTOTYPE: $@
PREINIT:
void *randcxt;
UV k;
Size_t nitems, i;
dMY_CXT;
PPCODE:
if (items == 1)
XSRETURN_EMPTY;
randcxt = MY_CXT.randcxt;
/*
* Fisher-Yates shuffle with first 'k' selections returned.
*
* There is only one algorithm here, no shortcuts other than
* detecting an empty list.
*
* With a list input, the input is on the stack ST(1),ST(2),...
* We move the last item to ST(0) then shuffle 'k' iterations.
*
* With an array reference input, we cannot modify the input at all.
* We create an index array and shuffle using that. Remembering to
* act like the last item is at the front so we match the list results.
* We optimize by pushing each selection onto the return stack as
* we find it rather than pushing them all at the end with another loop.
*/
if (items > 2 || !SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV) {
/* Standard form, where we are given an array of items */
nitems = items-1;
if (_validate_and_set(&k, aTHX_ svk, IFLAG_POS) == 0 || k > nitems)
k = nitems;
ST(0) = ST(items-1); /* Move last value to the first stack entry. */
for (i = 0; i < k; i++) {
uint32_t j = urandomm32(randcxt, nitems-i);
{ SV* t = ST(i); ST(i) = ST(i+j); ST(i+j) = t; }
}
} else { /* We are given a single array reference. Select from it. */
DECL_ARREF(avp);
USE_ARREF(avp, ST(1), SUBNAME, AR_READ);
nitems = len_avp;
if (_validate_and_set(&k, aTHX_ svk, IFLAG_POS) == 0 || k > nitems)
k = nitems;
if (k == 0)
XSRETURN_EMPTY;
if (nitems < 65536) {
uint16_t *I;
New(0, I, nitems, uint16_t);
I[0] = nitems-1; for (i = 1; i < nitems; i++) I[i] = i-1;
EXTEND(SP, (EXTEND_TYPE)k);
for (i = 0; i < k; i++) {
uint32_t j = urandomm32(randcxt, nitems-i);
uint16_t t = I[i+j]; I[i+j] = I[i];
PUSHs(FETCH_ARREF(avp,t));
}
Safefree(I);
} else {
size_t *I;
New(0, I, nitems, size_t);
I[0] = nitems-1; for (i = 1; i < nitems; i++) I[i] = i-1;
EXTEND(SP, (EXTEND_TYPE)k);
for (i = 0; i < k; i++) {
size_t j = urandomm64(randcxt, nitems-i);
size_t t = I[i+j]; I[i+j] = I[i];
PUSHs(FETCH_ARREF(avp,t));
}
Safefree(I);
}
}
XSRETURN(k);
void is_happy(SV* svn, UV base = 10, UV k = 2)
PREINIT:
UV n, sum;
int h, status;
PPCODE:
if (base < 2 || base > 36) croak("is_happy: invalid base %"UVuf, base);
if (k > 10) croak("is_happy: invalid exponent %"UVuf, k);
status = _validate_and_set(&n, aTHX_ svn, IFLAG_POS);
( run in 0.708 second using v1.01-cache-2.11-cpan-71847e10f99 )