boostorg / multiprecision

Boost.Multiprecision
Boost Software License 1.0
194 stars 111 forks source link

`denorm_min` is not zero #562

Closed ryanelandt closed 1 year ago

ryanelandt commented 1 year ago

A type T is specialized if std::numeric_limits<T>::is_specialized is true. For specialized floating point types that support denorms, denorm_min should be less than min. For specialized floating point types that don't support denorms, denorm_min should be equal to min, e.g., see this or this.

The types cpp_bin_float and cpp_dec_float are floating point types that do not support denorms. This PR changes the values of denorm_min for these types from 0 to min.

ckormanyos commented 1 year ago

Great PR it is awesome to see the formal correctness of the types get even closer to those of built-ins.

Thanks Ryan (@ryanelandt)

@jzmaddock I can add super-simple test case(s) for these if you think that's a good idea and handle this PR. Thoughts?

jzmaddock commented 1 year ago

@jzmaddock I can add super-simple test case(s) for these if you think that's a good idea and handle this PR. Thoughts?

Yes please! My apologies for being AWAL recently, hopefully I'll start catching up soon...

A trivial change to test_numeric_limits.cpp would do it.... we also need to fix up at least gmp.hpp and mpfr.hpp which have the same mistakes.

ckormanyos commented 1 year ago

trivial change to test_numeric_limits.cpp would do it.... we also need to fix up at least gmp.hpp and mpfr.hpp which have the same mistakes

Great. I can try this (if I may), ... get back into the game. Some of the recent stuff around here has been a bit too challenging for me. This one seems like a good one I could try.

Cc: @jzmaddock and @ryanelandt

ryanelandt commented 1 year ago

@ckormanyos feel free to make the necessary changes.

ckormanyos commented 1 year ago

Hi John (@jzmaddock) and Ryan (@ryanelandt) before I get started adding tests and the other two backends, a question, ...

Does the presence of (now or soon-to-be) non-zero denorm_min() mean that has_denorm needs to be changed to something other than std::denorm_absent?

ckormanyos commented 1 year ago

presence of (now or soon-to-be) non-zero denorm_min() mean that has_denorm needs to be changed

Ahhh OK, it is clear from the original post. My bad, ... it is clear from the description use has_denorm as absent and then denorm_min() is min().

ckormanyos commented 1 year ago

Hi Ryan (@ryanelandt)

Cc: @jzmaddock

ckormanyos commented 1 year ago

changes also to MPFR and GMP

And mpfi. I had also forgotten a few needed (min)() values. CI is cycling again and looking better...

ckormanyos commented 1 year ago

OK we have the change set, it's green on the new tests.

Ryan (@ryanelandt) and John (@jzmaddock) if you see anything i missed or suggest more testing depth, I'd be happy to go another round. Otherwise, form my side, this one is ready to merge.

ckormanyos commented 1 year ago

Ryan (@ryanelandt) thanks again and super good catch!

ryanelandt commented 1 year ago

Thank you for completing this PR for me. I think it looks good. I have a few questions about the unit tests.

  1. Why use BOOST_TEST(a == b) instead of BOOST_CHECK_EQUAL(a, b)? Is this to avoid needing to have print support for the quantities being tested?

  2. Could for example:

    BOOST_TEST(!(std::numeric_limits<Number>::denorm_min() > (std::numeric_limits<Number>::min)()));
    BOOST_TEST(!(std::numeric_limits<Number>::denorm_min() < (std::numeric_limits<Number>::min)()));

    Be replaced with:

    BOOST_TEST(std::numeric_limits<Number>::denorm_min() == (std::numeric_limits<Number>::min)());

    The latter in shorter, it also gives the expected result in the cases that (std::numeric_limits<Number>::min)() is NaN.

  3. Is the check that:

    BOOST_TEST(FP_ZERO != (boost::math::fpclassify)(std::numeric_limits<Number>::denorm_min()));

    necessary? Because of the check 2 lines above it, I think it's effect is to check if BOOST_TEST(FP_ZERO != FP_NORMAL).

ryanelandt commented 1 year ago

BTW, based on local tests, this PR breaks this test in Boost Math.

ckormanyos commented 1 year ago

BTW, based on local tests, this PR breaks

Then we can't merge it. I can look tomorrow. Maybe we need help from Matt (@mborland)?

ryanelandt commented 1 year ago

I made a fix for the Boost Math side.

ckormanyos commented 1 year ago

made a fix

Cool. I'd say handle the fix in Math, then we return here. Thanks

jzmaddock commented 1 year ago

Thanks Chris and Ryan!!

Other than a few minor comments above, this looks good to me.

ckormanyos commented 1 year ago

Other than a few minor comments above, this looks good to me

Thank you John.

This is a silly question, one that I've had for a while. Does anyone know how to simply accept all the suggested comments as a batch change that leads to a single renewed CI run? Or do I/we have to manually change all the codes? Rookie question, I know.

ckormanyos commented 1 year ago

OK I can handle all these review suggestions. Please give me a day or so to do the editing and run CI.

BTW, what is the reason that some of the sets of tests in test_cpp_bin_float.cpp seem to be disabled for ASAN and UBSAN?

ryanelandt commented 1 year ago

@ckormanyos there is a lot of code duplication testing things for both denorm_min and min_val. You might consider putting these tests in a lambda function that looks something like:

const auto fn_small_val_tests = [&](const T x){
  // Shared tests go here using x instead of `denorm_min` and `min_val`
};

fn_small_val_tests(denorm_min);
fn_small_val_tests(min_val);
ckormanyos commented 1 year ago

might consider putting these tests in a lambda function

Good catch Ryan, surely would be better. But, ... I've got refactoring goals on basically all files in Math, Multiprecision and in all of Boost for that matter.

So my basic philosophy in the test files, which are known by us to be very non-modernized, is, ... leave it until we have a chance to do a dedicated refactor in something like a GSoC.

ckormanyos commented 1 year ago

The failure is on a clone attempt on drone. Merging.

ryanelandt commented 1 year ago

@ckormanyos Thanks for getting this PR in!