numo-narray icon indicating copy to clipboard operation
numo-narray copied to clipboard

Numo::DFloat#nearly_eq

Open naitoh opened this issue 8 years ago • 2 comments

When I use Numo::DFloat instance nearly_eq method, I found difference. Ruby 2.3.0/2.4.1 gem version is 0.9.0.9.

expect case

> x = Numo::NArray[[[ -0.36133200184253111420, -0.26743056922401642339 , -0.15902724402321133379],
                    [ -1.19318994409269407697, -1.44963239638332885839, -1.91713985336221814926]],
                   [[ -0.64073243053171402561, -1.16473945661181144118, -0.71543932177509761416],
                    [ -0.74846194046881686646, -0.37397217072783262015, -0.67134116188410564163]]]
> y = Numo::NArray[[[ -0.36133200184253122522, -0.26743056922401642339, -0.15902724402321133379],
                    [ -1.19318994409269407697, -1.44963239638332885839, -1.91713985336221814926]],
                   [[ -0.64073243053171424766, -1.16473945661181144118, -0.71543932177509761416],
                    [ -0.74846194046881708850, -0.37397217072783262015, -0.67134116188410564163]]]
> p x - y
Numo::DFloat#shape=[2,2,3]
[[[1.11022e-16, 0, 0], 
  [0, 0, 0]], 
 [[2.22045e-16, 0, 0], 
  [2.22045e-16, 0, 0]]]
> p x.nearly_eq(y)
Numo::Bit#shape=[2,2,3]
 [[[1, 1, 1], 
   [1, 1, 1]], 
  [[1, 1, 1], 
   [1, 1, 1]]]

not expect case

> x = Numo::NArray[[[ -1.40903182174134045113, -0.35526599480177556423, -1.70191687578730643793],
                    [ -0.28021637271697175109, -1.20726809289862258012, -0.20130094472294335350]],
                   [[ -1.06148519722576439861, -1.51812278479952222909, -0.82032336416972229109],
                    [ -0.42455869150749364627, -0.24733742939520531046, -0.58033516033345322604]]]
> y = Numo::NArray[[[ -1.40903182174134067317, -0.35526599480177545320, -1.70191687578730643793],
                    [ -0.28021637271697186211, -1.20726809289862258012, -0.20130094472294324248]],
                   [[ -1.06148519722576439861, -1.51812278479952267318, -0.82032336416972218007],
                    [ -0.42455869150749375729, -0.24733742939520553250, -0.58033516033345311502]]]
> p x - y
Numo::DFloat#shape=[2,2,3]
[[[2.22045e-16, -1.11022e-16, 0], 
  [1.11022e-16, 0, -1.11022e-16]], 
 [[0, 4.44089e-16, -1.11022e-16], 
  [1.11022e-16, 2.22045e-16, -1.11022e-16]]]
> p x.nearly_eq(y)
Numo::Bit#shape=[2,2,3]
[[[1, 1, 1], 
  [1, 1, 1]], 
 [[1, 1, 1], 
  [1, 0, 1]]]

I expect all 1.

> x = Numo::DFloat[ -0.24733742939520531046]
> y = Numo::DFloat[ -0.24733742939520553250]
> p x - y
Numo::DFloat#shape=[1]
[2.22045e-16]
> p x.nearly_eq(y)
Numo::Bit#shape=[1]
[0]

Why return [0]?

naitoh avatar Nov 11 '17 04:11 naitoh

x.nearly_eq(y) is currently defined as

(x-y).lt((x.abs+y.abs)*Numo::DFloat::EPSILON*2)

Discussion on the definition of this method is welcome.

masa16 avatar Jan 07 '18 11:01 masa16

(x-y).lt((x.abs+y.abs)*Numo::DFloat::EPSILON * 2)

numo/types/float_def.h:#define DBL_EPSILON 2.2204460492503131e-16 numo/types/dfloat.h:#define m_nearly_eq(x,y) (fabs(x-y)<=(fabs(x)+fabs(y)) * DBL_EPSILON*2)

numo/types/float_def.h:#define FLT_EPSILON 1.1920928955078125e-07 numo/types/sfloat.h:#define m_nearly_eq(x,y) (fabs(x-y)<=(fabs(x)+fabs(y)) * FLT_EPSILON*2)

In the SFloat case, I think that you should use fabsf() instead of fabs().

And, I think that this accuracy is too strict.

expect case

> x = Numo::DFloat[1]
=> Numo::DFloat#shape=[1]
[1]
> log_z = Numo::NMath.log(Numo::NMath.exp(x).sum(keepdims:true))
=> Numo::DFloat#shape=[1]
[1]
> x - log_z
=> Numo::DFloat#shape=[1]
[0]
> Numo::DFloat[0].nearly_eq(x-log_z)
=> Numo::Bit#shape=[1]
[1]

not expect case

(x - log_z) does not become 0 due to the accuracy of the floating point number, but I want you to return that the results of nearly_eq() are equal.

> x = Numo::SFloat[1]
=> Numo::SFloat#shape=[1]
[1]
> log_z = Numo::NMath.log(Numo::NMath.exp(x).sum(keepdims:true))
=> Numo::SFloat#shape=[1]
[1]
> x - log_z
=> Numo::SFloat#shape=[1]
[5.96046e-08]
> Numo::SFloat[0].nearly_eq(x-log_z)
=> Numo::Bit#shape=[1]
[0]

I expect [1].

numpy

https://docs.scipy.org/doc/numpy/reference/generated/numpy.isclose.html

numpy.isclose(a, b, rtol=1e-05, atol=1e-08, equal_nan=False)

For finite values, isclose uses the following equation to test whether two floating point values are equivalent.

absolute(a - b) <= (atol + rtol * absolute(b))

In the case of numpy, the range of accuracy can be adjusted with the parameters of atol and rtol.

I also want to adjust the accuracy range with nearly_eq().

naitoh avatar Feb 02 '18 14:02 naitoh