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 3 of 4 — ← Prev page 1 2 [3] 4  Next page →


#46600

FromRoy Smith <roy@panix.com>
Date2013-05-31 09:20 -0400
Message-ID<roy-19C815.09200231052013@news.panix.com>
In reply to#46581
In article <51a86319$0$29966$c3e8da3$5496439d@news.astraweb.com>,
 Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote:

>     In an early talk Ken was explaining the advantages of tolerant
>     comparison. A member of the audience asked incredulously, 
>     “Surely you don’t mean that when A=B and B=C, A may not equal C?”
>     Without skipping a beat, Ken replied, “Any carpenter knows that!”
>     and went on to the next question. — Paul Berry

Any any good carpenter also knows it's better to copy than to measure.  
Let's say I have a door frame and I need to trim a door to fit it 
exactly.  I can do one of two things.

First, I could take out my tape measure and measure that the frame is 29 
and 11/32 inches wide.  Then, carry that tape measure to the door, 
measure off 29 and 11/32 inches, and make a mark.

Or, I could take a handy stick of wood which is 30-something inches 
long, lay it down at the bottom of the door frame with one end up snug 
against one side, and make a mark at the other side of the frame.  Then 
carry my stick to the door and keep trimming until it's the same width 
as the marked section on the stick.

Google for "story stick".

The tape measure is like digital floating point.  It introduces all 
sorts of ways for errors to creep in and people who care about getting 
doors to properly fit into door frames understand all that.

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


#46650

FromCarlos Nepomuceno <carlosnepomuceno@outlook.com>
Date2013-06-01 10:23 +0300
Message-ID<mailman.2520.1370071413.3114.python-list@python.org>
In reply to#46581
----------------------------------------
> From: steve+comp.lang.python@pearwood.info
> Subject: Re: Short-circuit Logic
> Date: Fri, 31 May 2013 08:45:13 +0000
> To: python-list@python.org
>
> On Fri, 31 May 2013 17:09:01 +1000, Chris Angelico wrote:
>
>> On Fri, May 31, 2013 at 3:13 PM, Steven D'Aprano
>> <steve+comp.lang.python@pearwood.info> wrote:
>>> What makes you think that the commutative law is relevant here?
>>>
>>>
>> Equality should be commutative. If a == b, then b == a. Also, it's
>> generally understood that if a == c and b == c, then a == b, though
>> there are more exceptions to that (especially in loosely-typed
>> languages).
>
> Who is talking about equality? Did I just pass through the Looking Glass
> into Wonderland again? *wink*
>
> We're talking about *approximate equality*, which is not the same thing,
> despite the presence of the word "equality" in it. It is non-commutative,
> just like other comparisons like "less than" and "greater than or equal
> to". Nobody gets their knickers in a twist because the>= operator is non-
> commutative.

Approximately equality CAN be commutative! I have just showed you that in the beginning using the following criteria:

|v-u| <= ε*max(|u|,|v|)

Which is implemented as fpc_aeq():

def fpc_aeq(u,v,eps=sys.float_info.epsilon):
    au=abs(u)
    av=abs(v)
    return abs(v-u) <= (eps*(au if au>av else av))  # |v-u| <= ε*max(|u|,|v|)


> Approximate equality is not just non-commutative, it's also intransitive.
> I'm reminded of a story about Ken Iverson, the creator of APL. Iverson
> was a strong proponent of what he called "tolerant equality", and APL
> defined the = operator as a relative approximate equal, rather than the
> more familiar exactly-equal operator most programming languages use.
>
> In an early talk Ken was explaining the advantages of tolerant
> comparison. A member of the audience asked incredulously,
> “Surely you don’t mean that when A=B and B=C, A may not equal C?”
> Without skipping a beat, Ken replied, “Any carpenter knows that!”
> and went on to the next question. — Paul Berry

That's true! But it's a consequence of floating points (discretes representing a continuous set -- real numbers).
Out of context, as you put it, looks like approximate equality is non-commutative, but that's wrong.

Did you read the paper[1] you have suggested? Because SHARP APL in fact uses the same criteria I have mentioned and it supports it extensively to the point of applying it by default to many primitive functions, according to Lathwell[2] wich is reference 19 of [1].

"less than                  a<b
less than or equal          a≤b
equal                       a=b
greater than or equal       a≥b
greater than                a>b
not equal                   a≠b
floor                       ⌊a
ceiling                     ⌈a
membership                  a∊b
index of                    a⍳b"


I'll quote Lathwell. He called "tolerant comparison" what we are now calling "approximate equality".

"Tolerant comparison considers two numbers to be equal if they are within some neighborhood. The neighborhood has a radius of ⎕ct times the larger of the two in absolute value."

He says "larger of the two" which means "max(|u|,|v|)". So, you reference just reaffirms what TAOCP have demonstrated to be the best practice.

I really don't know what the fuck you are arguing about?

Can you show me at least one case where the commutative law wouldn't benefit the use of the approximate equality operator?

[1] http://www.jsoftware.com/papers/APLEvol.htm
[2] http://www.jsoftware.com/papers/satn23.htm


> The intransitivity of [tolerant] equality is well known in
> practical situations and can be easily demonstrated by sawing
> several pieces of wood of equal length. In one case, use the
> first piece to measure subsequent lengths; in the second case,
> use the last piece cut to measure the next. Compare the lengths
> of the two final pieces.
> — Richard Lathwell, APL Comparison Tolerance, APL76, 1976
>
> See also here:
>
> http://www.jsoftware.com/papers/APLEvol.htm
>
> (search for "fuzz" or "tolerance".
>
>
>
> --
> Steven
> --
> http://mail.python.org/mailman/listinfo/python-list 		 	   		  

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


#46570

From88888 Dihedral <dihedral88888@gmail.com>
Date2013-05-30 20:11 -0700
Message-ID<987fed2a-e7c7-4bcc-8aaf-9608e21eff26@googlegroups.com>
In reply to#46424
Steven D'Aprano於 2013年5月30日星期四UTC+8上午10時28分57秒寫道:
> 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

The string used to represent a floating number
in a computer language is normally in the decimal base of very 
some limited digits.

Anyway with the advances of A/D-converters in the past 10 years
which are reflected in the anttena- transmitter parts in phones, 
the long integer part in Python can really beat the low cost 
32- 64 bit floating computations in scientific calculations.

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


#46420

FromDave Angel <davea@davea.name>
Date2013-05-29 20:23 -0400
Message-ID<mailman.2387.1369873394.3114.python-list@python.org>
In reply to#46384
On 05/29/2013 12:50 PM, 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.
>

Rounding error is just one of the problems.  Usually less obvious is 
quantization error.  If you represent a floating number in decimal, but 
you're using a binary floating point representation, it just might change.

Another error is roundoff error.  Even in a pure decimal system of (say) 
40 digits, I could type in a 42 digit number and it would get quantized. 
  So just because two 42 digit numbers are different doesn't imply that 
the 40 digit internal format would be.


-- 
DaveA

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


#46434

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-05-30 05:20 +0000
Message-ID<51a6e1aa$0$11118$c3e8da3@news.astraweb.com>
In reply to#46420
On Wed, 29 May 2013 20:23:00 -0400, Dave Angel wrote:

> Even in a pure decimal system of (say)
> 40 digits, I could type in a 42 digit number and it would get quantized.
>   So just because two 42 digit numbers are different doesn't imply that
> the 40 digit internal format would be.

Correct, and we can demonstrate it using Python:

py> from decimal import *
py> getcontext().prec = 3
py> a = +Decimal('1.0000')
py> b = +Decimal('1.0009')
py> a == b
True


(By default, the Decimal constructor does not honour the current 
precision. To force it to do so, use the unary + operator.)
    



-- 
Steven

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


#46433

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-05-30 05:10 +0000
Message-ID<51a6df59$0$11118$c3e8da3@news.astraweb.com>
In reply to#46382
On Wed, 29 May 2013 07:27:40 -0700, Ahmed Abdulshafy 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

This is an excellent example of misunderstanding what you are seeing. 
Both 0.33455857352426283 and 0.33455857352426282 represent the same 
float, so it is hardly a surprise that they compare equal -- they compare 
equal because they are equal.

py> a, b = 0.33455857352426283, 0.33455857352426282
py> a.as_integer_ratio()
(6026871468229899, 18014398509481984)
py> b.as_integer_ratio()
(6026871468229899, 18014398509481984)

You've made a common error: neglecting to take into account the finite 
precision of floats. Floats are not mathematical "real numbers", with 
infinite precision. The error is more obvious if we exaggerate it:

py> 0.3 == 0.300000000000000000000000000000000000000000000000000001
True

Most people who have seen an ordinary four-function calculator will 
realise that the issue here is *not* that the equality operator == is 
wrongly stating that two unequal numbers are equal, but that just because 
you enter 0.300...00001 doesn't mean that all those decimal places are 
actually used.


> 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."

I'm not denying that floats are tricky to use correctly, or that testing 
for exact equality is *sometimes* the wrong thing to do:

# Wrong, don't do this!
x = 0.1
while x != 17.3:
    print(x)
    x += 0.1


I'm just saying that a simple minded comparison with 
sys.float_info.epsilon is *also* often wrong.


-- 
Steven

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


#46435

FromChris Angelico <rosuav@gmail.com>
Date2013-05-30 15:22 +1000
Message-ID<mailman.2395.1369891346.3114.python-list@python.org>
In reply to#46433
On Thu, May 30, 2013 at 3:10 PM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> # Wrong, don't do this!
> x = 0.1
> while x != 17.3:
>     print(x)
>     x += 0.1
>

Actually, I wouldn't do that with integers either. There are too many
ways that a subsequent edit could get it wrong and go infinite, so I'd
*always* use an inequality for that:

x = 1
while x < 173:
    print(x)
    x += 1

Well, in Python I'd use for/range, but the equivalent still applies. A
range() is still based on an inequality:

>>> list(range(1,6))
[1, 2, 3, 4, 5]
>>> list(range(1,6,3))
[1, 4]

Stops once it's no longer less than the end. That's safe, since Python
can't do integer wraparound.

ChrisA

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


#46476

FromRoy Smith <roy@panix.com>
Date2013-05-30 08:40 -0400
Message-ID<roy-B251F4.08401630052013@news.panix.com>
In reply to#46435
In article <mailman.2395.1369891346.3114.python-list@python.org>,
 Chris Angelico <rosuav@gmail.com> wrote:

> On Thu, May 30, 2013 at 3:10 PM, Steven D'Aprano
> <steve+comp.lang.python@pearwood.info> wrote:
> > # Wrong, don't do this!
> > x = 0.1
> > while x != 17.3:
> >     print(x)
> >     x += 0.1
> >
> 
> Actually, I wouldn't do that with integers either. There are too many
> ways that a subsequent edit could get it wrong and go infinite, so I'd
> *always* use an inequality for that:
> 
> x = 1
> while x < 173:
>     print(x)
>     x += 1

There's a big difference between these two.  In the first case, using 
less-than instead of testing for equality, you are protecting against 
known and expected floating point behavior.

In the second case, you're protecting against some vague, unknown, 
speculative future programming botch.  So, what *is* the right behavior 
if somebody were to accidentally drop three zeros into the source code:

> x = 1000
> while x < 173:
>     print(x)
>     x += 1

should the loop just quietly not execute (which is what it will do 
here)?  Will that make your program correct again, or will it simply 
turn this into a difficult to find bug?  If you're really worried about 
that, why not:

> x = 1
> while x != 173:
>     assert < 172
>     print(x)
>     x += 1

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


#46482

FromChris Angelico <rosuav@gmail.com>
Date2013-05-30 22:58 +1000
Message-ID<mailman.2415.1369918710.3114.python-list@python.org>
In reply to#46476
On Thu, May 30, 2013 at 10:40 PM, Roy Smith <roy@panix.com> wrote:
> if somebody were to accidentally drop three zeros into the source code:
>
>> x = 1000
>> while x < 173:
>>     print(x)
>>     x += 1
>
> should the loop just quietly not execute (which is what it will do
> here)?  Will that make your program correct again, or will it simply
> turn this into a difficult to find bug?  If you're really worried about
> that, why not:

If you iterate from 1000 to 173, you get nowhere. This is the expected
behaviour; this is what a C-style for loop would be written as, it's
what range() does, it's the normal thing. Going from a particular
starting point to a particular ending point that's earlier than the
start results in no iterations. The alternative would be an infinite
number of iterations, which is far far worse.

ChrisA

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


#46511

Fromrusi <rustompmody@gmail.com>
Date2013-05-30 09:58 -0700
Message-ID<578a8e7f-4358-40ba-bcf8-d3a81b37c0d2@vy4g2000pbc.googlegroups.com>
In reply to#46482
On May 30, 5:58 pm, Chris Angelico <ros...@gmail.com> wrote:
> The alternative would be an infinite number of iterations, which is far far worse.

There was one heavyweight among programming teachers -- E.W. Dijkstra
-- who had some rather extreme views on this.

He taught that when writing a loop of the form

i = 0
while i < n:
  some code
  i += 1

one should write the loop test as i != n rather than i < n, precisely
because if i got erroneously initialized to some value greater than n,
(and thereby broke the loop invariant), it would loop infinitely
rather than stop with a wrong result.

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


#46515

FromChris Angelico <rosuav@gmail.com>
Date2013-05-31 03:23 +1000
Message-ID<mailman.2433.1369934594.3114.python-list@python.org>
In reply to#46511
On Fri, May 31, 2013 at 2:58 AM, rusi <rustompmody@gmail.com> wrote:
> On May 30, 5:58 pm, Chris Angelico <ros...@gmail.com> wrote:
>> The alternative would be an infinite number of iterations, which is far far worse.
>
> There was one heavyweight among programming teachers -- E.W. Dijkstra
> -- who had some rather extreme views on this.
>
> He taught that when writing a loop of the form
>
> i = 0
> while i < n:
>   some code
>   i += 1
>
> one should write the loop test as i != n rather than i < n, precisely
> because if i got erroneously initialized to some value greater than n,
> (and thereby broke the loop invariant), it would loop infinitely
> rather than stop with a wrong result.

And do you agree or disagree with him? :)

I disagree with Dijkstra on a number of points, and this might be one of them.

When you consider that the obvious Pythonic version of that code:

for i in range(n,m):
    some code

loops over nothing and does not go into an infinite loop (or throw an
exception) when n >= m, you have to at least acknowledge that I'm in
agreement with Python core code here :) That doesn't mean it's right,
of course, but it's at least a viewpoint that someone has seen fit to
enshrine in important core functionality.

ChrisA

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


#46563

FromRick Johnson <rantingrickjohnson@gmail.com>
Date2013-05-30 17:13 -0700
Message-ID<9e4d113b-23ec-4eb3-836a-fc80c505c846@googlegroups.com>
In reply to#46511
> On Fri, May 31, 2013 at 2:58 AM, rusi wrote:
> > On May 30, 5:58 pm, Chris Angelico wrote:
> > > The alternative would be an infinite number of iterations, which is far far worse.
> >
> > There was one heavyweight among programming teachers -- E.W. Dijkstra
> > -- who had some rather extreme views on this.
> > 
> > He taught that when writing a loop of the form
> >
> > i = 0
> > while i < n:
> >   some code
> >   i += 1
> >
> > one should write the loop test as i != n rather than i <
> > n, precisely because if i got erroneously initialized to
> > some value greater than n, (and thereby broke the loop
> > invariant), it would loop infinitely rather than stop
> > with a wrong result.
> > 
> 
> And do you agree or disagree with him? :) I disagree with
> Dijkstra on a number of points, and this might be one of
> them. When you consider that the obvious Pythonic version
> of that code:
> 
> for i in range(n,m):
>     some code

Maybe from your limited view point. What if you need to perform operations on a sequence (more than once) in a non-linear fashion? What if you need to modify the sequence whilst looping? In many cases your simplistic "for loop" will fail miserably. 

py> lst = range(5)
py> for n in lst:
...     print lst.pop()
4
3
2

Oops, can't do that with a for loop!

py> lst = range(5)
py> while len(lst):
...     print lst.pop()
4
3
2
1
0

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


#46568

FromChris Angelico <rosuav@gmail.com>
Date2013-05-31 12:29 +1000
Message-ID<mailman.2470.1369967856.3114.python-list@python.org>
In reply to#46563
On Fri, May 31, 2013 at 10:13 AM, Rick Johnson
<rantingrickjohnson@gmail.com> wrote:
> What if you need to perform operations on a sequence (more than once) in a non-linear fashion? What if you need to modify the sequence whilst looping? In many cases your simplistic "for loop" will fail miserably.


What has this to do with the original question of iterating across
integers? What you're now saying is that both the meaning of the
current index and the top boundary can change during iteration; that's
unrelated to whether to use equality or inequality for comparisons.

Oh wait. Rick's back. He's been away so long that I stopped looking
for his name in the headers.

ChrisA

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


#46504

FromEthan Furman <ethan@stoneleaf.us>
Date2013-05-30 08:02 -0700
Message-ID<mailman.2428.1369929032.3114.python-list@python.org>
In reply to#46476
On 05/30/2013 05:58 AM, Chris Angelico wrote:
> On Thu, May 30, 2013 at 10:40 PM, Roy Smith <roy@panix.com> wrote:
>> if somebody were to accidentally drop three zeros into the source code:
>>
>>> x = 1000
>>> while x < 173:
>>>      print(x)
>>>      x += 1
>>
>> should the loop just quietly not execute (which is what it will do
>> here)?  Will that make your program correct again, or will it simply
>> turn this into a difficult to find bug?  If you're really worried about
>> that, why not:
>
> If you iterate from 1000 to 173, you get nowhere. This is the expected
> behaviour; this is what a C-style for loop would be written as, it's
> what range() does, it's the normal thing. Going from a particular
> starting point to a particular ending point that's earlier than the
> start results in no iterations. The alternative would be an infinite
> number of iterations, which is far far worse.

If the bug is the extra three zeros (maybe it should have been two), 
then silently skipping the loop is the "far, far worse" scenario.  With 
the infinite loop you at least know something went wrong, and you know 
it pretty darn quick (since you are testing, right? ;).

--
~Ethan~

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


#46505

FromChris Angelico <rosuav@gmail.com>
Date2013-05-31 01:56 +1000
Message-ID<mailman.2429.1369929372.3114.python-list@python.org>
In reply to#46476
On Fri, May 31, 2013 at 1:02 AM, Ethan Furman <ethan@stoneleaf.us> wrote:
> On 05/30/2013 05:58 AM, Chris Angelico wrote:
>> If you iterate from 1000 to 173, you get nowhere. This is the expected
>> behaviour; this is what a C-style for loop would be written as, it's
>> what range() does, it's the normal thing. Going from a particular
>> starting point to a particular ending point that's earlier than the
>> start results in no iterations. The alternative would be an infinite
>> number of iterations, which is far far worse.
>
> If the bug is the extra three zeros (maybe it should have been two), then
> silently skipping the loop is the "far, far worse" scenario.  With the
> infinite loop you at least know something went wrong, and you know it pretty
> darn quick (since you are testing, right? ;).

You're assuming you can casually hit Ctrl-C to stop an infinite loop,
meaning that it's trivial. It's not. Not everything lets you do that;
or possibly halting the process will halt far more than you intended.
What if you're editing live code in something that's had uninterrupted
uptime for over a year? Doing nothing is much safer than getting stuck
in an infinite loop. And yes, I have done exactly that, though not in
Python. Don't forget, your start/stop figures mightn't be constants,
so you might not see it in testing. I can't imagine ANY scenario where
you'd actually *want* the infinite loop behaviour, while there are
plenty where you want it to skip the loop, and would otherwise have to
guard it with an if.

ChrisA

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


#46506

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-05-30 16:40 +0000
Message-ID<51a78113$0$29966$c3e8da3$5496439d@news.astraweb.com>
In reply to#46505
On Fri, 31 May 2013 01:56:09 +1000, Chris Angelico wrote:

> On Fri, May 31, 2013 at 1:02 AM, Ethan Furman <ethan@stoneleaf.us>
> wrote:
>> On 05/30/2013 05:58 AM, Chris Angelico wrote:
>>> If you iterate from 1000 to 173, you get nowhere. This is the expected
>>> behaviour; this is what a C-style for loop would be written as, it's
>>> what range() does, it's the normal thing. Going from a particular
>>> starting point to a particular ending point that's earlier than the
>>> start results in no iterations. The alternative would be an infinite
>>> number of iterations, which is far far worse.
>>
>> If the bug is the extra three zeros (maybe it should have been two),
>> then silently skipping the loop is the "far, far worse" scenario.  With
>> the infinite loop you at least know something went wrong, and you know
>> it pretty darn quick (since you are testing, right? ;).
> 
> You're assuming you can casually hit Ctrl-C to stop an infinite loop,
> meaning that it's trivial. It's not. Not everything lets you do that; or
> possibly halting the process will halt far more than you intended. What
> if you're editing live code in something that's had uninterrupted uptime
> for over a year? 

Then more fool you for editing live code.

By the way, this is Python. Editing live code is not easy, if it's 
possible at all.

But even when possible, it's certainly not sensible. You don't insist on 
your car mechanic giving your car a grease and oil change while you're 
driving at 100kmh down the freeway, and you shouldn't insist that your 
developers modify your code while it runs.

In any case, your arguing about such abstract, hypothetical ideas that, 
frankly, *anything at all* might be said about it. "What if Ctrl-C causes 
some great disaster?" can be answered with an equally hypothetical "What 
if Ctrl-C prevents some great disaster?"


> Doing nothing is much safer than getting stuck in an
> infinite loop. 

I disagree. And I agree. It all depends on the circumstances. But, given 
that we are talking about Python where infinite loops can be trivially 
broken out of, *in my experience* they are less-worse than silently doing 
nothing.

I've occasionally written faulty code that enters an infinite loop. When 
that happens, it's normally pretty obvious: something which should 
complete in a millisecond is still running after ten minutes. That's a 
clear, obvious, *immediate* sign that I've screwed up, which leads to me 
fixing the problem.

On the other hand, I've occasionally written faulty code that does 
nothing at all. The specific incident I am thinking of, I wrote a bunch 
of doctests which *weren't being run at all*. For nearly two weeks (not 
full time, but elapsed time) I was developing this code, before I started 
to get suspicious that *none* of the tests had failed, not even once. I 
mean, I'm not that good a programmer. Eventually I put in some deliberate 
errors, and they still didn't fail. 

In actuality, nearly every test was failing, my entire code base was 
rubbish, and I just didn't know it.

So, in this specific case, I would have *much* preferred an obvious 
failure (such as an infinite loop) than code that silently does the wrong 
thing.

We've drifted far from the original topic. There is a distinct difference 
between guarding against inaccuracies in floating point calculations:

# Don't do this!
total = 0.0
while total != 1.0:
    total += 0.1

and guarding against typos in source code:

total = 90  # Oops, I meant 0
while total != 10:
    total += 1

The second case is avoidable by paying attention when you code. The first 
case is not easily avoidable, because it reflects a fundamental 
difficulty with floating point types.

As a general rule, "defensive coding" does not extend to the idea of 
defending against mistakes in your code. The compiler, linter or unit 
tests are supposed to do that. Occasionally, I will code defensively when 
initialising tedious data sets:

prefixes = ['y', 'z', 'a', 'f', 'p', 'n', 'µ', 'm', 
            'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
assert len(prefixes) == 16


but that's about as far as I go.


-- 
Steven

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


#46534

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-05-30 19:22 +0000
Message-ID<51a7a706$0$29966$c3e8da3$5496439d@news.astraweb.com>
In reply to#46506
On Thu, 30 May 2013 16:40:52 +0000, Steven D'Aprano wrote:

> On Fri, 31 May 2013 01:56:09 +1000, Chris Angelico wrote:

>> You're assuming you can casually hit Ctrl-C to stop an infinite loop,
>> meaning that it's trivial. It's not. Not everything lets you do that;
>> or possibly halting the process will halt far more than you intended.
>> What if you're editing live code in something that's had uninterrupted
>> uptime for over a year?
> 
> Then more fool you for editing live code.

Ouch! That came out much harsher than it sounded in my head :(

Sorry Chris, that wasn't intended as a personal attack against you, just 
as a comment on the general inadvisability of modifying code on the fly 
while it is being run.


-- 
Steven

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


#46546

FromChris Angelico <rosuav@gmail.com>
Date2013-05-31 07:46 +1000
Message-ID<mailman.2455.1369950372.3114.python-list@python.org>
In reply to#46534
On Fri, May 31, 2013 at 5:22 AM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> On Thu, 30 May 2013 16:40:52 +0000, Steven D'Aprano wrote:
>
>> On Fri, 31 May 2013 01:56:09 +1000, Chris Angelico wrote:
>
>>> You're assuming you can casually hit Ctrl-C to stop an infinite loop,
>>> meaning that it's trivial. It's not. Not everything lets you do that;
>>> or possibly halting the process will halt far more than you intended.
>>> What if you're editing live code in something that's had uninterrupted
>>> uptime for over a year?
>>
>> Then more fool you for editing live code.
>
> Ouch! That came out much harsher than it sounded in my head :(
>
> Sorry Chris, that wasn't intended as a personal attack against you, just
> as a comment on the general inadvisability of modifying code on the fly
> while it is being run.

Apology accepted :)

You're right that, in theory, a staging area is a Good Thing. But it's
not always feasible. At work, we have a lot of Pike code that really
does keep running indefinitely (okay, we have yet to get anywhere near
a year's uptime for administrative reasons, but it'll be plausible
once we go live; the >1year figure came from one of my personal
projects). While all's going well, code changes follow a sane
progression:

dev -> alpha -> beta -> live

with testing at every stage. What happens when we get a problem,
though? Maybe some process is leaking resources, maybe we come under
some kind of crazy DOS attack, whatever. We need a solution, and we
need to not break things for the currently-connected clients. That
means editing the live code. Of course, there are *some* protections;
the new code won't be switched in unless it passes the compilation
phase (think "except ImportError: keep_existing_code", kinda), and
hopefully I would at least spin it up on my dev box before pushing it
to live, but even so, there's every possibility that there'll be a
specific case that I didn't think of - remembering that we're not
talking about iteration from constant to constant, but from variable
to constant or constant to variable or variable to variable. That's
why I would prefer, in language design, for a 'failed loop' to result
in no iterations than an infinite number of them. The infinite loop
might be easily caught on my dev test - but only if I pass the code
through that exact code path.

But to go back to your point about editing live code: You backed down
from the implication that it's *foolish*, but I would maintain it at a
weaker level. Editing code in a running process is a *rare* thing to
do. MOST programming is not done that way. It's like the old joke
about the car mechanic and the heart surgeon (see eg
http://www.medindia.net/jokes/viewjokes.asp?hid=200 if you haven't
heard it, and I will be spoiling the punch line in the next line or
so); most programmers are mechanics, shutting down the system to do
any work on it, but very occasionally there are times when you need to
do it with the engine running. It's like C compilers. Most of us never
write them, but a few people (relatively) actually need to drop to the
uber-low-level coding and think about how it all works in assembly
language. For everyone else, thinking about machine code is an utter
waste of time/effort, but that doesn't mean that it's folly for a
compiler writer. Does that make sense?

ChrisA

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


#46510

FromEthan Furman <ethan@stoneleaf.us>
Date2013-05-30 09:30 -0700
Message-ID<mailman.2431.1369932811.3114.python-list@python.org>
In reply to#46476
On 05/30/2013 08:56 AM, Chris Angelico wrote:
> On Fri, May 31, 2013 at 1:02 AM, Ethan Furman <ethan@stoneleaf.us> wrote:
>> On 05/30/2013 05:58 AM, Chris Angelico wrote:
>>> If you iterate from 1000 to 173, you get nowhere. This is the expected
>>> behaviour; this is what a C-style for loop would be written as, it's
>>> what range() does, it's the normal thing. Going from a particular
>>> starting point to a particular ending point that's earlier than the
>>> start results in no iterations. The alternative would be an infinite
>>> number of iterations, which is far far worse.
>>
>> If the bug is the extra three zeros (maybe it should have been two), then
>> silently skipping the loop is the "far, far worse" scenario.  With the
>> infinite loop you at least know something went wrong, and you know it pretty
>> darn quick (since you are testing, right? ;).
>
> You're assuming you can casually hit Ctrl-C to stop an infinite loop,
> meaning that it's trivial. It's not. Not everything lets you do that;
> or possibly halting the process will halt far more than you intended.
> What if you're editing live code in something that's had uninterrupted
> uptime for over a year? Doing nothing is much safer than getting stuck
> in an infinite loop. And yes, I have done exactly that, though not in
> Python. Don't forget, your start/stop figures mightn't be constants,
> so you might not see it in testing. I can't imagine ANY scenario where
> you'd actually *want* the infinite loop behaviour, while there are
> plenty where you want it to skip the loop, and would otherwise have to
> guard it with an if.

We're not talking about skipping the loop on purpose, but on accident. 
Sure, taking a system down is no fun -- on the other hand, how much data 
corruption can occur before somebody realises there's a problem, and 
then how long to track it down to a silently, accidently, skipped loop?

--
~Ethan~

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


#46536

FromNeil Cerutti <neilc@norwich.edu>
Date2013-05-30 19:30 +0000
Message-ID<b0pnn1F6r6uU1@mid.individual.net>
In reply to#46435
On 2013-05-30, Chris Angelico <rosuav@gmail.com> wrote:
> On Thu, May 30, 2013 at 3:10 PM, Steven D'Aprano
><steve+comp.lang.python@pearwood.info> wrote:
>> # Wrong, don't do this!
>> x = 0.1
>> while x != 17.3:
>>     print(x)
>>     x += 0.1
>
> Actually, I wouldn't do that with integers either.

I propose borrowing the concept of significant digits from the
world of Physics.

The above has at least three significant digits. With that scheme
x would approximately equal 17.3 when 17.25 <= x < 17.35.

But I don't see immediately how to calculate 17.25 and 17.35 from
17.3, 00.1 and 3 significant digits.

-- 
Neil Cerutti

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


Page 3 of 4 — ← Prev page 1 2 [3] 4  Next page →

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


csiph-web