diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 1f08f33bb36..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 ) @@ -284,13 +283,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 - ${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/inc/complex b/stl/inc/complex index acd727f40c6..fc9975e0bac 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. @@ -390,20 +395,13 @@ 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) { 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(); } @@ -429,7 +427,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) { @@ -528,7 +526,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 { @@ -536,18 +534,13 @@ 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(); } 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; @@ -556,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; @@ -573,7 +566,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 { @@ -672,7 +665,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 { @@ -680,11 +673,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(); } @@ -709,7 +697,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 { @@ -811,7 +799,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 { @@ -819,11 +807,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(); } @@ -848,7 +831,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 { @@ -1875,10 +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 - _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 _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/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 6c1adbe4421..00000000000 --- a/stl/inc/ymath.h +++ /dev/null @@ -1,43 +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 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; - -_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 diff --git a/stl/msbuild/stl_base/stl.files.settings.targets b/stl/msbuild/stl_base/stl.files.settings.targets index 95fd85f8970..f4a9a133986 100644 --- a/stl/msbuild/stl_base/stl.files.settings.targets +++ b/stl/msbuild/stl_base/stl.files.settings.targets @@ -78,13 +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..16e52df32b5 100644 --- a/stl/src/xcosh.cpp +++ b/stl/src/xcosh.cpp @@ -1,43 +1,23 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include "xmath.hpp" +#include _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; +} + +// 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 diff --git a/stl/src/xdtest.cpp b/stl/src/xdtest.cpp index caaa62f0851..6deac306079 100644 --- a/stl/src/xdtest.cpp +++ b/stl/src/xdtest.cpp @@ -1,27 +1,23 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// _Dtest function -- IEEE 754 version - -#include "xmath.hpp" +#include _EXTERN_C_UNLESS_PURE -_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Dtest(double* px) noexcept { // categorize *px - const auto ps = reinterpret_cast<_Dval*>(px); +// TRANSITION, ABI: preserved for binary compatibility +_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Dtest(double* px) noexcept { + return static_cast(_STD fpclassify(*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; - } +// TRANSITION, ABI: preserved for binary compatibility +_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _LDtest(long double* px) noexcept { + return static_cast(_STD fpclassify(*px)); } -_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 { + return static_cast(_STD fpclassify(*px)); } _END_EXTERN_C_UNLESS_PURE diff --git a/stl/src/xexp.cpp b/stl/src/xexp.cpp index 6b5a45ca5cb..6143474befc 100644 --- a/stl/src/xexp.cpp +++ b/stl/src/xexp.cpp @@ -1,163 +1,35 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#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 +#include _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 + if (y == 0.0) { *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 { + if (y == 0.0f) { + *px = y; + return 0; + } + + *px = _STD exp(*px) * y * _STD exp2(static_cast(eoff)); + return static_cast(_STD fpclassify(*px)); +} + _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 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/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 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/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 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/xmath.hpp b/stl/src/xmath.hpp deleted file mode 100644 index a884f145f89..00000000000 --- a/stl/src/xmath.hpp +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#pragma once - -#include -#include -#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 -#define _D2 1 -#define _D3 0 - -#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) - -_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; - -// double declarations -union _Dval { // pun floating type as integer array - unsigned short _Sh[8]; - double _Val; -}; - -extern const double _Xbig; - -// 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; - -extern const float _FXbig; - -_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 diff --git a/stl/src/xsinh.cpp b/stl/src/xsinh.cpp index 1def63635b0..f3fcdffb996 100644 --- a/stl/src/xsinh.cpp +++ b/stl/src/xsinh.cpp @@ -1,80 +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 +#include _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 { + return _STD sinh(x) * y; } _END_EXTERN_C_UNLESS_PURE diff --git a/stl/src/xvalues.cpp b/stl/src/xvalues.cpp index 0fb45636130..5fc593cdf0f 100644 --- a/stl/src/xvalues.cpp +++ b/stl/src/xvalues.cpp @@ -9,13 +9,10 @@ #endif #endif -#include "xmath.hpp" +#include _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/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 diff --git a/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp b/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp index 67d69e1bb9a..34799246784 100644 --- a/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp +++ b/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp @@ -2,62 +2,68 @@ // 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 #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 auto dValues{GenerateValues()}; - for (const auto& x : dValues) { - Test(x); + constexpr array, 3> dTests{{ + {0x1.2p+4, 0x1.f4f22091940bfp+24, 0x1.f4f22091940bbp+24}, + { + 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}, + }}; + + for (const auto& tc : fTests) { + test(tc); } - return 0; + for (const auto& tc : dTests) { + test(tc); + } }