From aba61fe8b7a91641ac7874d621996171327a2533 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 11 Dec 2025 01:11:36 -0800 Subject: [PATCH 01/18] Fuse xfcosh.cpp into xcosh.cpp. --- stl/CMakeLists.txt | 1 - .../stl_base/stl.files.settings.targets | 1 - stl/src/xcosh.cpp | 31 +++++++++++++++ stl/src/xfcosh.cpp | 39 ------------------- 4 files changed, 31 insertions(+), 41 deletions(-) delete mode 100644 stl/src/xfcosh.cpp diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 1f08f33bb36..a088c1ffae3 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -284,7 +284,6 @@ set(SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/xdateord.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xdtest.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xexp.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfcosh.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xfdnorm.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xfdscale.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xfdtest.cpp diff --git a/stl/msbuild/stl_base/stl.files.settings.targets b/stl/msbuild/stl_base/stl.files.settings.targets index 95fd85f8970..4db62e56d46 100644 --- a/stl/msbuild/stl_base/stl.files.settings.targets +++ b/stl/msbuild/stl_base/stl.files.settings.targets @@ -78,7 +78,6 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - diff --git a/stl/src/xcosh.cpp b/stl/src/xcosh.cpp index 16447fca0fd..01c70ca4eaf 100644 --- a/stl/src/xcosh.cpp +++ b/stl/src/xcosh.cpp @@ -40,4 +40,35 @@ _CRTIMP2_PURE long double __CLRCALL_PURE_OR_CDECL _LCosh(long double x, long dou return _Cosh(static_cast(x), static_cast(y)); } +_CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FCosh(float x, float y) noexcept { // compute y * cosh(x), |y| <= 1 + switch (_FDtest(&x)) { // test for special codes + case _NANCODE: + case _INFCODE: + return x; + case 0: + return y; + default: // finite + if (y == 0.0) { + return y; + } + + if (x < 0.0) { + x = -x; + } + + if (x < _FXbig) { // worth adding in exp(-x) + _FExp(&x, 1.0F, -1); + return y * (x + 0.25F / x); + } + switch (_FExp(&x, y, -1)) { // report over/underflow + case 0: + _Feraise(_FE_UNDERFLOW); + break; + case _INFCODE: + _Feraise(_FE_OVERFLOW); + } + return x; + } +} + _END_EXTERN_C_UNLESS_PURE diff --git a/stl/src/xfcosh.cpp b/stl/src/xfcosh.cpp deleted file mode 100644 index 5fb3ce51814..00000000000 --- a/stl/src/xfcosh.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include "xmath.hpp" - -_EXTERN_C_UNLESS_PURE - -_CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FCosh(float x, float y) noexcept { // compute y * cosh(x), |y| <= 1 - switch (_FDtest(&x)) { // test for special codes - case _NANCODE: - case _INFCODE: - return x; - case 0: - return y; - default: // finite - if (y == 0.0) { - return y; - } - - if (x < 0.0) { - x = -x; - } - - if (x < _FXbig) { // worth adding in exp(-x) - _FExp(&x, 1.0F, -1); - return y * (x + 0.25F / x); - } - switch (_FExp(&x, y, -1)) { // report over/underflow - case 0: - _Feraise(_FE_UNDERFLOW); - break; - case _INFCODE: - _Feraise(_FE_OVERFLOW); - } - return x; - } -} - -_END_EXTERN_C_UNLESS_PURE From 85ca57911b8dec70e4e5f908e84357f2823f096d Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 11 Dec 2025 01:13:29 -0800 Subject: [PATCH 02/18] Fuse xfsinh.cpp into xsinh.cpp. --- stl/CMakeLists.txt | 1 - .../stl_base/stl.files.settings.targets | 1 - stl/src/xfsinh.cpp | 60 ------------------- stl/src/xsinh.cpp | 52 ++++++++++++++++ 4 files changed, 52 insertions(+), 62 deletions(-) delete mode 100644 stl/src/xfsinh.cpp diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index a088c1ffae3..0e0cfa3b215 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -289,7 +289,6 @@ set(SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/xfdtest.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xferaise.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xfexp.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfsinh.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xgetwctype.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xlgamma.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xlocale.cpp diff --git a/stl/msbuild/stl_base/stl.files.settings.targets b/stl/msbuild/stl_base/stl.files.settings.targets index 4db62e56d46..f6d81af70f2 100644 --- a/stl/msbuild/stl_base/stl.files.settings.targets +++ b/stl/msbuild/stl_base/stl.files.settings.targets @@ -83,7 +83,6 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - diff --git a/stl/src/xfsinh.cpp b/stl/src/xfsinh.cpp deleted file mode 100644 index 4e551083f6e..00000000000 --- a/stl/src/xfsinh.cpp +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include "xmath.hpp" - -_EXTERN_C_UNLESS_PURE - -_CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FSinh(float x, float y) noexcept { - // compute y * sinh(x), |y| <= 1 - - // coefficients - static constexpr float p[] = {0.00020400F, 0.00832983F, 0.16666737F, 0.99999998F}; - - short neg; - - switch (_FDtest(&x)) { // test for special codes - case _NANCODE: - return x; - case _INFCODE: - return y != 0.0F ? x : FSIGN(x) ? -y : y; - case 0: - return x * y; - default: // finite - if (y == 0.0F) { - return x < 0.0F ? -y : y; - } - - if (x < 0.0F) { - x = -x; - neg = 1; - } else { - neg = 0; - } - - constexpr float rteps = 0x1p-12f; - if (x < rteps) { - x *= y; // x tiny - } else if (x < 1.0F) { - float w = x * x; - - x += ((p[0] * w + p[1]) * w + p[2]) * w * x; - x *= y; - } else if (x < _FXbig) { // worth adding in exp(-x) - _FExp(&x, 1.0F, -1); - x = y * (x - 0.25F / x); - } else { - switch (_FExp(&x, y, -1)) { // report over/underflow - case 0: - _Feraise(_FE_UNDERFLOW); - break; - case _INFCODE: - _Feraise(_FE_OVERFLOW); - } - } - - return neg ? -x : x; - } -} - -_END_EXTERN_C_UNLESS_PURE diff --git a/stl/src/xsinh.cpp b/stl/src/xsinh.cpp index 1def63635b0..5e38691a044 100644 --- a/stl/src/xsinh.cpp +++ b/stl/src/xsinh.cpp @@ -77,4 +77,56 @@ _CRTIMP2_PURE long double __CLRCALL_PURE_OR_CDECL _LSinh(long double x, long dou return _Sinh(static_cast(x), static_cast(y)); } +_CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FSinh(float x, float y) noexcept { + // compute y * sinh(x), |y| <= 1 + + // coefficients + static constexpr float p[] = {0.00020400F, 0.00832983F, 0.16666737F, 0.99999998F}; + + short neg; + + switch (_FDtest(&x)) { // test for special codes + case _NANCODE: + return x; + case _INFCODE: + return y != 0.0F ? x : FSIGN(x) ? -y : y; + case 0: + return x * y; + default: // finite + if (y == 0.0F) { + return x < 0.0F ? -y : y; + } + + if (x < 0.0F) { + x = -x; + neg = 1; + } else { + neg = 0; + } + + constexpr float rteps = 0x1p-12f; + if (x < rteps) { + x *= y; // x tiny + } else if (x < 1.0F) { + float w = x * x; + + x += ((p[0] * w + p[1]) * w + p[2]) * w * x; + x *= y; + } else if (x < _FXbig) { // worth adding in exp(-x) + _FExp(&x, 1.0F, -1); + x = y * (x - 0.25F / x); + } else { + switch (_FExp(&x, y, -1)) { // report over/underflow + case 0: + _Feraise(_FE_UNDERFLOW); + break; + case _INFCODE: + _Feraise(_FE_OVERFLOW); + } + } + + return neg ? -x : x; + } +} + _END_EXTERN_C_UNLESS_PURE From 273a6e3ff5f7588863c3354df42b73cd105e98f6 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 11 Dec 2025 01:23:37 -0800 Subject: [PATCH 03/18] `_CSTD _Cosh(_Left, _Right)` => `_STD cosh(_Left) * _Right` --- stl/inc/complex | 8 +++--- stl/inc/ymath.h | 3 --- stl/src/xcosh.cpp | 67 ++++++----------------------------------------- 3 files changed, 12 insertions(+), 66 deletions(-) diff --git a/stl/inc/complex b/stl/inc/complex index acd727f40c6..ccc52c67b17 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -390,7 +390,7 @@ public: } static _Ty _Cosh(_Ty _Left, _Ty _Right) { // return cosh(_Left) * _Right - return static_cast<_Ty>(_CSTD _Cosh(static_cast(_Left), static_cast(_Right))); + return static_cast<_Ty>(_STD cosh(static_cast(_Left)) * static_cast(_Right)); } static _Ty _Copysign(_Ty _Magnitude, _Ty _Sign) { @@ -528,7 +528,7 @@ public: } static _Ty _Cosh(_Ty _Left, _Ty _Right) noexcept { // return cosh(_Left) * _Right - return _CSTD _LCosh(_Left, _Right); + return _STD cosh(_Left) * _Right; } static _Ty _Copysign(_Ty _Magnitude, _Ty _Sign) noexcept { @@ -672,7 +672,7 @@ public: } static _Ty _Cosh(_Ty _Left, _Ty _Right) noexcept { // return cosh(_Left) * _Right - return _CSTD _Cosh(_Left, _Right); + return _STD cosh(_Left) * _Right; } static _Ty _Copysign(_Ty _Magnitude, _Ty _Sign) noexcept { @@ -811,7 +811,7 @@ public: } static _Ty _Cosh(_Ty _Left, _Ty _Right) noexcept { // return cosh(_Left) * _Right - return _CSTD _FCosh(_Left, _Right); + return _STD cosh(_Left) * _Right; } static _Ty _Copysign(_Ty _Magnitude, _Ty _Sign) noexcept { diff --git a/stl/inc/ymath.h b/stl/inc/ymath.h index 6c1adbe4421..ee8d357ad83 100644 --- a/stl/inc/ymath.h +++ b/stl/inc/ymath.h @@ -20,15 +20,12 @@ _EXTERN_C_UNLESS_PURE #define _INFCODE 1 #define _NANCODE 2 -_CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Cosh(double, double) noexcept; _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Sinh(double, double) noexcept; _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Exp(double*, double, short) noexcept; -_CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FCosh(float, float) noexcept; _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FSinh(float, float) noexcept; _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FExp(float*, float, short) noexcept; -_CRTIMP2_PURE long double __CLRCALL_PURE_OR_CDECL _LCosh(long double, long double) noexcept; _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _LDtest(long double*) noexcept; _CRTIMP2_PURE long double __CLRCALL_PURE_OR_CDECL _LSinh(long double, long double) noexcept; _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _LExp(long double*, long double, short) noexcept; diff --git a/stl/src/xcosh.cpp b/stl/src/xcosh.cpp index 01c70ca4eaf..5bf5c95d9d5 100644 --- a/stl/src/xcosh.cpp +++ b/stl/src/xcosh.cpp @@ -5,70 +5,19 @@ _EXTERN_C_UNLESS_PURE -_CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Cosh(double x, double y) noexcept { // compute y * cosh(x), |y| <= 1 - switch (_Dtest(&x)) { // test for special codes - case _NANCODE: - case _INFCODE: - return x; - case 0: - return y; - default: // finite - if (y == 0.0) { - return y; - } - - if (x < 0.0) { - x = -x; - } - - if (x < _Xbig) { // worth adding in exp(-x) - _Exp(&x, 1.0, -1); - return y * (x + 0.25 / x); - } - switch (_Exp(&x, y, -1)) { // report over/underflow - case 0: - _Feraise(_FE_UNDERFLOW); - break; - case _INFCODE: - _Feraise(_FE_OVERFLOW); - } - return x; - } +// TRANSITION, ABI: preserved for binary compatibility +_CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Cosh(double x, double y) noexcept { + return _STD cosh(x) * y; } +// TRANSITION, ABI: preserved for binary compatibility _CRTIMP2_PURE long double __CLRCALL_PURE_OR_CDECL _LCosh(long double x, long double y) noexcept { - return _Cosh(static_cast(x), static_cast(y)); + return _STD cosh(x) * y; } -_CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FCosh(float x, float y) noexcept { // compute y * cosh(x), |y| <= 1 - switch (_FDtest(&x)) { // test for special codes - case _NANCODE: - case _INFCODE: - return x; - case 0: - return y; - default: // finite - if (y == 0.0) { - return y; - } - - if (x < 0.0) { - x = -x; - } - - if (x < _FXbig) { // worth adding in exp(-x) - _FExp(&x, 1.0F, -1); - return y * (x + 0.25F / x); - } - switch (_FExp(&x, y, -1)) { // report over/underflow - case 0: - _Feraise(_FE_UNDERFLOW); - break; - case _INFCODE: - _Feraise(_FE_OVERFLOW); - } - return x; - } +// TRANSITION, ABI: preserved for binary compatibility +_CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FCosh(float x, float y) noexcept { + return _STD cosh(x) * y; } _END_EXTERN_C_UNLESS_PURE From e1a89bd279eda2d3908f6f45dc5b9f58cb4685c3 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 11 Dec 2025 01:30:37 -0800 Subject: [PATCH 04/18] `_CSTD _Sinh(_Left, _Right)` => `_STD sinh(_Left) * _Right` --- stl/inc/complex | 8 +-- stl/inc/ymath.h | 3 -- stl/src/xsinh.cpp | 121 +++------------------------------------------- 3 files changed, 10 insertions(+), 122 deletions(-) diff --git a/stl/inc/complex b/stl/inc/complex index ccc52c67b17..42714a26ad6 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -429,7 +429,7 @@ public: } static _Ty _Sinh(_Ty _Left, _Ty _Right) { // return sinh(_Left) * _Right - return static_cast<_Ty>(_CSTD _Sinh(static_cast(_Left), static_cast(_Right))); + return static_cast<_Ty>(_STD sinh(static_cast(_Left)) * static_cast(_Right)); } static _Ty asinh(_Ty _Left) { @@ -573,7 +573,7 @@ public: } static _Ty _Sinh(_Ty _Left, _Ty _Right) noexcept { // return sinh(_Left) * _Right - return _CSTD _LSinh(_Left, _Right); + return _STD sinh(_Left) * _Right; } static _Ty asinh(_Ty _Left) noexcept { @@ -709,7 +709,7 @@ public: } static _Ty _Sinh(_Ty _Left, _Ty _Right) noexcept { // return sinh(_Left) * _Right - return _CSTD _Sinh(_Left, _Right); + return _STD sinh(_Left) * _Right; } static _Ty asinh(_Ty _Left) noexcept { @@ -848,7 +848,7 @@ public: } static _Ty _Sinh(_Ty _Left, _Ty _Right) noexcept { // return sinh(_Left) * _Right - return _CSTD _FSinh(_Left, _Right); + return _STD sinh(_Left) * _Right; } static _Ty asinh(_Ty _Left) noexcept { diff --git a/stl/inc/ymath.h b/stl/inc/ymath.h index ee8d357ad83..062c7964760 100644 --- a/stl/inc/ymath.h +++ b/stl/inc/ymath.h @@ -20,14 +20,11 @@ _EXTERN_C_UNLESS_PURE #define _INFCODE 1 #define _NANCODE 2 -_CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Sinh(double, double) noexcept; _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Exp(double*, double, short) noexcept; -_CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FSinh(float, float) noexcept; _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FExp(float*, float, short) noexcept; _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _LDtest(long double*) noexcept; -_CRTIMP2_PURE long double __CLRCALL_PURE_OR_CDECL _LSinh(long double, long double) noexcept; _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _LExp(long double*, long double, short) noexcept; _END_EXTERN_C_UNLESS_PURE diff --git a/stl/src/xsinh.cpp b/stl/src/xsinh.cpp index 5e38691a044..d79b1aaf32d 100644 --- a/stl/src/xsinh.cpp +++ b/stl/src/xsinh.cpp @@ -1,132 +1,23 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include - #include "xmath.hpp" -namespace { - double _Poly(double x, const double* tab, int n) noexcept { // compute polynomial - double y; - - for (y = *tab; 0 <= --n;) { - y = y * x + *++tab; - } - - return y; - } -} // unnamed namespace - _EXTERN_C_UNLESS_PURE +// TRANSITION, ABI: preserved for binary compatibility _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Sinh(double x, double y) noexcept { - // compute y * sinh(x), |y| <= 1 - - // coefficients - static constexpr double p[] = {0.0000000001632881, 0.0000000250483893, 0.0000027557344615, 0.0001984126975233, - 0.0083333333334816, 0.1666666666666574, 1.0000000000000001}; - constexpr size_t NP = std::size(p) - 1; - - short neg; - - switch (_Dtest(&x)) { // test for special codes - case _NANCODE: - return x; - case _INFCODE: - return y != 0.0 ? x : DSIGN(x) ? -y : y; - case 0: - return x * y; - default: // finite - if (y == 0.0) { - return x < 0.0 ? -y : y; - } - - if (x < 0.0) { - x = -x; - neg = 1; - } else { - neg = 0; - } - - constexpr double rteps = 0x1p-27; - if (x < rteps) { - x *= y; // x tiny - } else if (x < 1.0) { - double w = x * x; - - x += x * w * _Poly(w, p, NP - 1); - x *= y; - } else if (x < _Xbig) { // worth adding in exp(-x) - _Exp(&x, 1.0, -1); - x = y * (x - 0.25 / x); - } else { - switch (_Exp(&x, y, -1)) { // report over/underflow - case 0: - _Feraise(_FE_UNDERFLOW); - break; - case _INFCODE: - _Feraise(_FE_OVERFLOW); - } - } - - return neg ? -x : x; - } + return _STD sinh(x) * y; } +// TRANSITION, ABI: preserved for binary compatibility _CRTIMP2_PURE long double __CLRCALL_PURE_OR_CDECL _LSinh(long double x, long double y) noexcept { - return _Sinh(static_cast(x), static_cast(y)); + return _STD sinh(x) * y; } +// TRANSITION, ABI: preserved for binary compatibility _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FSinh(float x, float y) noexcept { - // compute y * sinh(x), |y| <= 1 - - // coefficients - static constexpr float p[] = {0.00020400F, 0.00832983F, 0.16666737F, 0.99999998F}; - - short neg; - - switch (_FDtest(&x)) { // test for special codes - case _NANCODE: - return x; - case _INFCODE: - return y != 0.0F ? x : FSIGN(x) ? -y : y; - case 0: - return x * y; - default: // finite - if (y == 0.0F) { - return x < 0.0F ? -y : y; - } - - if (x < 0.0F) { - x = -x; - neg = 1; - } else { - neg = 0; - } - - constexpr float rteps = 0x1p-12f; - if (x < rteps) { - x *= y; // x tiny - } else if (x < 1.0F) { - float w = x * x; - - x += ((p[0] * w + p[1]) * w + p[2]) * w * x; - x *= y; - } else if (x < _FXbig) { // worth adding in exp(-x) - _FExp(&x, 1.0F, -1); - x = y * (x - 0.25F / x); - } else { - switch (_FExp(&x, y, -1)) { // report over/underflow - case 0: - _Feraise(_FE_UNDERFLOW); - break; - case _INFCODE: - _Feraise(_FE_OVERFLOW); - } - } - - return neg ? -x : x; - } + return _STD sinh(x) * y; } _END_EXTERN_C_UNLESS_PURE From 92fc84133c453f476779c291a28a361bec00a476 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 11 Dec 2025 01:33:14 -0800 Subject: [PATCH 05/18] Remove non-dllexported `_Xbig`, `_FXbig`. --- stl/src/xmath.hpp | 4 ---- stl/src/xvalues.cpp | 3 --- tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp | 4 ++-- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/stl/src/xmath.hpp b/stl/src/xmath.hpp index a884f145f89..ec7ca25de17 100644 --- a/stl/src/xmath.hpp +++ b/stl/src/xmath.hpp @@ -43,8 +43,6 @@ union _Dval { // pun floating type as integer array double _Val; }; -extern const double _Xbig; - // float declarations union _Fval { // pun floating type as integer array unsigned short _Sh[8]; @@ -54,8 +52,6 @@ union _Fval { // pun floating type as integer array short _FDnorm(_Fval*) noexcept; short _FDscale(float*, long) noexcept; -extern const float _FXbig; - _END_EXTERN_C_UNLESS_PURE // raise IEEE 754 exceptions diff --git a/stl/src/xvalues.cpp b/stl/src/xvalues.cpp index 0fb45636130..dcc48528ff4 100644 --- a/stl/src/xvalues.cpp +++ b/stl/src/xvalues.cpp @@ -13,9 +13,6 @@ _EXTERN_C_UNLESS_PURE -extern const double _Xbig = ((48 + _DOFF) + 2) * 0.347; -extern const float _FXbig = ((16 + _FOFF) + 2) * 0.347f; - // TRANSITION, ABI: preserved for binary compatibility union _Dconst { // pun float types as integer array unsigned short _Word[8]; diff --git a/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp b/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp index 67d69e1bb9a..0ab947ef960 100644 --- a/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp +++ b/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp @@ -2,8 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // GH-1059: "Incorrect const float values in xvalues.cpp files" -// The _Xbig constants, used to determine when the exp(-x) terms in -// cosh and sinh can be ignored, have off-by-one and integer +// Internal constants (used to determine when the exp(-x) terms in +// cosh and sinh could be ignored) had off-by-one and integer // truncation errors. #include From 239063b9bded12e78b83df948165db40e4419076 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 11 Dec 2025 01:35:34 -0800 Subject: [PATCH 06/18] Remove non-dllexported _Feraise() and its macros. --- stl/CMakeLists.txt | 1 - stl/msbuild/stl_base/stl.files.settings.targets | 1 - stl/src/xferaise.cpp | 16 ---------------- stl/src/xmath.hpp | 8 -------- 4 files changed, 26 deletions(-) delete mode 100644 stl/src/xferaise.cpp diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 0e0cfa3b215..6055354cede 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -287,7 +287,6 @@ set(SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/xfdnorm.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xfdscale.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xfdtest.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xferaise.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xfexp.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xgetwctype.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xlgamma.cpp diff --git a/stl/msbuild/stl_base/stl.files.settings.targets b/stl/msbuild/stl_base/stl.files.settings.targets index f6d81af70f2..90b97d069f3 100644 --- a/stl/msbuild/stl_base/stl.files.settings.targets +++ b/stl/msbuild/stl_base/stl.files.settings.targets @@ -81,7 +81,6 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - diff --git a/stl/src/xferaise.cpp b/stl/src/xferaise.cpp deleted file mode 100644 index b973fc23824..00000000000 --- a/stl/src/xferaise.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include "xmath.hpp" - -_EXTERN_C_UNLESS_PURE - -void __CLRCALL_PURE_OR_CDECL _Feraise(int except) noexcept { // report floating-point exception - if ((except & (_FE_DIVBYZERO | _FE_INVALID)) != 0) { - errno = EDOM; - } else if ((except & (_FE_UNDERFLOW | _FE_OVERFLOW)) != 0) { - errno = ERANGE; - } -} - -_END_EXTERN_C_UNLESS_PURE diff --git a/stl/src/xmath.hpp b/stl/src/xmath.hpp index ec7ca25de17..5ed84b0d1b4 100644 --- a/stl/src/xmath.hpp +++ b/stl/src/xmath.hpp @@ -8,12 +8,6 @@ #include #include -// macros for _Feraise argument -#define _FE_DIVBYZERO 0x04 -#define _FE_INVALID 0x01 -#define _FE_OVERFLOW 0x08 -#define _FE_UNDERFLOW 0x10 - // float properties #define _D0 3 // little-endian, small long doubles #define _D1 2 @@ -32,8 +26,6 @@ _EXTERN_C_UNLESS_PURE -void __CLRCALL_PURE_OR_CDECL _Feraise(int) noexcept; - _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Dtest(double*) noexcept; _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FDtest(float*) noexcept; From 7a1618ed3447cc238b317b2cb7565f2a859db50b Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 11 Dec 2025 01:38:32 -0800 Subject: [PATCH 07/18] Remove now-unused DSIGN, FSIGN macros. --- stl/src/xmath.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/stl/src/xmath.hpp b/stl/src/xmath.hpp index 5ed84b0d1b4..a4928d662dd 100644 --- a/stl/src/xmath.hpp +++ b/stl/src/xmath.hpp @@ -17,9 +17,6 @@ #define _F0 1 // little-endian #define _F1 0 -#define DSIGN(x) (reinterpret_cast<_Dval*>(&(x))->_Sh[_D0] & _DSIGN) -#define FSIGN(x) (reinterpret_cast<_Fval*>(&(x))->_Sh[_F0] & _FSIGN) - // macros for _Dtest return (0 => ZERO) #define _DENORM (-2) // C9X only #define _FINITE (-1) From 50dd871db74201746cc8a2118fb86cb0d613fd72 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 11 Dec 2025 01:43:38 -0800 Subject: [PATCH 08/18] Fuse xfdtest.cpp into xdtest.cpp. --- stl/CMakeLists.txt | 1 - .../stl_base/stl.files.settings.targets | 1 - stl/src/xdtest.cpp | 14 ++++++++++-- stl/src/xfdtest.cpp | 22 ------------------- 4 files changed, 12 insertions(+), 26 deletions(-) delete mode 100644 stl/src/xfdtest.cpp diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 6055354cede..052b3fdb9d3 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -286,7 +286,6 @@ set(SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/xexp.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xfdnorm.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xfdscale.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfdtest.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xfexp.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xgetwctype.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xlgamma.cpp diff --git a/stl/msbuild/stl_base/stl.files.settings.targets b/stl/msbuild/stl_base/stl.files.settings.targets index 90b97d069f3..2ae545a2f92 100644 --- a/stl/msbuild/stl_base/stl.files.settings.targets +++ b/stl/msbuild/stl_base/stl.files.settings.targets @@ -80,7 +80,6 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - diff --git a/stl/src/xdtest.cpp b/stl/src/xdtest.cpp index caaa62f0851..1f219ad5a28 100644 --- a/stl/src/xdtest.cpp +++ b/stl/src/xdtest.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// _Dtest function -- IEEE 754 version - #include "xmath.hpp" _EXTERN_C_UNLESS_PURE @@ -24,4 +22,16 @@ _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _LDtest(long double* px) noexcept { return _Dtest(reinterpret_cast(px)); } +_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FDtest(float* px) noexcept { // categorize *px + const auto ps = reinterpret_cast<_Fval*>(px); + + if ((ps->_Sh[_F0] & _FMASK) == _FMAX << _FOFF) { + return (ps->_Sh[_F0] & _FFRAC) != 0 || ps->_Sh[_F1] != 0 ? _NANCODE : _INFCODE; + } else if ((ps->_Sh[_F0] & ~_FSIGN) != 0 || ps->_Sh[_F1] != 0) { + return (ps->_Sh[_F0] & _FMASK) == 0 ? _DENORM : _FINITE; + } else { + return 0; + } +} + _END_EXTERN_C_UNLESS_PURE diff --git a/stl/src/xfdtest.cpp b/stl/src/xfdtest.cpp deleted file mode 100644 index 04556bca328..00000000000 --- a/stl/src/xfdtest.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -// _FDtest function -- IEEE 754 version - -#include "xmath.hpp" - -_EXTERN_C_UNLESS_PURE - -_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FDtest(float* px) noexcept { // categorize *px - const auto ps = reinterpret_cast<_Fval*>(px); - - if ((ps->_Sh[_F0] & _FMASK) == _FMAX << _FOFF) { - return (ps->_Sh[_F0] & _FFRAC) != 0 || ps->_Sh[_F1] != 0 ? _NANCODE : _INFCODE; - } else if ((ps->_Sh[_F0] & ~_FSIGN) != 0 || ps->_Sh[_F1] != 0) { - return (ps->_Sh[_F0] & _FMASK) == 0 ? _DENORM : _FINITE; - } else { - return 0; - } -} - -_END_EXTERN_C_UNLESS_PURE From 2d929dc16055990fac53c743063615effe071bba Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 11 Dec 2025 01:45:57 -0800 Subject: [PATCH 09/18] Preserve `_Dtest`, `_LDtest`, `_FDtest` for bincompat. `_LDtest` is used only for 80-bit `long double`. --- stl/src/xdtest.cpp | 3 +++ stl/src/xmath.hpp | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/src/xdtest.cpp b/stl/src/xdtest.cpp index 1f219ad5a28..4835d54d5eb 100644 --- a/stl/src/xdtest.cpp +++ b/stl/src/xdtest.cpp @@ -5,6 +5,7 @@ _EXTERN_C_UNLESS_PURE +// TRANSITION, ABI: preserved for binary compatibility _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Dtest(double* px) noexcept { // categorize *px const auto ps = reinterpret_cast<_Dval*>(px); @@ -18,10 +19,12 @@ _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Dtest(double* px) noexcept { // cat } } +// TRANSITION, ABI: preserved for binary compatibility _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _LDtest(long double* px) noexcept { // categorize *px -- 64-bit return _Dtest(reinterpret_cast(px)); } +// TRANSITION, ABI: preserved for binary compatibility _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FDtest(float* px) noexcept { // categorize *px const auto ps = reinterpret_cast<_Fval*>(px); diff --git a/stl/src/xmath.hpp b/stl/src/xmath.hpp index a4928d662dd..ec8ac20482e 100644 --- a/stl/src/xmath.hpp +++ b/stl/src/xmath.hpp @@ -23,9 +23,6 @@ _EXTERN_C_UNLESS_PURE -_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Dtest(double*) noexcept; -_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FDtest(float*) noexcept; - // double declarations union _Dval { // pun floating type as integer array unsigned short _Sh[8]; From b1c90af73136ea424c3873332100fbad07a7291b Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 11 Dec 2025 02:07:22 -0800 Subject: [PATCH 10/18] Implement `_Dtest` with `fpclassify`. They return the same values: C:\Temp>type meow.cpp #include #include #include 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::denorm_min()); classify(3.14); classify(0.0); classify(-0.0); classify(numeric_limits::infinity()); classify(numeric_limits::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 --- stl/src/xdtest.cpp | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/stl/src/xdtest.cpp b/stl/src/xdtest.cpp index 4835d54d5eb..4a00be6a988 100644 --- a/stl/src/xdtest.cpp +++ b/stl/src/xdtest.cpp @@ -6,35 +6,18 @@ _EXTERN_C_UNLESS_PURE // TRANSITION, ABI: preserved for binary compatibility -_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Dtest(double* px) noexcept { // categorize *px - const auto ps = reinterpret_cast<_Dval*>(px); - - if ((ps->_Sh[_D0] & _DMASK) == _DMAX << _DOFF) { - return (ps->_Sh[_D0] & _DFRAC) != 0 || ps->_Sh[_D1] != 0 || ps->_Sh[_D2] != 0 || ps->_Sh[_D3] != 0 ? _NANCODE - : _INFCODE; - } else if ((ps->_Sh[_D0] & ~_DSIGN) != 0 || ps->_Sh[_D1] != 0 || ps->_Sh[_D2] != 0 || ps->_Sh[_D3] != 0) { - return (ps->_Sh[_D0] & _DMASK) == 0 ? _DENORM : _FINITE; - } else { - return 0; - } +_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Dtest(double* px) noexcept { + return static_cast(_STD fpclassify(*px)); } // TRANSITION, ABI: preserved for binary compatibility -_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _LDtest(long double* px) noexcept { // categorize *px -- 64-bit - return _Dtest(reinterpret_cast(px)); +_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _LDtest(long double* px) noexcept { + return static_cast(_STD fpclassify(*px)); } // TRANSITION, ABI: preserved for binary compatibility -_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FDtest(float* px) noexcept { // categorize *px - const auto ps = reinterpret_cast<_Fval*>(px); - - if ((ps->_Sh[_F0] & _FMASK) == _FMAX << _FOFF) { - return (ps->_Sh[_F0] & _FFRAC) != 0 || ps->_Sh[_F1] != 0 ? _NANCODE : _INFCODE; - } else if ((ps->_Sh[_F0] & ~_FSIGN) != 0 || ps->_Sh[_F1] != 0) { - return (ps->_Sh[_F0] & _FMASK) == 0 ? _DENORM : _FINITE; - } else { - return 0; - } +_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FDtest(float* px) noexcept { + return static_cast(_STD fpclassify(*px)); } _END_EXTERN_C_UNLESS_PURE From 7d68c0595cad4a337984b5166c92497441c9869b Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 11 Dec 2025 02:47:29 -0800 Subject: [PATCH 11/18] Fuse xfexp.cpp into xexp.cpp. --- stl/CMakeLists.txt | 1 - .../stl_base/stl.files.settings.targets | 1 - stl/src/xexp.cpp | 55 ++++++++++++++++ stl/src/xfexp.cpp | 63 ------------------- 4 files changed, 55 insertions(+), 65 deletions(-) delete mode 100644 stl/src/xfexp.cpp diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 052b3fdb9d3..c8a38d881ff 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -286,7 +286,6 @@ set(SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/xexp.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xfdnorm.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xfdscale.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfexp.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xgetwctype.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xlgamma.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xlocale.cpp diff --git a/stl/msbuild/stl_base/stl.files.settings.targets b/stl/msbuild/stl_base/stl.files.settings.targets index 2ae545a2f92..0b1d1dd3117 100644 --- a/stl/msbuild/stl_base/stl.files.settings.targets +++ b/stl/msbuild/stl_base/stl.files.settings.targets @@ -80,7 +80,6 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - diff --git a/stl/src/xexp.cpp b/stl/src/xexp.cpp index 6b5a45ca5cb..4dd510b9eb7 100644 --- a/stl/src/xexp.cpp +++ b/stl/src/xexp.cpp @@ -160,4 +160,59 @@ _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _LExp(long double* px, long double y return _Exp(reinterpret_cast(px), static_cast(y), eoff); } +_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FExp(float* px, float y, short eoff) noexcept { + // compute y * e^(*px), (*px) finite, |y| not huge + + static constexpr float p[] = {1.0F, 60.09114349F}; + static constexpr float q[] = {12.01517514F, 120.18228722F}; + constexpr float c1 = (22713.0F / 32768.0F); + constexpr float c2 = 1.4286068203094172321214581765680755e-6F; + constexpr float hugexp = static_cast(_FMAX * 900L / 1000); + constexpr float invln2 = 1.4426950408889634073599246810018921F; + + if (y == 0.0F) { // zero + *px = y; + return 0; + } else if (*px < -hugexp) { // certain underflow + *px = _Xfe_underflow(y); + return 0; + } else if (hugexp < *px) { // certain overflow + *px = _Xfe_overflow(y); + return _INFCODE; + } else { // xexp won't overflow + float g = *px * invln2; + short xexp = static_cast(g + (g < 0.0F ? -0.5F : +0.5F)); + + g = xexp; + g = static_cast((*px - g * c1) - g * c2); + + constexpr float eps = 0x1p-25f; + if (-eps < g && g < eps) { + *px = y; + } else { // g * g worth computing + const float z = g * g; + const float w = q[0] * z + q[1]; + + g *= z + p[1]; + *px = (w + g) / (w - g) * 2.0F * y; + --xexp; + } + + const short result_code = _FDscale(px, static_cast(xexp) + eoff); + + switch (result_code) { + case 0: + *px = _Xfe_underflow(y); + break; + case _INFCODE: + *px = _Xfe_overflow(y); + break; + default: + break; + } + + return result_code; + } +} + _END_EXTERN_C_UNLESS_PURE diff --git a/stl/src/xfexp.cpp b/stl/src/xfexp.cpp deleted file mode 100644 index cfe5b7776d5..00000000000 --- a/stl/src/xfexp.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include "xmath.hpp" - -_EXTERN_C_UNLESS_PURE - -_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FExp(float* px, float y, short eoff) noexcept { - // compute y * e^(*px), (*px) finite, |y| not huge - - static constexpr float p[] = {1.0F, 60.09114349F}; - static constexpr float q[] = {12.01517514F, 120.18228722F}; - constexpr float c1 = (22713.0F / 32768.0F); - constexpr float c2 = 1.4286068203094172321214581765680755e-6F; - constexpr float hugexp = static_cast(_FMAX * 900L / 1000); - constexpr float invln2 = 1.4426950408889634073599246810018921F; - - if (y == 0.0F) { // zero - *px = y; - return 0; - } else if (*px < -hugexp) { // certain underflow - *px = _Xfe_underflow(y); - return 0; - } else if (hugexp < *px) { // certain overflow - *px = _Xfe_overflow(y); - return _INFCODE; - } else { // xexp won't overflow - float g = *px * invln2; - short xexp = static_cast(g + (g < 0.0F ? -0.5F : +0.5F)); - - g = xexp; - g = static_cast((*px - g * c1) - g * c2); - - constexpr float eps = 0x1p-25f; - if (-eps < g && g < eps) { - *px = y; - } else { // g * g worth computing - const float z = g * g; - const float w = q[0] * z + q[1]; - - g *= z + p[1]; - *px = (w + g) / (w - g) * 2.0F * y; - --xexp; - } - - const short result_code = _FDscale(px, static_cast(xexp) + eoff); - - switch (result_code) { - case 0: - *px = _Xfe_underflow(y); - break; - case _INFCODE: - *px = _Xfe_overflow(y); - break; - default: - break; - } - - return result_code; - } -} - -_END_EXTERN_C_UNLESS_PURE From d3fdf99b6d58aa9c98afe7742da460b18913cdb0 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 11 Dec 2025 03:06:51 -0800 Subject: [PATCH 12/18] Preserve `_Exp`, `_FExp`, `_LExp` for bincompat. I verified that this preserves their observable behavior (occasionally differing by 1 or 2 ULPs). This will allow `` to benefit from future compiler improvements to the accuracy of UCRT functions. Note that `` never used the `short` return value (an `fpclassify`-style code), and it always passed 0 for `short eoff`. --- stl/inc/complex | 28 +------ stl/inc/ymath.h | 5 -- stl/src/xexp.cpp | 207 ++--------------------------------------------- 3 files changed, 9 insertions(+), 231 deletions(-) diff --git a/stl/inc/complex b/stl/inc/complex index 42714a26ad6..04136d721bc 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -397,13 +397,6 @@ public: return static_cast<_Ty>(_Signbit(_Sign) ? -_Abs(_Magnitude) : _Abs(_Magnitude)); } - static short _Exp(_Ty* _Pleft, _Ty _Right, short _Exponent) { // compute exp(*_Pleft) * _Right * 2 ^ _Exponent - double _Tmp = static_cast(*_Pleft); - short _Ans = _CSTD _Exp(&_Tmp, static_cast(_Right), _Exponent); - *_Pleft = static_cast<_Ty>(_Tmp); - return _Ans; - } - static constexpr _Ty _Infv() { // return infinity return numeric_limits<_Ty>::infinity(); } @@ -536,11 +529,6 @@ public: return _CSTD copysignl(_Magnitude, _Sign); } - static short _Exp(_Ty* _Pleft, _Ty _Right, short _Exponent) noexcept { - // compute exp(*_Pleft) * _Right * 2 ^ _Exponent - return _CSTD _LExp(_Pleft, _Right, _Exponent); - } - static constexpr _Ty _Infv() noexcept { // return infinity return numeric_limits::infinity(); } @@ -680,11 +668,6 @@ public: return _CSTD copysign(_Magnitude, _Sign); } - static short _Exp(_Ty* _Pleft, _Ty _Right, short _Exponent) noexcept { - // compute exp(*_Pleft) * _Right * 2 ^ _Exponent - return _CSTD _Exp(_Pleft, _Right, _Exponent); - } - static constexpr _Ty _Infv() noexcept { // return infinity return numeric_limits::infinity(); } @@ -819,11 +802,6 @@ public: return _CSTD copysignf(_Magnitude, _Sign); } - static short _Exp(_Ty* _Pleft, _Ty _Right, short _Exponent) noexcept { - // compute exp(*_Pleft) * _Right * 2 ^ _Exponent - return _CSTD _FExp(_Pleft, _Right, _Exponent); - } - static constexpr _Ty _Infv() noexcept { // return infinity return numeric_limits::infinity(); } @@ -1875,10 +1853,8 @@ _NODISCARD complex<_Ty> exp(const complex<_Ty>& _Left) noexcept(_Is_unqual_fp<_T const _Ty _Theta = _STD imag(_Left); if (!_Ctraits<_Ty>::_Isnan(_Log_rho) && !_Ctraits<_Ty>::_Isinf(_Log_rho)) { // real component is finite - _Ty _Real = _Log_rho; - _Ty _Imag = _Log_rho; - _Ctraits<_Ty>::_Exp(&_Real, _Ctraits<_Ty>::cos(_Theta), 0); - _Ctraits<_Ty>::_Exp(&_Imag, _Ctraits<_Ty>::sin(_Theta), 0); + const _Ty _Real = _Ctraits<_Ty>::exp(_Log_rho) * _Ctraits<_Ty>::cos(_Theta); + const _Ty _Imag = _Ctraits<_Ty>::exp(_Log_rho) * _Ctraits<_Ty>::sin(_Theta); return complex<_Ty>(_Real, _Imag); } diff --git a/stl/inc/ymath.h b/stl/inc/ymath.h index 062c7964760..94550bfc751 100644 --- a/stl/inc/ymath.h +++ b/stl/inc/ymath.h @@ -20,12 +20,7 @@ _EXTERN_C_UNLESS_PURE #define _INFCODE 1 #define _NANCODE 2 -_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Exp(double*, double, short) noexcept; - -_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FExp(float*, float, short) noexcept; - _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _LDtest(long double*) noexcept; -_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _LExp(long double*, long double, short) noexcept; _END_EXTERN_C_UNLESS_PURE diff --git a/stl/src/xexp.cpp b/stl/src/xexp.cpp index 4dd510b9eb7..83182393a4b 100644 --- a/stl/src/xexp.cpp +++ b/stl/src/xexp.cpp @@ -3,216 +3,23 @@ #include "xmath.hpp" -namespace { - short _Dnorm(_Dval* ps) noexcept { // normalize double fraction - short xchar = 1; - unsigned short sign = static_cast(ps->_Sh[_D0] & _DSIGN); - - if ((ps->_Sh[_D0] &= _DFRAC) != 0 || ps->_Sh[_D1] || ps->_Sh[_D2] || ps->_Sh[_D3]) { // nonzero, scale - for (; ps->_Sh[_D0] == 0; xchar -= 16) { // shift left by 16 - ps->_Sh[_D0] = ps->_Sh[_D1]; - ps->_Sh[_D1] = ps->_Sh[_D2]; - ps->_Sh[_D2] = ps->_Sh[_D3]; - ps->_Sh[_D3] = 0; - } - for (; ps->_Sh[_D0] < 1 << _DOFF; --xchar) { // shift left by 1 - ps->_Sh[_D0] = static_cast(ps->_Sh[_D0] << 1 | ps->_Sh[_D1] >> 15); - ps->_Sh[_D1] = static_cast(ps->_Sh[_D1] << 1 | ps->_Sh[_D2] >> 15); - ps->_Sh[_D2] = static_cast(ps->_Sh[_D2] << 1 | ps->_Sh[_D3] >> 15); - ps->_Sh[_D3] <<= 1; - } - for (; 1 << (_DOFF + 1) <= ps->_Sh[_D0]; ++xchar) { // shift right by 1 - ps->_Sh[_D3] = static_cast(ps->_Sh[_D3] >> 1 | ps->_Sh[_D2] << 15); - ps->_Sh[_D2] = static_cast(ps->_Sh[_D2] >> 1 | ps->_Sh[_D1] << 15); - ps->_Sh[_D1] = static_cast(ps->_Sh[_D1] >> 1 | ps->_Sh[_D0] << 15); - ps->_Sh[_D0] >>= 1; - } - ps->_Sh[_D0] &= _DFRAC; - } - ps->_Sh[_D0] |= sign; - return xchar; - } - - short _Dscale(double* px, long lexp) noexcept { // scale *px by 2^xexp with checking - const auto ps = reinterpret_cast<_Dval*>(px); - short xchar = static_cast((ps->_Sh[_D0] & _DMASK) >> _DOFF); - - if (xchar == _DMAX) { - return (ps->_Sh[_D0] & _DFRAC) != 0 || ps->_Sh[_D1] != 0 || ps->_Sh[_D2] != 0 || ps->_Sh[_D3] != 0 - ? _NANCODE - : _INFCODE; - } else if (xchar == 0 && 0 < (xchar = _Dnorm(ps))) { - return 0; - } - - if (0 < lexp && _DMAX - xchar <= lexp) { // overflow, return +/-INF - constexpr double inf = _STD numeric_limits::infinity(); - - *px = ps->_Sh[_D0] & _DSIGN ? -inf : inf; - return _INFCODE; - } else if (-xchar < lexp) { // finite result, repack - ps->_Sh[_D0] = static_cast(ps->_Sh[_D0] & ~_DMASK | (lexp + xchar) << _DOFF); - return _FINITE; - } else { // denormalized, scale - unsigned short sign = static_cast(ps->_Sh[_D0] & _DSIGN); - - ps->_Sh[_D0] = static_cast(1 << _DOFF | ps->_Sh[_D0] & _DFRAC); - lexp += xchar - 1; - if (lexp < -(48 + 1 + _DOFF) || 0 <= lexp) { // certain underflow, return +/-0 - ps->_Sh[_D0] = sign; - ps->_Sh[_D1] = 0; - ps->_Sh[_D2] = 0; - ps->_Sh[_D3] = 0; - return 0; - } else { // nonzero, align fraction - short xexp = static_cast(lexp); - unsigned short psx = 0; - - for (; xexp <= -16; xexp += 16) { // scale by words - psx = ps->_Sh[_D3] | (psx != 0 ? 1 : 0); - ps->_Sh[_D3] = ps->_Sh[_D2]; - ps->_Sh[_D2] = ps->_Sh[_D1]; - ps->_Sh[_D1] = ps->_Sh[_D0]; - ps->_Sh[_D0] = 0; - } - if (xexp != 0) { // scale by bits - xexp = -xexp; - psx = (ps->_Sh[_D3] << (16 - xexp)) | (psx != 0 ? 1 : 0); - ps->_Sh[_D3] = static_cast(ps->_Sh[_D3] >> xexp | ps->_Sh[_D2] << (16 - xexp)); - ps->_Sh[_D2] = static_cast(ps->_Sh[_D2] >> xexp | ps->_Sh[_D1] << (16 - xexp)); - ps->_Sh[_D1] = static_cast(ps->_Sh[_D1] >> xexp | ps->_Sh[_D0] << (16 - xexp)); - ps->_Sh[_D0] >>= xexp; - } - - ps->_Sh[_D0] |= sign; - if ((0x8000 < psx || 0x8000 == psx && (ps->_Sh[_D3] & 0x0001) != 0) && (++ps->_Sh[_D3] & 0xffff) == 0 - && (++ps->_Sh[_D2] & 0xffff) == 0 && (++ps->_Sh[_D1] & 0xffff) == 0) { - ++ps->_Sh[_D0]; // round up - } else if (ps->_Sh[_D0] == sign && ps->_Sh[_D1] == 0 && ps->_Sh[_D2] == 0 && ps->_Sh[_D3] == 0) { - return 0; - } - - return _FINITE; - } - } - } -} // unnamed namespace - _EXTERN_C_UNLESS_PURE +// TRANSITION, ABI: preserved for binary compatibility _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Exp(double* px, double y, short eoff) noexcept { - // compute y * e^(*px), (*px) finite, |y| not huge - - // coefficients - static constexpr double p[] = {1.0, 420.30235984910635, 15132.70094680474802}; - static constexpr double q[] = {30.01511290683317, 3362.72154416553028, 30265.40189360949691}; - constexpr double c1 = 22713.0 / 32768.0; - constexpr double c2 = 1.4286068203094172321214581765680755e-6; - constexpr double hugexp = static_cast(_DMAX * 900L / 1000); - constexpr double invln2 = 1.4426950408889634073599246810018921; - - if (y == 0.0) { // zero - *px = y; - return 0; - } else if (*px < -hugexp) { // certain underflow - *px = _Xfe_underflow(y); - return 0; - } else if (hugexp < *px) { // certain overflow - *px = _Xfe_overflow(y); - return _INFCODE; - } else { // xexp won't overflow - double g = *px * invln2; - short xexp = static_cast(g + (g < 0.0 ? -0.5 : +0.5)); - - g = xexp; - g = (*px - g * c1) - g * c2; - - constexpr double eps = 0x1p-54; - if (-eps < g && g < eps) { - *px = y; - } else { // g * g worth computing - const double z = g * g; - const double w = (q[0] * z + q[1]) * z + q[2]; - - g *= (z + p[1]) * z + p[2]; - *px = (w + g) / (w - g) * 2.0 * y; - --xexp; - } - - const short result_code = _Dscale(px, static_cast(xexp) + eoff); - - switch (result_code) { - case 0: - *px = _Xfe_underflow(y); - break; - case _INFCODE: - *px = _Xfe_overflow(y); - break; - default: - break; - } - - return result_code; - } + *px = _STD exp(*px) * y * _STD exp2(static_cast(eoff)); + return static_cast(_STD fpclassify(*px)); } +// TRANSITION, ABI: preserved for binary compatibility _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _LExp(long double* px, long double y, short eoff) noexcept { return _Exp(reinterpret_cast(px), static_cast(y), eoff); } +// TRANSITION, ABI: preserved for binary compatibility _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FExp(float* px, float y, short eoff) noexcept { - // compute y * e^(*px), (*px) finite, |y| not huge - - static constexpr float p[] = {1.0F, 60.09114349F}; - static constexpr float q[] = {12.01517514F, 120.18228722F}; - constexpr float c1 = (22713.0F / 32768.0F); - constexpr float c2 = 1.4286068203094172321214581765680755e-6F; - constexpr float hugexp = static_cast(_FMAX * 900L / 1000); - constexpr float invln2 = 1.4426950408889634073599246810018921F; - - if (y == 0.0F) { // zero - *px = y; - return 0; - } else if (*px < -hugexp) { // certain underflow - *px = _Xfe_underflow(y); - return 0; - } else if (hugexp < *px) { // certain overflow - *px = _Xfe_overflow(y); - return _INFCODE; - } else { // xexp won't overflow - float g = *px * invln2; - short xexp = static_cast(g + (g < 0.0F ? -0.5F : +0.5F)); - - g = xexp; - g = static_cast((*px - g * c1) - g * c2); - - constexpr float eps = 0x1p-25f; - if (-eps < g && g < eps) { - *px = y; - } else { // g * g worth computing - const float z = g * g; - const float w = q[0] * z + q[1]; - - g *= z + p[1]; - *px = (w + g) / (w - g) * 2.0F * y; - --xexp; - } - - const short result_code = _FDscale(px, static_cast(xexp) + eoff); - - switch (result_code) { - case 0: - *px = _Xfe_underflow(y); - break; - case _INFCODE: - *px = _Xfe_overflow(y); - break; - default: - break; - } - - return result_code; - } + *px = _STD exp(*px) * y * _STD exp2(static_cast(eoff)); + return static_cast(_STD fpclassify(*px)); } _END_EXTERN_C_UNLESS_PURE From ba064e534e913c5b56e6d4598153df466fdd076e Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 11 Dec 2025 03:22:10 -0800 Subject: [PATCH 13/18] Remove non-dllexported `_FDnorm`, `_FDscale`, `_Xfe_overflow`, `_Xfe_underflow` functions, the `_Dval` and `_Fval` unions, and now-unused macros. --- stl/CMakeLists.txt | 2 - .../stl_base/stl.files.settings.targets | 2 - stl/src/xfdnorm.cpp | 35 ---------- stl/src/xfdscale.cpp | 67 ------------------- stl/src/xmath.hpp | 55 --------------- 5 files changed, 161 deletions(-) delete mode 100644 stl/src/xfdnorm.cpp delete mode 100644 stl/src/xfdscale.cpp diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index c8a38d881ff..f15d7ecbbfb 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -284,8 +284,6 @@ set(SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/xdateord.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xdtest.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xexp.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfdnorm.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfdscale.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xgetwctype.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xlgamma.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xlocale.cpp diff --git a/stl/msbuild/stl_base/stl.files.settings.targets b/stl/msbuild/stl_base/stl.files.settings.targets index 0b1d1dd3117..f4a9a133986 100644 --- a/stl/msbuild/stl_base/stl.files.settings.targets +++ b/stl/msbuild/stl_base/stl.files.settings.targets @@ -78,8 +78,6 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - - diff --git a/stl/src/xfdnorm.cpp b/stl/src/xfdnorm.cpp deleted file mode 100644 index 4ac5e671a0f..00000000000 --- a/stl/src/xfdnorm.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -// _FDnorm function -- IEEE 754 version - -#include "xmath.hpp" - -_EXTERN_C_UNLESS_PURE - -short _FDnorm(_Fval* ps) noexcept { // normalize float fraction - short xchar = 1; - unsigned short sign = static_cast(ps->_Sh[_F0] & _FSIGN); - - if ((ps->_Sh[_F0] &= _FFRAC) != 0 || ps->_Sh[_F1]) { // nonzero, scale - if (ps->_Sh[_F0] == 0) { - ps->_Sh[_F0] = ps->_Sh[_F1]; - ps->_Sh[_F1] = 0; - xchar -= 16; - } - - for (; ps->_Sh[_F0] < 1 << _FOFF; --xchar) { // shift left by 1 - ps->_Sh[_F0] = static_cast(ps->_Sh[_F0] << 1 | ps->_Sh[_F1] >> 15); - ps->_Sh[_F1] <<= 1; - } - for (; 1 << (_FOFF + 1) <= ps->_Sh[_F0]; ++xchar) { // shift right by 1 - ps->_Sh[_F1] = static_cast(ps->_Sh[_F1] >> 1 | ps->_Sh[_F0] << 15); - ps->_Sh[_F0] >>= 1; - } - ps->_Sh[_F0] &= _FFRAC; - } - ps->_Sh[_F0] |= sign; - return xchar; -} - -_END_EXTERN_C_UNLESS_PURE diff --git a/stl/src/xfdscale.cpp b/stl/src/xfdscale.cpp deleted file mode 100644 index cb5e27c2ef5..00000000000 --- a/stl/src/xfdscale.cpp +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -// _FDscale function -- IEEE 754 version - -#include "xmath.hpp" - -_EXTERN_C_UNLESS_PURE - -short _FDscale(float* px, long lexp) noexcept { // scale *px by 2^xexp with checking - const auto ps = reinterpret_cast<_Fval*>(px); - short xchar = static_cast((ps->_Sh[_F0] & _FMASK) >> _FOFF); - - if (xchar == _FMAX) { - return (ps->_Sh[_F0] & _FFRAC) != 0 || ps->_Sh[_F1] != 0 ? _NANCODE : _INFCODE; - } else if (xchar == 0 && 0 < (xchar = _FDnorm(ps))) { - return 0; - } - - if (0 < lexp && _FMAX - xchar <= lexp) { // overflow, return +/-INF - constexpr float inf = _STD numeric_limits::infinity(); - - *px = ps->_Sh[_F0] & _FSIGN ? -inf : inf; - return _INFCODE; - } else if (-xchar < lexp) { // finite result, repack - ps->_Sh[_F0] = static_cast(ps->_Sh[_F0] & ~_FMASK | (lexp + xchar) << _FOFF); - return _FINITE; - } else { // denormalized, scale - unsigned short sign = static_cast(ps->_Sh[_F0] & _FSIGN); - - ps->_Sh[_F0] = static_cast(1 << _FOFF | ps->_Sh[_F0] & _FFRAC); - lexp += xchar - 1; - if (lexp < -(16 + 1 + _FOFF) || 0 <= lexp) { // underflow, return +/-0 - ps->_Sh[_F0] = sign; - ps->_Sh[_F1] = 0; - return 0; - } else { // nonzero, align fraction - short xexp = static_cast(lexp); - unsigned short psx = 0; - - if (xexp <= -16) { // scale by words - psx = ps->_Sh[_F1]; - ps->_Sh[_F1] = ps->_Sh[_F0]; - ps->_Sh[_F0] = 0; - xexp += 16; - } - - if (xexp != 0) { // scale by bits - xexp = -xexp; - psx = (ps->_Sh[_F1] << (16 - xexp)) | (psx != 0 ? 1 : 0); - ps->_Sh[_F1] = static_cast(ps->_Sh[_F1] >> xexp | ps->_Sh[_F0] << (16 - xexp)); - ps->_Sh[_F0] >>= xexp; - } - - ps->_Sh[_F0] |= sign; - if ((0x8000 < psx || 0x8000 == psx && (ps->_Sh[_F1] & 0x0001) != 0) && (++ps->_Sh[_F1] & 0xffff) == 0) { - ++ps->_Sh[_F0]; // round up - } else if (ps->_Sh[_F0] == sign && ps->_Sh[_F1] == 0) { - return 0; - } - - return _FINITE; - } - } -} - -_END_EXTERN_C_UNLESS_PURE diff --git a/stl/src/xmath.hpp b/stl/src/xmath.hpp index ec8ac20482e..57c553c6843 100644 --- a/stl/src/xmath.hpp +++ b/stl/src/xmath.hpp @@ -7,58 +7,3 @@ #include #include #include - -// float properties -#define _D0 3 // little-endian, small long doubles -#define _D1 2 -#define _D2 1 -#define _D3 0 - -#define _F0 1 // little-endian -#define _F1 0 - -// macros for _Dtest return (0 => ZERO) -#define _DENORM (-2) // C9X only -#define _FINITE (-1) - -_EXTERN_C_UNLESS_PURE - -// double declarations -union _Dval { // pun floating type as integer array - unsigned short _Sh[8]; - double _Val; -}; - -// float declarations -union _Fval { // pun floating type as integer array - unsigned short _Sh[8]; - float _Val; -}; - -short _FDnorm(_Fval*) noexcept; -short _FDscale(float*, long) noexcept; - -_END_EXTERN_C_UNLESS_PURE - -// raise IEEE 754 exceptions -#ifndef _M_CEE_PURE -#pragma float_control(except, on, push) -#endif - -template -[[nodiscard]] T _Xfe_overflow(const T sign) noexcept { - static_assert(_STD is_floating_point_v, "Expected is_floating_point_v."); - constexpr T huge = _STD numeric_limits::max(); - return _STD copysign(huge, sign) * huge; -} - -template -[[nodiscard]] T _Xfe_underflow(const T sign) noexcept { - static_assert(_STD is_floating_point_v, "Expected is_floating_point_v."); - constexpr T tiny = _STD numeric_limits::min(); - return _STD copysign(tiny, sign) * tiny; -} - -#ifndef _M_CEE_PURE -#pragma float_control(pop) -#endif From 95883886b6692a0fed51331c6f619612e03783aa Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 11 Dec 2025 03:28:21 -0800 Subject: [PATCH 14/18] Delete xmath.hpp, replace with ``. --- stl/src/xcosh.cpp | 2 +- stl/src/xdtest.cpp | 2 +- stl/src/xexp.cpp | 2 +- stl/src/xmath.hpp | 9 --------- stl/src/xsinh.cpp | 2 +- stl/src/xvalues.cpp | 2 +- 6 files changed, 5 insertions(+), 14 deletions(-) delete mode 100644 stl/src/xmath.hpp diff --git a/stl/src/xcosh.cpp b/stl/src/xcosh.cpp index 5bf5c95d9d5..16e52df32b5 100644 --- a/stl/src/xcosh.cpp +++ b/stl/src/xcosh.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include "xmath.hpp" +#include _EXTERN_C_UNLESS_PURE diff --git a/stl/src/xdtest.cpp b/stl/src/xdtest.cpp index 4a00be6a988..6deac306079 100644 --- a/stl/src/xdtest.cpp +++ b/stl/src/xdtest.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include "xmath.hpp" +#include _EXTERN_C_UNLESS_PURE diff --git a/stl/src/xexp.cpp b/stl/src/xexp.cpp index 83182393a4b..56e6840802b 100644 --- a/stl/src/xexp.cpp +++ b/stl/src/xexp.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include "xmath.hpp" +#include _EXTERN_C_UNLESS_PURE diff --git a/stl/src/xmath.hpp b/stl/src/xmath.hpp deleted file mode 100644 index 57c553c6843..00000000000 --- a/stl/src/xmath.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#pragma once - -#include -#include -#include -#include diff --git a/stl/src/xsinh.cpp b/stl/src/xsinh.cpp index d79b1aaf32d..f3fcdffb996 100644 --- a/stl/src/xsinh.cpp +++ b/stl/src/xsinh.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include "xmath.hpp" +#include _EXTERN_C_UNLESS_PURE diff --git a/stl/src/xvalues.cpp b/stl/src/xvalues.cpp index dcc48528ff4..5fc593cdf0f 100644 --- a/stl/src/xvalues.cpp +++ b/stl/src/xvalues.cpp @@ -9,7 +9,7 @@ #endif #endif -#include "xmath.hpp" +#include _EXTERN_C_UNLESS_PURE From f97b4ad93ca124c78d4bfc08915f8f9c312e3930 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 11 Dec 2025 03:37:04 -0800 Subject: [PATCH 15/18] Delete internal but user-visible ``, fuse remnants into ``. --- stl/CMakeLists.txt | 1 - stl/inc/complex | 11 ++++++++--- stl/inc/header-units.json | 3 +-- stl/inc/ymath.h | 32 -------------------------------- 4 files changed, 9 insertions(+), 38 deletions(-) delete mode 100644 stl/inc/ymath.h diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index f15d7ecbbfb..c73165f7e37 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -174,7 +174,6 @@ set(HEADERS ${CMAKE_CURRENT_LIST_DIR}/inc/xtr1common ${CMAKE_CURRENT_LIST_DIR}/inc/xtree ${CMAKE_CURRENT_LIST_DIR}/inc/xutility - ${CMAKE_CURRENT_LIST_DIR}/inc/ymath.h ${CMAKE_CURRENT_LIST_DIR}/inc/yvals.h ${CMAKE_CURRENT_LIST_DIR}/inc/yvals_core.h ) diff --git a/stl/inc/complex b/stl/inc/complex index 04136d721bc..412338dfbf6 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -13,7 +13,6 @@ #include #include #include -#include #ifdef _M_CEE_PURE // no intrinsics for /clr:pure @@ -57,6 +56,12 @@ struct _C_ldouble_complex { #define _RE 0 #define _IM 1 +#if defined(__LDBL_DIG__) && __LDBL_DIG__ == 18 +_EXTERN_C_UNLESS_PURE +_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _LDtest(long double*) noexcept; +_END_EXTERN_C_UNLESS_PURE +#endif // ^^^ 80-bit long double (not supported by MSVC in general, see GH-1316) ^^^ + _STD_BEGIN // TRANSITION, workaround x86 ABI // On x86 ABI, floating-point by-value arguments and return values are passed in 80-bit x87 registers. @@ -535,7 +540,7 @@ public: static bool _Isinf(_Ty _Left) noexcept { // test for infinity #if defined(__LDBL_DIG__) && __LDBL_DIG__ == 18 - return _CSTD _LDtest(&_Left) == _INFCODE; + return _CSTD _LDtest(&_Left) == 1; // _INFCODE #else // ^^^ 80-bit long double (not supported by MSVC in general, see GH-1316) / 64-bit long double vvv const auto _Uint = _Bit_cast(_Left); return (_Uint & 0x7fffffffffffffffU) == 0x7ff0000000000000U; @@ -544,7 +549,7 @@ public: static _CONSTEXPR20 bool _Isnan(_Ty _Left) noexcept { #if defined(__LDBL_DIG__) && __LDBL_DIG__ == 18 - return _CSTD _LDtest(&_Left) == _NANCODE; + return _CSTD _LDtest(&_Left) == 2; // _NANCODE #else // ^^^ 80-bit long double (not supported by MSVC in general, see GH-1316) / 64-bit long double vvv const auto _Uint = _Bit_cast(_Left); return (_Uint & 0x7fffffffffffffffU) > 0x7ff0000000000000U; diff --git a/stl/inc/header-units.json b/stl/inc/header-units.json index 41d0c163b53..62242aa5fdc 100644 --- a/stl/inc/header-units.json +++ b/stl/inc/header-units.json @@ -167,8 +167,7 @@ "xtimec.h", "xtr1common", "xtree", - "xutility", - "ymath.h" + "xutility" // "yvals.h", // internal header, provides macros that control header inclusion // "yvals_core.h" // internal header, provides macros that control header inclusion ] diff --git a/stl/inc/ymath.h b/stl/inc/ymath.h deleted file mode 100644 index 94550bfc751..00000000000 --- a/stl/inc/ymath.h +++ /dev/null @@ -1,32 +0,0 @@ -// ymath.h internal header - -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#ifndef _YMATH -#define _YMATH -#include -#if _STL_COMPILER_PREPROCESSOR -#pragma pack(push, _CRT_PACKING) -#pragma warning(push, _STL_WARNING_LEVEL) -#pragma warning(disable : _STL_DISABLED_WARNINGS) -_STL_DISABLE_CLANG_WARNINGS -#pragma push_macro("new") -#undef new - -_EXTERN_C_UNLESS_PURE - -// macros for _Dtest return (0 => ZERO) -#define _INFCODE 1 -#define _NANCODE 2 - -_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _LDtest(long double*) noexcept; - -_END_EXTERN_C_UNLESS_PURE - -#pragma pop_macro("new") -_STL_RESTORE_CLANG_WARNINGS -#pragma warning(pop) -#pragma pack(pop) -#endif // _STL_COMPILER_PREPROCESSOR -#endif // _YMATH From 2ef76e019116f4d3f7b57fedbbdc1eb5660b9f7c Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 11 Dec 2025 05:19:34 -0800 Subject: [PATCH 16/18] Restore special case for zero to the `_Exp` codepaths. Enable passing libcxx tests. --- stl/inc/complex | 14 ++++++++++++-- stl/src/xexp.cpp | 10 ++++++++++ tests/libcxx/expected_results.txt | 2 -- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/stl/inc/complex b/stl/inc/complex index 412338dfbf6..fc9975e0bac 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -1858,8 +1858,18 @@ _NODISCARD complex<_Ty> exp(const complex<_Ty>& _Left) noexcept(_Is_unqual_fp<_T const _Ty _Theta = _STD imag(_Left); if (!_Ctraits<_Ty>::_Isnan(_Log_rho) && !_Ctraits<_Ty>::_Isinf(_Log_rho)) { // real component is finite - const _Ty _Real = _Ctraits<_Ty>::exp(_Log_rho) * _Ctraits<_Ty>::cos(_Theta); - const _Ty _Imag = _Ctraits<_Ty>::exp(_Log_rho) * _Ctraits<_Ty>::sin(_Theta); + const _Ty _Exp_log_rho = _Ctraits<_Ty>::exp(_Log_rho); + _Ty _Real = _Ctraits<_Ty>::cos(_Theta); + _Ty _Imag = _Ctraits<_Ty>::sin(_Theta); + + if (_Real != _Ty{0}) { + _Real = _Exp_log_rho * _Real; + } + + if (_Imag != _Ty{0}) { + _Imag = _Exp_log_rho * _Imag; + } + return complex<_Ty>(_Real, _Imag); } diff --git a/stl/src/xexp.cpp b/stl/src/xexp.cpp index 56e6840802b..6143474befc 100644 --- a/stl/src/xexp.cpp +++ b/stl/src/xexp.cpp @@ -7,6 +7,11 @@ _EXTERN_C_UNLESS_PURE // TRANSITION, ABI: preserved for binary compatibility _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Exp(double* px, double y, short eoff) noexcept { + if (y == 0.0) { + *px = y; + return 0; + } + *px = _STD exp(*px) * y * _STD exp2(static_cast(eoff)); return static_cast(_STD fpclassify(*px)); } @@ -18,6 +23,11 @@ _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _LExp(long double* px, long double y // TRANSITION, ABI: preserved for binary compatibility _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FExp(float* px, float y, short eoff) noexcept { + if (y == 0.0f) { + *px = y; + return 0; + } + *px = _STD exp(*px) * y * _STD exp2(static_cast(eoff)); return static_cast(_STD fpclassify(*px)); } diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index af5b3060adb..cddfedbe31b 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -1012,13 +1012,11 @@ std/numerics/complex.number/complex.transcendentals/acosh.pass.cpp FAIL std/numerics/complex.number/complex.transcendentals/asin.pass.cpp FAIL std/numerics/complex.number/complex.transcendentals/asinh.pass.cpp FAIL std/numerics/complex.number/complex.transcendentals/atanh.pass.cpp FAIL -std/numerics/complex.number/complex.transcendentals/cos.pass.cpp FAIL std/numerics/complex.number/complex.transcendentals/cosh.pass.cpp FAIL std/numerics/complex.number/complex.transcendentals/log10.pass.cpp FAIL std/numerics/complex.number/complex.transcendentals/pow_complex_complex.pass.cpp FAIL std/numerics/complex.number/complex.transcendentals/pow_complex_scalar.pass.cpp FAIL std/numerics/complex.number/complex.transcendentals/pow_scalar_complex.pass.cpp FAIL -std/numerics/complex.number/complex.transcendentals/sin.pass.cpp FAIL std/numerics/complex.number/complex.transcendentals/sinh.pass.cpp FAIL std/numerics/complex.number/complex.transcendentals/tanh.pass.cpp FAIL std/numerics/complex.number/complex.value.ops/norm.pass.cpp FAIL From 858b3b3200d2a0f927b3acda50e2ba7b239a80a9 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 11 Dec 2025 06:15:33 -0800 Subject: [PATCH 17/18] Overhaul GH_001059_hyperbolic_truncation to expect more accurate results. We're much closer to Wolfram Alpha now, although not quite perfect. --- .../GH_001059_hyperbolic_truncation/test.cpp | 78 +++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp b/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp index 0ab947ef960..e11a12d4ad9 100644 --- a/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp +++ b/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp @@ -8,56 +8,56 @@ #include #include -#include #include -#include -#include - +#include using namespace std; template -void Test(T x) { - const complex z{x}; - const T exp_over_2 = T{0.5} * real(exp(z)); - - const T cosh_expected = exp_over_2 + T{0.25} / exp_over_2; - const T cosh_calc = real(cosh(z)); - if (cosh_expected != cosh_calc) { - cout.precision(numeric_limits::digits10 + 2); - cout << "x = " << x << '\n' - << "cosh (expected) = " << cosh_expected << '\n' - << "cosh (calculated) = " << cosh_calc << endl; - assert(cosh_expected == cosh_calc); - } +struct TestCase { + T val; + T cosh_expected; + T sinh_expected; +}; - const T sinh_expected = exp_over_2 - T{0.25} / exp_over_2; - const T sinh_calc = real(sinh(z)); - if (sinh_expected != sinh_calc) { - cout.precision(numeric_limits::digits10 + 2); - cout << "x = " << x << '\n' - << "sinh (expected) = " << sinh_expected << '\n' - << "sinh (calculated) = " << sinh_calc << endl; - assert(sinh_expected == sinh_calc); +template +void test(const TestCase& tc) { + const complex z{tc.val}; + + const T cosh_calc = real(cosh(z)); + if (cosh_calc != tc.cosh_expected) { + printf("tc.val: %a (%.1000g); cosh_calc: %a (%.1000g); tc.cosh_expected: %a (%.1000g)\n", tc.val, tc.val, + cosh_calc, cosh_calc, tc.cosh_expected, tc.cosh_expected); + assert(cosh_calc == tc.cosh_expected); } -} -template -constexpr array GenerateValues() { - // {old crossover, difference ~ 1 ulp, difference ~ ulp/2} - constexpr int DIG = numeric_limits::digits; - return {DIG * 347L / 1000L, DIG * static_cast(0.347), (DIG + 1) * static_cast(0.347)}; + const T sinh_calc = real(sinh(z)); + if (sinh_calc != tc.sinh_expected) { + printf("tc.val: %a (%.1000g); sinh_calc: %a (%.1000g); tc.sinh_expected: %a (%.1000g)\n", tc.val, tc.val, + sinh_calc, sinh_calc, tc.sinh_expected, tc.sinh_expected); + assert(sinh_calc == tc.sinh_expected); + } } int main() { - constexpr auto fValues{GenerateValues()}; - for (const auto& x : fValues) { - Test(x); + // Precise values from Wolfram Alpha, rounded to float and double. + constexpr array, 3> fTests{{ + {0x1p+3f, 0x1.749eaap+10f, 0x1.749ea6p+10f}, + {0x1.0a7efap+3f, 0x1.02a222p+11f, 0x1.02a22p+11f}, + {0x1.15999ap+3f, 0x1.6deb38p+11f, 0x1.6deb36p+11f}, + }}; + + constexpr array, 3> dTests{{ + {0x1.2p+4, 0x1.f4f22091940bfp+24, 0x1.f4f22091940bbp+24}, + {0x1.264189374bc6ap+4, 0x1.7250551723516p+25, + 0x1.7250551723514p+25 /* TRANSITION, sinh_expected should be 0x1.7250551723515p+25 */}, + {0x1.2bced916872bp+4, 0x1.05f68c44177a1p+26, 0x1.05f68c44177ap+26}, + }}; + + for (const auto& tc : fTests) { + test(tc); } - constexpr auto dValues{GenerateValues()}; - for (const auto& x : dValues) { - Test(x); + for (const auto& tc : dTests) { + test(tc); } - - return 0; } From 3a6a997ca5bf9f5dc035988a140c083dbdb39019 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 11 Dec 2025 07:23:40 -0800 Subject: [PATCH 18/18] x86 actually behaves correctly. --- .../std/tests/GH_001059_hyperbolic_truncation/test.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp b/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp index e11a12d4ad9..34799246784 100644 --- a/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp +++ b/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp @@ -48,8 +48,14 @@ int main() { constexpr array, 3> dTests{{ {0x1.2p+4, 0x1.f4f22091940bfp+24, 0x1.f4f22091940bbp+24}, - {0x1.264189374bc6ap+4, 0x1.7250551723516p+25, - 0x1.7250551723514p+25 /* TRANSITION, sinh_expected should be 0x1.7250551723515p+25 */}, + { + 0x1.264189374bc6ap+4, 0x1.7250551723516p+25, +#ifdef _M_IX86 // TRANSITION, accuracy issue + 0x1.7250551723515p+25 // Wolfram Alpha +#else // ^^^ no workaround / workaround vvv + 0x1.7250551723514p+25 // observed behavior +#endif // ^^^ workaround ^^^ + }, {0x1.2bced916872bp+4, 0x1.05f68c44177a1p+26, 0x1.05f68c44177ap+26}, }};