Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
#line 2 "../src/kernel/gmp/mp.c"1/* Copyright (C) 2002-2003 The PARI group.23This file is part of the PARI/GP package.45PARI/GP is free software; you can redistribute it and/or modify it under the6terms of the GNU General Public License as published by the Free Software7Foundation; either version 2 of the License, or (at your option) any later8version. It is distributed in the hope that it will be useful, but WITHOUT9ANY WARRANTY WHATSOEVER.1011Check the License for details. You should have received a copy of it, along12with the package; see the file 'COPYING'. If not, write to the Free Software13Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */1415/***********************************************************************/16/** **/17/** GMP KERNEL **/18/** BA2002Sep24 **/19/***********************************************************************/20/* GMP t_INT as just like normal t_INT, just the mantissa is the other way21* round22*23* `How would you like to live in Looking-glass House, Kitty? I24* wonder if they'd give you milk in there? Perhaps Looking-glass25* milk isn't good to drink--But oh, Kitty! now we come to the26* passage. You can just see a little PEEP of the passage in27* Looking-glass House, if you leave the door of our drawing-room28* wide open: and it's very like our passage as far as you can see,29* only you know it may be quite different on beyond. Oh, Kitty!30* how nice it would be if we could only get through into Looking-31* glass House! I'm sure it's got, oh! such beautiful things in it!32*33* Through the Looking Glass, Lewis Carrol34*35* (pityful attempt to beat GN code/comments rate)36* */3738#include <gmp.h>39#include "pari.h"40#include "paripriv.h"41#include "../src/kernel/none/tune-gen.h"4243/*We need PARI invmod renamed to invmod_pari*/44#define INVMOD_PARI4546static void *pari_gmp_realloc(void *ptr, size_t old_size, size_t new_size) {47(void)old_size; return (void *) pari_realloc(ptr,new_size);48}4950static void pari_gmp_free(void *ptr, size_t old_size){51(void)old_size; pari_free(ptr);52}5354static void *(*old_gmp_malloc)(size_t new_size);55static void *(*old_gmp_realloc)(void *ptr, size_t old_size, size_t new_size);56static void (*old_gmp_free)(void *ptr, size_t old_size);5758void59pari_kernel_init(void)60{61mp_get_memory_functions (&old_gmp_malloc, &old_gmp_realloc, &old_gmp_free);62mp_set_memory_functions((void *(*)(size_t)) pari_malloc, pari_gmp_realloc, pari_gmp_free);63}6465const char *66pari_kernel_version(void)67{68#ifdef gmp_version69return gmp_version;70#else71return "";72#endif73}7475void76pari_kernel_close(void)77{78void *(*new_gmp_malloc)(size_t new_size);79void *(*new_gmp_realloc)(void *ptr, size_t old_size, size_t new_size);80void (*new_gmp_free)(void *ptr, size_t old_size);81mp_get_memory_functions (&new_gmp_malloc, &new_gmp_realloc, &new_gmp_free);82if (new_gmp_malloc==pari_malloc) new_gmp_malloc = old_gmp_malloc;83if (new_gmp_realloc==pari_gmp_realloc) new_gmp_realloc = old_gmp_realloc;84if (new_gmp_free==pari_gmp_free) new_gmp_free = old_gmp_free;85mp_set_memory_functions(new_gmp_malloc, new_gmp_realloc, new_gmp_free);86}8788#define LIMBS(x) ((mp_limb_t *)((x)+2))89#define NLIMBS(x) (lgefint(x)-2)90/*This one is for t_REALs to emphasize they are not t_INTs*/91#define RLIMBS(x) ((mp_limb_t *)((x)+2))92#define RNLIMBS(x) (lg(x)-2)9394INLINE void95xmpn_copy(mp_limb_t *x, mp_limb_t *y, long n)96{97while (--n >= 0) x[n]=y[n];98}99100INLINE void101xmpn_mirror(mp_limb_t *x, long n)102{103long i;104for(i=0;i<(n>>1);i++)105{106ulong m=x[i];107x[i]=x[n-1-i];108x[n-1-i]=m;109}110}111112INLINE void113xmpn_mirrorcopy(mp_limb_t *z, mp_limb_t *x, long n)114{115long i;116for(i=0;i<n;i++)117z[i]=x[n-1-i];118}119120INLINE void121xmpn_zero(mp_ptr x, mp_size_t n)122{123while (--n >= 0) x[n]=0;124}125126INLINE GEN127icopy_ef(GEN x, long l)128{129register long lx = lgefint(x);130const GEN y = cgeti(l);131132while (--lx > 0) y[lx]=x[lx];133return y;134}135136/* NOTE: arguments of "spec" routines (muliispec, addiispec, etc.) aren't137* GENs but pairs (long *a, long na) representing a list of digits (in basis138* BITS_IN_LONG) : a[0], ..., a[na-1]. [ In ordre to facilitate splitting: no139* need to reintroduce codewords ]140* Use speci(a,na) to visualize the corresponding GEN.141*/142143/***********************************************************************/144/** **/145/** ADDITION / SUBTRACTION **/146/** **/147/***********************************************************************/148149GEN150setloop(GEN a)151{152pari_sp av = avma - 2 * sizeof(long);153(void)cgetg(lgefint(a) + 3, t_VECSMALL);154return icopy_avma(a, av); /* two cells of extra space after a */155}156157/* we had a = setloop(?), then some incloops. Reset a to b */158GEN159resetloop(GEN a, GEN b) {160a[0] = evaltyp(t_INT) | evallg(lgefint(b));161affii(b, a); return a;162}163164/* assume a > 0, initialized by setloop. Do a++ */165static GEN166incpos(GEN a)167{168long i, l = lgefint(a);169for (i=2; i<l; i++)170if (++uel(a,i)) return a;171a[l] = 1; l++;172a[0]=evaltyp(t_INT) | _evallg(l);173a[1]=evalsigne(1) | evallgefint(l);174return a;175}176177/* assume a < 0, initialized by setloop. Do a++ */178static GEN179incneg(GEN a)180{181long i, l = lgefint(a)-1;182if (uel(a,2)--)183{184if (!a[l]) /* implies l = 2 */185{186a[0] = evaltyp(t_INT) | _evallg(2);187a[1] = evalsigne(0) | evallgefint(2);188}189return a;190}191for (i=3; i<=l; i++)192if (uel(a,i)--) break;193if (!a[l])194{195a[0] = evaltyp(t_INT) | _evallg(l);196a[1] = evalsigne(-1) | evallgefint(l);197}198return a;199}200201/* assume a initialized by setloop. Do a++ */202GEN203incloop(GEN a)204{205switch(signe(a))206{207case 0:208a[0]=evaltyp(t_INT) | _evallg(3);209a[1]=evalsigne(1) | evallgefint(3);210a[2]=1; return a;211case -1: return incneg(a);212default: return incpos(a);213}214}215216INLINE GEN217adduispec(ulong s, GEN x, long nx)218{219GEN zd;220long lz;221222if (nx == 1) return adduu(uel(x,0), s);223lz = nx+3; zd = cgeti(lz);224if (mpn_add_1(LIMBS(zd),(mp_limb_t *)x,nx,s))225zd[lz-1]=1;226else227lz--;228zd[1] = evalsigne(1) | evallgefint(lz);229return zd;230}231232GEN233adduispec_offset(ulong s, GEN x, long offset, long nx)234{235GEN xd=x+2+offset;236while (nx && *(xd+nx-1)==0) nx--;237if (!nx) return utoi(s);238return adduispec(s,xd,nx);239}240241INLINE GEN242addiispec(GEN x, GEN y, long nx, long ny)243{244GEN zd;245long lz;246247if (nx < ny) swapspec(x,y, nx,ny);248if (ny == 1) return adduispec(*y,x,nx);249lz = nx+3; zd = cgeti(lz);250251if (mpn_add(LIMBS(zd),(mp_limb_t *)x,nx,(mp_limb_t *)y,ny))252zd[lz-1]=1;253else254lz--;255256zd[1] = evalsigne(1) | evallgefint(lz);257return zd;258}259260/* assume x >= y */261INLINE GEN262subiuspec(GEN x, ulong s, long nx)263{264GEN zd;265long lz;266267if (nx == 1) return utoi(x[0] - s);268269lz = nx + 2; zd = cgeti(lz);270mpn_sub_1 (LIMBS(zd), (mp_limb_t *)x, nx, s);271if (! zd[lz - 1]) { --lz; }272273zd[1] = evalsigne(1) | evallgefint(lz);274return zd;275}276277/* assume x > y */278INLINE GEN279subiispec(GEN x, GEN y, long nx, long ny)280{281GEN zd;282long lz;283if (ny==1) return subiuspec(x,*y,nx);284lz = nx+2; zd = cgeti(lz);285286mpn_sub (LIMBS(zd), (mp_limb_t *)x, nx, (mp_limb_t *)y, ny);287while (lz >= 3 && zd[lz - 1] == 0) { lz--; }288289zd[1] = evalsigne(1) | evallgefint(lz);290return zd;291}292293static void294roundr_up_ip(GEN x, long l)295{296long i = l;297for(;;)298{299if (++((ulong*)x)[--i]) break;300if (i == 2) { x[2] = HIGHBIT; shiftr_inplace(x, 1); break; }301}302}303304void305affir(GEN x, GEN y)306{307const long s = signe(x), ly = lg(y);308long lx, sh, i;309310if (!s)311{312y[1] = evalexpo(-bit_accuracy(ly));313return;314}315lx = lgefint(x); sh = bfffo(*int_MSW(x));316y[1] = evalsigne(s) | evalexpo(bit_accuracy(lx)-sh-1);317if (sh) {318if (lx <= ly)319{320for (i=lx; i<ly; i++) y[i]=0;321mpn_lshift(LIMBS(y),LIMBS(x),lx-2,sh);322xmpn_mirror(LIMBS(y),lx-2);323return;324}325mpn_lshift(LIMBS(y),LIMBS(x)+lx-ly,ly-2,sh);326uel(y,2) |= uel(x,lx-ly+1) >> (BITS_IN_LONG-sh);327xmpn_mirror(LIMBS(y),ly-2);328/* lx > ly: round properly */329if ((uel(x,lx-ly+1)<<sh) & HIGHBIT) roundr_up_ip(y, ly);330}331else {332GEN xd=int_MSW(x);333if (lx <= ly)334{335for (i=2; i<lx; i++,xd=int_precW(xd)) y[i]=*xd;336for ( ; i<ly; i++) y[i]=0;337return;338}339for (i=2; i<ly; i++,xd=int_precW(xd)) y[i]=*xd;340/* lx > ly: round properly */341if (uel(x,lx-ly+1) & HIGHBIT) roundr_up_ip(y, ly);342}343}344345INLINE GEN346shiftispec(GEN x, long nx, long n)347{348long ny,m;349GEN yd, y;350351if (!n) return icopyspec(x, nx);352353if (n > 0)354{355long d = dvmdsBIL(n, &m);356long i;357358ny = nx + d + (m!=0);359y = cgeti(ny + 2); yd = y + 2;360for (i=0; i<d; i++) yd[i] = 0;361362if (!m) xmpn_copy((mp_limb_t *) (yd + d), (mp_limb_t *) x, nx);363else364{365ulong carryd = mpn_lshift((mp_limb_t *) (yd + d), (mp_limb_t *) x, nx, m);366if (carryd) yd[ny - 1] = carryd;367else ny--;368}369}370else371{372long d = dvmdsBIL(-n, &m);373374ny = nx - d;375if (ny < 1) return gen_0;376y = cgeti(ny + 2); yd = y + 2;377378if (!m) xmpn_copy((mp_limb_t *) yd, (mp_limb_t *) (x + d), nx - d);379else380{381mpn_rshift((mp_limb_t *) yd, (mp_limb_t *) (x + d), nx - d, m);382if (yd[ny - 1] == 0)383{384if (ny == 1) return gc_const((pari_sp)(yd + 1), gen_0);385ny--;386}387}388}389y[1] = evalsigne(1)|evallgefint(ny + 2);390return y;391}392393GEN394mantissa2nr(GEN x, long n)395{396long ly, i, m, s = signe(x), lx = lg(x);397GEN y;398if (!s) return gen_0;399if (!n)400{401y = cgeti(lx);402y[1] = evalsigne(s) | evallgefint(lx);403xmpn_mirrorcopy(LIMBS(y),RLIMBS(x),lx-2);404return y;405}406if (n > 0)407{408GEN z = (GEN)avma;409long d = dvmdsBIL(n, &m);410411ly = lx+d; y = new_chunk(ly);412for ( ; d; d--) *--z = 0;413if (!m) for (i=2; i<lx; i++) y[i]=x[i];414else415{416register const ulong sh = BITS_IN_LONG - m;417shift_left(y,x, 2,lx-1, 0,m);418i = uel(x,2) >> sh;419/* Extend y on the left? */420if (i) { ly++; y = new_chunk(1); y[2] = i; }421}422}423else424{425ly = lx - dvmdsBIL(-n, &m);426if (ly<3) return gen_0;427y = new_chunk(ly);428if (m) {429shift_right(y,x, 2,ly, 0,m);430if (y[2] == 0)431{432if (ly==3) return gc_const((pari_sp)(y+3), gen_0);433ly--; set_avma((pari_sp)(++y));434}435} else {436for (i=2; i<ly; i++) y[i]=x[i];437}438}439xmpn_mirror(LIMBS(y),ly-2);440y[1] = evalsigne(s)|evallgefint(ly);441y[0] = evaltyp(t_INT)|evallg(ly); return y;442}443444GEN445truncr(GEN x)446{447long s, e, d, m, i;448GEN y;449if ((s=signe(x)) == 0 || (e=expo(x)) < 0) return gen_0;450d = nbits2lg(e+1); m = remsBIL(e);451if (d > lg(x)) pari_err_PREC( "truncr (precision loss in truncation)");452453y=cgeti(d); y[1] = evalsigne(s) | evallgefint(d);454if (++m == BITS_IN_LONG)455for (i=2; i<d; i++) y[d-i+1]=x[i];456else457{458GEN z=cgeti(d);459for (i=2; i<d; i++) z[d-i+1]=x[i];460mpn_rshift(LIMBS(y),LIMBS(z),d-2,BITS_IN_LONG-m);461set_avma((pari_sp)y);462}463return y;464}465466/* integral part */467GEN468floorr(GEN x)469{470long e, d, m, i, lx;471GEN y;472if (signe(x) >= 0) return truncr(x);473if ((e=expo(x)) < 0) return gen_m1;474d = nbits2lg(e+1); m = remsBIL(e);475lx=lg(x); if (d>lx) pari_err_PREC( "floorr (precision loss in truncation)");476y = cgeti(d+1);477if (++m == BITS_IN_LONG)478{479for (i=2; i<d; i++) y[d-i+1]=x[i];480i=d; while (i<lx && !x[i]) i++;481if (i==lx) goto END;482}483else484{485GEN z=cgeti(d);486for (i=2; i<d; i++) z[d-i+1]=x[i];487mpn_rshift(LIMBS(y),LIMBS(z),d-2,BITS_IN_LONG-m);488if (uel(x,d-1)<<m == 0)489{490i=d; while (i<lx && !x[i]) i++;491if (i==lx) goto END;492}493}494if (mpn_add_1(LIMBS(y),LIMBS(y),d-2,1))495y[d++]=1;496END:497y[1] = evalsigne(-1) | evallgefint(d);498return y;499}500501INLINE int502cmpiispec(GEN x, GEN y, long lx, long ly)503{504if (lx < ly) return -1;505if (lx > ly) return 1;506return mpn_cmp((mp_limb_t*)x,(mp_limb_t*)y, lx);507}508509INLINE int510equaliispec(GEN x, GEN y, long lx, long ly)511{512if (lx != ly) return 0;513return !mpn_cmp((mp_limb_t*)x,(mp_limb_t*)y, lx);514}515516/***********************************************************************/517/** **/518/** MULTIPLICATION **/519/** **/520/***********************************************************************/521/* assume ny > 0 */522INLINE GEN523muluispec(ulong x, GEN y, long ny)524{525if (ny == 1)526return muluu(x, *y);527else528{529long lz = ny+3;530GEN z = cgeti(lz);531ulong hi = mpn_mul_1 (LIMBS(z), (mp_limb_t *)y, ny, x);532if (hi) { z[lz - 1] = hi; } else lz--;533z[1] = evalsigne(1) | evallgefint(lz);534return z;535}536}537538/* a + b*|y| */539GEN540addumului(ulong a, ulong b, GEN y)541{542GEN z;543long i, lz;544ulong hi;545if (!b || !signe(y)) return utoi(a);546lz = lgefint(y)+1;547z = cgeti(lz);548z[2]=a;549for(i=3;i<lz;i++) z[i]=0;550hi=mpn_addmul_1(LIMBS(z), LIMBS(y), NLIMBS(y), b);551if (hi) z[lz-1]=hi; else lz--;552z[1] = evalsigne(1) | evallgefint(lz);553return gc_const((pari_sp)z, z);554}555556/***********************************************************************/557/** **/558/** DIVISION **/559/** **/560/***********************************************************************/561562ulong563umodiu(GEN y, ulong x)564{565long sy=signe(y);566ulong hi;567if (!x) pari_err_INV("umodiu",gen_0);568if (!sy) return 0;569hi = mpn_mod_1(LIMBS(y),NLIMBS(y),x);570if (!hi) return 0;571return (sy > 0)? hi: x - hi;572}573574/* return |y| \/ x */575GEN576absdiviu_rem(GEN y, ulong x, ulong *rem)577{578long ly;579GEN z;580581if (!x) pari_err_INV("absdiviu_rem",gen_0);582if (!signe(y)) { *rem = 0; return gen_0; }583584ly = lgefint(y);585if (ly == 3 && (ulong)x > uel(y,2)) { *rem = uel(y,2); return gen_0; }586587z = cgeti(ly);588*rem = mpn_divrem_1(LIMBS(z), 0, LIMBS(y), NLIMBS(y), x);589if (z [ly - 1] == 0) ly--;590z[1] = evallgefint(ly) | evalsigne(1);591return z;592}593594GEN595divis_rem(GEN y, long x, long *rem)596{597long sy=signe(y),ly,s;598GEN z;599600if (!x) pari_err_INV("divis_rem",gen_0);601if (!sy) { *rem = 0; return gen_0; }602if (x<0) { s = -sy; x = -x; } else s = sy;603604ly = lgefint(y);605if (ly == 3 && (ulong)x > uel(y,2)) { *rem = itos(y); return gen_0; }606607z = cgeti(ly);608*rem = mpn_divrem_1(LIMBS(z), 0, LIMBS(y), NLIMBS(y), x);609if (sy<0) *rem = - *rem;610if (z[ly - 1] == 0) ly--;611z[1] = evallgefint(ly) | evalsigne(s);612return z;613}614615GEN616divis(GEN y, long x)617{618long sy=signe(y),ly,s;619GEN z;620621if (!x) pari_err_INV("divis",gen_0);622if (!sy) return gen_0;623if (x<0) { s = -sy; x = -x; } else s=sy;624625ly = lgefint(y);626if (ly == 3 && (ulong)x > uel(y,2)) return gen_0;627628z = cgeti(ly);629(void)mpn_divrem_1(LIMBS(z), 0, LIMBS(y), NLIMBS(y), x);630if (z[ly - 1] == 0) ly--;631z[1] = evallgefint(ly) | evalsigne(s);632return z;633}634635/* We keep llx bits of x and lly bits of y*/636static GEN637divrr_with_gmp(GEN x, GEN y)638{639long lx=RNLIMBS(x),ly=RNLIMBS(y);640long lw=minss(lx,ly);641long lly=minss(lw+1,ly);642GEN w=cgetr(lw+2);643long lu=lw+lly;644long llx=minss(lu,lx);645mp_limb_t *u=(mp_limb_t *)new_chunk(lu);646mp_limb_t *z=(mp_limb_t *)new_chunk(lly);647mp_limb_t *q,*r;648long e=expo(x)-expo(y);649long sx=signe(x),sy=signe(y);650xmpn_mirrorcopy(z,RLIMBS(y),lly);651xmpn_mirrorcopy(u+lu-llx,RLIMBS(x),llx);652xmpn_zero(u,lu-llx);653q = (mp_limb_t *)new_chunk(lw+1);654r = (mp_limb_t *)new_chunk(lly);655656mpn_tdiv_qr(q,r,0,u,lu,z,lly);657658/*Round up: This is not exactly correct we should test 2*r>z*/659if (uel(r,lly-1) > (uel(z,lly-1)>>1))660mpn_add_1(q,q,lw+1,1);661662xmpn_mirrorcopy(RLIMBS(w),q,lw);663664if (q[lw] == 0) e--;665else if (q[lw] == 1) { shift_right(w,w, 2,lw+2, 1,1); }666else { w[2] = HIGHBIT; e++; }667if (sy < 0) sx = -sx;668w[1] = evalsigne(sx) | evalexpo(e);669return gc_const((pari_sp)w, w);670}671672/* We keep llx bits of x and lly bits of y*/673static GEN674divri_with_gmp(GEN x, GEN y)675{676long llx=RNLIMBS(x),ly=NLIMBS(y);677long lly=minss(llx+1,ly);678GEN w=cgetr(llx+2);679long lu=llx+lly, ld=ly-lly;680mp_limb_t *u=(mp_limb_t *)new_chunk(lu);681mp_limb_t *z=(mp_limb_t *)new_chunk(lly);682mp_limb_t *q,*r;683long sh=bfffo(y[ly+1]);684long e=expo(x)-expi(y);685long sx=signe(x),sy=signe(y);686if (sh) mpn_lshift(z,LIMBS(y)+ld,lly,sh);687else xmpn_copy(z,LIMBS(y)+ld,lly);688xmpn_mirrorcopy(u+lu-llx,RLIMBS(x),llx);689xmpn_zero(u,lu-llx);690q = (mp_limb_t *)new_chunk(llx+1);691r = (mp_limb_t *)new_chunk(lly);692693mpn_tdiv_qr(q,r,0,u,lu,z,lly);694695/*Round up: This is not exactly correct we should test 2*r>z*/696if (uel(r,lly-1) > (uel(z,lly-1)>>1))697mpn_add_1(q,q,llx+1,1);698699xmpn_mirrorcopy(RLIMBS(w),q,llx);700701if (q[llx] == 0) e--;702else if (q[llx] == 1) { shift_right(w,w, 2,llx+2, 1,1); }703else { w[2] = HIGHBIT; e++; }704if (sy < 0) sx = -sx;705w[1] = evalsigne(sx) | evalexpo(e);706return gc_const((pari_sp)w, w);707}708709GEN710divri(GEN x, GEN y)711{712long s = signe(y);713714if (!s) pari_err_INV("divri",gen_0);715if (!signe(x)) return real_0_bit(expo(x) - expi(y));716if (!is_bigint(y)) {717GEN z = divru(x, y[2]);718if (s < 0) togglesign(z);719return z;720}721return divri_with_gmp(x,y);722}723724GEN725divrr(GEN x, GEN y)726{727long sx=signe(x), sy=signe(y), lx,ly,lr,e,i,j;728ulong y0,y1;729GEN r, r1;730731if (!sy) pari_err_INV("divrr",y);732e = expo(x) - expo(y);733if (!sx) return real_0_bit(e);734if (sy<0) sx = -sx;735736lx=lg(x); ly=lg(y);737if (ly==3)738{739ulong k = x[2], l = (lx>3)? x[3]: 0;740LOCAL_HIREMAINDER;741if (k < uel(y,2)) e--;742else743{744l >>= 1; if (k&1) l |= HIGHBIT;745k >>= 1;746}747hiremainder = k; k = divll(l,y[2]);748if (hiremainder > (uel(y,2) >> 1) && !++k) { k = HIGHBIT; e++; }749r = cgetr(3);750r[1] = evalsigne(sx) | evalexpo(e);751r[2] = k; return r;752}753754if (ly>=DIVRR_GMP_LIMIT)755return divrr_with_gmp(x,y);756757lr = minss(lx,ly); r = new_chunk(lr);758r1 = r-1;759r1[1] = 0; for (i=2; i<lr; i++) r1[i]=x[i];760r1[lr] = (lx>ly)? x[lr]: 0;761y0 = y[2]; y1 = y[3];762for (i=0; i<lr-1; i++)763{ /* r1 = r + (i-1), OK up to r1[2] (accesses at most r[lr]) */764ulong k, qp;765LOCAL_HIREMAINDER;766LOCAL_OVERFLOW;767768if (uel(r1,1) == y0) { qp = ULONG_MAX; k = addll(y0,r1[2]); }769else770{771if (uel(r1,1) > y0) /* can't happen if i=0 */772{773GEN y1 = y+1;774j = lr-i; r1[j] = subll(r1[j],y1[j]);775for (j--; j>0; j--) r1[j] = subllx(r1[j],y1[j]);776j=i; do uel(r,--j)++; while (j && !r[j]);777}778hiremainder = r1[1]; overflow = 0;779qp = divll(r1[2],y0); k = hiremainder;780}781j = lr-i+1;782if (!overflow)783{784long k3, k4;785k3 = mulll(qp,y1);786if (j == 3) /* i = lr - 2 maximal, r1[3] undefined -> 0 */787k4 = subll(hiremainder,k);788else789{790k3 = subll(k3, r1[3]);791k4 = subllx(hiremainder,k);792}793while (!overflow && k4) { qp--; k3=subll(k3,y1); k4=subllx(k4,y0); }794}795if (j<ly) (void)mulll(qp,y[j]); else { hiremainder = 0 ; j = ly; }796for (j--; j>1; j--)797{798r1[j] = subll(r1[j], addmul(qp,y[j]));799hiremainder += overflow;800}801if (uel(r1,1) != hiremainder)802{803if (uel(r1,1) < hiremainder)804{805qp--;806j = lr-i-(lr-i>=ly); r1[j] = addll(r1[j], y[j]);807for (j--; j>1; j--) r1[j] = addllx(r1[j], y[j]);808}809else810{811uel(r1,1) -= hiremainder;812while (r1[1])813{814qp++; if (!qp) { j=i; do uel(r,--j)++; while (j && !r[j]); }815j = lr-i-(lr-i>=ly); r1[j] = subll(r1[j],y[j]);816for (j--; j>1; j--) r1[j] = subllx(r1[j],y[j]);817uel(r1,1) -= overflow;818}819}820}821*++r1 = qp;822}823/* i = lr-1 */824/* round correctly */825if (uel(r1,1) > (y0>>1))826{827j=i; do uel(r,--j)++; while (j && !r[j]);828}829r1 = r-1; for (j=i; j>=2; j--) r[j]=r1[j];830if (r[0] == 0) e--;831else if (r[0] == 1) { shift_right(r,r, 2,lr, 1,1); }832else { /* possible only when rounding up to 0x2 0x0 ... */833r[2] = (long)HIGHBIT; e++;834}835r[0] = evaltyp(t_REAL)|evallg(lr);836r[1] = evalsigne(sx) | evalexpo(e);837return r;838}839840/* Integer division x / y: such that sign(r) = sign(x)841* if z = ONLY_REM return remainder, otherwise return quotient842* if z != NULL set *z to remainder843* *z is the last object on stack (and thus can be disposed of with cgiv844* instead of gerepile)845* If *z is zero, we put gen_0 here and no copy.846* space needed: lx + ly847*/848GEN849dvmdii(GEN x, GEN y, GEN *z)850{851long sx=signe(x),sy=signe(y);852long lx, ly, lq;853pari_sp av;854GEN r,q;855856if (!sy) pari_err_INV("dvmdii",y);857if (!sx)858{859if (!z || z == ONLY_REM) return gen_0;860*z=gen_0; return gen_0;861}862lx=lgefint(x);863ly=lgefint(y); lq=lx-ly;864if (lq <= 0)865{866if (lq == 0)867{868long s=mpn_cmp(LIMBS(x),LIMBS(y),NLIMBS(x));869if (s>0) goto DIVIDE;870if (s==0)871{872if (z == ONLY_REM) return gen_0;873if (z) *z = gen_0;874if (sx < 0) sy = -sy;875return stoi(sy);876}877}878if (z == ONLY_REM) return icopy(x);879if (z) *z = icopy(x);880return gen_0;881}882DIVIDE: /* quotient is nonzero */883av=avma; if (sx<0) sy = -sy;884if (ly==3)885{886ulong lq = lx;887ulong si;888q = cgeti(lq);889si = mpn_divrem_1(LIMBS(q), 0, LIMBS(x), NLIMBS(x), y[2]);890if (q[lq - 1] == 0) lq--;891if (z == ONLY_REM)892{893if (!si) return gc_const(av, gen_0);894set_avma(av); r = cgeti(3);895r[1] = evalsigne(sx) | evallgefint(3);896r[2] = si; return r;897}898q[1] = evalsigne(sy) | evallgefint(lq);899if (!z) return q;900if (!si) { *z=gen_0; return q; }901r=cgeti(3);902r[1] = evalsigne(sx) | evallgefint(3);903r[2] = si; *z=r; return q;904}905if (z == ONLY_REM)906{907ulong lr = lgefint(y);908ulong lq = lgefint(x)-lgefint(y)+3;909GEN r = cgeti(lr);910GEN q = cgeti(lq);911mpn_tdiv_qr(LIMBS(q), LIMBS(r),0, LIMBS(x), NLIMBS(x), LIMBS(y), NLIMBS(y));912if (!r[lr - 1])913{914while(lr>2 && !r[lr - 1]) lr--;915if (lr == 2) return gc_const(av, gen_0); /* exact division */916}917r[1] = evalsigne(sx) | evallgefint(lr);918return gc_const((pari_sp)r, r);919}920else921{922ulong lq = lgefint(x)-lgefint(y)+3;923ulong lr = lgefint(y);924GEN q = cgeti(lq);925GEN r = cgeti(lr);926mpn_tdiv_qr(LIMBS(q), LIMBS(r),0, LIMBS(x), NLIMBS(x), LIMBS(y), NLIMBS(y));927if (q[lq - 1] == 0) lq--;928q[1] = evalsigne(sy) | evallgefint(lq);929if (!z) return gc_const((pari_sp)q, q);930if (!r[lr - 1])931{932while(lr>2 && !r[lr - 1]) lr--;933if (lr == 2) { *z = gen_0; return gc_const((pari_sp)q, q); } /* exact */934}935r[1] = evalsigne(sx) | evallgefint(lr);936*z = gc_const((pari_sp)r, r); return q;937}938}939940/* Montgomery reduction.941* N has k words, assume T >= 0 has less than 2k.942* Return res := T / B^k mod N, where B = 2^BIL943* such that 0 <= res < T/B^k + N and res has less than k words */944GEN945red_montgomery(GEN T, GEN N, ulong inv)946{947pari_sp av;948GEN Te, Td, Ne, Nd, scratch;949ulong i, j, m, t, d, k = NLIMBS(N);950int carry;951LOCAL_HIREMAINDER;952LOCAL_OVERFLOW;953954if (k == 0) return gen_0;955d = NLIMBS(T); /* <= 2*k */956if (d == 0) return gen_0;957#ifdef DEBUG958if (d > 2*k) pari_err_BUG("red_montgomery");959#endif960if (k == 1)961{ /* as below, special cased for efficiency */962ulong n = uel(N,2);963if (d == 1) {964hiremainder = uel(T,2);965m = hiremainder * inv;966(void)addmul(m, n); /* t + m*n = 0 */967return utoi(hiremainder);968} else { /* d = 2 */969hiremainder = uel(T,2);970m = hiremainder * inv;971(void)addmul(m, n); /* t + m*n = 0 */972t = addll(hiremainder, uel(T,3));973if (overflow) t -= n; /* t > n doesn't fit in 1 word */974return utoi(t);975}976}977/* assume k >= 2 */978av = avma; scratch = new_chunk(k<<1); /* >= k + 2: result fits */979980/* copy T to scratch space (pad with zeroes to 2k words) */981Td = scratch;982Te = T + 2;983for (i=0; i < d ; i++) *Td++ = *Te++;984for ( ; i < (k<<1); i++) *Td++ = 0;985986Te = scratch - 1; /* 1 beyond end of current T mantissa (in scratch) */987Ne = N + 1; /* 1 beyond end of N mantissa */988989carry = 0;990for (i=0; i<k; i++) /* set T := T/B nod N, k times */991{992Td = Te; /* one beyond end of (new) T mantissa */993Nd = Ne;994hiremainder = *++Td;995m = hiremainder * inv; /* solve T + m N = O(B) */996997/* set T := (T + mN) / B */998Te = Td;999(void)addmul(m, *++Nd); /* = 0 */1000for (j=1; j<k; j++)1001{1002t = addll(addmul(m, *++Nd), *++Td);1003*Td = t;1004hiremainder += overflow;1005}1006t = addll(hiremainder, *++Td); *Td = t + carry;1007carry = (overflow || (carry && *Td == 0));1008}1009if (carry)1010{ /* Td > N overflows (k+1 words), set Td := Td - N */1011GEN NE = N + k+1;1012Td = Te;1013Nd = Ne;1014t = subll(*++Td, *++Nd); *Td = t;1015while (Nd < NE) { t = subllx(*++Td, *++Nd); *Td = t; }1016}10171018/* copy result */1019Td = (GEN)av - 1; /* *Td = high word of final result */1020while (*Td == 0 && Te < Td) Td--; /* strip leading 0s */1021k = Td - Te; if (!k) return gc_const(av, gen_0);1022Td = (GEN)av - k; /* will write mantissa there */1023(void)memmove(Td, Te+1, k*sizeof(long));1024Td -= 2;1025Td[0] = evaltyp(t_INT) | evallg(k+2);1026Td[1] = evalsigne(1) | evallgefint(k+2);1027#ifdef DEBUG1028{1029long l = NLIMBS(N), s = BITS_IN_LONG*l;1030GEN R = int2n(s);1031GEN res = remii(mulii(T, Fp_inv(R, N)), N);1032if (k > lgefint(N)1033|| !equalii(remii(Td,N),res)1034|| cmpii(Td, addii(shifti(T, -s), N)) >= 0) pari_err_BUG("red_montgomery");1035}1036#endif1037return gc_const((pari_sp)Td, Td);1038}10391040/* EXACT INTEGER DIVISION */10411042/* use undocumented GMP interface */1043static void1044GEN2mpz(mpz_t X, GEN x)1045{1046long l = lgefint(x)-2;1047X->_mp_alloc = l;1048X->_mp_size = signe(x) > 0? l: -l;1049X->_mp_d = LIMBS(x);1050}1051static void1052mpz2GEN(GEN z, mpz_t Z)1053{1054long l = Z->_mp_size;1055z[1] = evalsigne(l > 0? 1: -1) | evallgefint(labs(l)+2);1056}10571058#ifdef mpn_divexact_11059static GEN1060diviuexact_i(GEN x, ulong y)1061{1062long l = lgefint(x);1063GEN z = cgeti(l);1064mpn_divexact_1(LIMBS(z), LIMBS(x), NLIMBS(x), y);1065if (z[l-1] == 0) l--;1066z[1] = evallgefint(l) | evalsigne(signe(x));1067return z;1068}1069#elif 1 && !defined(_WIN64) /* mpz_divexact_ui is not LLP64 friendly */1070/* assume y != 0 and the division is exact */1071static GEN1072diviuexact_i(GEN x, ulong y)1073{1074long l = lgefint(x);1075GEN z = cgeti(l);1076mpz_t X, Z;1077GEN2mpz(X, x);1078Z->_mp_alloc = l-2;1079Z->_mp_size = l-2;1080Z->_mp_d = LIMBS(z);1081mpz_divexact_ui(Z, X, y);1082mpz2GEN(z, Z); return z;1083}1084#else1085/* assume y != 0 and the division is exact */1086static GEN1087diviuexact_i(GEN x, ulong y)1088{1089/*TODO: implement true exact division.*/1090return divii(x,utoi(y));1091}1092#endif10931094GEN1095diviuexact(GEN x, ulong y)1096{1097GEN z;1098if (!signe(x)) return gen_0;1099z = diviuexact_i(x, y);1100if (lgefint(z) == 2) pari_err_OP("exact division", x, utoi(y));1101return z;1102}11031104/* Find z such that x=y*z, knowing that y | x (unchecked) */1105GEN1106diviiexact(GEN x, GEN y)1107{1108GEN z;1109if (!signe(y)) pari_err_INV("diviiexact",y);1110if (!signe(x)) return gen_0;1111if (lgefint(y) == 3)1112{1113z = diviuexact_i(x, y[2]);1114if (signe(y) < 0) togglesign(z);1115}1116else1117{1118long l = lgefint(x);1119mpz_t X, Y, Z;1120z = cgeti(l);1121GEN2mpz(X, x);1122GEN2mpz(Y, y);1123Z->_mp_alloc = l-2;1124Z->_mp_size = l-2;1125Z->_mp_d = LIMBS(z);1126mpz_divexact(Z, X, Y);1127mpz2GEN(z, Z);1128}1129if (lgefint(z) == 2) pari_err_OP("exact division", x, y);1130return z;1131}11321133/* assume yz != and yz | x */1134GEN1135diviuuexact(GEN x, ulong y, ulong z)1136{1137long tmp[4];1138ulong t;1139LOCAL_HIREMAINDER;1140t = mulll(y, z);1141if (!hiremainder) return diviuexact(x, t);1142tmp[0] = evaltyp(t_INT)|_evallg(4);1143tmp[1] = evalsigne(1)|evallgefint(4);1144tmp[2] = t;1145tmp[3] = hiremainder;1146return diviiexact(x, tmp);1147}11481149/********************************************************************/1150/** **/1151/** INTEGER MULTIPLICATION **/1152/** **/1153/********************************************************************/11541155/* nx >= ny = num. of digits of x, y (not GEN, see mulii) */1156GEN1157muliispec(GEN x, GEN y, long nx, long ny)1158{1159GEN zd;1160long lz;1161ulong hi;11621163if (nx < ny) swapspec(x,y, nx,ny);1164if (!ny) return gen_0;1165if (ny == 1) return muluispec((ulong)*y, x, nx);11661167lz = nx+ny+2;1168zd = cgeti(lz);1169hi = mpn_mul(LIMBS(zd), (mp_limb_t *)x, nx, (mp_limb_t *)y, ny);1170if (!hi) lz--;1171/*else zd[lz-1]=hi; GH tell me it is not necessary.*/11721173zd[1] = evalsigne(1) | evallgefint(lz);1174return zd;1175}1176GEN1177muluui(ulong x, ulong y, GEN z)1178{1179long t, s = signe(z);1180GEN r;1181LOCAL_HIREMAINDER;11821183if (!x || !y || !signe(z)) return gen_0;1184t = mulll(x,y);1185if (!hiremainder)1186r = muluispec(t, z+2, lgefint(z)-2);1187else1188{1189long tmp[2];1190tmp[1] = hiremainder;1191tmp[0] = t;1192r = muliispec(z+2,tmp, lgefint(z)-2, 2);1193}1194setsigne(r,s); return r;1195}11961197GEN1198sqrispec(GEN x, long nx)1199{1200GEN zd;1201long lz;12021203if (!nx) return gen_0;1204if (nx==1) return sqru(*x);12051206lz = (nx<<1)+2;1207zd = cgeti(lz);1208#ifdef mpn_sqr1209mpn_sqr(LIMBS(zd), (mp_limb_t *)x, nx);1210#else1211mpn_mul_n(LIMBS(zd), (mp_limb_t *)x, (mp_limb_t *)x, nx);1212#endif1213if (zd[lz-1]==0) lz--;12141215zd[1] = evalsigne(1) | evallgefint(lz);1216return zd;1217}12181219INLINE GEN1220sqrispec_mirror(GEN x, long nx)1221{1222GEN cx=new_chunk(nx);1223GEN z;1224xmpn_mirrorcopy((mp_limb_t *)cx,(mp_limb_t *)x,nx);1225z=sqrispec(cx, nx);1226xmpn_mirror(LIMBS(z), NLIMBS(z));1227return z;1228}12291230/* leaves garbage on the stack. */1231INLINE GEN1232muliispec_mirror(GEN x, GEN y, long nx, long ny)1233{1234GEN cx, cy, z;1235long s = 0;1236while (nx && x[nx-1]==0) { nx--; s++; }1237while (ny && y[ny-1]==0) { ny--; s++; }1238cx=new_chunk(nx); cy=new_chunk(ny);1239xmpn_mirrorcopy((mp_limb_t *)cx,(mp_limb_t *)x,nx);1240xmpn_mirrorcopy((mp_limb_t *)cy,(mp_limb_t *)y,ny);1241z = nx>=ny ? muliispec(cx, cy, nx, ny): muliispec(cy, cx, ny, nx);1242if (s)1243{1244long i, lz = lgefint(z) + s;1245(void)new_chunk(s);1246z -= s;1247for (i=0; i<s; i++) z[2+i]=0;1248z[1] = evalsigne(1) | evallgefint(lz);1249z[0] = evaltyp(t_INT) | evallg(lz);1250}1251xmpn_mirror(LIMBS(z), NLIMBS(z));1252return z;1253}12541255/* x % (2^n), assuming n >= 0 */1256GEN1257remi2n(GEN x, long n)1258{1259ulong hi;1260long l, k, lx, ly, sx = signe(x);1261GEN z, xd, zd;12621263if (!sx || !n) return gen_0;12641265k = dvmdsBIL(n, &l);1266lx = lgefint(x);1267if (lx < k+3) return icopy(x);12681269xd = x + (2 + k);1270/* x = |k|...|1|#|... : copy the last l bits of # and the first k words1271* ^--- initial xd */1272hi = ((ulong)*xd) & ((1UL<<l)-1); /* last l bits of # = top bits of result */1273if (!hi)1274{ /* strip leading zeroes from result */1275xd--; while (k && !*xd) { k--; xd--; }1276if (!k) return gen_0;1277ly = k+2;1278}1279else1280ly = k+3;12811282zd = z = cgeti(ly);1283*++zd = evalsigne(sx) | evallgefint(ly);1284xd = x+1; for ( ;k; k--) *++zd = *++xd;1285if (hi) *++zd = hi;1286return z;1287}12881289/********************************************************************/1290/** **/1291/** INTEGER SQUARE ROOT **/1292/** **/1293/********************************************************************/12941295/* Return S (and set R) s.t S^2 + R = N, 0 <= R <= 2S.1296* As for dvmdii, R is last on stack and guaranteed to be gen_0 in case the1297* remainder is 0. R = NULL is allowed. */1298GEN1299sqrtremi(GEN a, GEN *r)1300{1301long l, na = NLIMBS(a);1302mp_size_t nr;1303GEN S;1304if (!na) {1305if (r) *r = gen_0;1306return gen_0;1307}1308l = (na + 5) >> 1; /* 2 + ceil(na/2) */1309S = cgetipos(l);1310if (r) {1311GEN R = cgeti(2 + na);1312nr = mpn_sqrtrem(LIMBS(S), LIMBS(R), LIMBS(a), na);1313if (nr) R[1] = evalsigne(1) | evallgefint(nr+2);1314else { set_avma((pari_sp)S); R = gen_0; }1315*r = R;1316}1317else1318(void)mpn_sqrtrem(LIMBS(S), NULL, LIMBS(a), na);1319return S;1320}13211322/* compute sqrt(|a|), assuming a != 0 */1323GEN1324sqrtr_abs(GEN a)1325{1326GEN res;1327mp_limb_t *b, *c;1328long l = RNLIMBS(a), e = expo(a), er = e>>1;1329long n;1330res = cgetr(2 + l);1331res[1] = evalsigne(1) | evalexpo(er);1332if (e&1)1333{1334b = (mp_limb_t *) new_chunk(l<<1);1335xmpn_zero(b,l);1336xmpn_mirrorcopy(b+l, RLIMBS(a), l);1337c = (mp_limb_t *) new_chunk(l);1338n = mpn_sqrtrem(c,b,b,l<<1); /* c <- sqrt; b <- rem */1339if (n>l || (n==l && mpn_cmp(b,c,l) > 0)) mpn_add_1(c,c,l,1);1340}1341else1342{1343ulong u;1344b = (mp_limb_t *) mantissa2nr(a,-1);1345b[1] = uel(a,l+1)<<(BITS_IN_LONG-1);1346b = (mp_limb_t *) new_chunk(l);1347xmpn_zero(b,l+1); /* overwrites the former b[0] */1348c = (mp_limb_t *) new_chunk(l + 1);1349n = mpn_sqrtrem(c,b,b,(l<<1)+2); /* c <- sqrt; b <- rem */1350u = (ulong)*c++;1351if ( u&HIGHBIT || (u == ~HIGHBIT &&1352(n>l || (n==l && mpn_cmp(b,c,l)>0))))1353mpn_add_1(c,c,l,1);1354}1355xmpn_mirrorcopy(RLIMBS(res),c,l);1356return gc_const((pari_sp)res, res);1357}13581359/* Normalize a nonnegative integer */1360GEN1361int_normalize(GEN x, long known_zero_words)1362{1363long i = lgefint(x) - 1 - known_zero_words;1364for ( ; i > 1; i--)1365if (x[i]) { setlgefint(x, i+1); return x; }1366x[1] = evalsigne(0) | evallgefint(2); return x;1367}13681369/********************************************************************1370** **1371** Base Conversion **1372** **1373********************************************************************/13741375ulong *1376convi(GEN x, long *l)1377{1378long n = nchar2nlong(2 + (long)(NLIMBS(x) * (BITS_IN_LONG * LOG10_2)));1379GEN str = cgetg(n+1, t_VECSMALL);1380unsigned char *res = (unsigned char*) GSTR(str);1381long llz = mpn_get_str(res, 10, LIMBS(icopy(x)), NLIMBS(x));1382long lz;1383ulong *z;1384long i, j;1385unsigned char *t;1386while (!*res) {res++; llz--;} /*Strip leading zeros*/1387lz = (8+llz)/9;1388z = (ulong*)new_chunk(1+lz);1389t=res+llz+9;1390for(i=0;i<llz-8;i+=9)1391{1392ulong s;1393t-=18;1394s=*t++;1395for (j=1; j<9;j++)1396s=10*s+*t++;1397*z++=s;1398}1399if (i<llz)1400{1401unsigned char *t = res;1402ulong s=*t++;1403for (j=i+1; j<llz;j++)1404s=10*s+*t++;1405*z++=s;1406}1407*l = lz;1408return z;1409}141014111412