Re: Floating point calculation problem

Discussion in 'Python' started by Chris Angelico, Feb 2, 2013.

  1. On Sat, Feb 2, 2013 at 9:27 PM, Schizoid Man <> wrote:
    > The quantity s is input with the following line: s = input("Enter s: ")
    >
    > To get rid of the compile error, I can cast this as a float: s =
    > float(input("Enter s: "))
    >
    > However, then the result returned by the method is wrong. Why does this
    > error occur in version 3.3.0 but not in 2.7.3? Why is the result incorrect
    > when s is cast as a float (the casting is not required in 2.7.3)? How is
    > Python dynamically typed if I need to cast (in version 3.3.0 at least) to
    > get rid of the compile error?


    Did you use input() or raw_input() in 2.7.3? If the former, you were
    actually doing this:

    s = eval(input("Enter s: "))

    That's extremely dangerous and inadvisable, so it's better to go with
    3.3 or the raw_input function.

    Passing it through float() is, most likely, the right way to do this.
    But what do you mean by "the result... is wrong"? That's the bit to
    look into.

    ChrisA
     
    Chris Angelico, Feb 2, 2013
    #1
    1. Advertising

  2. Chris Angelico

    Schizoid Man Guest

    "Chris Angelico" <> wrote in message
    news:...
    > On Sat, Feb 2, 2013 at 9:27 PM, Schizoid Man <>
    > wrote:
    >> The quantity s is input with the following line: s = input("Enter s: ")
    >>
    >> To get rid of the compile error, I can cast this as a float: s =
    >> float(input("Enter s: "))
    >>
    >> However, then the result returned by the method is wrong. Why does this
    >> error occur in version 3.3.0 but not in 2.7.3? Why is the result
    >> incorrect
    >> when s is cast as a float (the casting is not required in 2.7.3)? How is
    >> Python dynamically typed if I need to cast (in version 3.3.0 at least) to
    >> get rid of the compile error?

    >
    > Did you use input() or raw_input() in 2.7.3? If the former, you were
    > actually doing this:
    >
    > s = eval(input("Enter s: "))
    >
    > That's extremely dangerous and inadvisable, so it's better to go with
    > 3.3 or the raw_input function.


    Thanks for the reply. You're right - even in 2.7.3 if I toggle between
    float(input(x)) and input(x), the result of the calculation changes. What
    does the float cast do exactly?

    > Passing it through float() is, most likely, the right way to do this.
    > But what do you mean by "the result... is wrong"? That's the bit to
    > look into.


    Scratch that, I'm not sure which result is right now, so need to look at the
    full calculations in details. What would be the difference between
    raw_input() and float(input())?

    Thanks again.
     
    Schizoid Man, Feb 2, 2013
    #2
    1. Advertising

  3. On Sat, Feb 2, 2013 at 10:14 PM, Schizoid Man <> wrote:
    > Scratch that, I'm not sure which result is right now, so need to look at the
    > full calculations in details. What would be the difference between
    > raw_input() and float(input())?
    >
    > Thanks again.


    Depends on what you type in.

    raw_input() takes a line from the keyboard (handwave) and returns it
    as a string.

    input() in 2.X takes a line from the keyboard and evaluates it as a
    Python expression.

    float() takes a string, float, int, etc, and returns the
    nearest-equivalent floating point value.

    What's the input you're giving to it?

    ChrisA
     
    Chris Angelico, Feb 2, 2013
    #3
  4. Chris Angelico

    Schizoid Man Guest

    > raw_input() takes a line from the keyboard (handwave) and returns it
    > as a string.
    >
    > input() in 2.X takes a line from the keyboard and evaluates it as a
    > Python expression.
    >
    > float() takes a string, float, int, etc, and returns the
    > nearest-equivalent floating point value.
    >
    > What's the input you're giving to it?


    Something simple like 3.0.

    PS - I'm new to Python, hence the newbie questions.
     
    Schizoid Man, Feb 2, 2013
    #4
  5. On Sat, Feb 2, 2013 at 10:34 PM, Schizoid Man <> wrote:
    >> raw_input() takes a line from the keyboard (handwave) and returns it
    >> as a string.
    >>
    >> input() in 2.X takes a line from the keyboard and evaluates it as a
    >> Python expression.
    >>
    >> float() takes a string, float, int, etc, and returns the
    >> nearest-equivalent floating point value.
    >>
    >> What's the input you're giving to it?

    >
    >
    > Something simple like 3.0.


    If your input has no decimal point in it, eval (or input) will return
    an integer, not a float. Other than that, I can't see any obvious
    reason for there to be a difference. Can you put together a simple
    script that demonstrates the problem and post it, along with the exact
    input that you're giving it, and the different outputs?

    Chris Angelico
     
    Chris Angelico, Feb 2, 2013
    #5
  6. Schizoid Man wrote:

    > "Chris Angelico" <> wrote in message
    > news:...
    >> On Sat, Feb 2, 2013 at 9:27 PM, Schizoid Man <>
    >> wrote:
    >>> The quantity s is input with the following line: s = input("Enter s:
    >>> ")
    >>>
    >>> To get rid of the compile error, I can cast this as a float: s =
    >>> float(input("Enter s: "))
    >>>
    >>> However, then the result returned by the method is wrong. Why does this
    >>> error occur in version 3.3.0 but not in 2.7.3? Why is the result
    >>> incorrect
    >>> when s is cast as a float (the casting is not required in 2.7.3)? How is
    >>> Python dynamically typed if I need to cast (in version 3.3.0 at least)
    >>> to get rid of the compile error?

    >>
    >> Did you use input() or raw_input() in 2.7.3? If the former, you were
    >> actually doing this:
    >>
    >> s = eval(input("Enter s: "))
    >>
    >> That's extremely dangerous and inadvisable, so it's better to go with
    >> 3.3 or the raw_input function.

    >
    > Thanks for the reply. You're right - even in 2.7.3 if I toggle between
    > float(input(x)) and input(x), the result of the calculation changes.


    Highly unlikely. I'd say impossible, unless you type a different value for x
    of course. By the time the input() function returns, the result is already
    a float. Wrapping it in float() again cannot possibly change the value. If
    you have found a value that does change, please tell us what it is.

    The only examples I can think of that will behave that way involve NANs and
    INFs. If you don't know what they are, don't worry about it, and forget I
    mentioned them. For regular floating point values, I can't think of any
    possible way that float(input(x)) and input(x) could give different
    results.


    > What does the float cast do exactly?


    float(x) converts x into a float.

    - if x is already a float, it leaves it unchanged;

    - if x is a string, it converts it to the nearest possible float;

    - if x is some other numeric value (e.g. int, Decimal or Fraction,
    but not complex) it converts it to the nearest possible float.


    >> Passing it through float() is, most likely, the right way to do this.
    >> But what do you mean by "the result... is wrong"? That's the bit to
    >> look into.

    >
    > Scratch that, I'm not sure which result is right now, so need to look at
    > the full calculations in details. What would be the difference between
    > raw_input() and float(input())?


    In Python 2.x, raw_input returns a string. To turn it into a float, you need
    to use float(raw_input()).

    float(input()) is a waste of time. The dangerous part happens in the call to
    input(): a malicious user could type a Python command, and run arbitrary
    code; or they could type something like "10**100**100" and lock up your
    computer. Calling float *after* the call to input doesn't do anything.

    In Python 3.x, raw_input is gone, but float(input()) is safe -- it is
    exactly equivalent to float(raw_input()) in Python 2.x.

    One other difference between Python 2.7 and 3.3 is that they sometimes
    display floats slightly differently. Sometimes 3.3 will show more decimal
    places:

    [steve@ando ~]$ python2.7 -c "x = 1.0/33; print (x+x+x)"
    0.0909090909091
    [steve@ando ~]$ python3.3 -c "x = 1.0/33; print (x+x+x)"
    0.09090909090909091

    but you can be sure that they are the same value, it is just a difference in
    the default display of floats:

    [steve@ando ~]$ python2.7 -c "x = 1.0/33; print (x+x+x).hex()"
    0x1.745d1745d1746p-4
    [steve@ando ~]$ python3.3 -c "x = 1.0/33; print((x+x+x).hex())"
    0x1.745d1745d1746p-4



    --
    Steven
     
    Steven D'Aprano, Feb 2, 2013
    #6
  7. Chris Angelico

    Schizoid Man Guest

    > Highly unlikely. I'd say impossible, unless you type a different value for
    > x
    > of course. By the time the input() function returns, the result is already
    > a float. Wrapping it in float() again cannot possibly change the value. If
    > you have found a value that does change, please tell us what it is.
    >
    > The only examples I can think of that will behave that way involve NANs
    > and
    > INFs. If you don't know what they are, don't worry about it, and forget I
    > mentioned them. For regular floating point values, I can't think of any
    > possible way that float(input(x)) and input(x) could give different
    > results.
    >


    No, the calculation returns in neither NaN or Inf at any point.

    > float(x) converts x into a float.
    >
    > - if x is already a float, it leaves it unchanged;
    >
    > - if x is a string, it converts it to the nearest possible float;
    >
    > - if x is some other numeric value (e.g. int, Decimal or Fraction,
    > but not complex) it converts it to the nearest possible float.
    >
    >
    > float(input()) is a waste of time. The dangerous part happens in the call
    > to
    > input(): a malicious user could type a Python command, and run arbitrary
    > code; or they could type something like "10**100**100" and lock up your
    > computer. Calling float *after* the call to input doesn't do anything.
    >
    > In Python 3.x, raw_input is gone, but float(input()) is safe -- it is
    > exactly equivalent to float(raw_input()) in Python 2.x.
    >
    > One other difference between Python 2.7 and 3.3 is that they sometimes
    > display floats slightly differently. Sometimes 3.3 will show more decimal
    > places:


    Thanks for that, I'll post the problematic code here shortly.
     
    Schizoid Man, Feb 2, 2013
    #7
  8. Chris Angelico

    Schizoid Man Guest

    > If your input has no decimal point in it, eval (or input) will return
    > an integer, not a float. Other than that, I can't see any obvious
    > reason for there to be a difference. Can you put together a simple
    > script that demonstrates the problem and post it, along with the exact
    > input that you're giving it, and the different outputs?


    Understood. I'm trying to learn Python by porting an ODE solver I wrote over
    from C#, so what I'll do is break down the routine and append a small code
    snippet highlighting the difference.

    I know this is probably redundant but Python 2.7.3 is running on a Mac and
    3.3.0 on a PC, so it's not exactly an apples-v-apples comparison.
     
    Schizoid Man, Feb 2, 2013
    #8
  9. On Sat, Feb 2, 2013 at 10:51 PM, Schizoid Man <> wrote:
    >> If your input has no decimal point in it, eval (or input) will return
    >> an integer, not a float. Other than that, I can't see any obvious
    >> reason for there to be a difference. Can you put together a simple
    >> script that demonstrates the problem and post it, along with the exact
    >> input that you're giving it, and the different outputs?

    >
    >
    > Understood. I'm trying to learn Python by porting an ODE solver I wrote over
    > from C#, so what I'll do is break down the routine and append a small code
    > snippet highlighting the difference.


    Thanks, I think I can speak for all of us in expressing appreciation
    for that effort! It makes the job so much easier.

    > I know this is probably redundant but Python 2.7.3 is running on a Mac and
    > 3.3.0 on a PC, so it's not exactly an apples-v-apples comparison.


    Ah, there may well be something in that. Definitely post the code and
    outputs; chances are someone'll spot the difference.

    ChrisA
     
    Chris Angelico, Feb 2, 2013
    #9
  10. Schizoid Man wrote:

    > I know this is probably redundant but Python 2.7.3 is running on a Mac and
    > 3.3.0 on a PC, so it's not exactly an apples-v-apples comparison.


    It's not impossible that there is a slight difference in some of the
    floating point functions. E.g. when you call math.log(s), one version might
    be accurate to (say) 15 decimal places and the other to (say) 14 decimal
    places, and that difference is magnified by subsequent calculations.



    --
    Steven
     
    Steven D'Aprano, Feb 2, 2013
    #10
  11. Chris Angelico

    Schizoid Man Guest

    > Ah, there may well be something in that. Definitely post the code and
    > outputs; chances are someone'll spot the difference.


    Ok, I *think* I found the source of the difference:

    This is the base code that runs fine in v 3.3.0 (the output is correct):

    def Numer(s, k):
    return math.log(s / k)
    s = float(input("Enter s: "))
    k = float(input("Enter k: "))
    print("Result: ", Numer(s, k))

    For the v2.7 version, the only difference is the input lines:
    s = input("Enter s: ")
    k = input("Enter k: ")

    So for values of s=60 and k=50, the first code returns 0.1823215567939546
    (on the PC), whereas the second returns 0.0 (on the Mac). This this
    expression is evaluated in the numerator, it never returns a divide by zero
    error, and the result of 0 is treated as legitimate.

    However, if I cast the v2.7 inputs as float() then it does indeed return the
    right result. But what threw me was that no cast didn't result in a runtime
    error in 2.7, but did in 3.3.

    Also, if the cast is necessary, then now exactly does the dynamic typing
    work?

    Thanks.
     
    Schizoid Man, Feb 2, 2013
    #11
  12. Chris Angelico

    Schizoid Man Guest

    "Schizoid Man" <> wrote in message
    news:kejcfi$s70$...

    > So for values of s=60 and k=50, the first code returns 0.1823215567939546
    > (on the PC), whereas the second returns 0.0 (on the Mac). This this
    > expression is evaluated in the numerator, it never returns a divide by
    > zero error, and the result of 0 is treated as legitimate.


    D'oh! That's the error right there. My inputs are 60 and 50, not 60.0 and
    50.0. I am a dunderhead.

    Apologies for wasting your time.
     
    Schizoid Man, Feb 2, 2013
    #12
  13. On Sun, Feb 3, 2013 at 2:48 AM, Schizoid Man <> wrote:
    > def Numer(s, k):
    > return math.log(s / k)
    >
    > s = float(input("Enter s: "))
    > k = float(input("Enter k: "))
    > print("Result: ", Numer(s, k))
    >
    > For the v2.7 version, the only difference is the input lines:
    >
    > s = input("Enter s: ")
    > k = input("Enter k: ")
    >
    > So for values of s=60 and k=50, the first code returns 0.1823215567939546
    > (on the PC), whereas the second returns 0.0 (on the Mac). This this
    > expression is evaluated in the numerator, it never returns a divide by zero
    > error, and the result of 0 is treated as legitimate.


    So on your Python 2 install, you're working with integers, dividing
    one by another, and getting back a value of 1 - and log(1) is 0. The
    problem is your division operator, which can be fixed as Steven
    suggests, with the future directive.

    > However, if I cast the v2.7 inputs as float() then it does indeed return the
    > right result. But what threw me was that no cast didn't result in a runtime
    > error in 2.7, but did in 3.3.
    >
    > Also, if the cast is necessary, then now exactly does the dynamic typing
    > work?


    It's not quite a cast. Python's type system is broadly this: Every
    object (value) has a type, every name (variable, sort of) doesn't. So
    I can do this:

    spam = "hello, world" # spam is a string
    spam = 5 # spam is now an int
    spam = (1,2,3) # spam is now a tuple
    spam = object() # you get the idea

    I strongly recommend you either go with Python 3 or raw_input, but NOT
    with float(input()) in Py2. Go with float(raw_input()) and you're
    doing exactly one translation, and the correct one.

    ChrisA
     
    Chris Angelico, Feb 2, 2013
    #13
  14. On 02/02/2013 08:48 AM, Schizoid Man wrote:
    > Also, if the cast is necessary, then now exactly does the dynamic typing
    > work?


    Dynamic typing isn't referring to numeric type coercion. It refers to
    the fact that a name can be bound to an object of any type. So if you
    made a function like this:

    def add (num1, num2):
    return num1 + num2

    num1 and num2 could be any type. Even a custom type if you wanted.
    This function would work properly on any type that had implemented the
    __add__ method. And whether or not num2 has to be the same type as num1
    depends on whether the num1 type has implemented an __add__ method that
    can deal with the type of num2.

    Another case where dynamic typing comes into play is in a case know as
    duck typing:

    def squeeze_duck (duck):
    // return the quack
    return duck.squeeze()


    duck can be of any type as well, but as long as it implements the
    squeeze method, this function will work with an object of that type.

    In a language like C#, duck-typing can only be emulated by using
    interface classes.
     
    Michael Torrie, Feb 2, 2013
    #14
  15. Michael Torrie wrote:

    > def squeeze_duck (duck):
    > // return the quack
    > return duck.squeeze()


    I'm curious, what language were you thinking of when you wrote the comment
    using // instead of # ?



    --
    Steven
     
    Steven D'Aprano, Feb 3, 2013
    #15
  16. Chris Angelico

    Dave Angel Guest

    On 02/02/2013 08:25 PM, Steven D'Aprano wrote:
    > Michael Torrie wrote:
    >
    >> def squeeze_duck (duck):
    >> // return the quack
    >> return duck.squeeze()

    >
    > I'm curious, what language were you thinking of when you wrote the comment
    > using // instead of # ?
    >
    >


    I'm guessing that would probably be C++. Or more recent versions of C.

    --
    DaveA
     
    Dave Angel, Feb 3, 2013
    #16
  17. On 02/02/2013 06:25 PM, Steven D'Aprano wrote:
    > Michael Torrie wrote:
    >
    >> def squeeze_duck (duck):
    >> // return the quack
    >> return duck.squeeze()

    >
    > I'm curious, what language were you thinking of when you wrote the comment
    > using // instead of # ?


    Oh darn. Blew my cover. I'm beta testing Ranting Rick's wonderful
    fork, Rrython.

    Actually, my brain is full of Arduino code right now... which is fun,
    but C++, yuck.
     
    Michael Torrie, Feb 3, 2013
    #17
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. bei
    Replies:
    0
    Views:
    244
  2. bei
    Replies:
    4
    Views:
    408
  3. Saraswati lakki
    Replies:
    0
    Views:
    1,408
    Saraswati lakki
    Jan 6, 2012
  4. Hyun chul Park

    Floating point calculation problem

    Hyun chul Park, Jul 8, 2008, in forum: Ruby
    Replies:
    3
    Views:
    115
    Axel Etzold
    Jul 8, 2008
  5. Chris Rebert

    Re: Floating point calculation problem

    Chris Rebert, Feb 2, 2013, in forum: Python
    Replies:
    0
    Views:
    112
    Chris Rebert
    Feb 2, 2013
Loading...

Share This Page