[newbie] problem making equally spaced value array with linspace

Discussion in 'Python' started by Jean Dubois, Dec 18, 2012.

  1. Jean Dubois

    Jean Dubois Guest

    I have trouble with the code beneath to make an array with equally
    spaced values
    When I enter 100e-6 as start value, 700e-6 as end value and 100e-6 I
    get the following result:
    [ 0.0001 0.00022 0.00034 0.00046 0.00058 0.0007 ]
    But I was hoping for:
    [ 0.0001 0.0002 0.0003 0.0004 0.0005 0.0006 0.0007]
    It works correctly for other values like 1,7,1 but not for 0.1,0.7,0.1
    then again for 0.01,0.07,0.01

    What I find strange is that for the 1st example "1+abs(float(endvalue)-
    float(startvalue))/float(incr)" gives 7.0 but int() of this value
    gives 6
    can someone provide help with this issue?
    thanks
    jean

    #!/usr/bin/python
    import math
    import numpy as np
    print "Enter start value as a float (e.g. 0.001) or in scientific
    notation (e.g. 1e-3): ",
    startvalue = raw_input()
    print "Enter end value: ",
    endvalue = raw_input()
    print "Enter step: ",
    incr = raw_input()
    #nom = number of measurements
    nom=int(1+abs(float(endvalue)-float(startvalue))/float(incr))
    array=np.linspace(float(startvalue), float(endvalue), float(nom))
    print "Array with current values: ",array
    Jean Dubois, Dec 18, 2012
    #1
    1. Advertising

  2. Jean Dubois

    Peter Otten Guest

    Jean Dubois wrote:

    > I have trouble with the code beneath to make an array with equally
    > spaced values
    > When I enter 100e-6 as start value, 700e-6 as end value and 100e-6 I
    > get the following result:
    > [ 0.0001 0.00022 0.00034 0.00046 0.00058 0.0007 ]
    > But I was hoping for:
    > [ 0.0001 0.0002 0.0003 0.0004 0.0005 0.0006 0.0007]
    > It works correctly for other values like 1,7,1 but not for 0.1,0.7,0.1
    > then again for 0.01,0.07,0.01
    >
    > What I find strange is that for the 1st example "1+abs(float(endvalue)-
    > float(startvalue))/float(incr)" gives 7.0 but int() of this value
    > gives 6
    > can someone provide help with this issue?
    > thanks
    > jean
    >
    > #!/usr/bin/python
    > import math
    > import numpy as np
    > print "Enter start value as a float (e.g. 0.001) or in scientific
    > notation (e.g. 1e-3): ",
    > startvalue = raw_input()
    > print "Enter end value: ",
    > endvalue = raw_input()
    > print "Enter step: ",
    > incr = raw_input()
    > #nom = number of measurements
    > nom=int(1+abs(float(endvalue)-float(startvalue))/float(incr))
    > array=np.linspace(float(startvalue), float(endvalue), float(nom))
    > print "Array with current values: ",array


    If you repeat the calculation of the number of intervals in the interpreter
    you get

    >>> 1 + abs(0.0007-0.0001)/0.0001

    6.999999999999999

    Many numbers cannot be represented exactly as float (that's the price you
    have to pay for covering a wide range with just a few (8) bytes), and you
    have introduced such a small error. The subsequent int() call will round
    that float to the integer below it:

    >>> int(_)

    6


    While applying round() would work here

    >>> int(round(1 + abs(0.0007-0.0001)/0.0001))

    7

    there is no once-and-for-all solution to the underlying problem. E. g.

    >>> x = 2.**53
    >>> x == x + 1

    True
    Peter Otten, Dec 18, 2012
    #2
    1. Advertising

  3. Am 18.12.2012 13:37, schrieb Jean Dubois:
    > I have trouble with the code beneath to make an array with equally
    > spaced values
    > When I enter 100e-6 as start value, 700e-6 as end value and 100e-6 I
    > get the following result:
    > [ 0.0001 0.00022 0.00034 0.00046 0.00058 0.0007 ]
    > But I was hoping for:
    > [ 0.0001 0.0002 0.0003 0.0004 0.0005 0.0006 0.0007]
    > It works correctly for other values like 1,7,1 but not for 0.1,0.7,0.1
    > then again for 0.01,0.07,0.01
    >
    > What I find strange is that for the 1st example "1+abs(float(endvalue)-
    > float(startvalue))/float(incr)" gives 7.0 but int() of this value
    > gives 6
    > can someone provide help with this issue?
    > thanks
    > jean
    >
    > #!/usr/bin/python
    > import math
    > import numpy as np
    > print "Enter start value as a float (e.g. 0.001) or in scientific
    > notation (e.g. 1e-3): ",
    > startvalue = raw_input()
    > print "Enter end value: ",
    > endvalue = raw_input()
    > print "Enter step: ",
    > incr = raw_input()
    > #nom = number of measurements
    > nom=int(1+abs(float(endvalue)-float(startvalue))/float(incr))
    > array=np.linspace(float(startvalue), float(endvalue), float(nom))
    > print "Array with current values: ",array


    The Problem is the accuracy/precision of floating point operations

    Python 2.7.3 (default, Aug 1 2012, 05:14:39)
    [GCC 4.6.3] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> a = 100e-6 #start
    >>> b = 700e-6 #end
    >>> c = 100e-6 #incr
    >>> 1+(b-a)/c

    6.999999999999999

    and the fact that int() only takes the integer part of a floating point
    number.

    >>> int(1+(b-a)/c)

    6

    So you have to make a more detailed decision about the number of points
    in the case that (end-start)/incr is not exactly an integer which it
    will almost never be.

    The np.arange(a,b,c) function chooses a simple rule: give a list of
    numbers a + k * c with k running from 0 to the highest integer with a +
    k * c < b.

    >>> np.arange(a,b,c)

    array([ 0.0001, 0.0002, 0.0003, 0.0004, 0.0005, 0.0006])

    You can get your desired list by adding some epsilon to the value of b.
    Just make sure your epsilon is quite small compared to c.

    >>> np.arange(a,b+1e-15,c)

    array([ 0.0001, 0.0002, 0.0003, 0.0004, 0.0005, 0.0006, 0.0007])

    Greetings
    Alexander Blinne, Dec 18, 2012
    #3
  4. Jean Dubois

    Jean Dubois Guest

    Re: problem making equally spaced value array with linspace

    On 18 dec, 14:09, Peter Otten <> wrote:
    > Jean Dubois wrote:
    > > I have trouble with the code beneath to make an array with equally
    > > spaced values
    > > When I enter 100e-6 as start value, 700e-6 as end value and 100e-6 I
    > > get the following result:
    > > [ 0.0001   0.00022  0.00034  0.00046  0.00058  0.0007 ]
    > > But I was hoping for:
    > > [ 0.0001   0.0002  0.0003  0.0004  0.0005  0.0006 0.0007]
    > > It works correctly for other values like 1,7,1 but not for 0.1,0.7,0.1
    > > then again for 0.01,0.07,0.01

    >
    > > What I find strange is that for the 1st example "1+abs(float(endvalue)-
    > > float(startvalue))/float(incr)" gives 7.0 but int() of this value
    > > gives 6
    > > can someone provide help with this issue?
    > > thanks
    > > jean

    >
    > > #!/usr/bin/python
    > > import math
    > > import numpy as np
    > > print "Enter start value as a float (e.g. 0.001) or in scientific
    > > notation (e.g. 1e-3): ",
    > > startvalue = raw_input()
    > > print "Enter end value: ",
    > > endvalue = raw_input()
    > > print "Enter step: ",
    > > incr = raw_input()
    > > #nom = number of measurements
    > > nom=int(1+abs(float(endvalue)-float(startvalue))/float(incr))
    > > array=np.linspace(float(startvalue), float(endvalue), float(nom))
    > > print "Array with current values: ",array

    >
    > If you repeat the calculation of the number of intervals in the interpreter
    > you get
    >
    > >>> 1 + abs(0.0007-0.0001)/0.0001

    >
    > 6.999999999999999
    >
    > Many numbers cannot be represented exactly as float (that's the price you
    > have to pay for covering a wide range with just a few (8) bytes), and you
    > have introduced such a small error. The subsequent int() call will round
    > that float to the integer below it:
    >
    > >>> int(_)

    >
    > 6
    >
    > While applying round() would work here
    >
    > >>> int(round(1 + abs(0.0007-0.0001)/0.0001))

    >
    > 7
    >
    > there is no once-and-for-all solution to the underlying problem. E. g.
    >
    > >>> x = 2.**53
    > >>> x == x + 1

    >
    > True


    thanks

    jean
    Jean Dubois, Dec 18, 2012
    #4
  5. Jean Dubois

    Dave Angel Guest

    On 12/18/2012 07:37 AM, Jean Dubois wrote:
    > I have trouble with the code beneath to make an array with equally
    > spaced values
    > When I enter 100e-6 as start value, 700e-6 as end value and 100e-6 I
    > get the following result:
    > [ 0.0001 0.00022 0.00034 0.00046 0.00058 0.0007 ]
    > But I was hoping for:
    > [ 0.0001 0.0002 0.0003 0.0004 0.0005 0.0006 0.0007]
    > It works correctly for other values like 1,7,1 but not for 0.1,0.7,0.1
    > then again for 0.01,0.07,0.01

    I started this answer before there were any others visible, but had to
    rush off to the dentist. Now I'm finishing it and sending it, even
    though there's some overlap with the other posts.

    What Python has in common with nearly every other language is the use of
    binary floating point. Unlike integers, floating point values can have
    both roundoff and quantization errors. The former happen with many
    operations, like you can see with pencil and paper trying to divide 1 by
    3, and storing the result in 10 columns.

    But quantization errors aren't as obvious. They can occur whenever you
    convert a number from one format to another. In this case, you're
    converting from the decimal string to a binary float. To put it simply
    binary floats can't store any decimal number exactly exact integers, and
    mixed numbers where the fractional part happens to be an exact multiple
    of a power of two. So 0.5 is exact, but you get quantization error with
    0.1, 0.2, ... 0.9

    This is compounded by the fact that print will convert the number back
    to a decimal string. So sometimes the two quantization errors happen to
    cancel, and sometimes they don't.

    Now, your particular case is due to the convoluted way you calculate
    nom. And the easiest way to fix it would be to add 0.5 before
    truncating with int(). Or better yet, have the user tell you how many
    he wants in his list, and calculate the other way around. If instead of
    10 items, you have 100000 of them, you'll get a cumulative error with
    your approach. So you'd use a formula like
    start + (end-start)*i/nom

    which would assure that each value was really close without cumulative
    errors. No idea how that'd fit with numpy.

    Another approach is to use the Decimal package. It's not inherently any
    more accurate, but the errors are where you'd expect them, and you don't
    get the quantization error converting back and forth to string.


    --

    DaveA
    Dave Angel, Dec 18, 2012
    #5
    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. TheOne
    Replies:
    3
    Views:
    1,483
    Marcin Grunwald
    Mar 10, 2005
  2. repairs
    Replies:
    21
    Views:
    983
    dorayme
    Jul 27, 2005
  3. Dr_Locke_Z2A

    open source pong or equally simple game

    Dr_Locke_Z2A, Dec 22, 2005, in forum: C Programming
    Replies:
    4
    Views:
    438
    Chuck F.
    Dec 23, 2005
  4. Steven D'Aprano
    Replies:
    24
    Views:
    890
    Terry Reedy
    Sep 26, 2011
  5. Markus Fischer
    Replies:
    4
    Views:
    498
    Josh Cheek
    Jun 15, 2011
Loading...

Share This Page