Discussion:
[Numpy-discussion] array_equal too strict?
Nico Schlömer
2015-12-17 13:43:22 UTC
Permalink
Hi everyone,

I noticed a funny behavior in numpy's array_equal. The two arrays
```
a1 = numpy.array(
[3.14159265358979320],
dtype=numpy.float64
)
a2 = numpy.array(
[3.14159265358979329],
dtype=numpy.float64
)
```
(differing the in the 18th overall digit) are reported equal by array_equal:
```
print(numpy.array_equal(a1, a2))
# output: true
```
That's expected because the difference is only in the 18th overall digit,
and the mantissa length of float64 is 52 bits [1], i.e., approx 15.6
decimal digits. Moving the difference to the 17th overall digit should also
be fine, however:
```
a1 = numpy.array(
[3.1415926535897930],
dtype=numpy.float64
)
a2 = numpy.array(
[3.1415926535897939],
dtype=numpy.float64
)

print(numpy.array_equal(a1, a2))
# output: false
```
It gets even more visible with float32 and its 23 mantissa bits (i.e., 6.9
decimal digits):
```
a1 = numpy.array(
[3.14159260],
dtype=numpy.float32
)
a2 = numpy.array(
[3.14159269],
dtype=numpy.float32
)

print(numpy.array_equal(a1, a2))
# output: false
```
The difference is only in the 9th decimal digit, still `array_equal_
detects the difference.

I'm not sure where I'm going wrong here. Any hints?

Cheers,
Nico


[1] https://docs.scipy.org/doc/numpy-1.10.1/user/basics.types.html
Daπid
2015-12-17 14:01:48 UTC
Permalink
Post by Nico Schlömer
I'm not sure where I'm going wrong here. Any hints?
You are dancing around the boundary between close floating point numbers,
and when you are dealing with ULPs, number of decimal places is a bad
measure. Working with plain numbers, instead of arrays (just so that the
numbers are printed in full detail)

a1 = np.float64(3.1415926535897930)
a2 = np.float64(3.1415926535897939)

They are numerically different:
a2 - a1
8.8817841970012523e-16

In epsilons (defined as the smallest number such that (1 + eps) - 1 > 0):
(a2 - a1) / np.finfo(np.float64).eps
4.0

In fact, there is one number in between, two epsilons away from each one:
np.nextafter(a1, a2)
3.1415926535897936

np.nextafter(np.nextafter(a1, 10), 10) - a2
0.0

The next number on the other side:
np.nextafter(a1, 0)
3.1415926535897927

For more information:

print np.finfo(np.float64)
Machine parameters for float64
---------------------------------------------------------------
precision= 15 resolution= 1.0000000000000001e-15
machep= -52 eps= 2.2204460492503131e-16
negep = -53 epsneg= 1.1102230246251565e-16
minexp= -1022 tiny= 2.2250738585072014e-308
maxexp= 1024 max= 1.7976931348623157e+308
nexp = 11 min= -max
---------------------------------------------------------------


/David
Sebastian Berg
2015-12-17 14:19:40 UTC
Permalink
Post by Nico Schlömer
Hi everyone,
I noticed a funny behavior in numpy's array_equal. The two arrays
```
a1 = numpy.array(
[3.14159265358979320],
dtype=numpy.float64
)
a2 = numpy.array(
[3.14159265358979329],
dtype=numpy.float64
)
```
If you have some spare cycles, maybe you can open a pull request to add
np.isclose to the "See Also" section?

- Sebastian
Post by Nico Schlömer
```
print(numpy.array_equal(a1, a2))
# output: true
```
That's expected because the difference is only in the 18th overall
digit, and the mantissa length of float64 is 52 bits [1], i.e., approx
15.6 decimal digits. Moving the difference to the 17th overall digit
```
a1 = numpy.array(
[3.1415926535897930],
dtype=numpy.float64
)
a2 = numpy.array(
[3.1415926535897939],
dtype=numpy.float64
)
print(numpy.array_equal(a1, a2))
# output: false
```
It gets even more visible with float32 and its 23 mantissa bits (i.e.,
```
a1 = numpy.array(
[3.14159260],
dtype=numpy.float32
)
a2 = numpy.array(
[3.14159269],
dtype=numpy.float32
)
print(numpy.array_equal(a1, a2))
# output: false
```
The difference is only in the 9th decimal digit, still `array_equal_
detects the difference.
I'm not sure where I'm going wrong here. Any hints?
Cheers,
Nico
[1] https://docs.scipy.org/doc/numpy-1.10.1/user/basics.types.html
_______________________________________________
NumPy-Discussion mailing list
https://mail.scipy.org/mailman/listinfo/numpy-discussion
Chris Barker - NOAA Federal
2015-12-18 02:08:03 UTC
Permalink
Post by Sebastian Berg
If you have some spare cycles, maybe you can open a pull request to add
np.isclose to the "See Also" section?
That would be great.

Remember that equality for flits is bit-for but equality ( baring NaN
and inf...).

But you hardly ever actually want to do that with floats.

But probably np.allclose is most appropriate here.

CHB
Post by Sebastian Berg
- Sebastian
Post by Nico Schlömer
```
print(numpy.array_equal(a1, a2))
# output: true
```
That's expected because the difference is only in the 18th overall
digit, and the mantissa length of float64 is 52 bits [1], i.e., approx
15.6 decimal digits. Moving the difference to the 17th overall digit
```
a1 = numpy.array(
[3.1415926535897930],
dtype=numpy.float64
)
a2 = numpy.array(
[3.1415926535897939],
dtype=numpy.float64
)
print(numpy.array_equal(a1, a2))
# output: false
```
It gets even more visible with float32 and its 23 mantissa bits (i.e.,
```
a1 = numpy.array(
[3.14159260],
dtype=numpy.float32
)
a2 = numpy.array(
[3.14159269],
dtype=numpy.float32
)
print(numpy.array_equal(a1, a2))
# output: false
```
The difference is only in the 9th decimal digit, still `array_equal_
detects the difference.
I'm not sure where I'm going wrong here. Any hints?
Cheers,
Nico
[1] https://docs.scipy.org/doc/numpy-1.10.1/user/basics.types.html
_______________________________________________
NumPy-Discussion mailing list
https://mail.scipy.org/mailman/listinfo/numpy-discussion
_______________________________________________
NumPy-Discussion mailing list
https://mail.scipy.org/mailman/listinfo/numpy-discussion
Loading...