learn-go-with-tests icon indicating copy to clipboard operation
learn-go-with-tests copied to clipboard

Floats should not be tested for equality using ==

Open sorincezar opened this issue 3 years ago • 3 comments

https://github.com/quii/learn-go-with-tests/blob/2006553b99afb2bd5e1ef86b875d424883656336/structs/v8/shapes_test.go#L12

One should implement an approximately equal function

sorincezar avatar Nov 23 '20 13:11 sorincezar

Can you explain your reasoning?

I'm not a Go expert, but it seems that doing an approximation would be the wrong approach. It's actually testing float to floats. It (shouldn't) need an approximation function.

I'm personally learning Go, so I'm probably ignorant of something important.

asheingold avatar Jan 19 '21 22:01 asheingold

As a general rule: yes, floats should be compared with a tolerance. However, integers stored in float64 between -253 to 253 are precisely representable. Also the product of two such integers will be precisely represented if it is within that range. So for this specific test as for tests with integer values in that range no tolerance is needed. The test is fine, but if we were to use a table test with floating point values that have decimal values such as 0.1 ≠ float64(0.1) or the notorious (1.0 - 0.1 ≠ float64(0.9)) then we need tolerances.

Another reason that tolerances in tests with go are not an issue as with other languages is that go supports infinite precision floating point constants with a requirement that implementations at least have 256-bit accuracy in mantissa and 16-bits in exponent of representations. That minimum is extremely precise (My estimation is over 70 significant decimal digits). This means that if constants for tests are sufficiently precise for float64 no tolerances are needed. This of course only works if we know what the precise constant of the expected floating point value is.

In almost all cases we should really use an expectable tolerance value when comparing floating point values, unless:

  • The expected constant value is exactly representable in the floating point type
  • The test does not introduce a floating point error

Only in these two cases is it acceptable to use a comparison without tolerance

schellingerhout avatar Feb 18 '21 01:02 schellingerhout

Could use this https://pkg.go.dev/github.com/google/go-cmp/cmp#example-Option-ApproximateFloats

quii avatar Jan 14 '22 12:01 quii