| Ilya Zakharevich on Sat, 29 Sep 2001 11:51:05 -0400 |
[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]
| [PATCH CVS] 2-adic shift |
This adds a flag to shift() which changes the behaviour for
right-shift of negative numbers: instead of preserving-but-ignoring the
sign, the shift is performed as if modulo big power of 2.
This enables compatibility of shift() with 2-complement semantic of
negative numbers.
Enjoy,
Ilya
P.S. Tested with
shiftr(x,n)=if(x<0&&n<0,shift(x+1,n)-1,shift(x,n))
lim=66
for(s=0,lim,print1(".");forvec(X=[[0,lim],[0,lim]],n=2^X[2]-2^X[1];r=shift(-n,-s,1);r1=shiftr(-n,-s);if(r==r1,,print("shift(-"n",-"s",1) = "r" != "r1)),1))
Index: src/basemath/gen3.c
===================================================================
RCS file: /home/megrez/cvsroot/pari/src/basemath/gen3.c,v
retrieving revision 1.31
diff -p -u -r1.31 gen3.c
--- src/basemath/gen3.c 2001/09/05 17:33:31 1.31
+++ src/basemath/gen3.c 2001/09/29 15:43:38
@@ -890,13 +890,19 @@ gdivround(GEN x, GEN y)
GEN
gshift(GEN x, long n)
{
+ return gshift3(x, n, 0);
+}
+
+GEN
+gshift3(GEN x, long n, long flag)
+{
long i,l,lx, tx = typ(x);
GEN y;
switch(tx)
{
case t_INT:
- return shifti(x,n);
+ return shifti3(x,n,flag);
case t_REAL:
return shiftr(x,n);
Index: src/headers/paridecl.h
===================================================================
RCS file: /home/megrez/cvsroot/pari/src/headers/paridecl.h,v
retrieving revision 1.99
diff -p -u -r1.99 paridecl.h
--- src/headers/paridecl.h 2001/09/05 17:33:32 1.99
+++ src/headers/paridecl.h 2001/09/29 15:43:41
@@ -895,6 +895,7 @@ GEN greal(GEN x);
GEN grndtoi(GEN x, long *e);
GEN ground(GEN x);
GEN gshift(GEN x, long n);
+GEN gshift3(GEN x, long n, long flag);
GEN gsubst(GEN x, long v, GEN y);
GEN gtopoly(GEN x, long v);
GEN gtopolyrev(GEN x, long v);
@@ -1029,6 +1030,7 @@ int ratlift(GEN x, GEN m, GEN *a, GE
GEN resss(long x, long y);
double rtodbl(GEN x);
GEN shifti(GEN x, long n);
+GEN shifti3(GEN x, long n, long flag);
long smodsi(long x, GEN y);
GEN sqri(GEN x);
GEN truedvmdii(GEN x, GEN y, GEN *z);
Index: src/kernel/none/mp.c
===================================================================
RCS file: /home/megrez/cvsroot/pari/src/kernel/none/mp.c,v
retrieving revision 1.46
diff -p -u -r1.46 mp.c
--- src/kernel/none/mp.c 2001/08/28 17:55:36 1.46
+++ src/kernel/none/mp.c 2001/09/29 15:43:43
@@ -259,6 +259,12 @@ affrr(GEN x, GEN y)
GEN
shifti(GEN x, long n)
{
+ return shifti3(x, n, 0);
+}
+
+GEN
+shifti3(GEN x, long n, long flag)
+{
const long s=signe(x);
long lx,ly,i,m;
GEN y;
@@ -285,19 +291,50 @@ shifti(GEN x, long n)
}
else
{
+ long lyorig;
+
n = -n;
- ly = lx - (n>>TWOPOTBITS_IN_LONG);
- if (ly<3) return gzero;
+ ly = lyorig = lx - (n>>TWOPOTBITS_IN_LONG);
+ if (ly<3)
+ return flag ? stoi(-1) : gzero;
y = new_chunk(ly);
m = n & (BITS_IN_LONG-1);
- if (!m) for (i=2; i<ly; i++) y[i]=x[i];
- else
- {
+ if (m) {
shift_right(y,x, 2,ly, 0,m);
if (y[2] == 0)
{
- if (ly==3) { avma = (long)(y+3); return gzero; }
+ if (ly==3) { avma = (long)(y+3); return flag ? stoi(-1) : gzero; }
ly--; avma = (long)(++y);
+ }
+ } else {
+ for (i=2; i<ly; i++) y[i]=x[i];
+ }
+ /* With FLAG: round up instead of rounding down */
+ if (flag) { /* Check low bits of x */
+ i = lx;
+ flag = 0;
+ while (--i >= lyorig) {
+ if (x[i]) {
+ flag = 1; /* Need to increment y by 1 */
+ break;
+ }
+ }
+ if (!flag && m)
+ flag = x[lyorig - 1] & ((1<<m) - 1);
+ }
+ if (flag) { /* Increment i */
+ i = ly;
+ while (1) {
+ if (--i < 2) { /* Need to extend y on the left */
+ if (avma <= bot)
+ err(errpile);
+ avma = (long)(--y); ly++;
+ y[2] = 1;
+ break;
+ }
+ if (++y[i])
+ break;
+ /* Now we need to propagate the bit into the next longword... */
}
}
}
Index: src/language/helpmsg.c
===================================================================
RCS file: /home/megrez/cvsroot/pari/src/language/helpmsg.c,v
retrieving revision 1.26
diff -p -u -r1.26 helpmsg.c
--- src/language/helpmsg.c 2001/04/07 19:43:57 1.26
+++ src/language/helpmsg.c 2001/09/29 15:43:44
@@ -421,7 +421,7 @@ char *helpmessages_basic[]={
"setrand(n): reset the seed of the random number generator to n",
"setsearch(x,y,{flag=0}): looks if y belongs to the set x. If flag is 0 or omitted, returns 0 if it is not, otherwise returns the index j such that y==x[j]. If flag is non-zero, return 0 if y belongs to x, otherwise the index j where it should be inserted",
"setunion(x,y): union of the sets x and y",
- "shift(x,n): shift x left n bits if n>=0, right -n bits if n<0",
+ "shift(x,n,{flag=0}): shift x left n bits if n>=0, right -n bits if n<0. If flag is true and n is negative, will treat negative integer x as if modulo big power of 2, otherwise sign of x is ignored but preserved",
"shiftmul(x,n): multiply x by 2^n (n>=0 or n<0)",
"sigma(x,{k=1}): sum of the k-th powers of the divisors of x. k is optional and if omitted is assumed to be equal to 1",
"sign(x): sign of x, of type integer, real or fraction",
Index: src/language/init.c
===================================================================
RCS file: /home/megrez/cvsroot/pari/src/language/init.c,v
retrieving revision 1.89
diff -p -u -r1.89 init.c
--- src/language/init.c 2001/08/26 13:46:34 1.89
+++ src/language/init.c 2001/09/29 15:43:45
@@ -2122,7 +2122,7 @@ entree functions_basic[]={
{"setrand",99,(void*)setrand,11,"lL"},
{"setsearch",99,(void*)setsearch,8,"lGGD0,L,"},
{"setunion",2,(void*)setunion,8,"GG"},
-{"shift",99,(void*)gshift,1,"GL"},
+{"shift",99,(void*)gshift3,1,"GLD0,L,"},
{"shiftmul",99,(void*)gmul2n,1,"GL"},
{"sigma",99,(void*)gsumdivk,4,"GD1,L,"},
{"sign",10,(void*)gsigne,1,"lG"},