@zigc/lib 0.16.0-dev.3091 → 0.16.0-dev.3121

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/c/math.zig +111 -22
  2. package/compiler_rt/cos.zig +141 -52
  3. package/compiler_rt/long_double.zig +37 -0
  4. package/compiler_rt/rem_pio2l.zig +173 -0
  5. package/compiler_rt/sin.zig +140 -55
  6. package/compiler_rt/sincos.zig +279 -72
  7. package/compiler_rt/tan.zig +118 -47
  8. package/compiler_rt/trig.zig +256 -6
  9. package/package.json +1 -1
  10. package/std/debug/Info.zig +4 -0
  11. package/std/heap/ArenaAllocator.zig +145 -154
  12. package/std/mem/Allocator.zig +4 -5
  13. package/std/mem.zig +48 -0
  14. package/libc/mingw/math/arm/sincos.S +0 -30
  15. package/libc/mingw/math/arm-common/sincosl.c +0 -13
  16. package/libc/mingw/math/arm64/rint.c +0 -12
  17. package/libc/mingw/math/arm64/rintf.c +0 -12
  18. package/libc/mingw/math/arm64/sincos.S +0 -32
  19. package/libc/mingw/math/frexpf.c +0 -13
  20. package/libc/mingw/math/frexpl.c +0 -71
  21. package/libc/mingw/math/x86/cos.def.h +0 -65
  22. package/libc/mingw/math/x86/cosl.c +0 -46
  23. package/libc/mingw/math/x86/cosl_internal.S +0 -55
  24. package/libc/mingw/math/x86/sin.def.h +0 -65
  25. package/libc/mingw/math/x86/sinl.c +0 -46
  26. package/libc/mingw/math/x86/sinl_internal.S +0 -58
  27. package/libc/mingw/math/x86/tanl.S +0 -62
  28. package/libc/musl/src/math/__cosl.c +0 -96
  29. package/libc/musl/src/math/__sinl.c +0 -78
  30. package/libc/musl/src/math/__tanl.c +0 -143
  31. package/libc/musl/src/math/aarch64/lrint.c +0 -10
  32. package/libc/musl/src/math/aarch64/lrintf.c +0 -10
  33. package/libc/musl/src/math/aarch64/rintf.c +0 -7
  34. package/libc/musl/src/math/cosl.c +0 -39
  35. package/libc/musl/src/math/finite.c +0 -7
  36. package/libc/musl/src/math/finitef.c +0 -7
  37. package/libc/musl/src/math/frexp.c +0 -23
  38. package/libc/musl/src/math/frexpf.c +0 -23
  39. package/libc/musl/src/math/frexpl.c +0 -29
  40. package/libc/musl/src/math/i386/lrint.c +0 -8
  41. package/libc/musl/src/math/i386/lrintf.c +0 -8
  42. package/libc/musl/src/math/i386/rintf.c +0 -7
  43. package/libc/musl/src/math/lrint.c +0 -72
  44. package/libc/musl/src/math/lrintf.c +0 -8
  45. package/libc/musl/src/math/powerpc64/lrint.c +0 -16
  46. package/libc/musl/src/math/powerpc64/lrintf.c +0 -16
  47. package/libc/musl/src/math/rintf.c +0 -30
  48. package/libc/musl/src/math/s390x/rintf.c +0 -15
  49. package/libc/musl/src/math/sincosl.c +0 -60
  50. package/libc/musl/src/math/sinl.c +0 -41
  51. package/libc/musl/src/math/tanl.c +0 -29
  52. package/libc/musl/src/math/x32/lrint.s +0 -5
  53. package/libc/musl/src/math/x32/lrintf.s +0 -5
  54. package/libc/musl/src/math/x86_64/lrint.c +0 -8
  55. package/libc/musl/src/math/x86_64/lrintf.c +0 -8
package/c/math.zig CHANGED
@@ -36,6 +36,8 @@ comptime {
36
36
 
37
37
  if (builtin.target.isMinGW() or builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
38
38
  symbol(&coshf, "coshf");
39
+ symbol(&frexpf, "frexpf");
40
+ symbol(&frexpl, "frexpl");
39
41
  symbol(&hypotf, "hypotf");
40
42
  symbol(&hypotl, "hypotl");
41
43
  symbol(&modff, "modff");
@@ -46,6 +48,11 @@ comptime {
46
48
  symbol(&tanhf, "tanhf");
47
49
  }
48
50
 
51
+ if (builtin.target.isMinGW() or builtin.target.isMuslLibC()) {
52
+ symbol(&rint, "rint");
53
+ symbol(&rintf, "rintf");
54
+ }
55
+
49
56
  if (builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
50
57
  symbol(&acos, "acos");
51
58
  symbol(&acosf, "acosf");
@@ -60,7 +67,12 @@ comptime {
60
67
  symbol(&exp10, "exp10");
61
68
  symbol(&exp10f, "exp10f");
62
69
  symbol(&fdim, "fdim");
70
+ symbol(&finite, "finite");
71
+ symbol(&finitef, "finitef");
72
+ symbol(&frexp, "frexp");
63
73
  symbol(&hypot, "hypot");
74
+ symbol(&lrint, "lrint");
75
+ symbol(&lrintf, "lrintf");
64
76
  symbol(&modf, "modf");
65
77
  symbol(&pow, "pow");
66
78
  symbol(&pow10, "pow10");
@@ -71,7 +83,6 @@ comptime {
71
83
  if (builtin.target.isMuslLibC()) {
72
84
  symbol(&copysign, "copysign");
73
85
  symbol(&copysignf, "copysignf");
74
- symbol(&rint, "rint");
75
86
  }
76
87
 
77
88
  symbol(&copysignl, "copysignl");
@@ -161,6 +172,45 @@ fn fdim(x: f64, y: f64) callconv(.c) f64 {
161
172
  return 0;
162
173
  }
163
174
 
175
+ fn finite(x: f64) callconv(.c) c_int {
176
+ return if (math.isFinite(x)) 1 else 0;
177
+ }
178
+
179
+ fn finitef(x: f32) callconv(.c) c_int {
180
+ return if (math.isFinite(x)) 1 else 0;
181
+ }
182
+
183
+ fn frexpGeneric(comptime T: type, x: T, e: *c_int) T {
184
+ // libc expects `*e` to be unspecified in this case; an unspecified C value
185
+ // should be a valid value of the relevant type, yet Zig's std
186
+ // implementation sets it to `undefined` -- which can even be nonsense
187
+ // according to the type (int). Therefore, we're setting it to a valid
188
+ // int value in Zig -- a zero.
189
+ //
190
+ // This mirrors the handling of infinities, where libc also expects
191
+ // unspecified for the value of `*e` and Zig std sets it to a zero.
192
+ if (math.isNan(x)) {
193
+ e.* = 0;
194
+ return x;
195
+ }
196
+
197
+ const r = math.frexp(x);
198
+ e.* = r.exponent;
199
+ return r.significand;
200
+ }
201
+
202
+ fn frexp(x: f64, e: *c_int) callconv(.c) f64 {
203
+ return frexpGeneric(f64, x, e);
204
+ }
205
+
206
+ fn frexpf(x: f32, e: *c_int) callconv(.c) f32 {
207
+ return frexpGeneric(f32, x, e);
208
+ }
209
+
210
+ fn frexpl(x: c_longdouble, e: *c_int) callconv(.c) c_longdouble {
211
+ return frexpGeneric(c_longdouble, x, e);
212
+ }
213
+
164
214
  fn hypot(x: f64, y: f64) callconv(.c) f64 {
165
215
  return math.hypot(x, y);
166
216
  }
@@ -185,6 +235,14 @@ fn isnanl(x: c_longdouble) callconv(.c) c_int {
185
235
  return if (math.isNan(x)) 1 else 0;
186
236
  }
187
237
 
238
+ fn lrint(x: f64) callconv(.c) c_long {
239
+ return @intFromFloat(rint(x));
240
+ }
241
+
242
+ fn lrintf(x: f32) callconv(.c) c_long {
243
+ return @intFromFloat(rintf(x));
244
+ }
245
+
188
246
  fn modfGeneric(comptime T: type, x: T, iptr: *T) T {
189
247
  if (math.isNegativeInf(x)) {
190
248
  iptr.* = -math.inf(T);
@@ -299,7 +357,7 @@ fn pow10f(x: f32) callconv(.c) f32 {
299
357
  }
300
358
 
301
359
  fn rint(x: f64) callconv(.c) f64 {
302
- const toint: f64 = 1.0 / @as(f64, math.floatEps(f64));
360
+ const toint: f64 = 1.0 / math.floatEps(f64);
303
361
  const a: u64 = @bitCast(x);
304
362
  const e = a >> 52 & 0x7ff;
305
363
  const s = a >> 63;
@@ -319,39 +377,70 @@ fn rint(x: f64) callconv(.c) f64 {
319
377
  return y;
320
378
  }
321
379
 
322
- test "rint" {
380
+ fn rintf(x: f32) callconv(.c) f32 {
381
+ const toint: f32 = 1.0 / math.floatEps(f32);
382
+ const a: u32 = @bitCast(x);
383
+ const e = a >> 23 & 0xff;
384
+ const s = a >> 31;
385
+ var y: f32 = undefined;
386
+
387
+ if (e >= 0x7f + 23) {
388
+ return x;
389
+ }
390
+
391
+ if (s == 1) {
392
+ y = x - toint + toint;
393
+ } else {
394
+ y = x + toint - toint;
395
+ }
396
+
397
+ if (y == 0) {
398
+ return if (s == 1) -0.0 else 0;
399
+ }
400
+ return y;
401
+ }
402
+
403
+ fn testRint(comptime T: type) !void {
404
+ const f = switch (T) {
405
+ f32 => rintf,
406
+ f64 => rint,
407
+ else => @compileError("rint not implemented for" ++ @typeName(T)),
408
+ };
409
+
323
410
  // Positive numbers round correctly
324
- try expectEqual(@as(f64, 42.0), rint(42.2));
325
- try expectEqual(@as(f64, 42.0), rint(41.8));
411
+ try expectEqual(@as(T, 42.0), f(42.2));
412
+ try expectEqual(@as(T, 42.0), f(41.8));
326
413
 
327
414
  // Negative numbers round correctly
328
- try expectEqual(@as(f64, -6.0), rint(-5.9));
329
- try expectEqual(@as(f64, -6.0), rint(-6.1));
415
+ try expectEqual(@as(T, -6.0), f(-5.9));
416
+ try expectEqual(@as(T, -6.0), f(-6.1));
330
417
 
331
418
  // No rounding needed test
332
- try expectEqual(@as(f64, 5.0), rint(5.0));
333
- try expectEqual(@as(f64, -10.0), rint(-10.0));
334
- try expectEqual(@as(f64, 0.0), rint(0.0));
419
+ try expectEqual(@as(T, 5.0), f(5.0));
420
+ try expectEqual(@as(T, -10.0), f(-10.0));
421
+ try expectEqual(@as(T, 0.0), f(0.0));
335
422
 
336
423
  // Very large numbers return unchanged
337
- const large: f64 = 9007199254740992.0; // 2^53
338
- try expectEqual(large, rint(large));
339
- try expectEqual(-large, rint(-large));
424
+ const large: T = 9007199254740992.0; // 2^53
425
+ try expectEqual(large, f(large));
426
+ try expectEqual(-large, f(-large));
340
427
 
341
428
  // Small positive numbers round to zero
342
- const pos_result = rint(0.3);
343
- try expectEqual(@as(f64, 0.0), pos_result);
344
- try expect(@as(u64, @bitCast(pos_result)) == 0);
429
+ const pos_result = f(0.3);
430
+ try expect(math.isPositiveZero(pos_result));
345
431
 
346
432
  // Small negative numbers round to negative zero
347
- const neg_result = rint(-0.3);
348
- try expectEqual(@as(f64, 0.0), neg_result);
349
- const bits: u64 = @bitCast(neg_result);
350
- try expect((bits >> 63) == 1);
433
+ const neg_result = f(-0.3);
434
+ try expect(math.isNegativeZero(neg_result));
351
435
 
352
436
  // Exact half rounds to nearest even (banker's rounding)
353
- try expectEqual(@as(f64, 2.0), rint(2.5));
354
- try expectEqual(@as(f64, 4.0), rint(3.5));
437
+ try expectEqual(@as(T, 2.0), f(2.5));
438
+ try expectEqual(@as(T, 4.0), f(3.5));
439
+ }
440
+
441
+ test "rint" {
442
+ try testRint(f32);
443
+ try testRint(f64);
355
444
  }
356
445
 
357
446
  fn tanh(x: f64) callconv(.c) f64 {
@@ -1,19 +1,30 @@
1
+ //! Ported from musl, which is licensed under the MIT license:
2
+ //! https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3
+ //!
4
+ //! https://git.musl-libc.org/cgit/musl/tree/src/math/cosf.c
5
+ //! https://git.musl-libc.org/cgit/musl/tree/src/math/cos.c
6
+ //! https://git.musl-libc.org/cgit/musl/tree/src/math/cosl.c
7
+
1
8
  const std = @import("std");
2
9
  const math = std.math;
3
10
  const mem = std.mem;
4
11
  const expect = std.testing.expect;
12
+ const expectApproxEqAbs = std.testing.expectApproxEqAbs;
5
13
 
6
14
  const compiler_rt = @import("../compiler_rt.zig");
7
15
  const symbol = @import("../compiler_rt.zig").symbol;
8
16
  const trig = @import("trig.zig");
9
17
  const rem_pio2 = @import("rem_pio2.zig").rem_pio2;
10
18
  const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f;
19
+ const rem_pio2l = @import("rem_pio2l.zig").rem_pio2l;
20
+ const ld = @import("long_double.zig");
11
21
 
12
22
  comptime {
13
- symbol(&__cosh, "__cosh");
23
+ symbol(&cosh, "__cosh");
24
+ symbol(&cosl, "__cosl");
14
25
  symbol(&cosf, "cosf");
15
26
  symbol(&cos, "cos");
16
- symbol(&__cosx, "__cosx");
27
+ symbol(&cosx, "__cosx");
17
28
  if (compiler_rt.want_ppc_abi) {
18
29
  symbol(&cosq, "cosf128");
19
30
  }
@@ -21,7 +32,7 @@ comptime {
21
32
  symbol(&cosl, "cosl");
22
33
  }
23
34
 
24
- pub fn __cosh(a: f16) callconv(.c) f16 {
35
+ pub fn cosh(a: f16) callconv(.c) f16 {
25
36
  // TODO: more efficient implementation
26
37
  return @floatCast(cosf(a));
27
38
  }
@@ -43,27 +54,27 @@ pub fn cosf(x: f32) callconv(.c) f32 {
43
54
  if (compiler_rt.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1p120);
44
55
  return 1.0;
45
56
  }
46
- return trig.__cosdf(x);
57
+ return trig.cosdf(x);
47
58
  }
48
59
  if (ix <= 0x407b53d1) { // |x| ~<= 5*pi/4
49
60
  if (ix > 0x4016cbe3) { // |x| ~> 3*pi/4
50
- return -trig.__cosdf(if (sign) x + c2pio2 else x - c2pio2);
61
+ return -trig.cosdf(if (sign) x + c2pio2 else x - c2pio2);
51
62
  } else {
52
63
  if (sign) {
53
- return trig.__sindf(x + c1pio2);
64
+ return trig.sindf(x + c1pio2);
54
65
  } else {
55
- return trig.__sindf(c1pio2 - x);
66
+ return trig.sindf(c1pio2 - x);
56
67
  }
57
68
  }
58
69
  }
59
70
  if (ix <= 0x40e231d5) { // |x| ~<= 9*pi/4
60
71
  if (ix > 0x40afeddf) { // |x| ~> 7*pi/4
61
- return trig.__cosdf(if (sign) x + c4pio2 else x - c4pio2);
72
+ return trig.cosdf(if (sign) x + c4pio2 else x - c4pio2);
62
73
  } else {
63
74
  if (sign) {
64
- return trig.__sindf(-x - c3pio2);
75
+ return trig.sindf(-x - c3pio2);
65
76
  } else {
66
- return trig.__sindf(x - c3pio2);
77
+ return trig.sindf(x - c3pio2);
67
78
  }
68
79
  }
69
80
  }
@@ -76,10 +87,10 @@ pub fn cosf(x: f32) callconv(.c) f32 {
76
87
  var y: f64 = undefined;
77
88
  const n = rem_pio2f(x, &y);
78
89
  return switch (n & 3) {
79
- 0 => trig.__cosdf(y),
80
- 1 => trig.__sindf(-y),
81
- 2 => -trig.__cosdf(y),
82
- else => trig.__sindf(y),
90
+ 0 => trig.cosdf(y),
91
+ 1 => trig.sindf(-y),
92
+ 2 => -trig.cosdf(y),
93
+ else => trig.sindf(y),
83
94
  };
84
95
  }
85
96
 
@@ -94,7 +105,7 @@ pub fn cos(x: f64) callconv(.c) f64 {
94
105
  if (compiler_rt.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1p120);
95
106
  return 1.0;
96
107
  }
97
- return trig.__cos(x, 0);
108
+ return trig.cos(x, 0);
98
109
  }
99
110
 
100
111
  // cos(Inf or NaN) is NaN
@@ -105,66 +116,144 @@ pub fn cos(x: f64) callconv(.c) f64 {
105
116
  var y: [2]f64 = undefined;
106
117
  const n = rem_pio2(x, &y);
107
118
  return switch (n & 3) {
108
- 0 => trig.__cos(y[0], y[1]),
109
- 1 => -trig.__sin(y[0], y[1], 1),
110
- 2 => -trig.__cos(y[0], y[1]),
111
- else => trig.__sin(y[0], y[1], 1),
119
+ 0 => trig.cos(y[0], y[1]),
120
+ 1 => -trig.sin(y[0], y[1], 1),
121
+ 2 => -trig.cos(y[0], y[1]),
122
+ else => trig.sin(y[0], y[1], 1),
112
123
  };
113
124
  }
114
125
 
115
- pub fn __cosx(a: f80) callconv(.c) f80 {
116
- // TODO: more efficient implementation
117
- return @floatCast(cosq(a));
126
+ pub fn cosx(x: f80) callconv(.c) f80 {
127
+ const se = ld.signExponent(x) & 0x7fff;
128
+ if (se == 0x7fff) {
129
+ return x - x;
130
+ }
131
+
132
+ if (@abs(x) < trig.pi_4) {
133
+ if (se < 0x3fff - math.floatMantissaBits(f80)) {
134
+ // raise inexact if x!=0
135
+ return 1.0 + x;
136
+ }
137
+ return trig.cosx(x, 0.0);
138
+ }
139
+
140
+ var y: [2]f80 = undefined;
141
+ const n = rem_pio2l(f80, x, &y);
142
+ return switch (n & 3) {
143
+ 0 => trig.cosx(y[0], y[1]),
144
+ 1 => -trig.sinx(y[0], y[1], 1),
145
+ 2 => -trig.cosx(y[0], y[1]),
146
+ else => trig.sinx(y[0], y[1], 1),
147
+ };
118
148
  }
119
149
 
120
- pub fn cosq(a: f128) callconv(.c) f128 {
121
- // TODO: more correct implementation
122
- return cos(@floatCast(a));
150
+ pub fn cosq(x: f128) callconv(.c) f128 {
151
+ const se = ld.signExponent(x) & 0x7fff;
152
+ if (se == 0x7fff) {
153
+ return x - x;
154
+ }
155
+
156
+ if (@abs(x) < trig.pi_4) {
157
+ if (se < 0x3fff - math.floatMantissaBits(f128)) {
158
+ // raise inexact if x!=0
159
+ return 1.0 + x;
160
+ }
161
+ return trig.cosq(x, 0.0);
162
+ }
163
+
164
+ var y: [2]f128 = undefined;
165
+ const n = rem_pio2l(f128, x, &y);
166
+ return switch (n & 3) {
167
+ 0 => trig.cosq(y[0], y[1]),
168
+ 1 => -trig.sinq(y[0], y[1], 1),
169
+ 2 => -trig.cosq(y[0], y[1]),
170
+ else => trig.sinq(y[0], y[1], 1),
171
+ };
123
172
  }
124
173
 
125
174
  pub fn cosl(x: c_longdouble) callconv(.c) c_longdouble {
126
175
  switch (@typeInfo(c_longdouble).float.bits) {
127
- 16 => return __cosh(x),
176
+ 16 => return cosh(x),
128
177
  32 => return cosf(x),
129
178
  64 => return cos(x),
130
- 80 => return __cosx(x),
179
+ 80 => return cosx(x),
131
180
  128 => return cosq(x),
132
181
  else => @compileError("unreachable"),
133
182
  }
134
183
  }
135
184
 
136
- test "cos32" {
137
- const epsilon = 0.00001;
185
+ fn testCosSpecial(comptime T: type) !void {
186
+ const f = switch (T) {
187
+ f32 => cosf,
188
+ f64 => cos,
189
+ f80 => cosx,
190
+ f128 => cosq,
191
+ else => @compileError("unimplemented"),
192
+ };
138
193
 
139
- try expect(math.approxEqAbs(f32, cosf(0.0), 1.0, epsilon));
140
- try expect(math.approxEqAbs(f32, cosf(0.2), 0.980067, epsilon));
141
- try expect(math.approxEqAbs(f32, cosf(0.8923), 0.627623, epsilon));
142
- try expect(math.approxEqAbs(f32, cosf(1.5), 0.070737, epsilon));
143
- try expect(math.approxEqAbs(f32, cosf(-1.5), 0.070737, epsilon));
144
- try expect(math.approxEqAbs(f32, cosf(37.45), 0.969132, epsilon));
145
- try expect(math.approxEqAbs(f32, cosf(89.123), 0.400798, epsilon));
194
+ try expect(f(0.0) == 1.0);
195
+ try expect(f(-0.0) == 1.0);
196
+ try expect(math.isNan(f(math.inf(T))));
197
+ try expect(math.isNan(f(-math.inf(T))));
198
+ try expect(math.isNan(f(math.nan(T))));
146
199
  }
147
200
 
148
- test "cos64" {
149
- const epsilon = 0.000001;
150
-
151
- try expect(math.approxEqAbs(f64, cos(0.0), 1.0, epsilon));
152
- try expect(math.approxEqAbs(f64, cos(0.2), 0.980067, epsilon));
153
- try expect(math.approxEqAbs(f64, cos(0.8923), 0.627623, epsilon));
154
- try expect(math.approxEqAbs(f64, cos(1.5), 0.070737, epsilon));
155
- try expect(math.approxEqAbs(f64, cos(-1.5), 0.070737, epsilon));
156
- try expect(math.approxEqAbs(f64, cos(37.45), 0.969132, epsilon));
157
- try expect(math.approxEqAbs(f64, cos(89.123), 0.40080, epsilon));
201
+ test "cos32.normal" {
202
+ const epsilon = math.floatEps(f32);
203
+ try expectApproxEqAbs(@as(f32, 1.0), cosf(0.0), epsilon);
204
+ try expectApproxEqAbs(@as(f32, 0.9800666), cosf(0.2), epsilon);
205
+ try expectApproxEqAbs(@as(f32, 0.6276231), cosf(0.8923), epsilon);
206
+ try expectApproxEqAbs(@as(f32, 0.0707372), cosf(1.5), epsilon);
207
+ try expectApproxEqAbs(@as(f32, 0.0707372), cosf(-1.5), epsilon);
208
+ try expectApproxEqAbs(@as(f32, 0.96913195), cosf(37.45), epsilon);
209
+ try expectApproxEqAbs(@as(f32, 0.40079966), cosf(89.123), epsilon);
158
210
  }
159
211
 
160
212
  test "cos32.special" {
161
- try expect(math.isNan(cosf(math.inf(f32))));
162
- try expect(math.isNan(cosf(-math.inf(f32))));
163
- try expect(math.isNan(cosf(math.nan(f32))));
213
+ try testCosSpecial(f32);
214
+ }
215
+
216
+ test "cos64.normal" {
217
+ const epsilon = math.floatEps(f64);
218
+ try expectApproxEqAbs(@as(f64, 1.0), cos(0.0), epsilon);
219
+ try expectApproxEqAbs(@as(f64, 0.9800665778412416), cos(0.2), epsilon);
220
+ try expectApproxEqAbs(@as(f64, 0.6276230983360804), cos(0.8923), epsilon);
221
+ try expectApproxEqAbs(@as(f64, 0.0707372016677029), cos(1.5), epsilon);
222
+ try expectApproxEqAbs(@as(f64, 0.0707372016677029), cos(-1.5), epsilon);
223
+ try expectApproxEqAbs(@as(f64, 0.9691317730707778), cos(37.45), epsilon);
224
+ try expectApproxEqAbs(@as(f64, 0.4008006809354791), cos(89.123), epsilon);
164
225
  }
165
226
 
166
227
  test "cos64.special" {
167
- try expect(math.isNan(cos(math.inf(f64))));
168
- try expect(math.isNan(cos(-math.inf(f64))));
169
- try expect(math.isNan(cos(math.nan(f64))));
228
+ try testCosSpecial(f64);
229
+ }
230
+
231
+ test "cos80.normal" {
232
+ const epsilon = math.floatEps(f80);
233
+ try expectApproxEqAbs(@as(f80, 1.0), cosx(0.0), epsilon);
234
+ try expectApproxEqAbs(@as(f80, 0.98006657784124163112419651674816888), cosx(0.2), epsilon);
235
+ try expectApproxEqAbs(@as(f80, 0.62762309833608037003563995939286067), cosx(0.8923), epsilon);
236
+ try expectApproxEqAbs(@as(f80, 0.070737201667702910088189851434268747), cosx(1.5), epsilon);
237
+ try expectApproxEqAbs(@as(f80, 0.070737201667702910088189851434268747), cosx(-1.5), epsilon);
238
+ try expectApproxEqAbs(@as(f80, 0.9691317730707771246), cosx(37.45), epsilon);
239
+ try expectApproxEqAbs(@as(f80, 0.4008006809354834001), cosx(89.123), epsilon);
240
+ }
241
+
242
+ test "cos80.special" {
243
+ try testCosSpecial(f80);
244
+ }
245
+
246
+ test "cos128.normal" {
247
+ const epsilon = math.floatEps(f128);
248
+ try expectApproxEqAbs(@as(f128, 1.0), cosq(0.0), epsilon);
249
+ try expectApproxEqAbs(@as(f128, 0.98006657784124163112419651674816888), cosq(0.2), epsilon);
250
+ try expectApproxEqAbs(@as(f128, 0.62762309833608037003563995939286067), cosq(0.8923), epsilon);
251
+ try expectApproxEqAbs(@as(f128, 0.070737201667702910088189851434268747), cosq(1.5), epsilon);
252
+ try expectApproxEqAbs(@as(f128, 0.070737201667702910088189851434268747), cosq(-1.5), epsilon);
253
+ try expectApproxEqAbs(@as(f128, 0.96913177307077712443149563847233230), cosq(37.45), epsilon);
254
+ try expectApproxEqAbs(@as(f128, 0.40080068093548339848199454493704702), cosq(89.123), epsilon);
255
+ }
256
+
257
+ test "cos128.special" {
258
+ try testCosSpecial(f128);
170
259
  }
@@ -0,0 +1,37 @@
1
+ //! Utilities for dealing with the `long double` type (`f80` or `f128`)
2
+
3
+ const std = @import("std");
4
+
5
+ pub const U80 = std.meta.Int(.unsigned, 80);
6
+
7
+ /// Returns the sign + exponent bits of a `long double`
8
+ pub fn signExponent(x: anytype) u16 {
9
+ const T = @TypeOf(x);
10
+ switch (T) {
11
+ f80 => {
12
+ const bits: U80 = @bitCast(x);
13
+ return @intCast(bits >> 64);
14
+ },
15
+ f128 => {
16
+ const bits: u128 = @bitCast(x);
17
+ return @intCast(bits >> 112);
18
+ },
19
+ else => @compileError("`signExponent` supports only `f80` and `f128`, got: " ++ @typeName(T)),
20
+ }
21
+ }
22
+
23
+ /// Takes the top 16 bits of a `long double`'s mantissa
24
+ pub fn mantissaTop(x: anytype) u16 {
25
+ const T = @TypeOf(x);
26
+ switch (T) {
27
+ f80 => {
28
+ const bits: U80 = @bitCast(x);
29
+ return @intCast((bits >> 48) & 0xFFFF);
30
+ },
31
+ f128 => {
32
+ const bits: u128 = @bitCast(x);
33
+ return @intCast((bits >> 96) & 0xFFFF);
34
+ },
35
+ else => @compileError("`mantissaTop` supports only `f80` and `f128`, got: " ++ @typeName(T)),
36
+ }
37
+ }
@@ -0,0 +1,173 @@
1
+ // Ported from musl, which is licensed under the MIT license:
2
+ // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3
+ //
4
+ // https://git.musl-libc.org/cgit/musl/tree/src/math/__rem_pio2l.c
5
+
6
+ const std = @import("std");
7
+ const math = std.math;
8
+
9
+ const ld = @import("long_double.zig");
10
+ const rem_pio2_large = @import("rem_pio2_large.zig").rem_pio2_large;
11
+
12
+ pub fn rem_pio2l(comptime T: type, x: T, y: *[2]T) i32 {
13
+ const impl = switch (T) {
14
+ f80 => struct {
15
+ const round1: i8 = 22;
16
+ const round2: i8 = 61;
17
+ const nx: i8 = 3;
18
+ const ny: i8 = 2;
19
+
20
+ const pio4: T = 0x1.921fb54442d1846ap-1;
21
+ // 64 bits of 2/pi
22
+ const invpio2: T = 6.36619772367581343076e-01; // 0xa2f9836e4e44152a.0p-64
23
+ // first 39 bits of pi/2
24
+ const pio2_1: f64 = 1.57079632679597125389e+00; // 0x3FF921FB, 0x54444000
25
+ // pi/2 - pio2_1
26
+ const pio2_1t: T = -1.07463465549719416346e-12; // -0x973dcb3b399d747f.0p-103
27
+ // second 39 bits of pi/2
28
+ const pio2_2: f64 = -1.07463465549783099519e-12; // -0x12e7b967674000.0p-92
29
+ // pi/2 - (pio2_1+pio2_2)
30
+ const pio2_2t: T = 6.36831716351095013979e-25; // 0xc51701b839a25205.0p-144
31
+ // pi/2 - (pio2_1+pio2_2+pio2_3)
32
+ const pio2_3t: T = -2.75299651904407171810e-37; // -0xbb5bf6c7ddd660ce.0p-185
33
+ // third 39 bits of pi/2
34
+ const pio2_3: f64 = 6.36831716351370313614e-25; // 0x18a2e037074000.0p-133
35
+
36
+ fn small(x_val: T) bool {
37
+ const se = ld.signExponent(x_val);
38
+ const top = ld.mantissaTop(x_val);
39
+ const lhs = (@as(u32, se & 0x7fff) << 16) | top;
40
+ const rhs: u32 = ((0x3fff + 25) << 16) | 0x921f >> 1 | 0x8000;
41
+ return lhs < rhs;
42
+ }
43
+
44
+ fn quobits(v: T) i32 {
45
+ const q: i32 = @intFromFloat(v);
46
+ return @intCast(@as(u32, @bitCast(q)) & 0x7fffffff);
47
+ }
48
+ },
49
+ f128 => struct {
50
+ const round1: i8 = 51;
51
+ const round2: i8 = 119;
52
+ const nx: i8 = 5;
53
+ const ny: i8 = 3;
54
+
55
+ const pio4: T = 0x1.921fb54442d18469898cc51701b8p-1;
56
+ const invpio2: T = 6.3661977236758134307553505349005747e-01;
57
+ const pio2_1: T = 1.5707963267948966192292994253909555e+00;
58
+ const pio2_1t: T = 2.0222662487959507323996846200947577e-21;
59
+ const pio2_2: T = 2.0222662487959507323994779168837751e-21;
60
+ const pio2_2t: T = 2.0670321098263988236496903051604844e-43;
61
+ const pio2_3: T = 2.0670321098263988236499468110329591e-43;
62
+ const pio2_3t: T = -2.5650587247459238361625433492959285e-65;
63
+
64
+ fn small(x_val: T) bool {
65
+ const se = ld.signExponent(x_val);
66
+ const top = ld.mantissaTop(x_val);
67
+ const lhs = (@as(u32, se & 0x7fff) << 16) | top;
68
+ const rhs: u32 = ((0x3fff + 45) << 16) | 0x921f;
69
+ return lhs < rhs;
70
+ }
71
+
72
+ fn quobits(fn_val: T) i32 {
73
+ const q: i64 = @intFromFloat(fn_val);
74
+ return @intCast(@as(u64, @bitCast(q)) & 0x7fffffff);
75
+ }
76
+ },
77
+ else => @compileError("rem_pio2l supports only f80 and f128, got: " ++ @typeName(T)),
78
+ };
79
+
80
+ const x_se = ld.signExponent(x);
81
+ const ex: i32 = @intCast(x_se & 0x7fff);
82
+
83
+ if (impl.small(x)) {
84
+ // rint(x/(pi/2))
85
+ const toint: T = 1.5 / math.floatEps(T);
86
+ var fn_ = x * impl.invpio2 + toint - toint;
87
+ var n = impl.quobits(fn_);
88
+ var r = x - fn_ * @as(T, impl.pio2_1);
89
+ var w = fn_ * impl.pio2_1t; // 1st round good to 102/180 bits
90
+
91
+ // Matters with directed rounding.
92
+ if (r - w < -impl.pio4) {
93
+ @branchHint(.unlikely);
94
+ n -= 1;
95
+ fn_ -= 1;
96
+ r = x - fn_ * @as(T, impl.pio2_1);
97
+ w = fn_ * impl.pio2_1t;
98
+ } else if (r - w > impl.pio4) {
99
+ @branchHint(.unlikely);
100
+ n += 1;
101
+ fn_ += 1;
102
+ r = x - fn_ * @as(T, impl.pio2_1);
103
+ w = fn_ * impl.pio2_1t;
104
+ }
105
+
106
+ y[0] = r - w;
107
+
108
+ const ey: i32 = @intCast(ld.signExponent(y[0]) & 0x7fff);
109
+ if (ex - ey > impl.round1) {
110
+ var t = r;
111
+ w = fn_ * impl.pio2_2;
112
+ r = t - w;
113
+ w = fn_ * impl.pio2_2t - ((t - r) - w);
114
+ y[0] = r - w;
115
+ const ey2: i32 = @intCast(ld.signExponent(y[0]) & 0x7fff);
116
+ if (ex - ey2 > impl.round2) {
117
+ t = r;
118
+ w = fn_ * impl.pio2_3;
119
+ r = t - w;
120
+ w = fn_ * impl.pio2_3t - ((t - r) - w);
121
+ y[0] = r - w;
122
+ }
123
+ }
124
+ y[1] = (r - y[0]) - w;
125
+ return n;
126
+ }
127
+
128
+ // all other (large) arguments
129
+ if (ex == 0x7fff) { // x is inf or NaN
130
+ y[0] = x - x;
131
+ y[1] = y[0];
132
+ return 0;
133
+ }
134
+
135
+ var z: T = math.scalbn(@abs(x), -math.ilogb(x) + 23);
136
+ var tx: [impl.nx]f64 = undefined;
137
+ var ty: [impl.ny]f64 = undefined;
138
+ var i: usize = 0;
139
+
140
+ while (i < impl.nx - 1) : (i += 1) {
141
+ tx[i] = @floatFromInt(@as(i32, @intFromFloat(z)));
142
+ z = (z - @as(T, tx[i])) * 0x1p24;
143
+ }
144
+
145
+ tx[i] = @floatCast(z);
146
+ while (tx[i] == 0.0) {
147
+ i -= 1;
148
+ }
149
+
150
+ const n = rem_pio2_large(
151
+ tx[0..(i + 1)],
152
+ ty[0..impl.ny],
153
+ ex - 0x3fff - 23,
154
+ @intCast(i + 1),
155
+ impl.ny,
156
+ );
157
+ var w: f64 = ty[1];
158
+ if (impl.ny == 3) {
159
+ w += ty[2];
160
+ }
161
+ const r = ty[0] + w;
162
+ w -= r - ty[0];
163
+
164
+ if (x_se >> 15 != 0) {
165
+ y[0] = -@as(T, r);
166
+ y[1] = -@as(T, w);
167
+ return -n;
168
+ }
169
+
170
+ y[0] = @as(T, r);
171
+ y[1] = @as(T, w);
172
+ return n;
173
+ }