2

I have an interval range generated by python numpy. The values are as expected but when the array is transform into list, the values are not same as in array.

numpy.linspace(0.3,0.7,5)
array([ 0.3,  0.4,  0.5,  0.6,  0.7])

numpy.linspace(0.3,0.7,5).tolist()
[0.3, 0.39999999999999997, 0.5, 0.6, 0.7]

list(numpy.linspace(0.3,0.7,5))
 [0.29999999999999999,0.39999999999999997,0.5,0.59999999999999998,
 0.69999999999999996]

Why numpy behaves like this? Is there anyway to keep the values in the list the same as array without using another loop for rounding the values in the list?

cs95
  • 379,657
  • 97
  • 704
  • 746
Masih
  • 920
  • 2
  • 19
  • 36

1 Answers1

4

It happens to be because of the datatypes and the corresponding __repr__ implementations of each type:

l = numpy.linspace(0.3,0.7,5).tolist()

[type(x)  for x in l]
[float, float, float, float, float]

In the first case, tolist converts each np.float object to a python float object, whose __repr__ implementation automatically truncates floating point numbers according to the Gay algorithm. OTOH:

l = list(numpy.linspace(0.3,0.7,5))

[type(x)  for x in l]
[numpy.float64, numpy.float64, numpy.float64, numpy.float64, numpy.float64]

Just calling a list around the array does not convert the list elements to a float, but retains their original np.float type, which have different representations. Keep in mind that the float representations in the second case are how they are actually represented in memory:

import decimal

decimal.Decimal(0.3)
Decimal('0.299999999999999988897769753748434595763683319091796875')

Because many floating point numbers do not have exact bit representations. See our beloved canonical Is floating point math broken? for more details.

cs95
  • 379,657
  • 97
  • 704
  • 746
  • Thanks for explanation. I understood the reason for this problem. But it is surprising that numpy developers did not put any option for example for tolist() function to return the expected values. – Masih Nov 22 '17 at 21:38
  • @user3015703 If the answer helped, don't forget to vote on, and accept the answer. Thanks :) – cs95 Nov 22 '17 at 21:54
  • Already upvoted the explanation but I am still looking forward to get an answer on how to solve the problem. You mean I should not expect for a solution other than using a loop to round the values in the list? – Masih Nov 23 '17 at 00:16
  • 1
    @user3015703 Unfortunately no, short of subclassing `float` and re-inventing its repr, I don't think you can. This answer explores the same thing in a bit of detail. https://stackoverflow.com/questions/5326112/how-to-round-each-item-in-a-list-of-floats-to-2-decimal-places – cs95 Nov 23 '17 at 00:25