diff --git a/poincare/Makefile b/poincare/Makefile index 52e07d7dd..5fe9a9d1f 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -165,6 +165,7 @@ tests_src += $(addprefix poincare/test/,\ function_solver.cpp\ helper.cpp\ helpers.cpp\ + ieee754.cpp\ integer.cpp\ layout.cpp\ layout_cursor.cpp\ diff --git a/poincare/include/poincare/ieee754.h b/poincare/include/poincare/ieee754.h index 2b2b64200..d2e25d6ce 100644 --- a/poincare/include/poincare/ieee754.h +++ b/poincare/include/poincare/ieee754.h @@ -28,7 +28,6 @@ public: assert(k_totalNumberOfBits == 8*sizeof(T)); return k_totalNumberOfBits; } - static T buildFloat(bool sign, uint16_t exponent, uint64_t mantissa) { static uint64_t oneOnMantissaBits = ((uint64_t)1 << k_mantissaNbBits)-1; uint_float u; @@ -74,11 +73,41 @@ public: } return exponentBase10; } + static T next(T f) { + return nextOrPrevious(f, true); + } + + static T previous(T f) { + return nextOrPrevious(f, false); + } + private: union uint_float { uint64_t ui; T f; }; + static T nextOrPrevious(T f, bool isNext) { + if (std::isinf(f) || std::isnan(f)) { + return f; + } + uint_float u; + u.ui = 0; + u.f = f; + uint64_t oneBitOnSignBit = (uint64_t)1 << (k_exponentNbBits + k_mantissaNbBits); + if ((isNext && (u.ui & oneBitOnSignBit) > 0) // next: Negative float + || (!isNext && (u.ui & oneBitOnSignBit) == 0)) { // previous: Positive float + if ((isNext && u.ui == oneBitOnSignBit) // next: -0.0 + || (!isNext && u.ui == 0.0)) { // previous: 0.0 + u.ui = isNext ? 0 : oneBitOnSignBit; + } else { + u.ui -= 1; + } + } else { // next: Positive float, previous: Negative float + u.ui += 1; + } + return u.f; + } + constexpr static size_t k_signNbBits = 1; constexpr static size_t k_exponentNbBits = sizeof(T) == sizeof(float) ? 8 : 11; constexpr static size_t k_mantissaNbBits = sizeof(T) == sizeof(float) ? 23 : 52; diff --git a/poincare/test/ieee754.cpp b/poincare/test/ieee754.cpp new file mode 100644 index 000000000..3099513dc --- /dev/null +++ b/poincare/test/ieee754.cpp @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include +#include +#include +#include "helper.h" + +using namespace Poincare; + +template +void assert_next_and_previous_IEEE754_is(T a, T b) { + T next = IEEE754::next(a); + T previous = IEEE754::previous(b); + assert((std::isnan(next) && std::isnan(b)) || next == b); + assert((std::isnan(previous) && std::isnan(a)) || previous == a); +} + +QUIZ_CASE(ieee754_next_and_previous) { + assert_next_and_previous_IEEE754_is(0.0f, 1.4E-45f); + assert_next_and_previous_IEEE754_is(INFINITY, INFINITY); + assert_next_and_previous_IEEE754_is(NAN, NAN); + assert_next_and_previous_IEEE754_is(2.2566837E-10f, 2.2566839E-10f); + assert_next_and_previous_IEEE754_is(-INFINITY, -INFINITY); + assert_next_and_previous_IEEE754_is(-0.0f, 0.0f); + assert_next_and_previous_IEEE754_is(-1.4E-45f, -0.0f); + assert_next_and_previous_IEEE754_is(-3.4359738E10f, -3.43597363E10f); + assert(IEEE754::next(3.4028235E38f) == INFINITY); + assert(IEEE754::previous(-3.4028235E38f) == -INFINITY); + + assert_next_and_previous_IEEE754_is(0.0f, 4.94065645841246544176568792868E-324); + assert_next_and_previous_IEEE754_is(INFINITY, INFINITY); + assert_next_and_previous_IEEE754_is(NAN, NAN); + assert_next_and_previous_IEEE754_is(1.936766735060658315512927142E-282, 1.93676673506065869777770528092E-282); + assert_next_and_previous_IEEE754_is(-INFINITY, -INFINITY); + assert_next_and_previous_IEEE754_is(-0.0, 0.0); + assert_next_and_previous_IEEE754_is(-4.94065645841246544176568792868E-324, -0.0); + assert_next_and_previous_IEEE754_is(-1.38737906372912431085182213247E201, -1.38737906372912403890916981028E201); + assert(IEEE754::next(1.79769313486231570814527423732E308) == INFINITY); + assert(IEEE754::previous(-1.79769313486231570814527423732E308) == -INFINITY); + +}