unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Checking for loss of information on integer conversion
@ 2018-02-18  1:27 Paul Eggert
       [not found] ` <83y3jq9q4m.fsf@gnu.org>
  2018-02-18 22:31 ` Juliusz Chroboczek
  0 siblings, 2 replies; 16+ messages in thread
From: Paul Eggert @ 2018-02-18  1:27 UTC (permalink / raw)
  To: Emacs Development

[-- Attachment #1: Type: text/plain, Size: 1705 bytes --]

Bug#30408 reminded me of a problem that's bitten me before, which is that Emacs 
Lisp reading and printing sometimes loses information when converting from 
integers to strings or vice versa, and this loss of information can lead to real 
problems. Without going to bignums we can't fix this problem nicely in general; 
however, Emacs can do a better job of signaling an error when information is 
lost in the current implementation. I've proposed a patch here:

https://debbugs.gnu.org/30408#16

and am attaching it to this email for convenience.

Briefly, the patch is twofold. First, it causes calls like (format "%d" 
18446744073709551616) to return the mathematically-correct value 
"18446744073709551616" instead of silently returning the 
mathematically-incorrect value "9223372036854775807" as they do now. If the 
function cannot return the correct value due to an implementation limit -- e.g., 
(format "%x" 18446744073709551616) -- the patch causes the function to signal an 
overflow.

Second, although Emacs still reads large integers like 18446744073709551616 as 
if they were floating-point, it now signals an error if information is lost in 
the process. For example, the number 18446744073709551615 now causes the reader 
to signal an error, since it cannot be represented exactly either as a fixnum or 
as a floating-point number. If you want inexact representation, you can append 
".0" or "e0" to the integer.

As these are incompatible changes to Emacs I thought I'd mention them on this list.

Another possibility would be for Emacs to signal an error when reading any 
integer that does not fit in fixnum bounds. That would be a bigger change, though.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Avoid-losing-info-when-converting-integers.patch --]
[-- Type: text/x-patch; name="0001-Avoid-losing-info-when-converting-integers.patch", Size: 8127 bytes --]

From e1865be990e1a520feddc07507a71916d097d633 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Sat, 17 Feb 2018 16:45:17 -0800
Subject: [PATCH] Avoid losing info when converting integers

This fixes some glitches with large integers (Bug#30408).
* doc/lispref/numbers.texi (Integer Basics): Say that
decimal integers out of fixnum range must be representable
exactly as floating-point.
* etc/NEWS: Mention this.
* src/data.c (syms_of_data): Add Qinexact_error.
* src/editfns.c (styled_format): Use %.0f when formatting %d or %i
values outside machine integer range, to avoid losing info.
Signal an error for %o or %x values that are too large to be
formatted, to avoid losing info.
* src/lread.c (string_to_number): When converting an integer-format
string to floating-point, signal an error if info is lost.
---
 doc/lispref/numbers.texi |  8 +++--
 etc/NEWS                 |  9 +++++
 src/data.c               |  1 +
 src/editfns.c            | 93 ++++++++++++++++++++----------------------------
 src/lread.c              | 14 ++++++++
 5 files changed, 67 insertions(+), 58 deletions(-)

diff --git a/doc/lispref/numbers.texi b/doc/lispref/numbers.texi
index e692ee1cc2..252aafd8fd 100644
--- a/doc/lispref/numbers.texi
+++ b/doc/lispref/numbers.texi
@@ -53,9 +53,11 @@ Integer Basics
 chapter assume the minimum integer width of 30 bits.
 @cindex overflow
 
-  The Lisp reader reads an integer as a sequence of digits with optional
-initial sign and optional final period.  An integer that is out of the
-Emacs range is treated as a floating-point number.
+  The Lisp reader can read an integer as a nonempty sequence of
+decimal digits with optional initial sign and optional final period.
+A decimal integer that is out of the Emacs range is treated as
+floating-point if it can be represented exactly as a floating-point
+number.
 
 @example
  1               ; @r{The integer 1.}
diff --git a/etc/NEWS b/etc/NEWS
index 8db638e5ed..36cbcf6500 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -248,6 +248,12 @@ as new-style, bind the new variable 'force-new-style-backquotes' to t.
 'cl-struct-define' whose name clashes with a builtin type (e.g.,
 'integer' or 'hash-table') now signals an error.
 
+** When formatting a floating-point number as an octal or hexadecimal
+integer, Emacs now signals an error if the number is too large for the
+implementation to format.  When reading an integer outside Emacs
+fixnum range, Emacs now signals an error if the integer cannot be
+represented exactly as a floating-point number.  See Bug#30408.
+
 \f
 * Lisp Changes in Emacs 27.1
 
@@ -289,6 +295,9 @@ remote systems, which support this check.
 If the optional third argument is non-nil, 'make-string' will produce
 a multibyte string even if its second argument is an ASCII character.
 
+** (format "%d" X) no longer mishandles floating-point X values that
+do not fit in a machine integer (Bug#30408).
+
 ** New JSON parsing and serialization functions 'json-serialize',
 'json-insert', 'json-parse-string', and 'json-parse-buffer'.  These
 are implemented in C using the Jansson library.
diff --git a/src/data.c b/src/data.c
index 72abfefb01..8856583f13 100644
--- a/src/data.c
+++ b/src/data.c
@@ -3729,6 +3729,7 @@ syms_of_data (void)
   DEFSYM (Qrange_error, "range-error");
   DEFSYM (Qdomain_error, "domain-error");
   DEFSYM (Qsingularity_error, "singularity-error");
+  DEFSYM (Qinexact_error, "inexact-error");
   DEFSYM (Qoverflow_error, "overflow-error");
   DEFSYM (Qunderflow_error, "underflow-error");
 
diff --git a/src/editfns.c b/src/editfns.c
index 96bb271b2d..d26549ddb8 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -4563,32 +4563,30 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
 		 and with pM inserted for integer formats.
 		 At most two flags F can be specified at once.  */
 	      char convspec[sizeof "%FF.*d" + max (INT_AS_LDBL, pMlen)];
-	      {
-		char *f = convspec;
-		*f++ = '%';
-		/* MINUS_FLAG and ZERO_FLAG are dealt with later.  */
-		*f = '+'; f +=  plus_flag;
-		*f = ' '; f += space_flag;
-		*f = '#'; f += sharp_flag;
-                *f++ = '.';
-                *f++ = '*';
-		if (float_conversion)
-		  {
-		    if (INT_AS_LDBL)
-		      {
-			*f = 'L';
-			f += INTEGERP (arg);
-		      }
-		  }
-		else if (conversion != 'c')
-		  {
-		    memcpy (f, pMd, pMlen);
-		    f += pMlen;
-		    zero_flag &= ! precision_given;
-		  }
-		*f++ = conversion;
-		*f = '\0';
-	      }
+	      char *f = convspec;
+	      *f++ = '%';
+	      /* MINUS_FLAG and ZERO_FLAG are dealt with later.  */
+	      *f = '+'; f +=  plus_flag;
+	      *f = ' '; f += space_flag;
+	      *f = '#'; f += sharp_flag;
+	      *f++ = '.';
+	      *f++ = '*';
+	      if (float_conversion)
+		{
+		  if (INT_AS_LDBL)
+		    {
+		      *f = 'L';
+		      f += INTEGERP (arg);
+		    }
+		}
+	      else if (conversion != 'c')
+		{
+		  memcpy (f, pMd, pMlen);
+		  f += pMlen;
+		  zero_flag &= ! precision_given;
+		}
+	      *f++ = conversion;
+	      *f = '\0';
 
 	      int prec = -1;
 	      if (precision_given)
@@ -4630,29 +4628,18 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
 		}
 	      else if (conversion == 'd' || conversion == 'i')
 		{
-		  /* For float, maybe we should use "%1.0f"
-		     instead so it also works for values outside
-		     the integer range.  */
-		  printmax_t x;
 		  if (INTEGERP (arg))
-		    x = XINT (arg);
+		    {
+		      printmax_t x = XINT (arg);
+		      sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x);
+		    }
 		  else
 		    {
-		      double d = XFLOAT_DATA (arg);
-		      if (d < 0)
-			{
-			  x = TYPE_MINIMUM (printmax_t);
-			  if (x < d)
-			    x = d;
-			}
-		      else
-			{
-			  x = TYPE_MAXIMUM (printmax_t);
-			  if (d < x)
-			    x = d;
-			}
+		      strcpy (f - pMlen - 1, "f");
+		      prec = 0;
+		      double x = XFLOAT_DATA (arg);
+		      sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x);
 		    }
-		  sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x);
 		}
 	      else
 		{
@@ -4663,22 +4650,18 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
 		  else
 		    {
 		      double d = XFLOAT_DATA (arg);
-		      if (d < 0)
-			x = 0;
-		      else
-			{
-			  x = TYPE_MAXIMUM (uprintmax_t);
-			  if (d < x)
-			    x = d;
-			}
+		      if (! (0 <= d && d < TYPE_MAXIMUM (uprintmax_t)))
+			xsignal1 (Qoverflow_error, arg);
+		      x = d;
 		    }
 		  sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x);
 		}
 
 	      /* Now the length of the formatted item is known, except it omits
 		 padding and excess precision.  Deal with excess precision
-		 first.  This happens only when the format specifies
-		 ridiculously large precision.  */
+		 first.  This happens when the format specifies
+		 ridiculously large precision, or when %d or %i has
+		 nonzero precision and formats a float.  */
 	      ptrdiff_t excess_precision
 		= precision_given ? precision - prec : 0;
 	      ptrdiff_t leading_zeros = 0, trailing_zeros = 0;
diff --git a/src/lread.c b/src/lread.c
index d009bd0cd2..cfeaac8030 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -3794,6 +3794,20 @@ string_to_number (char const *string, int base, bool ignore_trailing)
   if (! value)
     value = atof (string + signedp);
 
+  if (! float_syntax)
+    {
+      /* Check that converting the integer-format STRING to a
+	 floating-point number does not lose info.  See Bug#30408.  */
+      char const *bp = string + signedp;
+      while (*bp == '0')
+	bp++;
+      char checkbuf[DBL_MAX_10_EXP + 2];
+      int checkbuflen = sprintf (checkbuf, "%.0f", value);
+      if (! (cp - bp - !!(state & DOT_CHAR) == checkbuflen
+	     && memcmp (bp, checkbuf, checkbuflen) == 0))
+	xsignal1 (Qinexact_error, build_string (string));
+    }
+
   return make_float (negative ? -value : value);
 }
 
-- 
2.14.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: Checking for loss of information on integer conversion
       [not found] ` <83y3jq9q4m.fsf@gnu.org>
@ 2018-02-18 20:04   ` Paul Eggert
  2018-02-18 20:24     ` Eli Zaretskii
  2018-02-18 21:52     ` bug#30408: " Drew Adams
  0 siblings, 2 replies; 16+ messages in thread
From: Paul Eggert @ 2018-02-18 20:04 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 30408, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 2618 bytes --]

Eli Zaretskii wrote:

> Emacs Lisp is not used to write software that controls
> aircraft and spaceships

Actually, I maintain Emacs Lisp code that controls timestamps used in aircraft 
and spaceships. I'm not saying that Emacs itself runs the aircraft and 
spaceships, but it definitely is used to develop software and data used there. 
As luck would have it, I'm currently engaged in an email thread about time 
transfer between Earth and Mars (yes, this is really a thing and people are 
trying to do it with millisecond precision) that is related to a project where I 
regularly use Emacs Lisp. See the thread containing this message:

https://mm.icann.org/pipermail/tz/2018-February/026257.html

> More generally, why signaling an error by default in this case is a
> good idea? ...  That would
> be similar to behavior of equivalent constructs in C programs

Sure, and C compilers typically issue diagnostics for situations similar to 
what's in Bug#30408. For example, for this C program:

int a = 18446744073709553664;

GCC issues a diagnostic, whereas for the similar Emacs Lisp program:

(setq b 18446744073709553664)

Emacs silently substitutes a number that is off by 2048. It's the latter 
behavior that causes the sort of problem seen in Bug#30408.

When people write a floating-point number they naturally expect it to have some 
fuzz. But when they write an integer they expect it to be represented exactly, 
and not to be rounded.  Emacs already reports an overflow error for the 
following code that attempts to use the same mathematical value:

(setq c #x10000000000000800)

so it's not like it would be a huge change to do something similar for decimal 
integers.

When Emacs was originally developed, its integers were typically 28 bits (not 
counting sign) and floating-point numbers could typically represent integers 
exactly up to 53 bits (not counting sign), so the old Emacs behavior was 
somewhat defensible: although it didn't do bignums, at least it could represent 
integers nearly twice as wide as fixnums. However, nowadays Emacs integers 
typically have more precision than floating point numbers, and the old Emacs 
behavior is more likely to lead to counterintuitive results such as those 
described in Bug#30408.

On thinking about it in the light of your comments, I suppose it's confusing 
that the proposal used a new signal 'inexact', whereas it should just signal 
overflow. After all, that's what string_to_number already does for out-of-range 
hexadecimal integers. That issue is easily fixed. Revised patch attached.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Avoid-losing-info-when-converting-integers.patch --]
[-- Type: text/x-patch; name="0001-Avoid-losing-info-when-converting-integers.patch", Size: 7603 bytes --]

From 49895e55ed7ac41dbf3752ab534cd665ef45ee71 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Sun, 18 Feb 2018 11:37:22 -0800
Subject: [PATCH] Avoid losing info when converting integers

This fixes some glitches with large integers (Bug#30408).
* doc/lispref/numbers.texi (Integer Basics): Say that
decimal integers out of fixnum range must be representable
exactly as floating-point.
* etc/NEWS: Mention this.
* src/editfns.c (styled_format): Use %.0f when formatting %d or %i
values outside machine integer range, to avoid losing info.
Signal an error for %o or %x values that are too large to be
formatted, to avoid losing info.
* src/lread.c (string_to_number): When converting an integer-format
string to floating-point, signal an error if info is lost.
---
 doc/lispref/numbers.texi |  8 +++--
 etc/NEWS                 |  9 +++++
 src/editfns.c            | 93 ++++++++++++++++++++----------------------------
 src/lread.c              | 14 ++++++++
 4 files changed, 66 insertions(+), 58 deletions(-)

diff --git a/doc/lispref/numbers.texi b/doc/lispref/numbers.texi
index e692ee1cc2..252aafd8fd 100644
--- a/doc/lispref/numbers.texi
+++ b/doc/lispref/numbers.texi
@@ -53,9 +53,11 @@ Integer Basics
 chapter assume the minimum integer width of 30 bits.
 @cindex overflow
 
-  The Lisp reader reads an integer as a sequence of digits with optional
-initial sign and optional final period.  An integer that is out of the
-Emacs range is treated as a floating-point number.
+  The Lisp reader can read an integer as a nonempty sequence of
+decimal digits with optional initial sign and optional final period.
+A decimal integer that is out of the Emacs range is treated as
+floating-point if it can be represented exactly as a floating-point
+number.
 
 @example
  1               ; @r{The integer 1.}
diff --git a/etc/NEWS b/etc/NEWS
index 8db638e5ed..36cbcf6500 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -248,6 +248,12 @@ as new-style, bind the new variable 'force-new-style-backquotes' to t.
 'cl-struct-define' whose name clashes with a builtin type (e.g.,
 'integer' or 'hash-table') now signals an error.
 
+** When formatting a floating-point number as an octal or hexadecimal
+integer, Emacs now signals an error if the number is too large for the
+implementation to format.  When reading an integer outside Emacs
+fixnum range, Emacs now signals an error if the integer cannot be
+represented exactly as a floating-point number.  See Bug#30408.
+
 \f
 * Lisp Changes in Emacs 27.1
 
@@ -289,6 +295,9 @@ remote systems, which support this check.
 If the optional third argument is non-nil, 'make-string' will produce
 a multibyte string even if its second argument is an ASCII character.
 
+** (format "%d" X) no longer mishandles floating-point X values that
+do not fit in a machine integer (Bug#30408).
+
 ** New JSON parsing and serialization functions 'json-serialize',
 'json-insert', 'json-parse-string', and 'json-parse-buffer'.  These
 are implemented in C using the Jansson library.
diff --git a/src/editfns.c b/src/editfns.c
index 96bb271b2d..d26549ddb8 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -4563,32 +4563,30 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
 		 and with pM inserted for integer formats.
 		 At most two flags F can be specified at once.  */
 	      char convspec[sizeof "%FF.*d" + max (INT_AS_LDBL, pMlen)];
-	      {
-		char *f = convspec;
-		*f++ = '%';
-		/* MINUS_FLAG and ZERO_FLAG are dealt with later.  */
-		*f = '+'; f +=  plus_flag;
-		*f = ' '; f += space_flag;
-		*f = '#'; f += sharp_flag;
-                *f++ = '.';
-                *f++ = '*';
-		if (float_conversion)
-		  {
-		    if (INT_AS_LDBL)
-		      {
-			*f = 'L';
-			f += INTEGERP (arg);
-		      }
-		  }
-		else if (conversion != 'c')
-		  {
-		    memcpy (f, pMd, pMlen);
-		    f += pMlen;
-		    zero_flag &= ! precision_given;
-		  }
-		*f++ = conversion;
-		*f = '\0';
-	      }
+	      char *f = convspec;
+	      *f++ = '%';
+	      /* MINUS_FLAG and ZERO_FLAG are dealt with later.  */
+	      *f = '+'; f +=  plus_flag;
+	      *f = ' '; f += space_flag;
+	      *f = '#'; f += sharp_flag;
+	      *f++ = '.';
+	      *f++ = '*';
+	      if (float_conversion)
+		{
+		  if (INT_AS_LDBL)
+		    {
+		      *f = 'L';
+		      f += INTEGERP (arg);
+		    }
+		}
+	      else if (conversion != 'c')
+		{
+		  memcpy (f, pMd, pMlen);
+		  f += pMlen;
+		  zero_flag &= ! precision_given;
+		}
+	      *f++ = conversion;
+	      *f = '\0';
 
 	      int prec = -1;
 	      if (precision_given)
@@ -4630,29 +4628,18 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
 		}
 	      else if (conversion == 'd' || conversion == 'i')
 		{
-		  /* For float, maybe we should use "%1.0f"
-		     instead so it also works for values outside
-		     the integer range.  */
-		  printmax_t x;
 		  if (INTEGERP (arg))
-		    x = XINT (arg);
+		    {
+		      printmax_t x = XINT (arg);
+		      sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x);
+		    }
 		  else
 		    {
-		      double d = XFLOAT_DATA (arg);
-		      if (d < 0)
-			{
-			  x = TYPE_MINIMUM (printmax_t);
-			  if (x < d)
-			    x = d;
-			}
-		      else
-			{
-			  x = TYPE_MAXIMUM (printmax_t);
-			  if (d < x)
-			    x = d;
-			}
+		      strcpy (f - pMlen - 1, "f");
+		      prec = 0;
+		      double x = XFLOAT_DATA (arg);
+		      sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x);
 		    }
-		  sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x);
 		}
 	      else
 		{
@@ -4663,22 +4650,18 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
 		  else
 		    {
 		      double d = XFLOAT_DATA (arg);
-		      if (d < 0)
-			x = 0;
-		      else
-			{
-			  x = TYPE_MAXIMUM (uprintmax_t);
-			  if (d < x)
-			    x = d;
-			}
+		      if (! (0 <= d && d < TYPE_MAXIMUM (uprintmax_t)))
+			xsignal1 (Qoverflow_error, arg);
+		      x = d;
 		    }
 		  sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x);
 		}
 
 	      /* Now the length of the formatted item is known, except it omits
 		 padding and excess precision.  Deal with excess precision
-		 first.  This happens only when the format specifies
-		 ridiculously large precision.  */
+		 first.  This happens when the format specifies
+		 ridiculously large precision, or when %d or %i has
+		 nonzero precision and formats a float.  */
 	      ptrdiff_t excess_precision
 		= precision_given ? precision - prec : 0;
 	      ptrdiff_t leading_zeros = 0, trailing_zeros = 0;
diff --git a/src/lread.c b/src/lread.c
index d009bd0cd2..9500ed8341 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -3794,6 +3794,20 @@ string_to_number (char const *string, int base, bool ignore_trailing)
   if (! value)
     value = atof (string + signedp);
 
+  if (! float_syntax)
+    {
+      /* Check that converting the integer-format STRING to a
+	 floating-point number does not lose info.  See Bug#30408.  */
+      char const *bp = string + signedp;
+      while (*bp == '0')
+	bp++;
+      char checkbuf[DBL_MAX_10_EXP + 2];
+      int checkbuflen = sprintf (checkbuf, "%.0f", value);
+      if (! (cp - bp - !!(state & DOT_CHAR) == checkbuflen
+	     && memcmp (bp, checkbuf, checkbuflen) == 0))
+	xsignal1 (Qoverflow_error, build_string (string));
+    }
+
   return make_float (negative ? -value : value);
 }
 
-- 
2.14.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: Checking for loss of information on integer conversion
  2018-02-18 20:04   ` Paul Eggert
@ 2018-02-18 20:24     ` Eli Zaretskii
  2018-02-18 21:52     ` bug#30408: " Drew Adams
  1 sibling, 0 replies; 16+ messages in thread
From: Eli Zaretskii @ 2018-02-18 20:24 UTC (permalink / raw)
  To: Paul Eggert; +Cc: 30408, emacs-devel

> From: Paul Eggert <eggert@cs.ucla.edu>
> Cc: emacs-devel@gnu.org, 30408@debbugs.gnu.org
> Date: Sun, 18 Feb 2018 12:04:20 -0800
> 
> > Emacs Lisp is not used to write software that controls
> > aircraft and spaceships
> 
> Actually, I maintain Emacs Lisp code that controls timestamps used in aircraft 
> and spaceships. I'm not saying that Emacs itself runs the aircraft and 
> spaceships, but it definitely is used to develop software and data used there. 
> As luck would have it, I'm currently engaged in an email thread about time 
> transfer between Earth and Mars (yes, this is really a thing and people are 
> trying to do it with millisecond precision) that is related to a project where I 
> regularly use Emacs Lisp. See the thread containing this message:

Interesting, but not really relevant to the issue at hand, IMO.  I was
talking about real-time control, not off-line calculations.  And I did
propose to have this feature as opt-in, so the kind of calculations
that transfer me to Mars could still be held safely and accurately.

> > More generally, why signaling an error by default in this case is a
> > good idea? ...  That would
> > be similar to behavior of equivalent constructs in C programs
> 
> Sure, and C compilers typically issue diagnostics for situations similar to 
> what's in Bug#30408. For example, for this C program:
> 
> int a = 18446744073709553664;
> 
> GCC issues a diagnostic, whereas for the similar Emacs Lisp program:
> 
> (setq b 18446744073709553664)
> 
> Emacs silently substitutes a number that is off by 2048.

I'm okay with flagging such constants during byte compilation.  I was
talking only about run-time diagnostics, not compile-time diagnostics.

> When people write a floating-point number they naturally expect it to have some 
> fuzz. But when they write an integer they expect it to be represented exactly, 
> and not to be rounded.

That is true, but Emacs behaved like it does today for many years, and
I'm worried by the possible breakage such a significant behavior
change could have, including on our own code.



^ permalink raw reply	[flat|nested] 16+ messages in thread

* bug#30408: Checking for loss of information on integer conversion
  2018-02-18 20:04   ` Paul Eggert
  2018-02-18 20:24     ` Eli Zaretskii
@ 2018-02-18 21:52     ` Drew Adams
  1 sibling, 0 replies; 16+ messages in thread
From: Drew Adams @ 2018-02-18 21:52 UTC (permalink / raw)
  To: Paul Eggert, Eli Zaretskii; +Cc: 30408, emacs-devel

Do you really need to send this thread to both the bug
list and emacs-devel?





^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Checking for loss of information on integer conversion
  2018-02-18  1:27 Checking for loss of information on integer conversion Paul Eggert
       [not found] ` <83y3jq9q4m.fsf@gnu.org>
@ 2018-02-18 22:31 ` Juliusz Chroboczek
  2018-02-18 22:41   ` Stefan Monnier
  2018-02-19  6:03   ` John Wiegley
  1 sibling, 2 replies; 16+ messages in thread
From: Juliusz Chroboczek @ 2018-02-18 22:31 UTC (permalink / raw)
  To: emacs-devel

> Second, although Emacs still reads large integers like
> 18446744073709551616 as if they were floating-point, it now signals an
> error if information is lost in the process.

That's better, but still horrible.

> Another possibility would be for Emacs to signal an error when reading any
> integer that does not fit in fixnum bounds.

Please do that.




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Checking for loss of information on integer conversion
  2018-02-18 22:31 ` Juliusz Chroboczek
@ 2018-02-18 22:41   ` Stefan Monnier
  2018-02-18 23:46     ` Juliusz Chroboczek
  2018-02-19  6:03   ` John Wiegley
  1 sibling, 1 reply; 16+ messages in thread
From: Stefan Monnier @ 2018-02-18 22:41 UTC (permalink / raw)
  To: emacs-devel

>> Another possibility would be for Emacs to signal an error when reading any
>> integer that does not fit in fixnum bounds.
> Please do that.

That would be a regression.  On 32bit systems, there are various
circumstances where we need to read a 32bit ID (i.e. one that
doesn't fit within our 30bit fixnums), as well as situations where we
read something like a file size which may also fail to fit.

On 64bit systems (and 32bit systems built with wide-ints),
I don't see such a clear need to convert a large integer into a float,
so on those systems I think it's OK to just signal an error.


        Stefan "still living in the 32bit world"




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Checking for loss of information on integer conversion
  2018-02-18 22:41   ` Stefan Monnier
@ 2018-02-18 23:46     ` Juliusz Chroboczek
  2018-02-19  1:47       ` Stefan Monnier
  2018-02-19 15:05       ` Richard Stallman
  0 siblings, 2 replies; 16+ messages in thread
From: Juliusz Chroboczek @ 2018-02-18 23:46 UTC (permalink / raw)
  To: emacs-devel

>>> Another possibility would be for Emacs to signal an error when
>>> reading any integer that does not fit in fixnum bounds.

>> Please do that.

> That would be a regression.  On 32bit systems, there are various
> circumstances where we need to read a 32bit ID

I can see how this could be a problem, but I still find the current
semantics pretty horrible, and completely different from what any Lisp
hacker would expect.

Perhaps Emacs could acquire small bignums?  Say, boxed 64-bit integers
with signal on overflow?

> On 64bit systems (and 32bit systems built with wide-ints),
> I don't see such a clear need to convert a large integer into a float,
> so on those systems I think it's OK to just signal an error.

Please.

>         Stefan "still living in the 32bit world"

We like you nonetheless.

-- Juliusz




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Checking for loss of information on integer conversion
  2018-02-18 23:46     ` Juliusz Chroboczek
@ 2018-02-19  1:47       ` Stefan Monnier
  2018-02-19  2:22         ` Paul Eggert
  2018-02-19 15:05       ` Richard Stallman
  1 sibling, 1 reply; 16+ messages in thread
From: Stefan Monnier @ 2018-02-19  1:47 UTC (permalink / raw)
  To: emacs-devel

>> That would be a regression.  On 32bit systems, there are various
>> circumstances where we need to read a 32bit ID
> I can see how this could be a problem, but I still find the current
> semantics pretty horrible,

It's not pretty indeed.

> Perhaps Emacs could acquire small bignums?  Say, boxed 64-bit integers
> with signal on overflow?

I don't think adding actual bignums via (say) libgmp would be
significantly harder than adding such "small bignums.


        Stefan




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Checking for loss of information on integer conversion
  2018-02-19  1:47       ` Stefan Monnier
@ 2018-02-19  2:22         ` Paul Eggert
  2018-02-19  3:20           ` Drew Adams
  0 siblings, 1 reply; 16+ messages in thread
From: Paul Eggert @ 2018-02-19  2:22 UTC (permalink / raw)
  To: Stefan Monnier, emacs-devel

Stefan Monnier wrote:
> I don't think adding actual bignums via (say) libgmp would be
> significantly harder than adding such "small bignums.

Although I suspect libgmp would be considerably more of a pain than small 
bignums (e.g., due to the memory-allocation hassle) I agree we should spend our 
limited development time on true bignums rather than on small ones. Emacs 
already links to libgmp so this shouldn't introduce any new dependencies. 
However, this is all a matter for a later day.

 > On 64bit systems (and 32bit systems built with wide-ints),
 > I don't see such a clear need to convert a large integer into a float,
 > so on those systems I think it's OK to just signal an error.

I'll take a look into doing things that way, and into following Eli's suggestion 
to make it configurable.



^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: Checking for loss of information on integer conversion
  2018-02-19  2:22         ` Paul Eggert
@ 2018-02-19  3:20           ` Drew Adams
  0 siblings, 0 replies; 16+ messages in thread
From: Drew Adams @ 2018-02-19  3:20 UTC (permalink / raw)
  To: Paul Eggert, Stefan Monnier, emacs-devel

Big smallnums first, then small bignums, then big bignums? ;-)

(Anyway, +1 for an intention to add bignums.)



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Checking for loss of information on integer conversion
  2018-02-18 22:31 ` Juliusz Chroboczek
  2018-02-18 22:41   ` Stefan Monnier
@ 2018-02-19  6:03   ` John Wiegley
  1 sibling, 0 replies; 16+ messages in thread
From: John Wiegley @ 2018-02-19  6:03 UTC (permalink / raw)
  To: Juliusz Chroboczek; +Cc: emacs-devel

>>>>> "JC" == Juliusz Chroboczek <jch@irif.fr> writes:

>> Second, although Emacs still reads large integers like
>> 18446744073709551616 as if they were floating-point, it now signals an
>> error if information is lost in the process.

JC> That's better, but still horrible.

Now you've made it hard for me to sleep soundly tonight.

-- 
John Wiegley                  GPG fingerprint = 4710 CF98 AF9B 327B B80F
http://newartisans.com                          60E1 46C4 BD1A 7AC1 4BA2



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Checking for loss of information on integer conversion
  2018-02-18 23:46     ` Juliusz Chroboczek
  2018-02-19  1:47       ` Stefan Monnier
@ 2018-02-19 15:05       ` Richard Stallman
  2018-02-22 16:31         ` Juliusz Chroboczek
  1 sibling, 1 reply; 16+ messages in thread
From: Richard Stallman @ 2018-02-19 15:05 UTC (permalink / raw)
  To: Juliusz Chroboczek; +Cc: emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > I can see how this could be a problem, but I still find the current
  > semantics pretty horrible, and completely different from what any Lisp
  > hacker would expect.

We should not exaggerate the importance of this.  The aim of Emacs
Lisp is to "get the job done", not to be maximally elegant.

  > Perhaps Emacs could acquire small bignums?  Say, boxed 64-bit integers
  > with signal on overflow?

Adding real bignums probably would not be much more work than that.
So IF we decide to do work in that area, let's add real bignums.
GNU MP does the hard part.

However, I'd rather prioritize progress in computing horizontal
alignment and widths with variable-width fonts.  That is something
we really need.

-- 
Dr Richard Stallman
President, Free Software Foundation (https://gnu.org, https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)
Skype: No way! See https://stallman.org/skype.html.




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Checking for loss of information on integer conversion
  2018-02-19 15:05       ` Richard Stallman
@ 2018-02-22 16:31         ` Juliusz Chroboczek
  2018-02-22 17:01           ` Eli Zaretskii
  2018-02-23  9:49           ` Richard Stallman
  0 siblings, 2 replies; 16+ messages in thread
From: Juliusz Chroboczek @ 2018-02-22 16:31 UTC (permalink / raw)
  To: emacs-devel

> Adding real bignums probably would not be much more work than that.
> So IF we decide to do work in that area, let's add real bignums.
> GNU MP does the hard part.

> However, I'd rather prioritize progress in computing horizontal
> alignment and widths with variable-width fonts.  That is something
> we really need.

I am tempted to argue that silently returning the wrong answer is a more
serious (but admittedly less visible) issue than minor cosmetic limitations
of the redisplay engine.

But who am I to argue?

-- Juliusz




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Checking for loss of information on integer conversion
  2018-02-22 16:31         ` Juliusz Chroboczek
@ 2018-02-22 17:01           ` Eli Zaretskii
  2018-02-22 19:31             ` Stefan Monnier
  2018-02-23  9:49           ` Richard Stallman
  1 sibling, 1 reply; 16+ messages in thread
From: Eli Zaretskii @ 2018-02-22 17:01 UTC (permalink / raw)
  To: Juliusz Chroboczek; +Cc: emacs-devel

> From: Juliusz Chroboczek <jch@irif.fr>
> Date: Thu, 22 Feb 2018 17:31:47 +0100
> 
> > However, I'd rather prioritize progress in computing horizontal
> > alignment and widths with variable-width fonts.  That is something
> > we really need.
> 
> I am tempted to argue that silently returning the wrong answer is a more
> serious (but admittedly less visible) issue than minor cosmetic limitations
> of the redisplay engine.

It's not a minor cosmetic limitation, it's a basic inability to line
up text displayed with a variable-pitch font.  It makes Emacs look
ugly and basically unusable when variable-pitch fonts are used to
display program source code, formatted text, tables, etc.  These are
all important and frequent use cases these days.

By contrast, silently returning a wrong result due to overflow is a
much more rare situation, especially since today 64-bit machines are
so ubiquitous.




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Checking for loss of information on integer conversion
  2018-02-22 17:01           ` Eli Zaretskii
@ 2018-02-22 19:31             ` Stefan Monnier
  0 siblings, 0 replies; 16+ messages in thread
From: Stefan Monnier @ 2018-02-22 19:31 UTC (permalink / raw)
  To: emacs-devel

> It's not a minor cosmetic limitation, it's a basic inability to line
> up text displayed with a variable-pitch font.  It makes Emacs look
> ugly and basically unusable when variable-pitch fonts are used to
> display program source code, formatted text, tables, etc.  These are
> all important and frequent use cases these days.
>
> By contrast, silently returning a wrong result due to overflow is a
> much more rare situation, especially since today 64-bit machines are
> so ubiquitous.

In any case, the relative importance doesn't matter: we all agree that
both are problems that deserve fixing; and I think it's unlikely that
the relative order we place them will influence which gets fixed first
(which depends rather on who decides to scratch which itch first).

Personnally, my money is on libgmp being implemented first (to a large
extent because I don't think anyone even has a clear idea of what
a solution to the variable-pitch-alignment problem would look like (in
terms of API and code, not in terms of visual display, of course)).


        Stefan




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Checking for loss of information on integer conversion
  2018-02-22 16:31         ` Juliusz Chroboczek
  2018-02-22 17:01           ` Eli Zaretskii
@ 2018-02-23  9:49           ` Richard Stallman
  1 sibling, 0 replies; 16+ messages in thread
From: Richard Stallman @ 2018-02-23  9:49 UTC (permalink / raw)
  To: Juliusz Chroboczek; +Cc: emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > I am tempted to argue that silently returning the wrong answer is a more
  > serious (but admittedly less visible) issue

That's a bug and we should fix it, but I don't expect
it to require big changes.

Adding any sort of bignums is a big change.

-- 
Dr Richard Stallman
President, Free Software Foundation (https://gnu.org, https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)
Skype: No way! See https://stallman.org/skype.html.




^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2018-02-23  9:49 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-02-18  1:27 Checking for loss of information on integer conversion Paul Eggert
     [not found] ` <83y3jq9q4m.fsf@gnu.org>
2018-02-18 20:04   ` Paul Eggert
2018-02-18 20:24     ` Eli Zaretskii
2018-02-18 21:52     ` bug#30408: " Drew Adams
2018-02-18 22:31 ` Juliusz Chroboczek
2018-02-18 22:41   ` Stefan Monnier
2018-02-18 23:46     ` Juliusz Chroboczek
2018-02-19  1:47       ` Stefan Monnier
2018-02-19  2:22         ` Paul Eggert
2018-02-19  3:20           ` Drew Adams
2018-02-19 15:05       ` Richard Stallman
2018-02-22 16:31         ` Juliusz Chroboczek
2018-02-22 17:01           ` Eli Zaretskii
2018-02-22 19:31             ` Stefan Monnier
2018-02-23  9:49           ` Richard Stallman
2018-02-19  6:03   ` John Wiegley

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).