Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed constants::signmask for GCC when using ffast-math #980

Merged
merged 5 commits into from
Nov 24, 2023

Conversation

maxmarsc
Copy link
Contributor

@maxmarsc maxmarsc commented Nov 24, 2023

This PR fix a bug than can occur with -ffast-math, where the compiler replace -0. values with 0. and therefore breaks the bitofsign function as well as several function (exp, sin, cos...) that make use of a bitwise & comparison with constants::signmask

To fix the bitofsign function I had to update it and stop using minuszero and use signmask instead. minuszero is therefore not used anywhere anymore and could maybe be deleted ?

I investigated a bit on how to do the same for clang but I didn't find a solution, and I wasn't able to reproduce the issue with a clang-based aarch64 compiler anyway.

This PR fixes #971

@serge-sans-paille
Copy link
Contributor

I'm fine with the change, as it's not intrusive. Should we try to add validation specific to -ffast-math?

@maxmarsc
Copy link
Contributor Author

It could be interesting, but it would probably need to adjust the tolerance for errors in the test base, which I'm not familiar with.
I tested with this PR on a rpi4 with GCC 10.2.1 and all these tests were broken :

$ ctest -j3 --output-on-failure
Test project /tmp/tmp.IXhhfXZgB6/xsimd/build
    Start 1: test_xsimd
1/1 Test #1: test_xsimd .......................***Failed    0.91 sec
[doctest] doctest version is "2.4.9"
[doctest] run with "--help" for options
===============================================================================
/tmp/tmp.IXhhfXZgB6/xsimd/test/test_basic_math.cpp:165:
TEST CASE:  [basic math tests]<xsimd::batch<float>>
  isfinite

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_basic_math.cpp:43: ERROR: CHECK_FALSE( xsimd::any(xsimd::isfinite(input)) ) is NOT correct!
  values: CHECK_FALSE( true )

===============================================================================
/tmp/tmp.IXhhfXZgB6/xsimd/test/test_basic_math.cpp:165:
TEST CASE:  [basic math tests]<xsimd::batch<double>>
  isfinite

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_basic_math.cpp:43: ERROR: CHECK_FALSE( xsimd::any(xsimd::isfinite(input)) ) is NOT correct!
  values: CHECK_FALSE( true )

===============================================================================
/tmp/tmp.IXhhfXZgB6/xsimd/test/test_complex_exponential.cpp:182:
TEST CASE:  [complex exponential]<xsimd::batch<std::complex<float> >>
  huge_exp

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_complex_exponential.cpp:98: ERROR: CHECK_EQ( diff, 0 ) is NOT correct!
  values: CHECK_EQ( 818, 0 )

===============================================================================
/tmp/tmp.IXhhfXZgB6/xsimd/test/test_complex_exponential.cpp:182:
TEST CASE:  [complex exponential]<xsimd::batch<std::complex<double> >>
  huge_exp

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_complex_exponential.cpp:98: ERROR: CHECK_EQ( diff, 0 ) is NOT correct!
  values: CHECK_EQ( 306, 0 )

===============================================================================
/tmp/tmp.IXhhfXZgB6/xsimd/test/test_complex_trigonometric.cpp:198:
TEST CASE:  [complex trigonometric]<xsimd::batch<std::complex<float> >>
  sin

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_complex_trigonometric.cpp:67: ERROR: CHECK_EQ( diff, 0 ) is NOT correct!
  values: CHECK_EQ( 227, 0 )

===============================================================================
/tmp/tmp.IXhhfXZgB6/xsimd/test/test_complex_trigonometric.cpp:198:
TEST CASE:  [complex trigonometric]<xsimd::batch<std::complex<float> >>
  cos

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_complex_trigonometric.cpp:83: ERROR: CHECK_EQ( diff, 0 ) is NOT correct!
  values: CHECK_EQ( 151, 0 )

===============================================================================
/tmp/tmp.IXhhfXZgB6/xsimd/test/test_complex_trigonometric.cpp:198:
TEST CASE:  [complex trigonometric]<xsimd::batch<std::complex<float> >>
  sincos

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_complex_trigonometric.cpp:104: ERROR: CHECK_EQ( diff, 0 ) is NOT correct!
  values: CHECK_EQ( 161, 0 )

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_complex_trigonometric.cpp:106: ERROR: CHECK_EQ( diff, 0 ) is NOT correct!
  values: CHECK_EQ( 161, 0 )

===============================================================================
/tmp/tmp.IXhhfXZgB6/xsimd/test/test_complex_trigonometric.cpp:198:
TEST CASE:  [complex trigonometric]<xsimd::batch<std::complex<double> >>
  sin

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_complex_trigonometric.cpp:67: ERROR: CHECK_EQ( diff, 0 ) is NOT correct!
  values: CHECK_EQ( 91, 0 )

===============================================================================
/tmp/tmp.IXhhfXZgB6/xsimd/test/test_complex_trigonometric.cpp:198:
TEST CASE:  [complex trigonometric]<xsimd::batch<std::complex<double> >>
  cos

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_complex_trigonometric.cpp:83: ERROR: CHECK_EQ( diff, 0 ) is NOT correct!
  values: CHECK_EQ( 91, 0 )

===============================================================================
/tmp/tmp.IXhhfXZgB6/xsimd/test/test_complex_trigonometric.cpp:198:
TEST CASE:  [complex trigonometric]<xsimd::batch<std::complex<double> >>
  sincos

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_complex_trigonometric.cpp:104: ERROR: CHECK_EQ( diff, 0 ) is NOT correct!
  values: CHECK_EQ( 91, 0 )

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_complex_trigonometric.cpp:106: ERROR: CHECK_EQ( diff, 0 ) is NOT correct!
  values: CHECK_EQ( 91, 0 )

===============================================================================
/tmp/tmp.IXhhfXZgB6/xsimd/test/test_power.cpp:156:
TEST CASE:  [power]<xsimd::batch<float>>

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_power.cpp:118: ERROR: CHECK_EQ( diff, 0 ) is NOT correct!
  values: CHECK_EQ( 39955, 0 )
  logged: ipow

===============================================================================
/tmp/tmp.IXhhfXZgB6/xsimd/test/test_power.cpp:156:
TEST CASE:  [power]<xsimd::batch<double>>

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_power.cpp:118: ERROR: CHECK_EQ( diff, 0 ) is NOT correct!
  values: CHECK_EQ( 19819, 0 )
  logged: ipow

===============================================================================
/tmp/tmp.IXhhfXZgB6/xsimd/test/test_trigonometric.cpp:195:
TEST CASE:  [trigonometric]<xsimd::batch<float>>
  trigonometric

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_trigonometric.cpp:64: ERROR: CHECK_EQ( diff, 0 ) is NOT correct!
  values: CHECK_EQ( 89, 0 )
  logged: sin

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_trigonometric.cpp:80: ERROR: CHECK_EQ( diff, 0 ) is NOT correct!
  values: CHECK_EQ( 91, 0 )
  logged: cos

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_trigonometric.cpp:101: ERROR: CHECK_EQ( diff, 0 ) is NOT correct!
  values: CHECK_EQ( 89, 0 )
  logged: sincos(sin)

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_trigonometric.cpp:104: ERROR: CHECK_EQ( diff, 0 ) is NOT correct!
  values: CHECK_EQ( 91, 0 )
  logged: sincos(sin)
          sincos(cos)

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_trigonometric.cpp:120: ERROR: CHECK_EQ( diff, 0 ) is NOT correct!
  values: CHECK_EQ( 204, 0 )
  logged: tan

===============================================================================
/tmp/tmp.IXhhfXZgB6/xsimd/test/test_trigonometric.cpp:195:
TEST CASE:  [trigonometric]<xsimd::batch<double>>
  trigonometric

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_trigonometric.cpp:64: ERROR: CHECK_EQ( diff, 0 ) is NOT correct!
  values: CHECK_EQ( 32, 0 )
  logged: sin

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_trigonometric.cpp:80: ERROR: CHECK_EQ( diff, 0 ) is NOT correct!
  values: CHECK_EQ( 35, 0 )
  logged: cos

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_trigonometric.cpp:101: ERROR: CHECK_EQ( diff, 0 ) is NOT correct!
  values: CHECK_EQ( 32, 0 )
  logged: sincos(sin)

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_trigonometric.cpp:104: ERROR: CHECK_EQ( diff, 0 ) is NOT correct!
  values: CHECK_EQ( 35, 0 )
  logged: sincos(sin)
          sincos(cos)

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_trigonometric.cpp:120: ERROR: CHECK_EQ( diff, 0 ) is NOT correct!
  values: CHECK_EQ( 77, 0 )
  logged: tan

===============================================================================
/tmp/tmp.IXhhfXZgB6/xsimd/test/test_xsimd_api.cpp:747:
TEST CASE:  [xsimd api | float types functions]<xsimd::batch<float>>
  exp10

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_xsimd_api.cpp:524: ERROR: CHECK_EQ( extract(xsimd::exp10(T(val))), std::pow(value_type(10), val) ) is NOT correct!
  values: CHECK_EQ( 100, 100 )

===============================================================================
/tmp/tmp.IXhhfXZgB6/xsimd/test/test_xsimd_api.cpp:747:
TEST CASE:  [xsimd api | float types functions]<xsimd::batch<double>>
  exp

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_xsimd_api.cpp:516: ERROR: CHECK_EQ( extract(xsimd::exp(T(val))), std::exp(val) ) is NOT correct!
  values: CHECK_EQ( 7.38906, 7.38906 )

===============================================================================
/tmp/tmp.IXhhfXZgB6/xsimd/test/test_xsimd_api.cpp:747:
TEST CASE:  [xsimd api | float types functions]<xsimd::batch<double>>
  expm1

/tmp/tmp.IXhhfXZgB6/xsimd/test/test_xsimd_api.cpp:535: ERROR: CHECK_EQ( extract(xsimd::expm1(T(val))), std::expm1(val) ) is NOT correct!
  values: CHECK_EQ( 6.38906, 6.38906 )

===============================================================================
[doctest] test cases:  308 |  296 passed | 12 failed | 0 skipped
[doctest] assertions: 8189 | 8162 passed | 27 failed |
[doctest] Status: FAILURE!


0% tests passed, 1 tests failed out of 1

Total Test time (real) =   0.91 sec

The following tests FAILED:
	  1 - test_xsimd (Failed)
Errors while running CTest

@JohanMabille
Copy link
Member

Thanks for this fix!

minuszero is therefore not used anywhere anymore and could maybe be deleted ?

I agree.

@maxmarsc
Copy link
Contributor Author

Thanks for this fix!

minuszero is therefore not used anywhere anymore and could maybe be deleted ?

I agree.

Should I delete it in my PR ?

About the tests : it would require a bit more thinking. The tests about NaN / finite and such wouldn't make any sense since fast-math usually disable such kinda logic. For the rest it would require to gather more information of the precision loss.

Also : there might be other bugs that I've not encountered.

@serge-sans-paille
Copy link
Contributor

And you're fine with that? I mean, it does mean that some function are not accurate enough. Let's see if we could relax the accuracy constraint under fast math.

@maxmarsc
Copy link
Contributor Author

maxmarsc commented Nov 24, 2023

With the precision loss you mean ?

So far I'm only using it with fast-math on a hobby project, I don't have a lot of time to put into it. With this fix, the precision of the complex exponential fit my needs, and usually people with high precision constraints won't enable unsafe optimization in the first place.

To be more complete it would be interesting to at least have an idea of the precision loss on some setup, to better inform the user. But considering the nature of ffast-math, which can produce really different results based on the fact that the compiler no longer has to give guaranties, it's theoretically not possible to prove it would always behave well. It would only give a hint of what would happen most of the time.

@JohanMabille
Copy link
Member

Should I delete it in my PR ?

Yes I think it would make sense.

@JohanMabille
Copy link
Member

Thanks again!

@JohanMabille JohanMabille merged commit be56a35 into xtensor-stack:master Nov 24, 2023
49 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

xsimd::exp broken on aarch64 and GCC 10.2.1 with --fast-math
3 participants