mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-27 00:28:14 +00:00
Merge pull request #10742 from 00xDisaster/feat/libc-lcosh
feat(libc): implement _LCosh and _LSinh
This commit is contained in:
4 files changed
+86
No files matched your search
@@ -692,6 +692,8 @@ void APS5_VABI srand_nid_postfix(unsigned int seed);
|
||||
int APS5_VABI __fpclassifyd_nid_postfix(double value);
|
||||
double APS5_VABI _Sinh_nid_postfix(double x, double y);
|
||||
double APS5_VABI _Cosh_nid_postfix(double x, double y);
|
||||
long double APS5_VABI _LCosh_nid_postfix(long double x, long double y);
|
||||
long double APS5_VABI _LSinh_nid_postfix(long double x, long double y);
|
||||
int APS5_VABI _Fltrounds_nid_postfix(void);
|
||||
int APS5_VABI fegetenv_nid_postfix(GuestFloatingPointEnvironment* environment);
|
||||
long double APS5_VABI copysignl_nid_postfix(long double x, long double y);
|
||||
|
||||
@@ -1531,6 +1531,50 @@ double APS5_VABI _Cosh_nid_postfix(double x, double y) {
|
||||
return std::scalbn(scale * (0.5 * std::exp(reduced)), scaleExponent + exponent);
|
||||
}
|
||||
|
||||
long double APS5_VABI _LCosh_nid_postfix(long double x, long double y) {
|
||||
if (!std::isfinite(x) || !std::isfinite(y)) return y * std::cosh(x);
|
||||
if (y == 0.0L) return std::copysign(0.0L, y);
|
||||
constexpr long double Ln2High = 0x1.62e42fefa0000p-1L;
|
||||
constexpr long double Ln2Low = 0x1.cf79abc9e3b398p-40L;
|
||||
constexpr long double InverseLn2 = 0x1.71547652b82fe178p+0L;
|
||||
const long double magnitude = std::abs(x);
|
||||
if (magnitude <= (std::numeric_limits<long double>::max_exponent - 1) * (Ln2High + Ln2Low))
|
||||
return y * std::cosh(x);
|
||||
int scaleExponent;
|
||||
const long double scale = std::frexp(y, &scaleExponent);
|
||||
constexpr int MaximumExponentSpan = std::numeric_limits<long double>::max_exponent -
|
||||
std::numeric_limits<long double>::min_exponent + std::numeric_limits<long double>::digits + 4;
|
||||
if (magnitude > MaximumExponentSpan * (Ln2High + Ln2Low))
|
||||
return std::scalbn(scale, INT_MAX);
|
||||
const int exponent = static_cast<int>(magnitude * InverseLn2);
|
||||
const long double reduced = std::fma(-exponent, Ln2Low, std::fma(-exponent, Ln2High, magnitude));
|
||||
return std::scalbn(scale * (0.5L * std::exp(reduced)), scaleExponent + exponent);
|
||||
}
|
||||
|
||||
long double APS5_VABI _LSinh_nid_postfix(long double x, long double y) {
|
||||
if (!std::isfinite(x) || !std::isfinite(y)) return y * std::sinh(x);
|
||||
if (y == 0.0L) {
|
||||
const bool negative = std::signbit(x) != std::signbit(y);
|
||||
return std::copysign(0.0L, negative ? -1.0L : 1.0L);
|
||||
}
|
||||
constexpr long double Ln2High = 0x1.62e42fefa0000p-1L;
|
||||
constexpr long double Ln2Low = 0x1.cf79abc9e3b398p-40L;
|
||||
constexpr long double InverseLn2 = 0x1.71547652b82fe178p+0L;
|
||||
const long double magnitude = std::abs(x);
|
||||
if (magnitude <= (std::numeric_limits<long double>::max_exponent - 1) * (Ln2High + Ln2Low))
|
||||
return y * std::sinh(x);
|
||||
int scaleExponent;
|
||||
const long double scale = std::frexp(y, &scaleExponent);
|
||||
constexpr int MaximumExponentSpan = std::numeric_limits<long double>::max_exponent -
|
||||
std::numeric_limits<long double>::min_exponent + std::numeric_limits<long double>::digits + 4;
|
||||
const long double sign = std::copysign(1.0L, x);
|
||||
if (magnitude > MaximumExponentSpan * (Ln2High + Ln2Low))
|
||||
return sign * std::scalbn(scale, INT_MAX);
|
||||
const int exponent = static_cast<int>(magnitude * InverseLn2);
|
||||
const long double reduced = std::fma(-exponent, Ln2Low, std::fma(-exponent, Ln2High, magnitude));
|
||||
return sign * std::scalbn(scale * (0.5L * std::exp(reduced)), scaleExponent + exponent);
|
||||
}
|
||||
|
||||
int APS5_VABI _Fltrounds_nid_postfix(void) {
|
||||
return SonyFltrounds();
|
||||
}
|
||||
|
||||
@@ -1475,6 +1475,44 @@ static void CheckAcosfMsun() {
|
||||
Require(std::bit_cast<std::uint32_t>(acosf_nid_postfix(std::bit_cast<float>(0x32800000u))) == 0x3fc90fdbu);
|
||||
}
|
||||
|
||||
static void CheckLongDoubleHyperbolic() {
|
||||
const long double infinity = std::numeric_limits<long double>::infinity();
|
||||
const long double nan = std::numeric_limits<long double>::quiet_NaN();
|
||||
Require(_LCosh_nid_postfix(0.0L, 2.0L) == 2.0L);
|
||||
Require(Near(_LCosh_nid_postfix(1.0L, 2.0L), 3.08616126963048755696L));
|
||||
Require(Near(_LCosh_nid_postfix(-1.0L, -2.0L), -3.08616126963048755696L));
|
||||
Require(std::isinf(_LCosh_nid_postfix(infinity, -1.0L)) && std::signbit(_LCosh_nid_postfix(infinity, -1.0L)));
|
||||
Require(std::isnan(_LCosh_nid_postfix(infinity, 0.0L)));
|
||||
Require(std::isnan(_LCosh_nid_postfix(nan, 1.0L)));
|
||||
Require(_LCosh_nid_postfix(720.0L, 0.0L) == 0.0L && !std::signbit(_LCosh_nid_postfix(720.0L, 0.0L)));
|
||||
Require(_LCosh_nid_postfix(720.0L, -0.0L) == 0.0L && std::signbit(_LCosh_nid_postfix(720.0L, -0.0L)));
|
||||
Require(Near(_LCosh_nid_postfix(11357.0L, 0x1p-16000L), 0xc.e2773666cc8cc68p+380L));
|
||||
Require(Near(_LCosh_nid_postfix(-11357.0L, 0x1p-16000L), 0xc.e2773666cc8cc68p+380L));
|
||||
Require(Near(_LCosh_nid_postfix(11360.0L, 0x1p-16384L), 0x8.165ba1f5c0ff231p+1L));
|
||||
Require(std::isinf(_LCosh_nid_postfix(11360.0L, 1.0L)));
|
||||
Require(_LSinh_nid_postfix(0.0L, 2.0L) == 0.0L && !std::signbit(_LSinh_nid_postfix(0.0L, 2.0L)));
|
||||
Require(_LSinh_nid_postfix(0.0L, -2.0L) == 0.0L && std::signbit(_LSinh_nid_postfix(0.0L, -2.0L)));
|
||||
Require(Near(_LSinh_nid_postfix(1.0L, 2.0L), 2.35040238728760291376L));
|
||||
Require(Near(_LSinh_nid_postfix(-1.0L, -2.0L), 2.35040238728760291376L));
|
||||
Require(Near(_LSinh_nid_postfix(1.0L, -2.0L), -2.35040238728760291376L));
|
||||
Require(std::isinf(_LSinh_nid_postfix(infinity, -1.0L)) && std::signbit(_LSinh_nid_postfix(infinity, -1.0L)));
|
||||
Require(std::isinf(_LSinh_nid_postfix(-infinity, -1.0L)) && !std::signbit(_LSinh_nid_postfix(-infinity, -1.0L)));
|
||||
Require(std::isnan(_LSinh_nid_postfix(infinity, 0.0L)));
|
||||
Require(std::isnan(_LSinh_nid_postfix(nan, 1.0L)));
|
||||
Require(_LSinh_nid_postfix(720.0L, 0.0L) == 0.0L && !std::signbit(_LSinh_nid_postfix(720.0L, 0.0L)));
|
||||
Require(_LSinh_nid_postfix(720.0L, -0.0L) == 0.0L && std::signbit(_LSinh_nid_postfix(720.0L, -0.0L)));
|
||||
Require(_LSinh_nid_postfix(-720.0L, 0.0L) == 0.0L && std::signbit(_LSinh_nid_postfix(-720.0L, 0.0L)));
|
||||
Require(_LSinh_nid_postfix(-720.0L, -0.0L) == 0.0L && !std::signbit(_LSinh_nid_postfix(-720.0L, -0.0L)));
|
||||
Require(Near(_LSinh_nid_postfix(11357.0L, 0x1p-16000L), 0xc.e2773666cc8cc68p+380L));
|
||||
Require(Near(_LSinh_nid_postfix(-11357.0L, 0x1p-16000L), -0xc.e2773666cc8cc68p+380L));
|
||||
Require(Near(_LSinh_nid_postfix(11357.0L, -0x1p-16000L), -0xc.e2773666cc8cc68p+380L));
|
||||
Require(Near(_LSinh_nid_postfix(-11357.0L, -0x1p-16000L), 0xc.e2773666cc8cc68p+380L));
|
||||
Require(Near(_LSinh_nid_postfix(11360.0L, 0x1p-16384L), 0x8.165ba1f5c0ff231p+1L));
|
||||
Require(Near(_LSinh_nid_postfix(-11360.0L, 0x1p-16384L), -0x8.165ba1f5c0ff231p+1L));
|
||||
Require(std::isinf(_LSinh_nid_postfix(11360.0L, 1.0L)));
|
||||
Require(std::isinf(_LSinh_nid_postfix(-11360.0L, 1.0L)) && std::signbit(_LSinh_nid_postfix(-11360.0L, 1.0L)));
|
||||
}
|
||||
|
||||
static void CheckLongDoubleFunctions() {
|
||||
const long double infinity = std::numeric_limits<long double>::infinity();
|
||||
const long double nan = std::numeric_limits<long double>::quiet_NaN();
|
||||
@@ -1956,5 +1994,6 @@ int main() {
|
||||
CheckIntegerAbsAndDivision();
|
||||
CheckScaling();
|
||||
CheckLongDoubleFunctions();
|
||||
CheckLongDoubleHyperbolic();
|
||||
CheckDinkumwareFloatCharacteristics();
|
||||
}
|
||||
@@ -75,6 +75,7 @@
|
||||
- [_Cosh](../../../core/libs/prx/libc/src/Math.cpp) (libc) follows the two-argument Dinkumware CRT helper used by `std::complex`, including a scaled large-finite-input path; the signature, exact result and floating-point exception behavior are not verified against the console.
|
||||
- [std::thread::hardware_concurrency](../../../core/libs/prx/libc/src/Threads.cpp) (libc, NID `CHrhwd8QSBs`) returns the host's `std::thread::hardware_concurrency()` (which may be 0 when unknown) instead of the console's processor count; no reference implements it and the value a title expects (PPSA34015 imports it) is unverified.
|
||||
- [fmodf](../../../core/libs/prx/libc/src/Math.cpp) (libc) - console `errno`, exception flags and NaN payloads remain unverified. The wrapper preserves `errno` like the existing double `fmod`, following FreeBSD 11.4 [`e_fmodf.c`](https://github.com/freebsd/freebsd-src/blob/release/11.4.0/lib/msun/src/e_fmodf.c); host `std::fmod` still supplies the result and exception flags.
|
||||
- [_LCosh and _LSinh](../../../core/libs/prx/libc/src/Math.cpp) (libc) follow the two-argument Dinkumware CRT helpers `y * cosh(x)` and `y * sinh(x)`, including scaled large-finite-input paths; the signatures are confirmed by Dinkumware's public `ymath.h`, but the exact console results, range-error thresholds and floating-point exception behavior are not verified.
|
||||
- [_FSinh and _FCosh](../../../core/libs/prx/libc/src/Math.cpp) (libc) finite results are not verified bit for bit against the console: the scaled product uses the host's binary64 hyperbolic function before rounding to binary32, rather than the float rational and `_FExp` sequence in PRAGMATA's bundled `libc.prx`. NaN preference and payloads, signed zeros, infinite operands and the range-error thresholds follow that binary's instructions; the system `libSceLibcInternal` implementation and nondefault flush-to-zero modes are unverified. Against `libSceLibcInternal.sprx` on a PS5 (firmware 13.60), 12 of 36 measured results differ by one unit in the last place (`_FSinh(0.5, y)` and `_FCosh(1, y)`, `_FCosh(10, y)` for y of 0.5, 1 and 2); zeros, the overflow to infinity at 89 and 90 and the tiny-argument results matched
|
||||
- [_Divide, _FDivide, _Recip and _FRecip](../../../core/libs/prx/libc/src/DinkumwareInternals.cpp) (libc) follow the Dinkumware CRT division and reciprocal contracts with IEEE-754 signed-zero, infinity and NaN behavior. The exact console results, signaling-NaN handling and floating-point exception behavior are not verified.
|
||||
|
||||
|
||||
Reference in new issue
Block a user