Repository navigation
Expand file tree
/
Copy pathMathExact.cpp
More file actions
261 lines (218 loc) · 8.07 KB
/
Copy pathMathExact.cpp
File metadata and controls
261 lines (218 loc) · 8.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
#include <algorithm>
#include <cerrno>
#include <climits>
#include <cmath>
#include <cstdint>
#include <cstring>
#include <limits>
#include "prx/libc/include/General.hpp"
namespace {
class ErrnoGuard {
public:
ErrnoGuard() : saved(errno) {}
~ErrnoGuard() { errno = saved; }
ErrnoGuard(const ErrnoGuard&) = delete;
ErrnoGuard& operator=(const ErrnoGuard&) = delete;
private:
int saved;
};
struct ExtendedBits {
std::uint64_t mantissa;
std::uint16_t signExponent;
};
ExtendedBits Bits(const long double& value) {
ExtendedBits bits;
unsigned char bytes[sizeof(long double)];
std::memcpy(bytes, &value, sizeof(bytes));
std::memcpy(&bits.mantissa, bytes, sizeof(bits.mantissa));
std::memcpy(&bits.signExponent, bytes + 8, sizeof(bits.signExponent));
return bits;
}
constexpr short Denormal = -2, Finite = -1, Zero = 0, Infinite = 1, NotANumber = 2;
short TestExtended(const ExtendedBits& bits) {
const int exponent = bits.signExponent & 0x7fff;
const std::uint64_t fraction = bits.mantissa & 0x7fffffffffffffffull;
if (exponent == 0x7fff) return fraction != 0 ? NotANumber : Infinite;
if (exponent != 0 || (bits.mantissa >> 63) != 0) return Finite;
return bits.mantissa != 0 ? Denormal : Zero;
}
template<typename TFloat>
short TestFloat(TFloat value) {
switch (std::fpclassify(value)) {
case FP_NAN:
return NotANumber;
case FP_INFINITE:
return Infinite;
case FP_ZERO:
return Zero;
case FP_SUBNORMAL:
return Denormal;
default:
return Finite;
}
}
template <typename T>
T Remainder(T x, T y) {
const bool domain = !std::isnan(x) && !std::isnan(y) && (std::isinf(x) || y == T(0));
T result;
{
ErrnoGuard guard;
result = std::remainder(x, y);
}
if (domain) errno = EDOM;
return result;
}
int Exponent(std::int64_t exponent) {
return static_cast<int>(std::clamp<std::int64_t>(exponent, INT_MIN, INT_MAX));
}
}
extern "C" {
long double APS5_VABI copysignl_nid_postfix(long double x, long double y) { return std::copysign(x, y); }
long double APS5_VABI fdiml_nid_postfix(long double x, long double y) {
if (std::isnan(x)) return x;
if (std::isnan(y)) return y;
return x > y ? x - y : 0.0L;
}
long double APS5_VABI fmodl_nid_postfix(long double x, long double y) {
if (!std::isfinite(x) || y == 0.0L || std::isnan(y)) {
errno = EDOM;
return (x * y) / (x * y);
}
ErrnoGuard guard;
return std::fmod(x, y);
}
long double APS5_VABI remainderl_nid_postfix(long double x, long double y) {
return Remainder(x, y);
}
long double APS5_VABI remquol_nid_postfix(long double x, long double y, int* quotient) {
const bool domain = !std::isnan(x) && !std::isnan(y) && (std::isinf(x) || y == 0.0L);
int bits = 0;
long double result;
{
ErrnoGuard guard;
result = std::remquo(x, y, &bits);
}
if (domain) errno = EDOM;
if (!std::isnan(result)) *quotient = bits < 0 ? -(-bits & 7) : (bits & 7);
return result;
}
long double APS5_VABI logbl_nid_postfix(long double x) {
ErrnoGuard guard;
return std::logb(x);
}
int APS5_VABI ilogbl_nid_postfix(long double x) {
if ((Bits(x).signExponent & 0x7fff) == 0x7fff) return INT_MAX;
ErrnoGuard guard;
return std::ilogb(x);
}
long double APS5_VABI rintl_nid_postfix(long double x) { return std::rint(x); }
long double APS5_VABI roundl_nid_postfix(long double x) { return std::isfinite(x) ? std::round(x) : x; }
std::int64_t APS5_VABI lroundl_nid_postfix(long double x) {
ErrnoGuard guard;
return std::llround(x);
}
std::int64_t APS5_VABI lrintl_nid_postfix(long double x) {
ErrnoGuard guard;
return std::llrint(x);
}
long long APS5_VABI llrintl_nid_postfix(long double x) {
ErrnoGuard guard;
return std::llrint(x);
}
long double APS5_VABI sqrtl_nid_postfix(long double x) {
return std::sqrt(x);
}
long double APS5_VABI modfl_nid_postfix(long double x, long double* integral) {
if (std::isnan(x)) {
*integral = x;
return x;
}
return std::modf(x, integral);
}
long double APS5_VABI nanl_nid_postfix(const char*) { return std::numeric_limits<long double>::quiet_NaN(); }
long double APS5_VABI scalblnl_nid_postfix(long double x, std::int64_t exponent) {
ErrnoGuard guard;
return std::scalbn(x, static_cast<int>(exponent));
}
long double APS5_VABI fmal_nid_postfix(long double x, long double y, long double z) {
if (x == 0.0L || y == 0.0L) return x * y + z;
if (z == 0.0L) return x * y;
if (!std::isfinite(x) || !std::isfinite(y)) return x * y + z;
if (!std::isfinite(z)) return z;
int xExponent = 0, yExponent = 0, zExponent = 0;
std::frexp(x, &xExponent);
std::frexp(y, &yExponent);
std::frexp(z, &zExponent);
if (xExponent + yExponent - zExponent > 2 * std::numeric_limits<long double>::digits) return x * y;
ErrnoGuard guard;
return std::fma(x, y, z);
}
double APS5_VABI rint_nid_postfix(double x) { return std::isnan(x) ? x + x : std::rint(x); }
float APS5_VABI rintf_nid_postfix(float x) { return std::isnan(x) ? x + x : std::rint(x); }
std::int64_t APS5_VABI lrint_nid_postfix(double x) {
ErrnoGuard guard;
return std::llrint(x);
}
std::int64_t APS5_VABI lrintf_nid_postfix(float x) {
ErrnoGuard guard;
return std::llrint(x);
}
long long APS5_VABI llrint_nid_postfix(double x) {
ErrnoGuard guard;
return std::llrint(x);
}
long long APS5_VABI llrintf_nid_postfix(float x) {
ErrnoGuard guard;
return std::llrint(x);
}
double APS5_VABI drem_nid_postfix(double x, double y) {
return Remainder(x, y);
}
float APS5_VABI dremf_nid_postfix(float x, float y) {
return Remainder(x, y);
}
double APS5_VABI scalbln_nid_postfix(double x, std::int64_t exponent) {
ErrnoGuard guard;
return std::scalbn(x, Exponent(exponent));
}
float APS5_VABI scalblnf_nid_postfix(float x, std::int64_t exponent) {
ErrnoGuard guard;
return std::scalbn(x, Exponent(exponent));
}
double APS5_VABI scalb_nid_postfix(double x, double exponent) {
ErrnoGuard guard;
if (std::isnan(x) || std::isnan(exponent)) return x * exponent;
if (std::isinf(exponent)) return exponent > 0 ? x * exponent : x / -exponent;
if (std::rint(exponent) != exponent) return (exponent - exponent) / (exponent - exponent);
if (exponent > 65000.0) return std::scalbn(x, 65000);
if (exponent < -65000.0) return std::scalbn(x, -65000);
return std::scalbn(x, static_cast<int>(exponent));
}
float APS5_VABI scalbf_nid_postfix(float x, float exponent) {
ErrnoGuard guard;
if (std::isnan(x) || std::isnan(exponent)) return x * exponent;
if (std::isinf(exponent)) return exponent > 0 ? x * exponent : x / -exponent;
if (std::rint(exponent) != exponent) return (exponent - exponent) / (exponent - exponent);
if (exponent > 65000.0f) return std::scalbn(x, 65000);
if (exponent < -65000.0f) return std::scalbn(x, -65000);
return std::scalbn(x, static_cast<int>(exponent));
}
int APS5_VABI finite_nid_postfix(double x) { return std::isfinite(x) ? 1 : 0; }
int APS5_VABI finitef_nid_postfix(float x) { return std::isfinite(x) ? 1 : 0; }
int APS5_VABI __fpclassifyl_nid_postfix(long double x) {
const ExtendedBits bits = Bits(x);
if ((bits.signExponent & 0x7fff) != 0 || bits.mantissa == 0) return TestExtended(bits);
return Denormal;
}
int APS5_VABI __isinfl_nid_postfix(long double x) { return TestExtended(Bits(x)) == Infinite ? 1 : 0; }
int APS5_VABI __isnanl_nid_postfix(long double x) { return TestExtended(Bits(x)) == NotANumber ? 1 : 0; }
int APS5_VABI __isnormall_nid_postfix(long double x) {
const int exponent = Bits(x).signExponent & 0x7fff;
return exponent != 0 && exponent != 0x7fff ? 1 : 0;
}
short APS5_VABI _LDtest_nid_postfix(const long double* value) { return TestExtended(Bits(*value)); }
int APS5_VABI _Dclass_nid_postfix(double x) { return TestFloat(x); }
int APS5_VABI _FDclass_nid_postfix(float x) { return TestFloat(x); }
int APS5_VABI _LDclass_nid_postfix(long double x) { return TestExtended(Bits(x)); }
short APS5_VABI _LDsign_nid_postfix(long double x) { return static_cast<short>(Bits(x).signExponent & 0x8000); }
}