@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.
- package/c/math.zig +111 -22
- package/compiler_rt/cos.zig +141 -52
- package/compiler_rt/long_double.zig +37 -0
- package/compiler_rt/rem_pio2l.zig +173 -0
- package/compiler_rt/sin.zig +140 -55
- package/compiler_rt/sincos.zig +279 -72
- package/compiler_rt/tan.zig +118 -47
- package/compiler_rt/trig.zig +256 -6
- package/package.json +1 -1
- package/std/debug/Info.zig +4 -0
- package/std/heap/ArenaAllocator.zig +145 -154
- package/std/mem/Allocator.zig +4 -5
- package/std/mem.zig +48 -0
- package/libc/mingw/math/arm/sincos.S +0 -30
- package/libc/mingw/math/arm-common/sincosl.c +0 -13
- package/libc/mingw/math/arm64/rint.c +0 -12
- package/libc/mingw/math/arm64/rintf.c +0 -12
- package/libc/mingw/math/arm64/sincos.S +0 -32
- package/libc/mingw/math/frexpf.c +0 -13
- package/libc/mingw/math/frexpl.c +0 -71
- package/libc/mingw/math/x86/cos.def.h +0 -65
- package/libc/mingw/math/x86/cosl.c +0 -46
- package/libc/mingw/math/x86/cosl_internal.S +0 -55
- package/libc/mingw/math/x86/sin.def.h +0 -65
- package/libc/mingw/math/x86/sinl.c +0 -46
- package/libc/mingw/math/x86/sinl_internal.S +0 -58
- package/libc/mingw/math/x86/tanl.S +0 -62
- package/libc/musl/src/math/__cosl.c +0 -96
- package/libc/musl/src/math/__sinl.c +0 -78
- package/libc/musl/src/math/__tanl.c +0 -143
- package/libc/musl/src/math/aarch64/lrint.c +0 -10
- package/libc/musl/src/math/aarch64/lrintf.c +0 -10
- package/libc/musl/src/math/aarch64/rintf.c +0 -7
- package/libc/musl/src/math/cosl.c +0 -39
- package/libc/musl/src/math/finite.c +0 -7
- package/libc/musl/src/math/finitef.c +0 -7
- package/libc/musl/src/math/frexp.c +0 -23
- package/libc/musl/src/math/frexpf.c +0 -23
- package/libc/musl/src/math/frexpl.c +0 -29
- package/libc/musl/src/math/i386/lrint.c +0 -8
- package/libc/musl/src/math/i386/lrintf.c +0 -8
- package/libc/musl/src/math/i386/rintf.c +0 -7
- package/libc/musl/src/math/lrint.c +0 -72
- package/libc/musl/src/math/lrintf.c +0 -8
- package/libc/musl/src/math/powerpc64/lrint.c +0 -16
- package/libc/musl/src/math/powerpc64/lrintf.c +0 -16
- package/libc/musl/src/math/rintf.c +0 -30
- package/libc/musl/src/math/s390x/rintf.c +0 -15
- package/libc/musl/src/math/sincosl.c +0 -60
- package/libc/musl/src/math/sinl.c +0 -41
- package/libc/musl/src/math/tanl.c +0 -29
- package/libc/musl/src/math/x32/lrint.s +0 -5
- package/libc/musl/src/math/x32/lrintf.s +0 -5
- package/libc/musl/src/math/x86_64/lrint.c +0 -8
- 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(©sign, "copysign");
|
|
73
85
|
symbol(©signf, "copysignf");
|
|
74
|
-
symbol(&rint, "rint");
|
|
75
86
|
}
|
|
76
87
|
|
|
77
88
|
symbol(©signl, "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 /
|
|
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
|
-
|
|
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(
|
|
325
|
-
try expectEqual(@as(
|
|
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(
|
|
329
|
-
try expectEqual(@as(
|
|
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(
|
|
333
|
-
try expectEqual(@as(
|
|
334
|
-
try expectEqual(@as(
|
|
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:
|
|
338
|
-
try expectEqual(large,
|
|
339
|
-
try expectEqual(-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 =
|
|
343
|
-
try
|
|
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 =
|
|
348
|
-
try
|
|
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(
|
|
354
|
-
try expectEqual(@as(
|
|
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 {
|
package/compiler_rt/cos.zig
CHANGED
|
@@ -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(&
|
|
23
|
+
symbol(&cosh, "__cosh");
|
|
24
|
+
symbol(&cosl, "__cosl");
|
|
14
25
|
symbol(&cosf, "cosf");
|
|
15
26
|
symbol(&cos, "cos");
|
|
16
|
-
symbol(&
|
|
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
|
|
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.
|
|
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.
|
|
61
|
+
return -trig.cosdf(if (sign) x + c2pio2 else x - c2pio2);
|
|
51
62
|
} else {
|
|
52
63
|
if (sign) {
|
|
53
|
-
return trig.
|
|
64
|
+
return trig.sindf(x + c1pio2);
|
|
54
65
|
} else {
|
|
55
|
-
return trig.
|
|
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.
|
|
72
|
+
return trig.cosdf(if (sign) x + c4pio2 else x - c4pio2);
|
|
62
73
|
} else {
|
|
63
74
|
if (sign) {
|
|
64
|
-
return trig.
|
|
75
|
+
return trig.sindf(-x - c3pio2);
|
|
65
76
|
} else {
|
|
66
|
-
return trig.
|
|
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.
|
|
80
|
-
1 => trig.
|
|
81
|
-
2 => -trig.
|
|
82
|
-
else => trig.
|
|
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.
|
|
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.
|
|
109
|
-
1 => -trig.
|
|
110
|
-
2 => -trig.
|
|
111
|
-
else => trig.
|
|
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
|
|
116
|
-
|
|
117
|
-
|
|
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(
|
|
121
|
-
|
|
122
|
-
|
|
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
|
|
176
|
+
16 => return cosh(x),
|
|
128
177
|
32 => return cosf(x),
|
|
129
178
|
64 => return cos(x),
|
|
130
|
-
80 => return
|
|
179
|
+
80 => return cosx(x),
|
|
131
180
|
128 => return cosq(x),
|
|
132
181
|
else => @compileError("unreachable"),
|
|
133
182
|
}
|
|
134
183
|
}
|
|
135
184
|
|
|
136
|
-
|
|
137
|
-
const
|
|
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(
|
|
140
|
-
try expect(
|
|
141
|
-
try expect(math.
|
|
142
|
-
try expect(math.
|
|
143
|
-
try expect(math.
|
|
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 "
|
|
149
|
-
const epsilon =
|
|
150
|
-
|
|
151
|
-
try
|
|
152
|
-
try
|
|
153
|
-
try
|
|
154
|
-
try
|
|
155
|
-
try
|
|
156
|
-
try
|
|
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
|
|
162
|
-
|
|
163
|
-
|
|
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
|
|
168
|
-
|
|
169
|
-
|
|
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
|
+
}
|