# [newbie] problem making equally spaced value array with linspace

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

1. ### Jean DuboisGuest

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

2. ### Peter OttenGuest

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

3. ### Alexander BlinneGuest

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
>>> 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
4. ### Jean DuboisGuest

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
5. ### Dave AngelGuest

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