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

Incorrect division for values near zero. #808

Open
libbooze opened this issue Jan 20, 2025 · 2 comments
Open

Incorrect division for values near zero. #808

libbooze opened this issue Jan 20, 2025 · 2 comments
Assignees
Labels
Boost Review Collected Comments from Boost Review Period Bug Something isn't working

Comments

@libbooze
Copy link

I am not certain what rounding can be done here, but I am pretty sure this is incorrect behavior and final result should be zero.

I have modified the library to make functions to get sig and exp public, no changes to library beside that. This was not necessary needed, but
I wanted to show issues is not just in printing.

code:

template<typename Dec>
void div_tiny()
{
    const auto display = [](const auto& val)
    {
        std::print("{:.40e}\n", val);
        if constexpr (boost::decimal::detail::impl::decimal_val_v<Dec> >= 128)
        {
            std::print("{}|{}  {}\n", val.full_significand().high, val.full_significand().low, val.biased_exponent());
        }
        else
        if constexpr(boost::decimal::detail::is_decimal_floating_point_v<Dec>)
        {
            std::print("{}  {}\n", val.full_significand(), val.biased_exponent());
        }
    };
    std::print("{}\n", boost::typeindex::type_id<Dec>().pretty_name());
    std::print("denorm_min: {:.20e}\n", std::numeric_limits<Dec>::denorm_min());
    const auto tiny = std::numeric_limits<Dec>::denorm_min() * Dec{7.0};
    display(tiny);
    const auto tiny2 = tiny/ Dec{2.0};
    display(tiny2);
    const auto tiny3 = tiny2/ Dec{3.0};
    display(tiny3);
    const auto tiny4 = tiny3/ Dec{5.0};
    display(tiny4);
    std::print("is zero {}\n\n", tiny4 == Dec{0.0});
}
float
denorm_min: 1.40129846432481707092e-45
9.8090892502737194964661070830294129189618e-45
5.6051938572992682836949183331596645251210e-45
1.4012984643248170709237295832899161312803e-45
0.0000000000000000000000000000000000000000e+00
is zero true

double
denorm_min: 4.94065645841246544177e-324
3.4584595208887258092359815500775496065554e-323
1.9762625833649861767062751714728854894602e-323
4.9406564584124654417656879286822137236506e-324
0.0000000000000000000000000000000000000000e+00
is zero true

boost::decimal::decimal32
denorm_min: 1.00000000000000000000e-101
inf
8388608  91
inf
8388608  91
inf
8388608  91
inf
8388608  91
is zero false

boost::decimal::decimal32_fast
denorm_min: 1.00000000000000000000e-95
7.0000000000000000000000000000000000000000e-95
7000000  -101
3.5000000000000000000000000000000000000000e-95
3500000  -101
1.1666670000000000000000000000000000000000e-95
1166667  -101
inf
18446744073709551615  -101
is zero false

boost::decimal::decimal64
denorm_min: 1.00000000000000000000e-398
inf
9007199254740992  370
inf
9007199254740992  370
inf
9007199254740992  370
inf
9007199254740992  370
is zero false

boost::decimal::decimal64_fast
denorm_min: 1.00000000000000000000e-383
7.0000000000000000000000000000000000000000e-383
7000000000000000  -398
3.5000000000000000000000000000000000000000e-383
3500000000000000  -398
1.1666666666666670000000000000000000000000e-383
1166666666666667  -398
inf
18446744073709551615  -398
is zero false

boost::decimal::decimal128
denorm_min: 1.00000000000000000000e-6176
7.0000000000000000000000000000000000000000e-6176
0|7  -6176
0.0000000000000000000000000000000000000000e+00
0|0  0
0.0000000000000000000000000000000000000000e+00
0|0  0
0.0000000000000000000000000000000000000000e+00
0|0  0
is zero true

boost::decimal::decimal128_fast
denorm_min: 1.00000000000000000000e-6143
7.0000000000000000000000000000000000000000e-6143
379470760369926|10180806172248899584  -6176
3.5000000000000000000000000000000000000000e-6143
189735380184963|5090403086124449792  -6176
1.1666666666666666666666666666666670000000e-6143
63245126728321|1696801028708149931  -6176
inf
18446744073709551613|18446744073709551615  -6176
is zero false

Although decimal128 prints is zero true I still believe it's division behavior is incorrect since it should not go to 0 after first division.

@mborland
Copy link
Member

The fast types don't support denorms (https://github.com/cppalliance/decimal/blob/develop/include/boost/decimal/decimal32_fast.hpp#L1463) so we return min by convention: https://en.cppreference.com/w/cpp/types/numeric_limits/denorm_min. I'll look at other cases.

@libbooze
Copy link
Author

libbooze commented Jan 21, 2025

The fast types don't support denorms (https://github.com/cppalliance/decimal/blob/develop/include/boost/decimal/decimal32_fast.hpp#L1463) so we return min by convention: https://en.cppreference.com/w/cpp/types/numeric_limits/denorm_min. I'll look at other cases.

Use of denorm_min is just to get tiny number. I could have manually constructed it but I think this way test is clearer. I believe bug is that end state of computation should be 0 in all cases.

@mborland mborland self-assigned this Jan 23, 2025
@mborland mborland added Bug Something isn't working Boost Review Collected Comments from Boost Review Period labels Jan 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Boost Review Collected Comments from Boost Review Period Bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants