Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #46060 > unrolled thread

Short-circuit Logic

Started byAhmed Abdulshafy <abdulshafy@gmail.com>
First post2013-05-26 04:11 -0700
Last post2013-05-27 21:36 -0400
Articles 20 on this page of 71 — 22 participants

Back to article view | Back to comp.lang.python


Contents

  Short-circuit Logic Ahmed Abdulshafy <abdulshafy@gmail.com> - 2013-05-26 04:11 -0700
    Re: Short-circuit Logic Roy Smith <roy@panix.com> - 2013-05-26 07:38 -0400
    Re: Short-circuit Logic Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-26 12:13 +0000
      Re: Short-circuit Logic Ahmed Abdulshafy <abdulshafy@gmail.com> - 2013-05-27 13:11 -0700
        Re: Short-circuit Logic Nobody <nobody@nowhere.com> - 2013-05-28 01:10 +0100
          Re: Short-circuit Logic Ahmed Abdulshafy <abdulshafy@gmail.com> - 2013-05-28 01:39 -0700
            RE: Short-circuit Logic Carlos Nepomuceno <carlosnepomuceno@outlook.com> - 2013-05-28 12:32 +0300
            Re: Short-circuit Logic Mark Lawrence <breamoreboy@yahoo.co.uk> - 2013-05-28 12:45 +0100
            Re: Short-circuit Logic Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-28 13:51 +0000
              Re: Short-circuit Logic Grant Edwards <invalid@invalid.invalid> - 2013-05-28 15:14 +0000
                Re: Short-circuit Logic Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-28 15:55 +0000
        Re: Short-circuit Logic Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-28 13:48 +0000
          Re: Short-circuit Logic Chris Angelico <rosuav@gmail.com> - 2013-05-29 00:01 +1000
          Re: Short-circuit Logic Ahmed Abdulshafy <abdulshafy@gmail.com> - 2013-05-29 07:27 -0700
            Re: Short-circuit Logic Chris Angelico <rosuav@gmail.com> - 2013-05-30 00:32 +1000
            Re: Short-circuit Logic rusi <rustompmody@gmail.com> - 2013-05-29 07:33 -0700
              Re: Short-circuit Logic Ian Kelly <ian.g.kelly@gmail.com> - 2013-05-29 10:50 -0600
                Re: Short-circuit Logic Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-30 02:28 +0000
                  Re: Short-circuit Logic Chris Angelico <rosuav@gmail.com> - 2013-05-30 13:45 +1000
                    Re: Short-circuit Logic Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-30 05:42 +0000
                      Re: Short-circuit Logic Jussi Piitulainen <jpiitula@ling.helsinki.fi> - 2013-05-30 10:22 +0300
                        Re: Short-circuit Logic Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-30 08:29 +0000
                          Re: Short-circuit Logic Jussi Piitulainen <jpiitula@ling.helsinki.fi> - 2013-05-30 12:07 +0300
                            Re: Short-circuit Logic Nobody <nobody@nowhere.com> - 2013-05-30 23:55 +0100
                          Re: Short-circuit Logic Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2013-05-30 19:31 -0400
                          Re: Short-circuit Logic Stefan Drees <stefan@drees.name> - 2013-05-31 17:34 +0200
                        Re: Short-circuit Logic Roy Smith <roy@panix.com> - 2013-05-30 08:48 -0400
                          Re: Short-circuit Logic Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2013-05-30 19:38 -0400
                            Re: Short-circuit Logic Nobody <nobody@nowhere.com> - 2013-05-31 02:10 +0100
                              Re: Short-circuit Logic Roy Smith <roy@panix.com> - 2013-05-30 21:21 -0400
                              Re: Short-circuit Logic Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2013-05-30 21:57 -0400
                              Re: Short-circuit Logic Michael Torrie <torriem@gmail.com> - 2013-05-30 21:33 -0600
                          RE: Short-circuit Logic Carlos Nepomuceno <carlosnepomuceno@outlook.com> - 2013-05-31 03:03 +0300
                      Re: Short-circuit Logic Chris Angelico <rosuav@gmail.com> - 2013-05-30 18:29 +1000
                      RE: Short-circuit Logic Carlos Nepomuceno <carlosnepomuceno@outlook.com> - 2013-05-31 00:03 +0300
                        Re: Short-circuit Logic Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-31 05:13 +0000
                          RE: Short-circuit Logic Carlos Nepomuceno <carlosnepomuceno@outlook.com> - 2013-05-31 09:42 +0300
                            Re: Short-circuit Logic Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-31 08:11 +0000
                          Re: Short-circuit Logic Chris Angelico <rosuav@gmail.com> - 2013-05-31 17:09 +1000
                            Re: Short-circuit Logic Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-31 08:45 +0000
                              Re: Short-circuit Logic Roy Smith <roy@panix.com> - 2013-05-31 09:20 -0400
                              RE: Short-circuit Logic Carlos Nepomuceno <carlosnepomuceno@outlook.com> - 2013-06-01 10:23 +0300
                  Re: Short-circuit Logic 88888 Dihedral <dihedral88888@gmail.com> - 2013-05-30 20:11 -0700
              Re: Short-circuit Logic Dave Angel <davea@davea.name> - 2013-05-29 20:23 -0400
                Re: Short-circuit Logic Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-30 05:20 +0000
            Re: Short-circuit Logic Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-30 05:10 +0000
              Re: Short-circuit Logic Chris Angelico <rosuav@gmail.com> - 2013-05-30 15:22 +1000
                Re: Short-circuit Logic Roy Smith <roy@panix.com> - 2013-05-30 08:40 -0400
                  Re: Short-circuit Logic Chris Angelico <rosuav@gmail.com> - 2013-05-30 22:58 +1000
                    Re: Short-circuit Logic rusi <rustompmody@gmail.com> - 2013-05-30 09:58 -0700
                      Re: Short-circuit Logic Chris Angelico <rosuav@gmail.com> - 2013-05-31 03:23 +1000
                      Re: Short-circuit Logic Rick Johnson <rantingrickjohnson@gmail.com> - 2013-05-30 17:13 -0700
                        Re: Short-circuit Logic Chris Angelico <rosuav@gmail.com> - 2013-05-31 12:29 +1000
                  Re: Short-circuit Logic Ethan Furman <ethan@stoneleaf.us> - 2013-05-30 08:02 -0700
                  Re: Short-circuit Logic Chris Angelico <rosuav@gmail.com> - 2013-05-31 01:56 +1000
                    Re: Short-circuit Logic Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-30 16:40 +0000
                      Re: Short-circuit Logic Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-30 19:22 +0000
                        Re: Short-circuit Logic Chris Angelico <rosuav@gmail.com> - 2013-05-31 07:46 +1000
                  Re: Short-circuit Logic Ethan Furman <ethan@stoneleaf.us> - 2013-05-30 09:30 -0700
                Re: Short-circuit Logic Neil Cerutti <neilc@norwich.edu> - 2013-05-30 19:30 +0000
                  Re: Short-circuit Logic Ian Kelly <ian.g.kelly@gmail.com> - 2013-05-30 13:49 -0600
    Re: Short-circuit Logic Terry Jan Reedy <tjreedy@udel.edu> - 2013-05-26 16:19 -0400
      Re: Short-circuit Logic Roy Smith <roy@panix.com> - 2013-05-26 16:22 -0400
        Re: Short-circuit Logic Terry Jan Reedy <tjreedy@udel.edu> - 2013-05-26 17:28 -0400
        Re: Short-circuit Logic Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-27 00:40 +0000
          Re: Short-circuit Logic Cameron Simpson <cs@zip.com.au> - 2013-05-27 11:57 +1000
          Re: Short-circuit Logic rusi <rustompmody@gmail.com> - 2013-05-26 21:44 -0700
          Re: Short-circuit Logic Vito De Tullio <vito.detullio@gmail.com> - 2013-05-27 06:59 +0200
    Re: Short-circuit Logic Nobody <nobody@nowhere.com> - 2013-05-27 18:52 +0100
    Re: Short-circuit Logic Ahmed Abdulshafy <abdulshafy@gmail.com> - 2013-05-27 13:08 -0700
      Re: Short-circuit Logic Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2013-05-27 21:36 -0400

Page 1 of 4  [1] 2 3 4  Next page →


#46060 — Short-circuit Logic

FromAhmed Abdulshafy <abdulshafy@gmail.com>
Date2013-05-26 04:11 -0700
SubjectShort-circuit Logic
Message-ID<5f101d70-e51f-4531-9153-c92ee2486fd9@googlegroups.com>
Hi,
I'm having a hard time wrapping my head around short-circuit logic that's used by Python, coming from a C/C++ background; so I don't understand why the following condition is written this way!>

     if not allow_zero and abs(x) < sys.float_info.epsilon:
                print("zero is not allowed")

The purpose of this snippet is to print the given line when allow_zero is False and x is 0.

[toc] | [next] | [standalone]


#46062

FromRoy Smith <roy@panix.com>
Date2013-05-26 07:38 -0400
Message-ID<roy-370944.07383826052013@news.panix.com>
In reply to#46060
In article <5f101d70-e51f-4531-9153-c92ee2486fd9@googlegroups.com>,
 Ahmed Abdulshafy <abdulshafy@gmail.com> wrote:

> Hi,
> I'm having a hard time wrapping my head around short-circuit logic that's 
> used by Python, coming from a C/C++ background; so I don't understand why the 
> following condition is written this way!>
> 
>      if not allow_zero and abs(x) < sys.float_info.epsilon:
>                 print("zero is not allowed")
> 
> The purpose of this snippet is to print the given line when allow_zero is 
> False and x is 0.

I don't understand your confusion.  Short-circuit evaluation works in 
Python exactly the same way it works in C.  When you have a boolean 
operation, the operands are evaluated left-to-right, and evaluation 
stops as soon as the truth value of the expression is known.

In C, you would write:

   if (p && p->foo) {
        blah();
    }

to make sure that you don't dereference a null pointer.  A similar 
example in Python might be:

    if d and d["foo"]:
        blah()

which protects against trying to access an element of a dictionary if 
the dictionary is None (which might happen if d was an optional argument 
to a method and wasn't passed on this invocation).

But, none of that applies to your example.  The condition is

    not allow_zero and abs(x) < sys.float_info.epsilon:

it's safe to evaluate "abs(x) < sys.float_info.epsilon" no matter what 
the value of "not allow_zero".  For the purposes of understanding your 
code, you can pretend that short-circuit evaluation doesn't exist!

So, what is your code doing that you don't understand?

[toc] | [prev] | [next] | [standalone]


#46065

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-05-26 12:13 +0000
Message-ID<51a1fc7b$0$30002$c3e8da3$5496439d@news.astraweb.com>
In reply to#46060
On Sun, 26 May 2013 04:11:56 -0700, Ahmed Abdulshafy wrote:

> Hi,
> I'm having a hard time wrapping my head around short-circuit logic
> that's used by Python, coming from a C/C++ background; so I don't
> understand why the following condition is written this way!
> 
>      if not allow_zero and abs(x) < sys.float_info.epsilon:
>                 print("zero is not allowed")

Follow the logic.

If allow_zero is a true value, then "not allow_zero" is False, and the 
"and" clause cannot evaluate to true. (False and X is always False.) So 
print is not called.

If allow_zero is a false value, then "not allow_zero" is True, and the 
"and" clause depends on the second argument. (True and X is always X.) So
abs(x) < sys.float_info.epsilon is tested, and if that is True, print is 
called.

By the way, I don't think much of this logic. Values smaller than epsilon 
are not necessarily zero:

py> import sys
py> epsilon = sys.float_info.epsilon
py> x = epsilon/10000
py> x == 0
False
py> x * 3 == 0
False
py> x + epsilon == 0
False
py> x + epsilon == epsilon
False

The above logic throws away many perfectly good numbers and treats them 
as zero even though they aren't.


> The purpose of this snippet is to print the given line when allow_zero
> is False and x is 0.

Then the snippet utterly fails at that, since it prints the line for many 
values of x which can be distinguished from zero. The way to test whether 
x equals zero is:

x == 0

What the above actually tests for is whether x is so small that (1.0+x) 
cannot be distinguished from 1.0, which is not the same thing. It is also 
quite arbitrary. Why 1.0? Why not (0.0001+x)? Or (0.00000001+x)? Or 
(10000.0+x)?



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#46221

FromAhmed Abdulshafy <abdulshafy@gmail.com>
Date2013-05-27 13:11 -0700
Message-ID<2abf4e9c-8c3b-4e2f-80c9-50c1f1d75c9d@googlegroups.com>
In reply to#46065
On Sunday, May 26, 2013 2:13:47 PM UTC+2, Steven D'Aprano wrote:
> On Sun, 26 May 2013 04:11:56 -0700, Ahmed Abdulshafy wrote:
> 
> 
> 
> > Hi,
> 
> > I'm having a hard time wrapping my head around short-circuit logic
> 
> > that's used by Python, coming from a C/C++ background; so I don't
> 
> > understand why the following condition is written this way!
> 
> > 
> 
> >      if not allow_zero and abs(x) < sys.float_info.epsilon:
> 
> >                 print("zero is not allowed")
> 
> 
> 
> Follow the logic.
> 
> 
> 
> If allow_zero is a true value, then "not allow_zero" is False, and the 
> 
> "and" clause cannot evaluate to true. (False and X is always False.) So 
> 
> print is not called.
> 
> 
> 
> If allow_zero is a false value, then "not allow_zero" is True, and the 
> 
> "and" clause depends on the second argument. (True and X is always X.) So
> 
> abs(x) < sys.float_info.epsilon is tested, and if that is True, print is 
> 
> called.
> 
> 
> 
> By the way, I don't think much of this logic. Values smaller than epsilon 
> 
> are not necessarily zero:
> 
> 
> 
> py> import sys
> 
> py> epsilon = sys.float_info.epsilon
> 
> py> x = epsilon/10000
> 
> py> x == 0
> 
> False
> 
> py> x * 3 == 0
> 
> False
> 
> py> x + epsilon == 0
> 
> False
> 
> py> x + epsilon == epsilon
> 
> False
> 
> 
> 
> The above logic throws away many perfectly good numbers and treats them 
> 
> as zero even though they aren't.
> 
> 
> 
> 
> 
> > The purpose of this snippet is to print the given line when allow_zero
> 
> > is False and x is 0.
> 
> 
> 
> Then the snippet utterly fails at that, since it prints the line for many 
> 
> values of x which can be distinguished from zero. The way to test whether 
> 
> x equals zero is:
> 
> 
> 
> x == 0
> 
> 
> 
> What the above actually tests for is whether x is so small that (1.0+x) 
> 
> cannot be distinguished from 1.0, which is not the same thing. It is also 
> 
> quite arbitrary. Why 1.0? Why not (0.0001+x)? Or (0.00000001+x)? Or 
> 
> (10000.0+x)?
> 
> 
> 
> 
> 
> 
> 
> -- 
> 
> Steven

That may be true for integers, but for floats, testing for equality is not always precise

[toc] | [prev] | [next] | [standalone]


#46233

FromNobody <nobody@nowhere.com>
Date2013-05-28 01:10 +0100
Message-ID<pan.2013.05.28.00.10.04.235000@nowhere.com>
In reply to#46221
On Mon, 27 May 2013 13:11:28 -0700, Ahmed Abdulshafy wrote:

> On Sunday, May 26, 2013 2:13:47 PM UTC+2, Steven D'Aprano wrote:
>
>> What the above actually tests for is whether x is so small that (1.0+x)
>> cannot be distinguished from 1.0, which is not the same thing. It is
>> also quite arbitrary. Why 1.0? Why not (0.0001+x)? Or (0.00000001+x)?
>> Or (10000.0+x)?
> 
> That may be true for integers,

What may be true for integers?

> but for floats, testing for equality is not always precise

And your point is?

What Steven wrote is entirely correct: sys.float_info.epsilon is the
smallest value x such that 1.0 and 1.0+x have distinct floating-point
representations. It has no relevance for comparing to zero.

[toc] | [prev] | [next] | [standalone]


#46268

FromAhmed Abdulshafy <abdulshafy@gmail.com>
Date2013-05-28 01:39 -0700
Message-ID<48a99056-fa56-4352-b8b4-f52d3467ac96@googlegroups.com>
In reply to#46233
On Tuesday, May 28, 2013 2:10:05 AM UTC+2, Nobody wrote:
> On Mon, 27 May 2013 13:11:28 -0700, Ahmed Abdulshafy wrote:
> 
> 
> 
> > On Sunday, May 26, 2013 2:13:47 PM UTC+2, Steven D'Aprano wrote:
> 
> >
> 
> >> What the above actually tests for is whether x is so small that (1.0+x)
> 
> >> cannot be distinguished from 1.0, which is not the same thing. It is
> 
> >> also quite arbitrary. Why 1.0? Why not (0.0001+x)? Or (0.00000001+x)?
> 
> >> Or (10000.0+x)?
> 
> > 
> 
> > That may be true for integers,
> 
> 
> 
> What may be true for integers?
> 
> 
> 
> > but for floats, testing for equality is not always precise
> 
> 
> 
> And your point is?
> 
> 
> 
> What Steven wrote is entirely correct: sys.float_info.epsilon is the
> 
> smallest value x such that 1.0 and 1.0+x have distinct floating-point
> 
> representations. It has no relevance for comparing to zero.

He just said that the way to test for zero equality is x == 0, and I meant that this is true for integers but not necessarily for floats. And that's not specific to Python.

[toc] | [prev] | [next] | [standalone]


#46269

FromCarlos Nepomuceno <carlosnepomuceno@outlook.com>
Date2013-05-28 12:32 +0300
Message-ID<mailman.2290.1369733548.3114.python-list@python.org>
In reply to#46268
----------------------------------------
> Date: Tue, 28 May 2013 01:39:09 -0700
> Subject: Re: Short-circuit Logic
> From: abdulshafy@gmail.com
[...]
>> What Steven wrote is entirely correct: sys.float_info.epsilon is the
>>
>> smallest value x such that 1.0 and 1.0+x have distinct floating-point
>>
>> representations. It has no relevance for comparing to zero.
>
> He just said that the way to test for zero equality is x == 0, and I meant that this is true for integers but not necessarily for floats. And that's not specific to Python.


Have you read [1]? There's a section "Infernal Zero" that discuss this problem. I think it's very interesting to know! ;)

Just my 49.99999999999998¢! lol


[1] http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ 		 	   		  

[toc] | [prev] | [next] | [standalone]


#46275

FromMark Lawrence <breamoreboy@yahoo.co.uk>
Date2013-05-28 12:45 +0100
Message-ID<mailman.2293.1369741519.3114.python-list@python.org>
In reply to#46268
On 28/05/2013 09:39, Ahmed Abdulshafy wrote:
>
> And that's not specific to Python.
>

Using google products is also not specific to Python.  However whereever 
it's used it's a PITA as people are forced into reading double spaced 
crap.  Please check out the link in my signature.

-- 
If you're using GoogleCrap™ please read this 
http://wiki.python.org/moin/GoogleGroupsPython.

Mark Lawrence

[toc] | [prev] | [next] | [standalone]


#46287

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-05-28 13:51 +0000
Message-ID<51a4b669$0$29966$c3e8da3$5496439d@news.astraweb.com>
In reply to#46268
On Tue, 28 May 2013 01:39:09 -0700, Ahmed Abdulshafy wrote:

> He just said that the way to test for zero equality is x == 0, and I
> meant that this is true for integers but not necessarily for floats. And
> that's not specific to Python.

Can you show me a value of x where x == 0.0 returns False, but x actually 
isn't zero?

Built-in floats only, if you subclass you can do anything you like:

class Cheating(float):
    def __eq__(self, other):
        return False


-- 
Steven

[toc] | [prev] | [next] | [standalone]


#46294

FromGrant Edwards <invalid@invalid.invalid>
Date2013-05-28 15:14 +0000
Message-ID<ko2hjr$i4q$2@reader1.panix.com>
In reply to#46287
On 2013-05-28, Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote:
> On Tue, 28 May 2013 01:39:09 -0700, Ahmed Abdulshafy wrote:
>
>> He just said that the way to test for zero equality is x == 0, and I
>> meant that this is true for integers but not necessarily for floats. And
>> that's not specific to Python.
>
> Can you show me a value of x where x == 0.0 returns False, but x actually 
> isn't zero?

I'm confused.  Don't all non-zero values satisfy your conditions?

>>> x = 1.0
>>> x == 0.0
False
>>> x is 0.0
False



-- 
Grant Edwards               grant.b.edwards        Yow! I'm dressing up in
                                  at               an ill-fitting IVY-LEAGUE
                              gmail.com            SUIT!!  Too late...

[toc] | [prev] | [next] | [standalone]


#46299

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-05-28 15:55 +0000
Message-ID<51a4d37e$0$29966$c3e8da3$5496439d@news.astraweb.com>
In reply to#46294
On Tue, 28 May 2013 15:14:03 +0000, Grant Edwards wrote:

> On 2013-05-28, Steven D'Aprano <steve+comp.lang.python@pearwood.info>
> wrote:
>> On Tue, 28 May 2013 01:39:09 -0700, Ahmed Abdulshafy wrote:
>>
>>> He just said that the way to test for zero equality is x == 0, and I
>>> meant that this is true for integers but not necessarily for floats.
>>> And that's not specific to Python.
>>
>> Can you show me a value of x where x == 0.0 returns False, but x
>> actually isn't zero?
> 
> I'm confused.  Don't all non-zero values satisfy your conditions?

Of course they do :-(

I meant "but x actually *is* zero". Sorry for the confusion. I blame the 
terrists.



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#46286

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-05-28 13:48 +0000
Message-ID<51a4b5a1$0$29966$c3e8da3$5496439d@news.astraweb.com>
In reply to#46221
On Mon, 27 May 2013 13:11:28 -0700, Ahmed Abdulshafy wrote:

> That may be true for integers, but for floats, testing for equality is
> not always precise

Incorrect. Testing for equality is always precise, and exact. The problem 
is not the *equality test*, but that you don't always have the number 
that you think you have. The problem lies elsewhere, not equality!
Unfortunately, people who say "never test floats for equality" have 
misdiagnosed the problem, or they are giving a simple work-around which 
can be misleading to those who don't understand what is actually going on.

Any floating point libraries that support IEEE-754 semantics can 
guarantee a few things, including:

x == 0.0 if, and only if, x actually equals zero.

This was not always the case for all floating point systems prior to 
IEEE-754. In his forward to the Apple Numerics Manual, William Kahan 
describes a Capriciously Designed Computer where 1/x can give a Division 
By Zero error even though x != 0. Fortunately, if you are programming in 
Python on Intel-compatible hardware, you do not have to worry about 
nightmares like that.

Let me repeat that: in Python, you can trust that if x == 0.0 returns 
False, then x is definitely not zero.

In any case, the test that you show is not a good test. I have already 
shown that it wrongly treats many non-zero numbers which can be 
distinguished from zero as if they were zero. But worse, it also fails as 
a guard against numbers which cannot be distinguished from zero!

py> import sys
py> epsilon = sys.float_info.epsilon
py> x < epsilon  # Is x so tiny it looks like zero?
False
py> y = 1e17 + x  # x is not zero, so y should be > 1e17
py> 1/(1e17 - y)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: float division by zero


So as you can see, testing for "zero" by comparing to machine epsilon 
does not save you from Zero Division errors.


-- 
Steven

[toc] | [prev] | [next] | [standalone]


#46290

FromChris Angelico <rosuav@gmail.com>
Date2013-05-29 00:01 +1000
Message-ID<mailman.2298.1369749670.3114.python-list@python.org>
In reply to#46286
On Tue, May 28, 2013 at 11:48 PM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> py> y = 1e17 + x  # x is not zero, so y should be > 1e17
> py> 1/(1e17 - y)
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> ZeroDivisionError: float division by zero

You don't even need to go for 1e17. By definition:

>>> sys.float_info.epsilon+1.0==1.0
False
>>> sys.float_info.epsilon+2.0==2.0
True

Therefore the same can be done with 2 as you did with 1e17.

>>> y = 2 + sys.float_info.epsilon
>>> 1/(2-y)
Traceback (most recent call last):
  File "<pyshell#182>", line 1, in <module>
    1/(2-y)
ZeroDivisionError: float division by zero

Of course, since we're working with a number greater than epsilon, we
need to go a little further, but we can still work with small numbers:

>>> x = sys.float_info.epsilon * 2   # Definitely greater than epsilon
>>> y = 4 + x
>>> 1/(4-y)
Traceback (most recent call last):
  File "<pyshell#191>", line 1, in <module>
    1/(4-y)
ZeroDivisionError: float division by zero


ChrisA

[toc] | [prev] | [next] | [standalone]


#46382

FromAhmed Abdulshafy <abdulshafy@gmail.com>
Date2013-05-29 07:27 -0700
Message-ID<04b90c02-833a-4bad-88ad-ab71178b8f79@googlegroups.com>
In reply to#46286
On Tuesday, May 28, 2013 3:48:17 PM UTC+2, Steven D'Aprano wrote:
> On Mon, 27 May 2013 13:11:28 -0700, Ahmed Abdulshafy wrote:
> 
> 
> 
> > That may be true for integers, but for floats, testing for equality is
> 
> > not always precise
> 
> 
> 
> Incorrect. Testing for equality is always precise, and exact. The problem 
> 
> is not the *equality test*, but that you don't always have the number 
> 
> that you think you have. The problem lies elsewhere, not equality!
> 
> 
> Steven

Well, this is taken from my python shell>

>>> 0.33455857352426283 == 0.33455857352426282
True

Anyway, man, those were not my words anyway, most programming books I've read state so. Here's an excerpt from the Python book, I'm currently reading>

">>> 0.0, 5.4, -2.5, 8.9e-4
(0.0, 5.4000000000000004, -2.5, 0.00088999999999999995)


The inexactness is not a problem specific to Python—all programming languages have this problem with floating-point numbers."

[toc] | [prev] | [next] | [standalone]


#46383

FromChris Angelico <rosuav@gmail.com>
Date2013-05-30 00:32 +1000
Message-ID<mailman.2360.1369837963.3114.python-list@python.org>
In reply to#46382
On Thu, May 30, 2013 at 12:27 AM, Ahmed Abdulshafy <abdulshafy@gmail.com> wrote:
> Well, this is taken from my python shell>
>
>>>> 0.33455857352426283 == 0.33455857352426282
> True


>>> 0.33455857352426283,0.33455857352426282
(0.3345585735242628, 0.3345585735242628)

They're not representably different.

ChrisA

[toc] | [prev] | [next] | [standalone]


#46384

Fromrusi <rustompmody@gmail.com>
Date2013-05-29 07:33 -0700
Message-ID<48519aa0-d0cd-4ffc-a2f5-2107465321d8@qn4g2000pbc.googlegroups.com>
In reply to#46382
On May 29, 7:27 pm, Ahmed Abdulshafy <abdulsh...@gmail.com> wrote:
> On Tuesday, May 28, 2013 3:48:17 PM UTC+2, Steven D'Aprano wrote:
> > On Mon, 27 May 2013 13:11:28 -0700, Ahmed Abdulshafy wrote:
>
> > > That may be true for integers, but for floats, testing for equality is
>
> > > not always precise
>
> > Incorrect. Testing for equality is always precise, and exact. The problem
>
> > is not the *equality test*, but that you don't always have the number
>
> > that you think you have. The problem lies elsewhere, not equality!
>
> > Steven
>
> Well, this is taken from my python shell>
>
> >>> 0.33455857352426283 == 0.33455857352426282
>
> True
>
> Anyway, man, those were not my words anyway, most programming books I've read state so. Here's an excerpt from the Python book, I'm currently reading>
>
> ">>> 0.0, 5.4, -2.5, 8.9e-4
> (0.0, 5.4000000000000004, -2.5, 0.00088999999999999995)
>
> The inexactness is not a problem specific to Python—all programming languages have this problem with floating-point numbers."

0.0 == 0.0 implies 5.4 == 5.4
is not a true statement is what (I think) Steven is saying.
0 (or if you prefer 0.0) is special and is treated specially.

Naturally if you reach (nearabout) 0.0 by some numerical process thats
another matter...

[toc] | [prev] | [next] | [standalone]


#46394

FromIan Kelly <ian.g.kelly@gmail.com>
Date2013-05-29 10:50 -0600
Message-ID<mailman.2365.1369847746.3114.python-list@python.org>
In reply to#46384
On Wed, May 29, 2013 at 8:33 AM, rusi <rustompmody@gmail.com> wrote:
> 0.0 == 0.0 implies 5.4 == 5.4
> is not a true statement is what (I think) Steven is saying.
> 0 (or if you prefer 0.0) is special and is treated specially.

It has nothing to do with 0 being special.  A floating point number
will always equal itself (except for nan, which is even more special),
and in particular 5.4 == 5.4.  But if you have two different
calculations that produce 0, or two different calculations that
produce 5.4, you might actually get two different numbers that
approximate 0 or 5.4 thanks to rounding error.  If you then compare
those two ever-so-slightly different numbers, you will find them
unequal.

[toc] | [prev] | [next] | [standalone]


#46424

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-05-30 02:28 +0000
Message-ID<51a6b969$0$29966$c3e8da3$5496439d@news.astraweb.com>
In reply to#46394
On Wed, 29 May 2013 10:50:47 -0600, Ian Kelly wrote:

> On Wed, May 29, 2013 at 8:33 AM, rusi <rustompmody@gmail.com> wrote:
>> 0.0 == 0.0 implies 5.4 == 5.4
>> is not a true statement is what (I think) Steven is saying. 0 (or if
>> you prefer 0.0) is special and is treated specially.
> 
> It has nothing to do with 0 being special.  A floating point number will
> always equal itself (except for nan, which is even more special), and in
> particular 5.4 == 5.4.  But if you have two different calculations that
> produce 0, or two different calculations that produce 5.4, you might
> actually get two different numbers that approximate 0 or 5.4 thanks to
> rounding error.  If you then compare those two ever-so-slightly
> different numbers, you will find them unequal.

EXACTLY!

The problem does not lie with the *equality operator*, it lies with the 
calculations. And that is an intractable problem -- in general, floating 
point is *hard*. So the problem occurs when we start with a perfectly 
good statement of the facts:

"If you naively test the results of a calculation for equality without 
understanding what you are doing, you will often get surprising results"

which then turns into a general heuristic that is often, but not always, 
reasonable:

"In general, you should test for floating point *approximate* equality, 
in some appropriate sense, rather than exact equality"

which then gets mangled to:

"Never test floating point numbers for equality"

and then implemented badly by people who have no clue what they are doing 
and have misunderstood the nature of the problem, leading to either:

* de facto exact equality testing, only slower and with the *illusion* of 
avoiding equality, e.g. "abs(x-y) < sys.float_info.epsilon" is just a 
long and slow way of saying "x == y" when both numbers are sufficiently 
large;

* incorrectly accepting non-equal numbers as "equal" just because they 
happen to be "close".


The problem is that there is *no one right answer*, except "have everyone 
become an expert in floating point, then judge every case on its merits", 
which will never happen.

But if nothing else, I wish that we can get past the rank superstition 
that you should "never" test floats for equality. That would be a step 
forward.



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#46428

FromChris Angelico <rosuav@gmail.com>
Date2013-05-30 13:45 +1000
Message-ID<mailman.2392.1369885517.3114.python-list@python.org>
In reply to#46424
On Thu, May 30, 2013 at 12:28 PM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> * de facto exact equality testing, only slower and with the *illusion* of
> avoiding equality, e.g. "abs(x-y) < sys.float_info.epsilon" is just a
> long and slow way of saying "x == y" when both numbers are sufficiently
> large;
>

The problem here, I think, is that "epsilon" has two meanings:

* sys.float_info.epsilon, which is an extremely specific value (the
smallest x such that 1.0+x != x)

* the mathematical concept, which is where the other got its name from.

Let's suppose someone is told to compare floating point numbers by
seeing if the absolute value of the difference is less than some
epsilon. They look up "absolute value" and find abs(); they look up
"epsilon" and think they've found it. Trouble is, they've found the
wrong epsilon... and really, there's an engineering issue here too.
Here's one of my favourite examples of equality comparisons:

http://xkcd.com/1047/

# Let's say we measured this accurately to one part in 40
x = one_light_year_in_meters

y = pow(99,8)
x == y  # False
abs(x-y) < x/40  # True

Measurement accuracy is usually far FAR worse than floating-point
accuracy. It's pretty pointless to compare for some kind of "equality"
that ignores this. Say you measure the diameter and circumference of a
circle, accurate to one meter, and got values of 79 and 248; does this
mean that pi is less than 3.14? No - in fact:

pi = 248/79
# math.pi = 3.141592653589793
abs(pi-math.pi) < pi/79  # True

Worst error is 1 in 79, so all comparisons are done with epsilon
derived from that.

ChrisA

[toc] | [prev] | [next] | [standalone]


#46436

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-05-30 05:42 +0000
Message-ID<51a6e6b8$0$11118$c3e8da3@news.astraweb.com>
In reply to#46428
On Thu, 30 May 2013 13:45:13 +1000, Chris Angelico wrote:

> Let's suppose someone is told to compare floating point numbers by
> seeing if the absolute value of the difference is less than some
> epsilon. 

Which is usually the wrong way to do it! Normally one would prefer 
*relative* error, not absolute:

# absolute error:
abs(a - b) < epsilon


# relative error:
abs(a - b)/a < epsilon


One problem with absolute error is that it can give an entirely spurious 
image of "fuzziness", when in reality it is actually performing the same 
exact equality as == only slower and more verbosely. If a and b are 
sufficiently large, the smallest possible difference between a and b may 
be greater than epsilon (for whichever epsilon you pick). When that 
happens, you might as well just use == and be done with it.

But using relative error also raises questions:

- what if a is negative?

- why relative to a instead of relative to b?

- what if a is zero?

The first, at least, is easy to solve: take the absolute value of a. But 
strangely, you rarely see programming books mention that, so I expect 
that there is a lot of code in the real world that assumes a is positive 
and does the wrong thing when it isn't.

Here's another way, mathematically equivalent (although not necessarily 
equivalent using floating point computations!) which avoids the divide-by-
zero problem:

abs(a - b) < epsilon*a


Whichever method you choose, there are gotchas to watch out for.

> http://xkcd.com/1047/

Nice!


-- 
Steven

[toc] | [prev] | [next] | [standalone]


Page 1 of 4  [1] 2 3 4  Next page →

Back to top | Article view | comp.lang.python


csiph-web