Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@StephanTLavavej
Copy link
Member

@StephanTLavavej StephanTLavavej commented Dec 11, 2025

Followup to #5836. This is unusually daring, even for me, and I would appreciate reviews from our math wizards.

This purges what I believe is the last of our legacy math machinery, which was powering various <complex> transcendental functions. As their previous comments indicated, they appeared to be equivalent to simple combinations of UCRT functions (which I verified through spot checks of behavior).

I'm a little worried that I'm removing important special cases, but I got all of the tests to pass (I did have to restore one special case for zero that made sense). One positive sign is that a couple of libcxx tests started passing. We also had a very picky test GH_001059_hyperbolic_truncation that was comparing one set of function calls to another set of function calls, instead of ground truth. This was failing until I took the original values, ran them through Wolfram Alpha to get known-good results for cosh and sinh, and then overhauled the test to expect them. The previous implementation gets most of the results incorrect according to Wolfram Alpha. The new implementation gets all but one correct, with only 1 ULP of difference, which I regard as an improvement. And x86 actually behaves correctly, so I believe that UCRT behavior variation is responsible.

I've verified that the dllexport surface is unchanged.

Commits

  • Fuse xfcosh.cpp into xcosh.cpp.
  • Fuse xfsinh.cpp into xsinh.cpp.
  • _CSTD _Cosh(_Left, _Right) => _STD cosh(_Left) * _Right
  • _CSTD _Sinh(_Left, _Right) => _STD sinh(_Left) * _Right
  • Remove non-dllexported _Xbig, _FXbig.
  • Remove non-dllexported _Feraise() and its macros.
  • Remove now-unused DSIGN, FSIGN macros.
  • Fuse xfdtest.cpp into xdtest.cpp.
  • Preserve _Dtest, _LDtest, _FDtest for bincompat.
    • _LDtest is used only for 80-bit long double.
  • Implement _Dtest with fpclassify.
    • They return the same values.
  • Fuse xfexp.cpp into xexp.cpp.
  • Preserve _Exp, _FExp, _LExp for bincompat.
    • I verified that this preserves their observable behavior (occasionally differing by 1 or 2 ULPs).
    • This will allow <complex> to benefit from future compiler improvements to the accuracy of UCRT functions.
    • Note that <complex> never used the short return value (an fpclassify-style code), and it always passed 0 for short eoff.
  • Remove non-dllexported _FDnorm, _FDscale, _Xfe_overflow, _Xfe_underflow functions, the _Dval and _Fval unions, and now-unused macros.
  • Delete xmath.hpp, replace with <cmath>.
  • Delete internal but user-visible <ymath.h>, fuse remnants into <complex>.
  • Restore special case for zero to the _Exp codepaths. Enable passing libcxx tests.
  • Overhaul GH_001059_hyperbolic_truncation to expect more accurate results.
    • We're much closer to Wolfram Alpha now, although not quite perfect.
  • x86 actually behaves correctly.

`_LDtest` is used only for 80-bit `long double`.
They return the same values:

    C:\Temp>type meow.cpp
    #include <cmath>
    #include <limits>
    #include <print>
    using namespace std;

    extern "C" _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Dtest(double*) noexcept;

    void classify(double dbl) {
        const short stl = _Dtest(&dbl);
        const int crt   = fpclassify(dbl);
        println("dbl: {:6}; stl: {:2}; crt: {:2}; Equal: {}", dbl, stl, crt, stl == crt);
    }

    int main() {
        classify(numeric_limits<double>::denorm_min());
        classify(3.14);
        classify(0.0);
        classify(-0.0);
        classify(numeric_limits<double>::infinity());
        classify(numeric_limits<double>::quiet_NaN());
    }

    C:\Temp>cl /EHsc /nologo /W4 /std:c++latest /MTd /Od meow.cpp && meow
    meow.cpp
    dbl: 5e-324; stl: -2; crt: -2; Equal: true
    dbl:   3.14; stl: -1; crt: -1; Equal: true
    dbl:      0; stl:  0; crt:  0; Equal: true
    dbl:     -0; stl:  0; crt:  0; Equal: true
    dbl:    inf; stl:  1; crt:  1; Equal: true
    dbl:    nan; stl:  2; crt:  2; Equal: true
I verified that this preserves their observable behavior (occasionally differing by 1 or 2 ULPs).

This will allow `<complex>` to benefit from future compiler improvements to the accuracy of UCRT functions.

Note that `<complex>` never used the `short` return value (an `fpclassify`-style code), and it always passed 0 for `short eoff`.
…underflow` functions, the `_Dval` and `_Fval` unions, and now-unused macros.
…lts.

We're much closer to Wolfram Alpha now, although not quite perfect.
@StephanTLavavej StephanTLavavej requested a review from a team as a code owner December 11, 2025 14:38
@StephanTLavavej StephanTLavavej added the enhancement Something can be improved label Dec 11, 2025
@github-project-automation github-project-automation bot moved this to Initial Review in STL Code Reviews Dec 11, 2025
@StephanTLavavej StephanTLavavej moved this from Initial Review to Work In Progress in STL Code Reviews Dec 11, 2025
@StephanTLavavej

This comment was marked as resolved.

@AlexGuteniev
Copy link
Contributor

This still doesn't look serious enough:

# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
RUNALL_INCLUDE ..\usual_matrix.lst

I think floating_point_model_matrix.lst should be used.

@statementreply
Copy link
Contributor

statementreply commented Dec 12, 2025

_Cosh, _Sinh and _Exp also handle the cases where cosh|sinh|exp(x) overflows but cosh|sinh|exp(x) * y doesn't.

#include <complex>
#include <print>
using namespace std;

#define EVAL_AND_PRINT(expr)                                                  \
    {                                                                         \
        const auto result = (expr);                                           \
        println("{} = complex{{{}, {}}}", #expr, real(result), imag(result)); \
    }

int main() {
    EVAL_AND_PRINT(exp(complex{710.0, 0.8}));
    EVAL_AND_PRINT(sin(complex{0.5, 710.5}));
}

Before PR:

exp(complex{710.0, 0.8}) = complex{1.5564391422313157e+308, 1.6025697525437584e+308}
sin(complex{0.5, 710.5}) = complex{8.829183874344383e+307, 1.616171267472897e+308}

After PR:

exp(complex{710.0, 0.8}) = complex{inf, inf}
sin(complex{0.5, 710.5}) = complex{inf, inf}

@StephanTLavavej
Copy link
Member Author

Thanks, that's what I feared. I'll abandon this attempt for now, but may salvage smaller pieces.

@github-project-automation github-project-automation bot moved this from Work In Progress to Done in STL Code Reviews Dec 12, 2025
@StephanTLavavej StephanTLavavej deleted the math-blaster branch December 12, 2025 10:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Something can be improved

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

4 participants