emacs-devel
[Top][All Lists]
Advanced

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

Re: [Emacs-diffs] master 37940b3: min and max now return one of their ar


From: Eli Zaretskii
Subject: Re: [Emacs-diffs] master 37940b3: min and max now return one of their arguments
Date: Wed, 08 Mar 2017 17:54:26 +0200

> From: Paul Eggert <address@hidden>
> Date: Tue, 7 Mar 2017 22:08:39 -0800
> 
> Stefan Monnier wrote:
> 
>     I'm wondering what is the motivation for this change.
> 
> It avoids nonsensical behavior where 'min' and 'max' were inconsistent with 
> '<' and '>'. Before the patch, (max A B) could return A even when (< A B) 
> returned t. For example:
> 
>   (let* ((a 1e16)
>          (b (1+ (floor a))))
>     (list a b (max a b) (< a b) (if (< a b) b a)))
> 
> returned (1e+16 10000000000000001 1e+16 t 10000000000000001) on a 64-bit 
> GNU/Linux host just before the patch was applied.

That's because you recently changed how '<' works; before those
changes, '<' would report that a is neither less nor greater than b,
and thus was consistent with 'max'.  With a binary from last month, I
get this:

   (1e+16 10000000000000001 1e+16 nil 1e+16)

which shows that '<' and 'max' were consistent then.

> In this example, '<' is behaving correctly since A is less than B, and 'max' 
> is behaving incorrectly since it is returning the lesser of A and B. (Come to 
> think of it, this example is clearer than what's in etc/NEWS, so I'll update 
> etc/NEWS.)

See above: this example will not necessarily make sense to someone who
upgrades from Emacs 25.

> In the old days Emacs could assume that every Emacs integer had an exact 
> floating-point representation, so it was OK for functions like '<' and 'max' 
> to convert integer arguments to floating-point before doing their comparisons 
> since these conversions could not lose information. This is no longer true, 
> and the low-level code now needs to be more careful when comparing fixnums to 
> floats.

I'm not sure I like these changes in behavior.  Don't programmers
assume in general that comparisons between values some of which are
floats are always done after converting _all_ values to the
floating-point representation?  I, FWIW, do expect that, but maybe
Lisp programmers whose background is not C or Fortran don't.  In those
other languages, the above values of a and b cannot be meaningfully
compared in double floating-point representation, because the relative
difference between them is less than the machine epsilon.  IOW, these
two values are equal when represented as doubles.  Under this POV,
programs that want to take advantage of a wider integer data type are
supposed to manually convert them to integers, e.g. with 'floor',
before comparing or taking their 'max'.

Your changes break those expectations.  For example, the following C
program

  #include <stdio.h>

  int
  main (void)
  {
    double a = 1.e16;
    long long b = 10000000000000001LL;

    if (a < b)
      printf ("a < b\n");
    else if (a > b)
      printf ("a > b\n");
    else
      printf ("a = b\n");

    return 0;
  }

prints "a = b".  After your changes, the equivalent Lisp program will
behave differently.  Is this a good idea?

P.S. I find the commentary in 'arithcompare' not detailed enough to
explain to a casual reader some tricky code such as this:

        i1 = f2 = i2 = XINT (num2);
      fneq = f1 != f2;

The general idea is explained, but the devil is in the details, and
those are not commented at all.  Please consider adding more
explanations, so that the implementation becomes easier to grasp.  I
don't think it's a good idea to have our code present puzzles to the
reader, especially a reader who is not privy to the subtleties of FP
calculations.  TIA.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]