Jeroen Demeyer on Wed, 06 Apr 2016 16:37:54 +0200


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

Fix itos() for LONG_MIN


The PARI function itos() gives an error for LONG_MIN. Attached patch fixes this.

Cheers,
Jeroen.
>From 0716c072db8e50aad2edfb770d76f579e6e04134 Mon Sep 17 00:00:00 2001
From: Jeroen Demeyer <jdemeyer@cage.ugent.be>
Date: Wed, 6 Apr 2016 16:09:08 +0200
Subject: [PATCH] Fix itos() for LONG_MIN

---
 doc/usersch5.tex         |  5 +----
 src/headers/pariinl.h    |  8 +++++++-
 src/kernel/none/level1.h | 27 ++++++++++++++++++---------
 src/language/es.c        |  2 +-
 src/test/32/arith        |  1 +
 src/test/in/arith        |  1 +
 6 files changed, 29 insertions(+), 15 deletions(-)

diff --git a/doc/usersch5.tex b/doc/usersch5.tex
index 5b51ca2..f3a557a 100644
--- a/doc/usersch5.tex
+++ b/doc/usersch5.tex
@@ -2233,10 +2233,7 @@ possible, otherwise raise an exception.
 \fun{long}{itos_or_0}{GEN x} converts the \typ{INT}~\kbd{x} to a \kbd{long} if
 possible, otherwise return $0$.
 
-\fun{int}{is_bigint}{GEN n} true if \kbd{itos(n)} would succeed.
-
-\fun{int}{is_bigint_lg}{GEN n, long l} true if \kbd{itos(n)} would succeed.
-Assumes \kbd{lgefint(n)} is equal to \kbd{l}.
+\fun{int}{is_bigint}{GEN n} true if \kbd{itos(n)} would give an error.
 
 \fun{ulong}{itou}{GEN x} converts the \typ{INT}~\kbd{|x|} to an \kbd{ulong} if
 possible, otherwise raise an exception.
diff --git a/src/headers/pariinl.h b/src/headers/pariinl.h
index dc48cf9..16784e5 100644
--- a/src/headers/pariinl.h
+++ b/src/headers/pariinl.h
@@ -1841,7 +1841,13 @@ INLINE int equalim1(GEN n)
 INLINE int is_pm1(GEN n)
 { return lgefint(n) == 3 && n[2] == 1; }
 INLINE int is_bigint(GEN n)
-{ long l = lgefint(n); return l > 3 || (l == 3 && (n[2] & HIGHBIT)); }
+{
+  pari_ulong u;
+  long l = lgefint(n);
+  if (l != 3) return (l > 3);
+  u = n[2];
+  return (u > HIGHBIT) || (u == HIGHBIT && signe(n) >= 0);
+}
 
 INLINE int odd(long x) { return x & 1; }
 INLINE int both_odd(long x, long y) { return x & y & 1; }
diff --git a/src/kernel/none/level1.h b/src/kernel/none/level1.h
index 99b849d..f7b90b0 100644
--- a/src/kernel/none/level1.h
+++ b/src/kernel/none/level1.h
@@ -308,21 +308,30 @@ uutoineg(ulong x, ulong y)
 INLINE long
 itos(GEN x)
 {
-  long s = signe(x);
-  long u;
+  long n;
 
-  if (!s) return 0;
-  u = x[2];
-  if (lgefint(x) > 3 || u < 0)
+  if (!signe(x)) return 0;
+  n = itos_or_0(x);
+  if (!n)
     pari_err_OVERFLOW("t_INT-->long assignment");
-  return (s>0) ? u : -u;
+  return n;
 }
 /* as itos, but return 0 if too large. Cf is_bigint */
 INLINE long
 itos_or_0(GEN x) {
-  long n;
-  if (lgefint(x) != 3 || (n = x[2]) & HIGHBIT) return 0;
-  return signe(x) > 0? n: -n;
+  pari_ulong u;
+
+  if (lgefint(x) != 3) return 0;
+  u = x[2];
+  if (signe(x) >= 0)
+  {
+    if (u < HIGHBIT) return u;
+  }
+  else
+  {
+    if (u <= HIGHBIT) return -u;
+  }
+  return 0;
 }
 INLINE ulong
 itou(GEN x)
diff --git a/src/language/es.c b/src/language/es.c
index 5da0e5f..66e6931 100644
--- a/src/language/es.c
+++ b/src/language/es.c
@@ -2025,7 +2025,7 @@ static void
 str_long(outString *S, long e)
 {
   if (e >= 0) str_ulong(S, (ulong)e);
-  else { str_putc(S, '-'); str_ulong(S, (ulong)(-e)); }
+  else { str_putc(S, '-'); str_ulong(S, -(ulong)e); }
 }
 
 static void
diff --git a/src/test/32/arith b/src/test/32/arith
index 86a8892..64364da 100644
--- a/src/test/32/arith
+++ b/src/test/32/arith
@@ -1,3 +1,4 @@
 0
 4162330905307
+Vecsmall([-2147483648])
 Total time spent: 4
diff --git a/src/test/in/arith b/src/test/in/arith
index 7af4539..b7f5562 100644
--- a/src/test/in/arith
+++ b/src/test/in/arith
@@ -2,3 +2,4 @@
 issquarefree(0)
 \\#1412
 core(4*10^15+27)
+Vecsmall([-2^31])
-- 
2.0.5