authorgravatar for 3575188313@qq.comZhenming-Lin <3575188313@qq.com> 2026-01-28 23:33:35+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-28 23:33:35+01:00
log757ec185f0eb91a15c4bdbe0201f0d998f30258c
tree0334713c4c82f8f0d0879e66e02aa92d5796f56e
parent3b10383114f7aee96f18f7b3aac7c0e08d840b42

Add `f16`, `f80` and `f128` support for `acos` and `asin` (#30997)

The software impl of `acos` and `asin` depends on the `sqrt` op. Since support for `sqrt` in `f16`, `f80`, and `f128` has been added, the impl of `acos` and `asin` for `f16`, `f80`, and `f128` is now being supplemented. Reviewed-on: https://codeberg.org/ziglang/zig/pulls/30997 Reviewed-by: Andrew Kelley <andrew@ziglang.org> Co-authored-by: lzm-build <3575188313@qq.com> Co-committed-by: lzm-build <3575188313@qq.com>

2 files changed, 675 insertions(+), 168 deletions(-)

lib/std/math/acos.zig+331-78
......@@ -3,10 +3,13 @@
33//
44// https://git.musl-libc.org/cgit/musl/tree/src/math/acosf.c
55// https://git.musl-libc.org/cgit/musl/tree/src/math/acos.c
6// https://git.musl-libc.org/cgit/musl/tree/src/math/acosl.c
67
78const std = @import("../std.zig");
89const math = std.math;
9const expect = std.testing.expect;
10const testing = std.testing;
11const builtin = @import("builtin");
12const native_endian = builtin.cpu.arch.endian();
1013
1114/// Returns the arc-cosine of x.
1215///
......@@ -15,71 +18,120 @@ const expect = std.testing.expect;
1518pub fn acos(x: anytype) @TypeOf(x) {
1619 const T = @TypeOf(x);
1720 return switch (T) {
18 f32 => acos32(x),
19 f64 => acos64(x),
21 f16 => acosBinary16(x),
22 f32 => acosBinary32(x),
23 f64 => acosBinary64(x),
24 f80 => acosExtended80(x),
25 f128 => acosBinary128(x),
2026 else => @compileError("acos not implemented for " ++ @typeName(T)),
2127 };
2228}
2329
24fn r32(z: f32) f32 {
25 const pS0 = 1.6666586697e-01;
26 const pS1 = -4.2743422091e-02;
27 const pS2 = -8.6563630030e-03;
28 const qS1 = -7.0662963390e-01;
30fn approxBinary16(z: f32) f32 {
31 const S0: f32 = 1.0000001e0;
32 const S1: f32 = 1.6664918e-1;
33 const S2: f32 = 7.55022e-2;
34 const S3: f32 = 3.9513987e-2;
35 const S4: f32 = 5.0883885e-2;
36 return S0 + z * (S1 + z * (S2 + z * (S3 + z * S4)));
37}
38
39fn acosBinary16(x: f16) f16 {
40 const pio2: f32 = math.pi / 2.0;
41
42 const hx: u16 = @bitCast(x);
43 const ix: u16 = hx & 0x7fff;
44
45 // |x| >= 1 or nan
46 if (ix >= 0x3c00) {
47 if (ix == 0x3c00) {
48 if (hx >> 15 != 0) {
49 return @floatCast(2.0 * pio2 + 0x1p-120);
50 }
51 return 0.0;
52 }
53 return 0.0 / (x - x);
54 }
55
56 const xf: f32 = @floatCast(x);
57
58 // |x| < 0.5
59 if (ix < 0x3800) {
60 return @floatCast(pio2 - xf * approxBinary16(xf * xf));
61 }
62
63 // x < -0.5
64 if (hx >> 15 != 0) {
65 const z = (1.0 + xf) * 0.5;
66 const s = @sqrt(z);
67 const w = approxBinary16(z) * s;
68 return @floatCast(2.0 * (pio2 - w));
69 }
70
71 // x > 0.5
72 const z = (1.0 - xf) * 0.5;
73 const s = @sqrt(z);
74 const w = approxBinary16(z) * s;
75 return @floatCast(2.0 * w);
76}
77
78fn rationalApproxBinary32(z: f32) f32 {
79 const pS0: f32 = 1.6666586697e-01;
80 const pS1: f32 = -4.2743422091e-02;
81 const pS2: f32 = -8.6563630030e-03;
82 const qS1: f32 = -7.0662963390e-01;
2983
3084 const p = z * (pS0 + z * (pS1 + z * pS2));
3185 const q = 1.0 + z * qS1;
3286 return p / q;
3387}
3488
35fn acos32(x: f32) f32 {
36 const pio2_hi = 1.5707962513e+00;
37 const pio2_lo = 7.5497894159e-08;
89fn acosBinary32(x: f32) f32 {
90 const pio2_hi: f32 = 1.5707962513e+00;
91 const pio2_lo: f32 = 7.5497894159e-08;
3892
39 const hx: u32 = @as(u32, @bitCast(x));
40 const ix: u32 = hx & 0x7FFFFFFF;
93 const hx: u32 = @bitCast(x);
94 const ix: u32 = hx & 0x7fff_ffff;
4195
4296 // |x| >= 1 or nan
43 if (ix >= 0x3F800000) {
44 if (ix == 0x3F800000) {
97 if (ix >= 0x3f800000) {
98 if (ix == 0x3f800000) {
4599 if (hx >> 31 != 0) {
46100 return 2.0 * pio2_hi + 0x1.0p-120;
47 } else {
48 return 0.0;
49101 }
50 } else {
51 return (x - x) / 0;
102 return 0.0;
52103 }
104 return 0.0 / (x - x);
53105 }
54106
55107 // |x| < 0.5
56 if (ix < 0x3F000000) {
57 if (ix <= 0x32800000) { // |x| < 2^(-26)
108 if (ix < 0x3f00_0000) {
109 // |x| < 2^(-26)
110 if (ix <= 0x3280_0000) {
58111 return pio2_hi + 0x1.0p-120;
59 } else {
60 return pio2_hi - (x - (pio2_lo - x * r32(x * x)));
61112 }
113 return pio2_hi - (x - (pio2_lo - x * rationalApproxBinary32(x * x)));
62114 }
63115
64116 // x < -0.5
65117 if (hx >> 31 != 0) {
66118 const z = (1 + x) * 0.5;
67119 const s = @sqrt(z);
68 const w = r32(z) * s - pio2_lo;
69 return 2 * (pio2_hi - (s + w));
120 const w = rationalApproxBinary32(z) * s - pio2_lo;
121 return 2.0 * (pio2_hi - (s + w));
70122 }
71123
72124 // x > 0.5
73125 const z = (1.0 - x) * 0.5;
74126 const s = @sqrt(z);
75 const jx = @as(u32, @bitCast(s));
76 const df = @as(f32, @bitCast(jx & 0xFFFFF000));
127 const hs: u32 = @bitCast(s);
128 const df: f32 = @bitCast(hs & 0xffff_f000);
77129 const c = (z - df * df) / (s + df);
78 const w = r32(z) * s + c;
79 return 2 * (df + w);
130 const w = rationalApproxBinary32(z) * s + c;
131 return 2.0 * (df + w);
80132}
81133
82fn r64(z: f64) f64 {
134fn rationalApproxBinary64(z: f64) f64 {
83135 const pS0: f64 = 1.66666666666666657415e-01;
84136 const pS1: f64 = -3.25565818622400915405e-01;
85137 const pS2: f64 = 2.01212532134862925881e-01;
......@@ -96,91 +148,292 @@ fn r64(z: f64) f64 {
96148 return p / q;
97149}
98150
99fn acos64(x: f64) f64 {
151fn acosBinary64(x: f64) f64 {
100152 const pio2_hi: f64 = 1.57079632679489655800e+00;
101153 const pio2_lo: f64 = 6.12323399573676603587e-17;
102154
103 const ux = @as(u64, @bitCast(x));
104 const hx = @as(u32, @intCast(ux >> 32));
105 const ix = hx & 0x7FFFFFFF;
155 const hx: u32 = @intCast(@as(u64, @bitCast(x)) >> 32);
156 const ix: u32 = hx & 0x7fff_ffff;
106157
107158 // |x| >= 1 or nan
108 if (ix >= 0x3FF00000) {
109 const lx = @as(u32, @intCast(ux & 0xFFFFFFFF));
110
111 // acos(1) = 0, acos(-1) = pi
112 if ((ix - 0x3FF00000) | lx == 0) {
159 if (ix >= 0x3ff0_0000) {
160 const lx: u32 = @truncate(@as(u64, @bitCast(x)));
161 if ((ix - 0x3ff0_0000 | lx) == 0) {
113162 if (hx >> 31 != 0) {
114 return 2 * pio2_hi + 0x1.0p-120;
115 } else {
116 return 0;
163 return 2.0 * pio2_hi + 0x1.0p-120;
117164 }
165 return 0.0;
118166 }
119
120 return (x - x) / 0;
167 return 0.0 / (x - x);
121168 }
122169
123170 // |x| < 0.5
124 if (ix < 0x3FE00000) {
171 if (ix < 0x3fe0_0000) {
125172 // |x| < 2^(-57)
126 if (ix <= 0x3C600000) {
173 if (ix <= 0x3c60_0000) {
127174 return pio2_hi + 0x1.0p-120;
128 } else {
129 return pio2_hi - (x - (pio2_lo - x * r64(x * x)));
130175 }
176 return pio2_hi - (x - (pio2_lo - x * rationalApproxBinary64(x * x)));
131177 }
132178
133179 // x < -0.5
134180 if (hx >> 31 != 0) {
135181 const z = (1.0 + x) * 0.5;
136182 const s = @sqrt(z);
137 const w = r64(z) * s - pio2_lo;
183 const w = rationalApproxBinary64(z) * s - pio2_lo;
138184 return 2 * (pio2_hi - (s + w));
139185 }
140186
141187 // x > 0.5
142188 const z = (1.0 - x) * 0.5;
143189 const s = @sqrt(z);
144 const jx = @as(u64, @bitCast(s));
145 const df = @as(f64, @bitCast(jx & 0xFFFFFFFF00000000));
190 const df: f64 = @bitCast(@as(u64, @bitCast(s)) & 0xffff_ffff_0000_0000);
146191 const c = (z - df * df) / (s + df);
147 const w = r64(z) * s + c;
148 return 2 * (df + w);
192 const w = rationalApproxBinary64(z) * s + c;
193 return 2.0 * (df + w);
149194}
150195
151test acos {
152 try expect(acos(@as(f32, 0.0)) == acos32(0.0));
153 try expect(acos(@as(f64, 0.0)) == acos64(0.0));
196fn rationalApproxExtended80(z: f80) f80 {
197 const pS0: f80 = 1.66666666666666666631e-01;
198 const pS1: f80 = -4.16313987993683104320e-01;
199 const pS2: f80 = 3.69068046323246813704e-01;
200 const pS3: f80 = -1.36213932016738603108e-01;
201 const pS4: f80 = 1.78324189708471965733e-02;
202 const pS5: f80 = -2.19216428382605211588e-04;
203 const pS6: f80 = -7.10526623669075243183e-06;
204 const qS1: f80 = -2.94788392796209867269e+00;
205 const qS2: f80 = 3.27309890266528636716e+00;
206 const qS3: f80 = -1.68285799854822427013e+00;
207 const qS4: f80 = 3.90699412641738801874e-01;
208 const qS5: f80 = -3.14365703596053263322e-02;
209
210 const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * (pS5 + z * pS6))))));
211 const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * (qS4 + z * qS5))));
212 return p / q;
154213}
155214
156test acos32 {
157 const epsilon = 0.000001;
215fn acosExtended80(x: f80) f80 {
216 const pio2_hi: f80 = 1.57079632679489661926;
217 const pio2_lo: f80 = -2.50827880633416601173e-20;
218
219 const hx: u80 = @bitCast(x);
220 const se: u16 = @truncate(hx >> 64);
221 const e = se & 0x7fff;
158222
159 try expect(math.approxEqAbs(f32, acos32(0.0), 1.570796, epsilon));
160 try expect(math.approxEqAbs(f32, acos32(0.2), 1.369438, epsilon));
161 try expect(math.approxEqAbs(f32, acos32(0.3434), 1.220262, epsilon));
162 try expect(math.approxEqAbs(f32, acos32(0.5), 1.047198, epsilon));
163 try expect(math.approxEqAbs(f32, acos32(0.8923), 0.468382, epsilon));
164 try expect(math.approxEqAbs(f32, acos32(-0.2), 1.772154, epsilon));
223 // |x| >= 1 or nan
224 if (e >= 0x3fff) {
225 if (x == 1.0) {
226 return 0.0;
227 }
228 if (x == -1.0) {
229 return 2.0 * pio2_hi + 0x1p-120;
230 }
231 return 0.0 / (x - x);
232 }
233 // |x| < 0.5
234 if (e < 0x3fff - 1) {
235 if (e < 0x3fff - math.floatFractionalBits(f80)) {
236 return pio2_hi + 0x1p-120;
237 }
238 return pio2_hi - (rationalApproxExtended80(x * x) * x - pio2_lo + x);
239 }
240 // x < -0.5
241 if (se >> 15 != 0) {
242 const z = (1 + x) * 0.5;
243 const s = @sqrt(z);
244 return 2.0 * (pio2_hi - (rationalApproxExtended80(z) * s - pio2_lo + s));
245 }
246 // x > 0.5
247 const z = (1.0 - x) * 0.5;
248 const s = @sqrt(z);
249 const hs: u80 = @bitCast(s);
250 const f: f80 = @bitCast(hs & 0xffff_ffff_ffff_0000_0000);
251 const c = (z - f * f) / (s + f);
252 return 2.0 * (rationalApproxExtended80(z) * s + c + f);
253}
254
255fn rationalApproxBinary128(z: f128) f128 {
256 const pS0: f128 = 1.66666666666666666666666666666700314e-01;
257 const pS1: f128 = -7.32816946414566252574527475428622708e-01;
258 const pS2: f128 = 1.34215708714992334609030036562143589e+00;
259 const pS3: f128 = -1.32483151677116409805070261790752040e+00;
260 const pS4: f128 = 7.61206183613632558824485341162121989e-01;
261 const pS5: f128 = -2.56165783329023486777386833928147375e-01;
262 const pS6: f128 = 4.80718586374448793411019434585413855e-02;
263 const pS7: f128 = -4.42523267167024279410230886239774718e-03;
264 const pS8: f128 = 1.44551535183911458253205638280410064e-04;
265 const pS9: f128 = -2.10558957916600254061591040482706179e-07;
266 const qS1: f128 = -4.84690167848739751544716485245697428e+00;
267 const qS2: f128 = 9.96619113536172610135016921140206980e+00;
268 const qS3: f128 = -1.13177895428973036660836798461641458e+01;
269 const qS4: f128 = 7.74004374389488266169304117714658761e+00;
270 const qS5: f128 = -3.25871986053534084709023539900339905e+00;
271 const qS6: f128 = 8.27830318881232209752469022352928864e-01;
272 const qS7: f128 = -1.18768052702942805423330715206348004e-01;
273 const qS8: f128 = 8.32600764660522313269101537926539470e-03;
274 const qS9: f128 = -1.99407384882605586705979504567947007e-04;
275
276 const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * (pS5 + z * (pS6 + z * (pS7 + z * (pS8 + z * pS9)))))))));
277 const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * (qS4 + z * (qS5 + z * (qS6 + z * (qS7 + z * (qS8 + z * qS9))))))));
278 return p / q;
279}
280
281fn acosBinary128(x: f128) f128 {
282 const pio2_hi: f128 = 1.57079632679489661923132169163975140;
283 const pio2_lo: f128 = 4.33590506506189051239852201302167613e-35;
284
285 const hx: u128 = @bitCast(x);
286 const se: u16 = @truncate(hx >> 112);
287 const e = se & 0x7fff;
288
289 // |x| >= 1 or nan
290 if (e >= 0x3fff) {
291 if (x == 1.0) {
292 return 0.0;
293 }
294 if (x == -1.0) {
295 return 2 * pio2_hi + 0x1p-120;
296 }
297 return 0.0 / (x - x);
298 }
299 // |x| < 0.5
300 if (e < 0x3fff - 1) {
301 if (e < 0x3fff - math.floatFractionalBits(f128)) {
302 return pio2_hi + 0x1p-120;
303 }
304 return pio2_hi - (rationalApproxBinary128(x * x) * x - pio2_lo + x);
305 }
306 // x < -0.5
307 if (se >> 15 != 0) {
308 const z = (1 + x) * 0.5;
309 const s = @sqrt(z);
310 return 2 * (pio2_hi - (rationalApproxBinary128(z) * s - pio2_lo + s));
311 }
312 // x > 0.5
313 const z = (1.0 - x) * 0.5;
314 const s = @sqrt(z);
315 const hs: u128 = @bitCast(s);
316 const f: f128 = @bitCast(hs & 0xffff_ffff_ffff_ffff_0000_0000_0000_0000);
317 const c = (z - f * f) / (s + f);
318 return 2.0 * (rationalApproxBinary128(z) * s + c + f);
319}
320
321test "acosBinary16.special" {
322 try testing.expectApproxEqAbs(acosBinary16(0x0p+0), 0x1.92p0, math.floatEpsAt(f16, 0x1.92p0));
323 try testing.expectApproxEqAbs(acosBinary16(-0x1p+0), 0x1.92p1, math.floatEpsAt(f16, 0x1.92p1));
324 try testing.expectEqual(acosBinary16(0x1p+0), 0x0p+0);
325 try testing.expect(math.isNan(acosBinary16(0x1.004p0)));
326 try testing.expect(math.isNan(acosBinary16(-0x1.004p0)));
327 try testing.expect(math.isNan(acosBinary16(math.inf(f16))));
328 try testing.expect(math.isNan(acosBinary16(-math.inf(f16))));
329 try testing.expect(math.isNan(acosBinary16(math.nan(f16))));
330}
331
332test "acosBinary16" {
333 try testing.expectApproxEqAbs(acosBinary16(0x1.db4p-5), 0x1.834p0, math.floatEpsAt(f16, 0x1.834p0));
334 try testing.expectApproxEqAbs(acosBinary16(-0x1.068p-2), 0x1.d48p0, math.floatEpsAt(f16, 0x1.d48p0));
335 try testing.expectApproxEqAbs(acosBinary16(-0x1.2c4p-3), 0x1.b7cp0, math.floatEpsAt(f16, 0x1.b7cp0));
336 try testing.expectApproxEqAbs(acosBinary16(0x1.65p-3), 0x1.654p0, math.floatEpsAt(f16, 0x1.654p0));
337 try testing.expectApproxEqAbs(acosBinary16(0x1.dfcp-1), 0x1.6d8p-2, math.floatEpsAt(f16, 0x1.6d8p-2));
338 try testing.expectApproxEqAbs(acosBinary16(-0x1.764p-1), 0x1.32p1, math.floatEpsAt(f16, 0x1.32p1));
339 try testing.expectApproxEqAbs(acosBinary16(0x1.b18p-3), 0x1.5b8p0, math.floatEpsAt(f16, 0x1.5b8p0));
340 try testing.expectApproxEqAbs(acosBinary16(0x1.5acp-3), 0x1.668p0, math.floatEpsAt(f16, 0x1.668p0));
341 try testing.expectApproxEqAbs(acosBinary16(-0x1.18cp-1), 0x1.134p1, math.floatEpsAt(f16, 0x1.134p1));
342 try testing.expectApproxEqAbs(acosBinary16(-0x1.03p-1), 0x1.0dp1, math.floatEpsAt(f16, 0x1.0dp1));
165343}
166344
167test acos64 {
168 const epsilon = 0.000001;
345test "acosBinary32.special" {
346 try testing.expectApproxEqAbs(acosBinary32(0x0p+0), 0x1.921fb6p+0, math.floatEpsAt(f32, 0x1.921fb6p+0));
347 try testing.expectApproxEqAbs(acosBinary32(-0x1p+0), 0x1.921fb6p+1, math.floatEpsAt(f32, 0x1.921fb6p+1));
348 try testing.expectEqual(acosBinary32(0x1p+0), 0x0p+0);
349 try testing.expect(math.isNan(acosBinary32(0x1.000002p+0)));
350 try testing.expect(math.isNan(acosBinary32(-0x1.000002p+0)));
351 try testing.expect(math.isNan(acosBinary32(math.inf(f32))));
352 try testing.expect(math.isNan(acosBinary32(-math.inf(f32))));
353 try testing.expect(math.isNan(acosBinary32(math.nan(f32))));
354}
355
356test "acosBinary32" {
357 try testing.expectApproxEqAbs(acosBinary32(-0x1.13284cp-2), 0x1.d7c4e6p+0, math.floatEpsAt(f32, 0x1.d7c4e6p+0));
358 try testing.expectApproxEqAbs(acosBinary32(0x1.6ca8ep-1), 0x1.8e6756p-1, math.floatEpsAt(f32, 0x1.8e6756p-1));
359 try testing.expectApproxEqAbs(acosBinary32(0x1.c2ca6p-1), 0x1.f9d74cp-2, math.floatEpsAt(f32, 0x1.f9d74cp-2));
360 try testing.expectApproxEqAbs(acosBinary32(-0x1.55f12p-1), 0x1.26abdcp+1, math.floatEpsAt(f32, 0x1.26abdcp+1));
361 try testing.expectApproxEqAbs(acosBinary32(-0x1.15679ep-2), 0x1.d85a44p+0, math.floatEpsAt(f32, 0x1.d85a44p+0));
362 try testing.expectApproxEqAbs(acosBinary32(-0x1.41e132p-5), 0x1.9c2f68p+0, math.floatEpsAt(f32, 0x1.9c2f68p+0));
363 try testing.expectApproxEqAbs(acosBinary32(0x1.281b0ep-1), 0x1.e881bp-1, math.floatEpsAt(f32, 0x1.e881bp-1));
364 try testing.expectApproxEqAbs(acosBinary32(0x1.b5ce34p-1), 0x1.1713f6p-1, math.floatEpsAt(f32, 0x1.1713f6p-1));
365 try testing.expectApproxEqAbs(acosBinary32(-0x1.583482p-3), 0x1.bd5accp+0, math.floatEpsAt(f32, 0x1.bd5accp+0));
366 try testing.expectApproxEqAbs(acosBinary32(-0x1.ea8224p-1), 0x1.6ce7d8p+1, math.floatEpsAt(f32, 0x1.6ce7d8p+1));
367}
368
369test "acosBinary64.special" {
370 try testing.expectApproxEqAbs(acosBinary64(0x0p+0), 0x1.921fb54442d18p+0, math.floatEpsAt(f64, 0x1.921fb54442d18p+0));
371 try testing.expectApproxEqAbs(acosBinary64(-0x1p+0), 0x1.921fb54442d18p+1, math.floatEpsAt(f64, 0x1.921fb54442d18p+1));
372 try testing.expectEqual(acosBinary64(0x1p+0), 0x0p+0);
373 try testing.expect(math.isNan(acosBinary64(0x1.0000000000001p+0)));
374 try testing.expect(math.isNan(acosBinary64(-0x1.0000000000001p+0)));
375 try testing.expect(math.isNan(acosBinary64(math.inf(f64))));
376 try testing.expect(math.isNan(acosBinary64(-math.inf(f64))));
377 try testing.expect(math.isNan(acosBinary64(math.nan(f64))));
378}
379
380test "acosBinary64" {
381 try testing.expectApproxEqAbs(acosBinary64(-0x1.13284b2b5006dp-2), 0x1.d7c4e61020905p+0, math.floatEpsAt(f64, 0x1.d7c4e61020905p+0));
382 try testing.expectApproxEqAbs(acosBinary64(0x1.6ca8dfb825911p-1), 0x1.8e6756e27c366p-1, math.floatEpsAt(f64, 0x1.8e6756e27c366p-1));
383 try testing.expectApproxEqAbs(acosBinary64(0x1.c2ca609de7505p-1), 0x1.f9d748eaf956p-2, math.floatEpsAt(f64, 0x1.f9d748eaf956p-2));
384 try testing.expectApproxEqAbs(acosBinary64(-0x1.55f11fba96889p-1), 0x1.26abdc68d07aap+1, math.floatEpsAt(f64, 0x1.26abdc68d07aap+1));
385 try testing.expectApproxEqAbs(acosBinary64(-0x1.15679e27084ddp-2), 0x1.d85a44ea44fe4p+0, math.floatEpsAt(f64, 0x1.d85a44ea44fe4p+0));
386 try testing.expectApproxEqAbs(acosBinary64(-0x1.41e131b093c41p-5), 0x1.9c2f688eee8abp+0, math.floatEpsAt(f64, 0x1.9c2f688eee8abp+0));
387 try testing.expectApproxEqAbs(acosBinary64(0x1.281b0d18455f5p-1), 0x1.e881b1d4eb2a1p-1, math.floatEpsAt(f64, 0x1.e881b1d4eb2a1p-1));
388 try testing.expectApproxEqAbs(acosBinary64(0x1.b5ce34a51b239p-1), 0x1.1713f567a87efp-1, math.floatEpsAt(f64, 0x1.1713f567a87efp-1));
389 try testing.expectApproxEqAbs(acosBinary64(-0x1.583481079de4dp-3), 0x1.bd5acbe8fcc59p+0, math.floatEpsAt(f64, 0x1.bd5acbe8fcc59p+0));
390 try testing.expectApproxEqAbs(acosBinary64(-0x1.ea8223103b871p-1), 0x1.6ce7d66f628e5p+1, math.floatEpsAt(f64, 0x1.6ce7d66f628e5p+1));
391}
392
393test "acosExtended80.special" {
394 try testing.expectApproxEqAbs(acosExtended80(0x0p+0), 0x1.921fb54442d1846ap+0, math.floatEpsAt(f80, 0x1.921fb54442d1846ap+0));
395 try testing.expectApproxEqAbs(acosExtended80(-0x1p+0), 0x1.921fb54442d1846ap+1, math.floatEpsAt(f80, 0x1.921fb54442d1846ap+1));
396 try testing.expectEqual(acosExtended80(0x1p+0), 0x0p+0);
397 try testing.expect(math.isNan(acosExtended80(0x1.0000000000000002p+0)));
398 try testing.expect(math.isNan(acosExtended80(-0x1.0000000000000002p+0)));
399 try testing.expect(math.isNan(acosExtended80(math.inf(f80))));
400 try testing.expect(math.isNan(acosExtended80(-math.inf(f80))));
401 try testing.expect(math.isNan(acosExtended80(math.nan(f80))));
402}
169403
170 try expect(math.approxEqAbs(f64, acos64(0.0), 1.570796, epsilon));
171 try expect(math.approxEqAbs(f64, acos64(0.2), 1.369438, epsilon));
172 try expect(math.approxEqAbs(f64, acos64(0.3434), 1.220262, epsilon));
173 try expect(math.approxEqAbs(f64, acos64(0.5), 1.047198, epsilon));
174 try expect(math.approxEqAbs(f64, acos64(0.8923), 0.468382, epsilon));
175 try expect(math.approxEqAbs(f64, acos64(-0.2), 1.772154, epsilon));
404test "acosExtended80" {
405 try testing.expectApproxEqAbs(acosExtended80(0x1.72068a321edc8804p-1), 0x1.86b349040d28f794p-1, math.floatEpsAt(f80, 0x1.86b349040d28f794p-1));
406 try testing.expectApproxEqAbs(acosExtended80(-0x1.06d0a467d22977ecp-2), 0x1.d4923ade73ec379cp0, math.floatEpsAt(f80, 0x1.d4923ade73ec379cp0));
407 try testing.expectApproxEqAbs(acosExtended80(0x1.77d21385faa9798ap-3), 0x1.62e0e8898c6d04f2p0, math.floatEpsAt(f80, 0x1.62e0e8898c6d04f2p0));
408 try testing.expectApproxEqAbs(acosExtended80(-0x1.73ee3e8bc2a44dbep-1), 0x1.3123cbcd5dc4bd58p1, math.floatEpsAt(f80, 0x1.3123cbcd5dc4bd58p1));
409 try testing.expectApproxEqAbs(acosExtended80(0x1.0a2dd1f6ffcf668ap-1), 0x1.062a6d562df2d316p0, math.floatEpsAt(f80, 0x1.062a6d562df2d316p0));
410 try testing.expectApproxEqAbs(acosExtended80(0x1.8e835c490a3aff9ep-3), 0x1.5ffd68b520aa55fap0, math.floatEpsAt(f80, 0x1.5ffd68b520aa55fap0));
411 try testing.expectApproxEqAbs(acosExtended80(0x1.add20cdc1565064cp-3), 0x1.5bfe6cabda700684p0, math.floatEpsAt(f80, 0x1.5bfe6cabda700684p0));
412 try testing.expectApproxEqAbs(acosExtended80(0x1.21986d43727fca72p-8), 0x1.90fe1c993b571924p0, math.floatEpsAt(f80, 0x1.90fe1c993b571924p0));
413 try testing.expectApproxEqAbs(acosExtended80(0x1.d61e0b3fae6a0564p-2), 0x1.18044ccc626e7f9ep0, math.floatEpsAt(f80, 0x1.18044ccc626e7f9ep0));
414 try testing.expectApproxEqAbs(acosExtended80(-0x1.171e7c4a41883ccap-4), 0x1.a39513b6c16532b4p0, math.floatEpsAt(f80, 0x1.a39513b6c16532b4p0));
176415}
177416
178test "acos32.special" {
179 try expect(math.isNan(acos32(-2)));
180 try expect(math.isNan(acos32(1.5)));
417test "acosBinary128.special" {
418 try testing.expectApproxEqAbs(acosBinary128(0x0p+0), 0x1.921fb54442d18469898cc51701b8p0, math.floatEpsAt(f128, 0x1.921fb54442d18469898cc51701b8p0));
419 try testing.expectApproxEqAbs(acosBinary128(-0x1p+0), 0x1.921fb54442d18469898cc51701b8p1, math.floatEpsAt(f128, 0x1.921fb54442d18469898cc51701b8p1));
420 try testing.expectEqual(acosBinary128(0x1p+0), 0x0p+0);
421 try testing.expect(math.isNan(acosBinary128(0x1.0000000000000000000000000001p0)));
422 try testing.expect(math.isNan(acosBinary128(-0x1.0000000000000000000000000001p0)));
423 try testing.expect(math.isNan(acosBinary128(math.inf(f128))));
424 try testing.expect(math.isNan(acosBinary128(-math.inf(f128))));
425 try testing.expect(math.isNan(acosBinary128(math.nan(f128))));
181426}
182427
183test "acos64.special" {
184 try expect(math.isNan(acos64(-2)));
185 try expect(math.isNan(acos64(1.5)));
428test "acosBinary128" {
429 try testing.expectApproxEqAbs(acosBinary128(-0x1.511bdb99a3c4373bedf834ef4f68p-1), 0x1.250e9a58f049eeafa99db4360c88p1, math.floatEpsAt(f128, 0x1.250e9a58f049eeafa99db4360c88p1));
430 try testing.expectApproxEqAbs(acosBinary128(-0x1.5879cc3ad6dfd2a52e9891c69808p-1), 0x1.2786664b1c676c99437b68590004p1, math.floatEpsAt(f128, 0x1.2786664b1c676c99437b68590004p1));
431 try testing.expectApproxEqAbs(acosBinary128(0x1.3f988ba64a7eb97a751c5f0b3077p-1), 0x1.cb190cd361c7c03a09c470b4caebp-1, math.floatEpsAt(f128, 0x1.cb190cd361c7c03a09c470b4caebp-1));
432 try testing.expectApproxEqAbs(acosBinary128(-0x1.3f2d96c7768e4c4fa02315727959p-1), 0x1.1f373be697880111758f582b1a96p1, math.floatEpsAt(f128, 0x1.1f373be697880111758f582b1a96p1));
433 try testing.expectApproxEqAbs(acosBinary128(0x1.fad303c2e28c1f4d8f9fd0e5686fp-2), 0x1.0d92fd2a0a6ca3e4853c1de9ea6ap0, math.floatEpsAt(f128, 0x1.0d92fd2a0a6ca3e4853c1de9ea6ap0));
434 try testing.expectApproxEqAbs(acosBinary128(0x1.ddde322bd1a2ee50c5ba30c9c617p-2), 0x1.15d4b306e16fbf9ea4f29e82b154p0, math.floatEpsAt(f128, 0x1.15d4b306e16fbf9ea4f29e82b154p0));
435 try testing.expectApproxEqAbs(acosBinary128(-0x1.b02f6adefcbeb1d48666b827ff17p-1), 0x1.49b0a0355a5539052388e8a6dc11p1, math.floatEpsAt(f128, 0x1.49b0a0355a5539052388e8a6dc11p1));
436 try testing.expectApproxEqAbs(acosBinary128(0x1.c8581cce7cd3f6efab0fc60d9b7dp-2), 0x1.1be0b757f4cef022f5d2422b9c78p0, math.floatEpsAt(f128, 0x1.1be0b757f4cef022f5d2422b9c78p0));
437 try testing.expectApproxEqAbs(acosBinary128(-0x1.bf887b8c4e33cbef59993056f3dep-1), 0x1.513270e671db2d840f20b0186c2cp1, math.floatEpsAt(f128, 0x1.513270e671db2d840f20b0186c2cp1));
438 try testing.expectApproxEqAbs(acosBinary128(0x1.0c0f600ab6f9c84c6102942044cep-3), 0x1.70851a509f0e8bfbe780aa8f29f9p0, math.floatEpsAt(f128, 0x1.70851a509f0e8bfbe780aa8f29f9p0));
186439}
lib/std/math/asin.zig+344-90
......@@ -3,10 +3,14 @@
33//
44// https://git.musl-libc.org/cgit/musl/tree/src/math/asinf.c
55// https://git.musl-libc.org/cgit/musl/tree/src/math/asin.c
6// https://git.musl-libc.org/cgit/musl/tree/src/math/asinl.c
67
78const std = @import("../std.zig");
89const math = std.math;
9const expect = std.testing.expect;
10const mem = std.mem;
11const testing = std.testing;
12const builtin = @import("builtin");
13const native_endian = builtin.cpu.arch.endian();
1014
1115/// Returns the arc-sin of x.
1216///
......@@ -16,62 +20,101 @@ const expect = std.testing.expect;
1620pub fn asin(x: anytype) @TypeOf(x) {
1721 const T = @TypeOf(x);
1822 return switch (T) {
19 f32 => asin32(x),
20 f64 => asin64(x),
23 f16 => asinBinary16(x),
24 f32 => asinBinary32(x),
25 f64 => asinBinary64(x),
26 f80 => asinExtended80(x),
27 f128 => asinBinary128(x),
2128 else => @compileError("asin not implemented for " ++ @typeName(T)),
2229 };
2330}
2431
25fn r32(z: f32) f32 {
26 const pS0 = 1.6666586697e-01;
27 const pS1 = -4.2743422091e-02;
28 const pS2 = -8.6563630030e-03;
29 const qS1 = -7.0662963390e-01;
32fn approxBinary16(z: f32) f32 {
33 const S0: f32 = 1.0000001e0;
34 const S1: f32 = 1.6664918e-1;
35 const S2: f32 = 7.55022e-2;
36 const S3: f32 = 3.9513987e-2;
37 const S4: f32 = 5.0883885e-2;
38 return S0 + z * (S1 + z * (S2 + z * (S3 + z * S4)));
39}
40
41fn asinBinary16(x: f16) f16 {
42 const pio2: f32 = math.pi / 2.0;
43
44 const hx: u16 = @bitCast(x);
45 const ix = hx & 0x7fff;
46
47 // |x| >= 1
48 if (ix >= 0x3c00) {
49 // |x| == 1
50 if (ix == 0x3c00) {
51 // asin(+-1) = +-pi/2 with inexact
52 return @floatCast(x * pio2 + 0x1.0p-120);
53 }
54 // asin(|x| > 1) is nan
55 return 0.0 / (x - x);
56 }
57
58 // |x| < 0.5
59 if (ix < 0x3800) {
60 return @floatCast(x * approxBinary16(x * x));
61 }
62
63 // 1 > |x| >= 0.5
64 const z = (1.0 - @abs(x)) * 0.5;
65 const s = @sqrt(z);
66 const x_local = pio2 - 2.0 * s * approxBinary16(z);
67 if (hx >> 15 != 0) {
68 return @floatCast(-x_local);
69 }
70 return @floatCast(x_local);
71}
72
73fn rationalApproxBinary32(z: f32) f32 {
74 const pS0: f32 = 1.6666586697e-01;
75 const pS1: f32 = -4.2743422091e-02;
76 const pS2: f32 = -8.6563630030e-03;
77 const qS1: f32 = -7.0662963390e-01;
3078
3179 const p = z * (pS0 + z * (pS1 + z * pS2));
3280 const q = 1.0 + z * qS1;
3381 return p / q;
3482}
3583
36fn asin32(x: f32) f32 {
37 const pio2 = 1.570796326794896558e+00;
84fn asinBinary32(x: f32) f32 {
85 const pio2: f64 = 1.570796326794896558e+00;
3886
39 const hx: u32 = @as(u32, @bitCast(x));
40 const ix: u32 = hx & 0x7FFFFFFF;
87 const hx: u32 = @bitCast(x);
88 const ix = hx & 0x7fff_ffff;
4189
4290 // |x| >= 1
43 if (ix >= 0x3F800000) {
44 // |x| >= 1
45 if (ix == 0x3F800000) {
46 return x * pio2 + 0x1.0p-120; // asin(+-1) = +-pi/2 with inexact
47 } else {
48 return math.nan(f32); // asin(|x| > 1) is nan
91 if (ix >= 0x3f80_0000) {
92 // |x| == 1
93 if (ix == 0x3f80_0000) {
94 // asin(+-1) = +-pi/2 with inexact
95 return @floatCast(@as(f64, @floatCast(x)) * pio2 + 0x1.0p-120);
4996 }
97 // asin(|x| > 1) is nan
98 return 0.0 / (x - x);
5099 }
51100
52101 // |x| < 0.5
53 if (ix < 0x3F000000) {
102 if (ix < 0x3f00_0000) {
54103 // 0x1p-126 <= |x| < 0x1p-12
55 if (ix < 0x39800000 and ix >= 0x00800000) {
104 if (ix < 0x3980_0000 and ix >= 0x0080_0000) {
56105 return x;
57 } else {
58 return x + x * r32(x * x);
59106 }
107 return x + x * rationalApproxBinary32(x * x);
60108 }
61109
62110 // 1 > |x| >= 0.5
63 const z = (1 - @abs(x)) * 0.5;
64 const s = @sqrt(z);
65 const fx = pio2 - 2 * (s + s * r32(z));
66
67 if (hx >> 31 != 0) {
68 return -fx;
69 } else {
70 return fx;
71 }
111 const z = (1.0 - @abs(x)) * 0.5;
112 const s: f64 = @floatCast(@sqrt(z));
113 const x_local: f32 = @floatCast(pio2 - 2.0 * (s + s * @as(f64, @floatCast(rationalApproxBinary32(z)))));
114 return if (hx >> 31 != 0) -x_local else x_local;
72115}
73116
74fn r64(z: f64) f64 {
117fn rationalApproxBinary64(z: f64) f64 {
75118 const pS0: f64 = 1.66666666666666657415e-01;
76119 const pS1: f64 = -3.25565818622400915405e-01;
77120 const pS2: f64 = 2.01212532134862925881e-01;
......@@ -88,96 +131,307 @@ fn r64(z: f64) f64 {
88131 return p / q;
89132}
90133
91fn asin64(x: f64) f64 {
134fn asinBinary64(x: f64) f64 {
92135 const pio2_hi: f64 = 1.57079632679489655800e+00;
93136 const pio2_lo: f64 = 6.12323399573676603587e-17;
94137
95 const ux = @as(u64, @bitCast(x));
96 const hx = @as(u32, @intCast(ux >> 32));
97 const ix = hx & 0x7FFFFFFF;
138 const hx: u32 = @intCast(@as(u64, @bitCast(x)) >> 32);
139 const ix = hx & 0x7fffffff;
98140
99141 // |x| >= 1 or nan
100 if (ix >= 0x3FF00000) {
101 const lx = @as(u32, @intCast(ux & 0xFFFFFFFF));
102
142 if (ix >= 0x3ff0_0000) {
143 const lx: u32 = @truncate(@as(u64, @bitCast(x)));
103144 // asin(1) = +-pi/2 with inexact
104 if ((ix - 0x3FF00000) | lx == 0) {
145 if ((ix - 0x3ff0_0000 | lx) == 0) {
105146 return x * pio2_hi + 0x1.0p-120;
106 } else {
107 return math.nan(f64);
108147 }
148 return 0.0 / (x - x);
109149 }
110150
111151 // |x| < 0.5
112 if (ix < 0x3FE00000) {
152 if (ix < 0x3fe0_0000) {
113153 // if 0x1p-1022 <= |x| < 0x1p-26 avoid raising overflow
114 if (ix < 0x3E500000 and ix >= 0x00100000) {
154 if (ix < 0x3e50_0000 and ix >= 0x0010_0000) {
115155 return x;
116 } else {
117 return x + x * r64(x * x);
118156 }
157 return x + x * rationalApproxBinary64(x * x);
119158 }
120159
121160 // 1 > |x| >= 0.5
122 const z = (1 - @abs(x)) * 0.5;
161 const z = (1.0 - @abs(x)) * 0.5;
123162 const s = @sqrt(z);
124 const r = r64(z);
125 var fx: f64 = undefined;
126
163 const r = rationalApproxBinary64(z);
127164 // |x| > 0.975
128 if (ix >= 0x3FEF3333) {
129 fx = pio2_hi - 2 * (s + s * r);
130 } else {
131 const jx = @as(u64, @bitCast(s));
132 const df = @as(f64, @bitCast(jx & 0xFFFFFFFF00000000));
133 const c = (z - df * df) / (s + df);
134 fx = 0.5 * pio2_hi - (2 * s * r - (pio2_lo - 2 * c) - (0.5 * pio2_hi - 2 * df));
165 if (ix >= 0x3fef_3333) {
166 const x_local = pio2_hi - (2 * (s + s * r) - pio2_lo);
167 return if (hx >> 31 != 0) -x_local else x_local;
168 }
169 // f+c = sqrt(z)
170 const hs: u64 = @bitCast(s);
171 const f: f64 = @bitCast(hs & 0xffff_ffff_0000_0000);
172 const c: f64 = (z - f * f) / (s + f);
173 const x_local = 0.5 * pio2_hi - (2.0 * s * r - (pio2_lo - 2.0 * c) - (0.5 * pio2_hi - 2.0 * f));
174 return if (hx >> 31 != 0) -x_local else x_local;
175}
176
177fn rationalApproxExtended80(z: f80) f80 {
178 const pS0: f80 = 1.66666666666666666631e-01;
179 const pS1: f80 = -4.16313987993683104320e-01;
180 const pS2: f80 = 3.69068046323246813704e-01;
181 const pS3: f80 = -1.36213932016738603108e-01;
182 const pS4: f80 = 1.78324189708471965733e-02;
183 const pS5: f80 = -2.19216428382605211588e-04;
184 const pS6: f80 = -7.10526623669075243183e-06;
185 const qS1: f80 = -2.94788392796209867269e+00;
186 const qS2: f80 = 3.27309890266528636716e+00;
187 const qS3: f80 = -1.68285799854822427013e+00;
188 const qS4: f80 = 3.90699412641738801874e-01;
189 const qS5: f80 = -3.14365703596053263322e-02;
190
191 const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * (pS5 + z * pS6))))));
192 const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * (qS4 + z * qS5))));
193 return p / q;
194}
195
196fn asinExtended80(x: f80) f80 {
197 const pio2_hi: f80 = 1.57079632679489661926;
198 const pio2_lo: f80 = -2.50827880633416601173e-20;
199
200 const hx: u80 = @bitCast(x);
201 const se: u16 = @truncate(hx >> 64);
202 const e = se & 0x7fff;
203 const sign = se >> 15 != 0;
204
205 // |x| >= 1 or nan
206 if (e >= 0x3fff) {
207 // asin(+-1)=+-pi/2 with inexact
208 if (x == 1.0 or x == -1.0) {
209 return x * pio2_hi + 0x1p-120;
210 }
211 return 0.0 / (x - x);
135212 }
136213
137 if (hx >> 31 != 0) {
138 return -fx;
139 } else {
140 return fx;
214 // |x| < 0.5
215 if (e < 0x3fff - 1) {
216 if (e < 0x3fff - (math.floatMantissaBits(f80) + 1) / 2) {
217 // return x with inexact if x!=0
218 mem.doNotOptimizeAway(x + 0x1p120);
219 return x;
220 }
221 return x + x * rationalApproxExtended80(x * x);
141222 }
223
224 // 1 > |x| >= 0.5
225 const z = (1.0 - @abs(x)) * 0.5;
226 const s = @sqrt(z);
227 const r = rationalApproxExtended80(z);
228
229 const m: u64 = @truncate(hx & 0x0000_ffff_ffff_ffff_ffff);
230 if ((m >> 56) >= 0xf7) {
231 const x_local = pio2_hi - (2.0 * (s + s * r) - pio2_lo);
232 return if (sign) -x_local else x_local;
233 }
234
235 const hs: u80 = @bitCast(s);
236 const f: f80 = @bitCast(hs & 0xffff_ffff_ffff_0000_0000);
237 const c = (z - f * f) / (s + f);
238 const x_local = 0.5 * pio2_hi - (2.0 * s * r - (pio2_lo - 2.0 * c) - (0.5 * pio2_hi - 2.0 * f));
239 return if (sign) -x_local else x_local;
142240}
143241
144test asin {
145 try expect(asin(@as(f32, 0.0)) == asin32(0.0));
146 try expect(asin(@as(f64, 0.0)) == asin64(0.0));
242fn rationalApproxBinary128(z: f128) f128 {
243 const pS0: f128 = 1.66666666666666666666666666666700314e-01;
244 const pS1: f128 = -7.32816946414566252574527475428622708e-01;
245 const pS2: f128 = 1.34215708714992334609030036562143589e+00;
246 const pS3: f128 = -1.32483151677116409805070261790752040e+00;
247 const pS4: f128 = 7.61206183613632558824485341162121989e-01;
248 const pS5: f128 = -2.56165783329023486777386833928147375e-01;
249 const pS6: f128 = 4.80718586374448793411019434585413855e-02;
250 const pS7: f128 = -4.42523267167024279410230886239774718e-03;
251 const pS8: f128 = 1.44551535183911458253205638280410064e-04;
252 const pS9: f128 = -2.10558957916600254061591040482706179e-07;
253 const qS1: f128 = -4.84690167848739751544716485245697428e+00;
254 const qS2: f128 = 9.96619113536172610135016921140206980e+00;
255 const qS3: f128 = -1.13177895428973036660836798461641458e+01;
256 const qS4: f128 = 7.74004374389488266169304117714658761e+00;
257 const qS5: f128 = -3.25871986053534084709023539900339905e+00;
258 const qS6: f128 = 8.27830318881232209752469022352928864e-01;
259 const qS7: f128 = -1.18768052702942805423330715206348004e-01;
260 const qS8: f128 = 8.32600764660522313269101537926539470e-03;
261 const qS9: f128 = -1.99407384882605586705979504567947007e-04;
262
263 const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * (pS5 + z * (pS6 + z * (pS7 + z * (pS8 + z * pS9)))))))));
264 const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * (qS4 + z * (qS5 + z * (qS6 + z * (qS7 + z * (qS8 + z * qS9))))))));
265 return p / q;
147266}
148267
149test asin32 {
150 const epsilon = 0.000001;
268fn asinBinary128(x: f128) f128 {
269 const pio2_hi: f128 = 1.57079632679489661923132169163975140;
270 const pio2_lo: f128 = 4.33590506506189051239852201302167613e-35;
271
272 const hx: u128 = @bitCast(x);
273 const se: u16 = @truncate(hx >> 112);
274 const e = se & 0x7fff;
275 const sign = se >> 15 != 0;
276
277 // |x| >= 1 or nan
278 if (e >= 0x3fff) {
279 // asin(+-1)=+-pi/2 with inexact
280 if (x == 1.0 or x == -1.0) {
281 return x * pio2_hi + 0x1p-120;
282 }
283 return 0.0 / (x - x);
284 }
151285
152 try expect(math.approxEqAbs(f32, asin32(0.0), 0.0, epsilon));
153 try expect(math.approxEqAbs(f32, asin32(0.2), 0.201358, epsilon));
154 try expect(math.approxEqAbs(f32, asin32(-0.2), -0.201358, epsilon));
155 try expect(math.approxEqAbs(f32, asin32(0.3434), 0.350535, epsilon));
156 try expect(math.approxEqAbs(f32, asin32(0.5), 0.523599, epsilon));
157 try expect(math.approxEqAbs(f32, asin32(0.8923), 1.102415, epsilon));
286 // |x| < 0.5
287 if (e < 0x3fff - 1) {
288 if (e < 0x3fff - (math.floatMantissaBits(f128) + 2) / 2) {
289 // return x with inexact if x!=0
290 mem.doNotOptimizeAway(x + 0x1p120);
291 return x;
292 }
293 return x + x * rationalApproxBinary128(x * x);
294 }
295
296 // 1 > |x| >= 0.5
297 const z = (1.0 - @abs(x)) * 0.5;
298 const s = @sqrt(z);
299 const r = rationalApproxBinary128(z);
300
301 const top: u16 = @truncate((hx >> 96) & 0x0000_ffff);
302 if (top >= 0xee00) {
303 const x_local = pio2_hi - (2.0 * (s + s * r) - pio2_lo);
304 return if (sign) -x_local else x_local;
305 }
306
307 const hs: u128 = @bitCast(s);
308 const f: f128 = @bitCast(hs & 0xffff_ffff_ffff_ffff_0000_0000_0000_0000);
309 const c = (z - f * f) / (s + f);
310 const x_local = 0.5 * pio2_hi - (2.0 * s * r - (pio2_lo - 2.0 * c) - (0.5 * pio2_hi - 2.0 * f));
311 return if (sign) -x_local else x_local;
158312}
159313
160test asin64 {
161 const epsilon = 0.000001;
314test "asinBinary16.special" {
315 try testing.expectApproxEqAbs(asinBinary16(0x1p+0), 0x1.92p0, math.floatEpsAt(f16, 0x1.92p0));
316 try testing.expectApproxEqAbs(asinBinary16(-0x1p+0), -0x1.92p0, math.floatEpsAt(f16, -0x1.92p0));
317 try testing.expectEqual(asinBinary16(0x0p+0), 0x0p+0);
318 try testing.expectEqual(asinBinary16(-0x0p+0), 0x0p+0);
319 try testing.expect(math.isNan(asinBinary16(0x1.004p0)));
320 try testing.expect(math.isNan(asinBinary16(-0x1.004p0)));
321 try testing.expect(math.isNan(asinBinary16(math.inf(f16))));
322 try testing.expect(math.isNan(asinBinary16(-math.inf(f16))));
323 try testing.expect(math.isNan(asinBinary16(math.nan(f16))));
324}
325
326test "asinBinary16" {
327 try testing.expectApproxEqAbs(asinBinary16(-0x1.e4cp-6), -0x1.e4cp-6, math.floatEpsAt(f16, -0x1.e4cp-6));
328 try testing.expectApproxEqAbs(asinBinary16(0x1.d68p-1), 0x1.2a8p0, math.floatEpsAt(f16, 0x1.2a8p0));
329 try testing.expectApproxEqAbs(asinBinary16(-0x1.a4cp-1), -0x1.eep-1, math.floatEpsAt(f16, -0x1.eep-1));
330 try testing.expectApproxEqAbs(asinBinary16(-0x1.0a4p-2), -0x1.0d4p-2, math.floatEpsAt(f16, -0x1.0d4p-2));
331 try testing.expectApproxEqAbs(asinBinary16(0x1.28cp-1), 0x1.3c8p-1, math.floatEpsAt(f16, 0x1.3c8p-1));
332 try testing.expectApproxEqAbs(asinBinary16(0x1.284p-3), 0x1.298p-3, math.floatEpsAt(f16, 0x1.298p-3));
333 try testing.expectApproxEqAbs(asinBinary16(-0x1.574p-1), -0x1.784p-1, math.floatEpsAt(f16, -0x1.784p-1));
334 try testing.expectApproxEqAbs(asinBinary16(-0x1.4ccp-1), -0x1.6a4p-1, math.floatEpsAt(f16, -0x1.6a4p-1));
335 try testing.expectApproxEqAbs(asinBinary16(0x1.a18p-1), 0x1.e84p-1, math.floatEpsAt(f16, 0x1.e84p-1));
336 try testing.expectApproxEqAbs(asinBinary16(0x1.7a8p-2), 0x1.83cp-2, math.floatEpsAt(f16, 0x1.83cp-2));
337}
338
339test "asinBinary32.special" {
340 try testing.expectApproxEqAbs(asinBinary32(0x1p+0), 0x1.921fb6p+0, math.floatEpsAt(f32, 0x1.921fb6p+0));
341 try testing.expectApproxEqAbs(asinBinary32(-0x1p+0), -0x1.921fb6p+0, math.floatEpsAt(f32, -0x1.921fb6p+0));
342 try testing.expectEqual(asinBinary32(0x0p+0), 0x0p+0);
343 try testing.expectEqual(asinBinary32(-0x0p+0), 0x0p+0);
344 try testing.expect(math.isNan(asinBinary32(0x1.000002p+0)));
345 try testing.expect(math.isNan(asinBinary32(-0x1.000002p+0)));
346 try testing.expect(math.isNan(asinBinary32(math.inf(f32))));
347 try testing.expect(math.isNan(asinBinary32(-math.inf(f32))));
348 try testing.expect(math.isNan(asinBinary32(math.nan(f32))));
349}
350
351test "asinBinary32" {
352 try testing.expectApproxEqAbs(asinBinary32(-0x1.4c2906p-4), -0x1.4c868p-4, math.floatEpsAt(f32, -0x1.4c868p-4));
353 try testing.expectApproxEqAbs(asinBinary32(0x1.05fcfap-1), 0x1.130648p-1, math.floatEpsAt(f32, 0x1.130648p-1));
354 try testing.expectApproxEqAbs(asinBinary32(0x1.fab976p-2), 0x1.090abcp-1, math.floatEpsAt(f32, 0x1.090abcp-1));
355 try testing.expectApproxEqAbs(asinBinary32(0x1.8b4b8cp-1), 0x1.c39fa2p-1, math.floatEpsAt(f32, 0x1.c39fa2p-1));
356 try testing.expectApproxEqAbs(asinBinary32(0x1.7117c2p-1), 0x1.9c332p-1, math.floatEpsAt(f32, 0x1.9c332p-1));
357 try testing.expectApproxEqAbs(asinBinary32(0x1.e5e112p-5), 0x1.e62a1cp-5, math.floatEpsAt(f32, 0x1.e62a1cp-5));
358 try testing.expectApproxEqAbs(asinBinary32(-0x1.07673p-2), -0x1.0a65dep-2, math.floatEpsAt(f32, -0x1.0a65dep-2));
359 try testing.expectApproxEqAbs(asinBinary32(-0x1.2108dep-2), -0x1.25046p-2, math.floatEpsAt(f32, -0x1.25046p-2));
360 try testing.expectApproxEqAbs(asinBinary32(-0x1.4e6e6cp-1), -0x1.6c6f0cp-1, math.floatEpsAt(f32, -0x1.6c6f0cp-1));
361 try testing.expectApproxEqAbs(asinBinary32(0x1.22a16ap-1), 0x1.350f7ap-1, math.floatEpsAt(f32, 0x1.350f7ap-1));
362}
363
364test "asinBinary64.special" {
365 try testing.expectApproxEqAbs(asinBinary64(0x1p+0), 0x1.921fb54442d18p+0, math.floatEpsAt(f64, 0x1.921fb54442d18p+0));
366 try testing.expectApproxEqAbs(asinBinary64(-0x1p+0), -0x1.921fb54442d18p+0, math.floatEpsAt(f64, -0x1.921fb54442d18p+0));
367 try testing.expectEqual(asinBinary64(0x0p+0), 0x0p+0);
368 try testing.expectEqual(asinBinary64(-0x0p+0), 0x0p+0);
369 try testing.expect(math.isNan(asinBinary64(0x1.000002p+0)));
370 try testing.expect(math.isNan(asinBinary64(-0x1.000002p+0)));
371 try testing.expect(math.isNan(asinBinary64(math.inf(f64))));
372 try testing.expect(math.isNan(asinBinary64(-math.inf(f64))));
373 try testing.expect(math.isNan(asinBinary64(math.nan(f64))));
374}
375
376test "asinBinary64" {
377 try testing.expectApproxEqAbs(asinBinary64(0x1.e674fba3e40d5p-2), 0x1.fae86c5941692p-2, math.floatEpsAt(f64, 0x1.fae86c5941692p-2));
378 try testing.expectApproxEqAbs(asinBinary64(-0x1.30fd0566fd979p-1), -0x1.46b6ad730c93ap-1, math.floatEpsAt(f64, -0x1.46b6ad730c93ap-1));
379 try testing.expectApproxEqAbs(asinBinary64(0x1.6444a25abfeaap-2), 0x1.6be0be8074eep-2, math.floatEpsAt(f64, 0x1.6be0be8074eep-2));
380 try testing.expectApproxEqAbs(asinBinary64(0x1.40a53228d1a13p-1), 0x1.5a7e98f53f717p-1, math.floatEpsAt(f64, 0x1.5a7e98f53f717p-1));
381 try testing.expectApproxEqAbs(asinBinary64(-0x1.ccc6d64845cfdp-1), -0x1.1ea2602d14e8p0, math.floatEpsAt(f64, -0x1.1ea2602d14e8p0));
382 try testing.expectApproxEqAbs(asinBinary64(-0x1.94bd91b7fc74bp-1), -0x1.d2c2634193158p-1, math.floatEpsAt(f64, -0x1.d2c2634193158p-1));
383 try testing.expectApproxEqAbs(asinBinary64(-0x1.8d741b5797fccp-2), -0x1.982d5f1895d2p-2, math.floatEpsAt(f64, -0x1.982d5f1895d2p-2));
384 try testing.expectApproxEqAbs(asinBinary64(-0x1.3e8e7e15881c5p-3), -0x1.3fdaf7dfdc864p-3, math.floatEpsAt(f64, -0x1.3fdaf7dfdc864p-3));
385 try testing.expectApproxEqAbs(asinBinary64(-0x1.88222d8ab8ca9p-2), -0x1.9269540735b7bp-2, math.floatEpsAt(f64, -0x1.9269540735b7bp-2));
386 try testing.expectApproxEqAbs(asinBinary64(-0x1.41c0e9babcbd2p-2), -0x1.474c4c6625527p-2, math.floatEpsAt(f64, -0x1.474c4c6625527p-2));
387}
388
389test "asinExtended80.special" {
390 try testing.expectApproxEqAbs(asinExtended80(0x1p+0), 0x1.921fb54442d1846ap+0, math.floatEpsAt(f80, 0x1.921fb54442d1846ap+0));
391 try testing.expectApproxEqAbs(asinExtended80(-0x1p+0), -0x1.921fb54442d1846ap+0, math.floatEpsAt(f80, -0x1.921fb54442d1846ap+0));
392 try testing.expectEqual(asinExtended80(0x0p+0), 0x0p+0);
393 try testing.expectEqual(asinExtended80(-0x0p+0), 0x0p+0);
394 try testing.expect(math.isNan(asinExtended80(0x1.0000000000000002p+0)));
395 try testing.expect(math.isNan(asinExtended80(-0x1.0000000000000002p+0)));
396 try testing.expect(math.isNan(asinExtended80(math.inf(f80))));
397 try testing.expect(math.isNan(asinExtended80(-math.inf(f80))));
398 try testing.expect(math.isNan(asinExtended80(math.nan(f80))));
399}
162400
163 try expect(math.approxEqAbs(f64, asin64(0.0), 0.0, epsilon));
164 try expect(math.approxEqAbs(f64, asin64(0.2), 0.201358, epsilon));
165 try expect(math.approxEqAbs(f64, asin64(-0.2), -0.201358, epsilon));
166 try expect(math.approxEqAbs(f64, asin64(0.3434), 0.350535, epsilon));
167 try expect(math.approxEqAbs(f64, asin64(0.5), 0.523599, epsilon));
168 try expect(math.approxEqAbs(f64, asin64(0.8923), 1.102415, epsilon));
401test "asinExtended80" {
402 try testing.expectApproxEqAbs(asinExtended80(0x1.63cf98bc52ce0da8p-9), 0x1.63cfb560149daa9p-9, math.floatEpsAt(f80, 0x1.63cfb560149daa9p-9));
403 try testing.expectApproxEqAbs(asinExtended80(-0x1.0473756f7ae930dp-1), -0x1.113cbacd8cd1b96cp-1, math.floatEpsAt(f80, -0x1.113cbacd8cd1b96cp-1));
404 try testing.expectApproxEqAbs(asinExtended80(-0x1.2310057e005cc288p-2), -0x1.2721b231d197b064p-2, math.floatEpsAt(f80, -0x1.2721b231d197b064p-2));
405 try testing.expectApproxEqAbs(asinExtended80(0x1.f13b03bd685d96eap-1), 0x1.547c408c5d2b05aap0, math.floatEpsAt(f80, 0x1.547c408c5d2b05aap0));
406 try testing.expectApproxEqAbs(asinExtended80(-0x1.d5c507e3ef84041cp-1), -0x1.296b76bfadbb5cecp0, math.floatEpsAt(f80, -0x1.296b76bfadbb5cecp0));
407 try testing.expectApproxEqAbs(asinExtended80(0x1.8222cbc9147153d8p-1), 0x1.b572da8729a84f2ap-1, math.floatEpsAt(f80, 0x1.b572da8729a84f2ap-1));
408 try testing.expectApproxEqAbs(asinExtended80(-0x1.42c9e6b4a088a246p-11), -0x1.42c9e80ac0524dap-11, math.floatEpsAt(f80, -0x1.42c9e80ac0524dap-11));
409 try testing.expectApproxEqAbs(asinExtended80(-0x1.8f78d49deadb521cp-3), -0x1.920ca86aef6c3028p-3, math.floatEpsAt(f80, -0x1.920ca86aef6c3028p-3));
410 try testing.expectApproxEqAbs(asinExtended80(-0x1.ab98792783515774p-2), -0x1.b91cb4f7204d92fp-2, math.floatEpsAt(f80, -0x1.b91cb4f7204d92fp-2));
411 try testing.expectApproxEqAbs(asinExtended80(-0x1.104fe30cef6800aap-1), -0x1.1f20815fdc4c5304p-1, math.floatEpsAt(f80, -0x1.1f20815fdc4c5304p-1));
169412}
170413
171test "asin32.special" {
172 try expect(math.isPositiveZero(asin32(0.0)));
173 try expect(math.isNegativeZero(asin32(-0.0)));
174 try expect(math.isNan(asin32(-2)));
175 try expect(math.isNan(asin32(1.5)));
414test "asinBinary128.special" {
415 try testing.expectApproxEqAbs(asinBinary128(0x1p+0), 0x1.921fb54442d18469898cc51701b8p0, math.floatEpsAt(f128, 0x1.921fb54442d18469898cc51701b8p0));
416 try testing.expectApproxEqAbs(asinBinary128(-0x1p+0), -0x1.921fb54442d18469898cc51701b8p0, math.floatEpsAt(f128, -0x1.921fb54442d18469898cc51701b8p0));
417 try testing.expectEqual(asinBinary128(0x0p+0), 0x0p+0);
418 try testing.expectEqual(asinBinary128(-0x0p+0), 0x0p+0);
419 try testing.expect(math.isNan(asinBinary128(0x1.0000000000000000000000000001p0)));
420 try testing.expect(math.isNan(asinBinary128(-0x1.0000000000000000000000000001p0)));
421 try testing.expect(math.isNan(asinBinary128(math.inf(f128))));
422 try testing.expect(math.isNan(asinBinary128(-math.inf(f128))));
423 try testing.expect(math.isNan(asinBinary128(math.nan(f128))));
176424}
177425
178test "asin64.special" {
179 try expect(math.isPositiveZero(asin64(0.0)));
180 try expect(math.isNegativeZero(asin64(-0.0)));
181 try expect(math.isNan(asin64(-2)));
182 try expect(math.isNan(asin64(1.5)));
426test "asinBinary128" {
427 try testing.expectApproxEqAbs(asinBinary128(0x1.85868ce287ca0196b01c25fec5ffp-3), 0x1.87e9c740d7837f8e8fa667988fbep-3, math.floatEpsAt(f128, 0x1.87e9c740d7837f8e8fa667988fbep-3));
428 try testing.expectApproxEqAbs(asinBinary128(0x1.8718d6d30b4daed08d04ef59f478p-1), 0x1.bd11a474e864213b48e0f005f1f4p-1, math.floatEpsAt(f128, 0x1.bd11a474e864213b48e0f005f1f4p-1));
429 try testing.expectApproxEqAbs(asinBinary128(0x1.11a67640cd7f0ba5d5e362f3abfap-1), 0x1.20b56f8b42649fe72d1f8d68a378p-1, math.floatEpsAt(f128, 0x1.20b56f8b42649fe72d1f8d68a378p-1));
430 try testing.expectApproxEqAbs(asinBinary128(-0x1.bd13bf14a9dce22188e52650daa7p-1), -0x1.0dc3a7ddb9736e5ad699bf338566p0, math.floatEpsAt(f128, -0x1.0dc3a7ddb9736e5ad699bf338566p0));
431 try testing.expectApproxEqAbs(asinBinary128(-0x1.dee0bc217fc462af57c484eefa71p-2), -0x1.f250716038f70fa50a5826c03802p-2, math.floatEpsAt(f128, -0x1.f250716038f70fa50a5826c03802p-2));
432 try testing.expectApproxEqAbs(asinBinary128(-0x1.ea7df9139371c10b9d6fd2bbccd3p-1), -0x1.47a8b4cdd327f90056722feddbabp0, math.floatEpsAt(f128, -0x1.47a8b4cdd327f90056722feddbabp0));
433 try testing.expectApproxEqAbs(asinBinary128(0x1.04aaea6de3b5a616460702f26dfcp-2), 0x1.079178d52be662dec67e2cd7f6e9p-2, math.floatEpsAt(f128, 0x1.079178d52be662dec67e2cd7f6e9p-2));
434 try testing.expectApproxEqAbs(asinBinary128(-0x1.c7ea85e6b61be666435a7d99444cp-1), -0x1.192df5a8d71702cf1e27014887b2p0, math.floatEpsAt(f128, -0x1.192df5a8d71702cf1e27014887b2p0));
435 try testing.expectApproxEqAbs(asinBinary128(-0x1.6e210214e40edf6c8479998189d1p-1), -0x1.97f1092fd94ac0fdfddae2e1222bp-1, math.floatEpsAt(f128, -0x1.97f1092fd94ac0fdfddae2e1222bp-1));
436 try testing.expectApproxEqAbs(asinBinary128(-0x1.95061bf93ed6986a45d20f0e1064p-3), -0x1.97b62bc5ae6512093828828325e1p-3, math.floatEpsAt(f128, -0x1.97b62bc5ae6512093828828325e1p-3));
183437}