feat(libc): implement the long double math functions RetroArch imports
This commit is contained in:
parent
8d57710c95
commit
a36b9092d1
|
|
@ -168,6 +168,22 @@ double APS5_VABI modf_nid_postfix(double x, double* integral) { return std::modf
|
|||
float APS5_VABI modff_nid_postfix(float x, float* integral) { return std::modf(x, integral); }
|
||||
double APS5_VABI tanh_nid_postfix(double x) { return std::tanh(x); }
|
||||
float APS5_VABI tanhf_nid_postfix(float x) { return std::tanh(x); }
|
||||
long double APS5_VABI atanl_nid_postfix(long double x) { return std::atan(x); }
|
||||
long double APS5_VABI sinl_nid_postfix(long double x) { return std::sin(x); }
|
||||
long double APS5_VABI cosl_nid_postfix(long double x) { return std::cos(x); }
|
||||
long double APS5_VABI tanl_nid_postfix(long double x) { return std::tan(x); }
|
||||
long double APS5_VABI sinhl_nid_postfix(long double x) { return std::sinh(x); }
|
||||
long double APS5_VABI coshl_nid_postfix(long double x) { return std::cosh(x); }
|
||||
long double APS5_VABI tanhl_nid_postfix(long double x) { return std::tanh(x); }
|
||||
long double APS5_VABI expl_nid_postfix(long double x) { return std::exp(x); }
|
||||
long double APS5_VABI exp2l_nid_postfix(long double x) { return std::exp2(x); }
|
||||
long double APS5_VABI logl_nid_postfix(long double x) { return std::log(x); }
|
||||
long double APS5_VABI log10l_nid_postfix(long double x) { return std::log10(x); }
|
||||
long double APS5_VABI powl_nid_postfix(long double base, long double exp) { return std::pow(base, exp); }
|
||||
long double APS5_VABI ldexpl_nid_postfix(long double x, int exp) { return std::ldexp(x, exp); }
|
||||
long double APS5_VABI truncl_nid_postfix(long double x) { return std::trunc(x); }
|
||||
double APS5_VABI logb_nid_postfix(double x) { return std::logb(x); }
|
||||
double APS5_VABI remainder_nid_postfix(double x, double y) { return std::remainder(x, y); }
|
||||
float APS5_VABI _FSinh_nid_postfix(float x, float y) { return y * std::sinh(x); }
|
||||
float APS5_VABI _FCosh_nid_postfix(float x, float y) { return y * std::cosh(x); }
|
||||
|
||||
|
|
|
|||
|
|
@ -83,6 +83,22 @@ std::lldiv_t APS5_VABI lldiv_nid_postfix(long long, long long);
|
|||
std::lldiv_t APS5_VABI ldiv_nid_postfix(std::int64_t, std::int64_t);
|
||||
float APS5_VABI nanf_nid_postfix(const char*);
|
||||
double APS5_VABI nan_nid_postfix(const char*);
|
||||
long double APS5_VABI atanl_nid_postfix(long double);
|
||||
long double APS5_VABI sinl_nid_postfix(long double);
|
||||
long double APS5_VABI cosl_nid_postfix(long double);
|
||||
long double APS5_VABI tanl_nid_postfix(long double);
|
||||
long double APS5_VABI sinhl_nid_postfix(long double);
|
||||
long double APS5_VABI coshl_nid_postfix(long double);
|
||||
long double APS5_VABI tanhl_nid_postfix(long double);
|
||||
long double APS5_VABI expl_nid_postfix(long double);
|
||||
long double APS5_VABI exp2l_nid_postfix(long double);
|
||||
long double APS5_VABI logl_nid_postfix(long double);
|
||||
long double APS5_VABI log10l_nid_postfix(long double);
|
||||
long double APS5_VABI powl_nid_postfix(long double, long double);
|
||||
long double APS5_VABI ldexpl_nid_postfix(long double, int);
|
||||
long double APS5_VABI truncl_nid_postfix(long double);
|
||||
double APS5_VABI logb_nid_postfix(double);
|
||||
double APS5_VABI remainder_nid_postfix(double, double);
|
||||
}
|
||||
static void Require(bool value) { if (!value) std::abort(); }
|
||||
|
||||
|
|
@ -313,6 +329,40 @@ static void CheckAsin() {
|
|||
Require(!std::fetestexcept(FE_INVALID));
|
||||
}
|
||||
|
||||
static void CheckExtendedMath() {
|
||||
Require(ExtendedBits(atanl_nid_postfix(INFINITY), 0xc90fdaa22168c235ull, 0x3fff));
|
||||
Require(std::fabs(atanl_nid_postfix(1.0L) - 0.785398163397448309616L) < 1e-18L);
|
||||
Require(std::fabs(sinl_nid_postfix(0.5L) - 0.479425538604203000273L) < 1e-18L);
|
||||
Require(std::fabs(cosl_nid_postfix(0.5L) - 0.877582561890372716116L) < 1e-18L);
|
||||
Require(std::fabs(tanl_nid_postfix(0.5L) - 0.546302489843790513255L) < 1e-18L);
|
||||
Require(std::fabs(sinhl_nid_postfix(1.0L) - 1.17520119364380145688L) < 1e-18L);
|
||||
Require(std::fabs(coshl_nid_postfix(1.0L) - 1.54308063481524377848L) < 1e-18L);
|
||||
Require(std::fabs(tanhl_nid_postfix(0.5L) - 0.462117157260009758502L) < 1e-18L);
|
||||
Require(std::fabs(expl_nid_postfix(1.0L) - 2.71828182845904523536L) < 1e-18L);
|
||||
Require(std::fabs(logl_nid_postfix(2.0L) - 0.693147180559945309417L) < 1e-18L);
|
||||
Require(sinl_nid_postfix(0.0L) == 0.0L && std::signbit(sinl_nid_postfix(-0.0L)) && cosl_nid_postfix(0.0L) == 1.0L);
|
||||
Require(std::isnan(sinl_nid_postfix(INFINITY)) && std::isnan(cosl_nid_postfix(-INFINITY)) && std::isnan(tanl_nid_postfix(INFINITY)));
|
||||
Require(sinhl_nid_postfix(-INFINITY) == -INFINITY && coshl_nid_postfix(-INFINITY) == INFINITY && tanhl_nid_postfix(INFINITY) == 1.0L);
|
||||
Require(sinhl_nid_postfix(11358.0L) == INFINITY && std::isfinite(sinhl_nid_postfix(11356.0L)) && std::isfinite(coshl_nid_postfix(11356.0L)));
|
||||
Require(expl_nid_postfix(0.0L) == 1.0L && expl_nid_postfix(-INFINITY) == 0.0L && expl_nid_postfix(11357.0L) == INFINITY);
|
||||
Require(exp2l_nid_postfix(10.0L) == 1024.0L && exp2l_nid_postfix(-16446.0L) == 0.0L && exp2l_nid_postfix(16384.0L) == INFINITY);
|
||||
Require(ExtendedBits(exp2l_nid_postfix(-16445.0L), 1, 0) && ExtendedBits(exp2l_nid_postfix(-16444.0L), 2, 0));
|
||||
Require(logl_nid_postfix(1.0L) == 0.0L && logl_nid_postfix(0.0L) == -INFINITY && std::isnan(logl_nid_postfix(-1.0L)));
|
||||
Require(std::fabs(log10l_nid_postfix(1000.0L) - 3.0L) < 1e-18L && log10l_nid_postfix(1.0L) == 0.0L);
|
||||
Require(log10l_nid_postfix(0.0L) == -INFINITY && std::isnan(log10l_nid_postfix(-1.0L)));
|
||||
Require(powl_nid_postfix(2.0L, 64.0L) == 18446744073709551616.0L && powl_nid_postfix(-2.0L, 3.0L) == -8.0L);
|
||||
Require(powl_nid_postfix(0.0L, -1.0L) == INFINITY && powl_nid_postfix(1.0L, NAN) == 1.0L && std::isnan(powl_nid_postfix(-2.0L, 0.5L)));
|
||||
Require(ldexpl_nid_postfix(1.0L, 16383) == 0x1p16383L && ldexpl_nid_postfix(1.0L, 16384) == INFINITY && ldexpl_nid_postfix(3.0L, -2) == 0.75L);
|
||||
Require(ExtendedBits(ldexpl_nid_postfix(1.0L, -16445), 1, 0) && ldexpl_nid_postfix(1.0L, -16446) == 0.0L);
|
||||
Require(truncl_nid_postfix(2.7L) == 2.0L && truncl_nid_postfix(-2.7L) == -2.0L && ExtendedBits(truncl_nid_postfix(-0.5L), 0, 0x8000));
|
||||
Require(truncl_nid_postfix(9223372036854775807.5L) == 9223372036854775807.0L && truncl_nid_postfix(-INFINITY) == -INFINITY);
|
||||
Require(logb_nid_postfix(8.0) == 3.0 && logb_nid_postfix(0.75) == -1.0 && logb_nid_postfix(0x1p-1074) == -1074.0);
|
||||
Require(logb_nid_postfix(0.0) == -INFINITY && logb_nid_postfix(-INFINITY) == INFINITY && std::isnan(logb_nid_postfix(NAN)));
|
||||
Require(remainder_nid_postfix(5.0, 3.0) == -1.0 && remainder_nid_postfix(7.0, 2.0) == -1.0 && remainder_nid_postfix(5.0, 2.0) == 1.0);
|
||||
Require(std::signbit(remainder_nid_postfix(-4.0, 2.0)) && remainder_nid_postfix(1.0, INFINITY) == 1.0);
|
||||
Require(std::isnan(remainder_nid_postfix(1.0, 0.0)) && std::isnan(remainder_nid_postfix(INFINITY, 1.0)));
|
||||
}
|
||||
|
||||
static void CheckHyperbolic() {
|
||||
const double infinity = std::numeric_limits<double>::infinity();
|
||||
Require(sinh_nid_postfix(0.) == 0. && std::signbit(sinh_nid_postfix(-0.)));
|
||||
|
|
@ -385,6 +435,7 @@ static void CheckFloatRounding(float value, std::int64_t expected, bool invalid)
|
|||
int main() {
|
||||
CheckFloatClassification();
|
||||
CheckIntegerConversions();
|
||||
CheckExtendedMath();
|
||||
Require(atof_nid_postfix(" -12.5tail") == -12.5);
|
||||
char* end = nullptr;
|
||||
const char input[] = "0x1.8p+2 remainder";
|
||||
|
|
|
|||
|
|
@ -195,6 +195,7 @@ Throughout the project, every function at every stage either **does exactly what
|
|||
- [sceImeGetPanelPositionAndForm](../../core/libs/prx/libSceIme/Export.cpp) (libSceIme) - the output is taken to be the `PositionAndForm` that `sceImeDialogGetPanelPositionAndForm` fills; it is never written, since no panel can be open. That a closed panel is reported before a null output is assumed by analogy with `sceImeSetCaret`, not confirmed on a PS5 title
|
||||
- [_sceLibcInternalForceTlsDestructor](../../core/libs/prx/libSceLibcInternal/Export.cpp) (libSceLibcInternal) - behaviour follows `sceLibcForceTlsDestructor(int)` in a title's `libc.prx` (disassembly): the calling thread's destructors whose dso belongs to the module run newest first, only if the dso's module is loaded and the dso points to itself, in up to 4 passes. The return type is unknown (that function returns nothing), 0 is returned. The module of each dso is looked up when the destructors are forced, not when they are registered as `libc.prx` does, and the lookup is Linux only, so on Windows the call throws when the thread has destructors
|
||||
- [acosl](../../core/libs/prx/libc/src/Math.cpp) (libc) - computed by the host's math library, like the other libc math functions here, not by the console's (FreeBSD msun ld80 code in Sony's `libc.prx`): results can differ from the console's in the last bit, and on Linux glibc sets `errno` to `EDOM` for `acosl` outside [-1, 1] where msun only raises the floating-point exception. `long double` is the x87 80-bit format, as Sony's `frexpl` uses it (`fldt 0x8(%rsp)`, result in `st(0)`)
|
||||
- [atanl, sinl, cosl, tanl, sinhl, coshl, tanhl, expl, exp2l, logl, log10l and powl](../../core/libs/prx/libc/src/Math.cpp) (libc) - computed by the host's math library, as `acosl` is, not by the console's FreeBSD msun ld80 code: results can differ from the console's in the last bit (glibc's `log10l(1000)` is not exactly 3), and on Linux glibc sets `errno` to `EDOM` or `ERANGE` where msun only raises the floating-point exception. `ldexpl`, `truncl`, `logb` and `remainder` are exact operations and give the console's result
|
||||
- [std_execute_once](../../core/libs/prx/libc/Export.cpp) (libc) - assumed to be the plain-named twin of `std::_Execute_once` (`_ZSt13_Execute_onceRSt9once_flagPFiPvS1_PS1_ES1_`, the callee of Dinkumware `call_once`): it delegates there and gets the [thread.once.callonce] semantics already verified for that symbol (one invocation per flag, concurrent callers block until it completes, and a failing or throwing invocation leaves the flag unready so the next caller runs it). The name equivalence is not confirmed on a title, and the callback convention (called with (null, arg, null), non-zero return meaning success) is the twin's, unverified for this symbol
|
||||
- [Dinkumware mutexes and conditions](../../core/libs/prx/libc/src/Threads.cpp) (libc) use pointer-to-handle arguments, matching the console aerolib signatures reported in [#3079](https://github.com/boykopovar/AnyPS5/pull/3079). The title's `_Mtx_lock` maps `0` to `_Thrd_success` (0), `0x8002000b` to `_Thrd_busy` (3), and other failures to `_Thrd_error` (4); its internal mutex init recognizes recursive flag `0x100`, while every other type uses default attributes. The observed relock failure for a plain mutex suggests those defaults are error-checking, but that has not been confirmed on hardware. The title's `_Mtx_unlock` and `_Cnd_wait` return success regardless of their internal result. The host implementation treats invalid ownership preconditions as no-ops, and throws for invalid handles, host wait errors and destroying a locked mutex as debug guards; those cases are not confirmed against the console.
|
||||
- [random, srandom, initstate, setstate](../../core/libs/prx/libc/src/Random.cpp) (libc) follow FreeBSD 11 [random.c](https://github.com/freebsd/freebsd-src/blob/4ab2e064d7950be84256d671a7ae93f87cc6aa36/lib/libc/stdlib/random.c): the additive feedback generator on a default 128-byte `TYPE_3` table, `good_rand` seeding, state sizes rounded down to 8, 32, 64, 128 or 256 bytes, and `setstate` returning the previous state or null for a rear position past the degree. `initstate` below 8 bytes returns null without setting errno, as that file and its manual do (glibc sets `EINVAL`). FreeBSD does not lock the generator; here every call is serialised by one lock, so concurrent callers draw the serial sequence between them. A null state throws, where FreeBSD faults. That the console's `libSceLibcInternal` uses this FreeBSD code and not another generator is unverified
|
||||
|
|
|
|||
Loading…
Reference in New Issue