authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-04-26 10:13:55-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-04-27 12:20:44-07:00
log41dd2beaacade94c5c98400a4a655aea07b9e2f3
treed7cd75c3ded0e8517e801f62dbb883d93f3cd585
parent6f4343b61afe36a709e713735947561a2b76bce8

compiler-rt: math functions reorg

* unify the logic for exporting math functions from compiler-rt, with the appropriate suffixes and prefixes. - add all missing f128 and f80 exports. Functions with missing implementations call other functions and have TODO comments. - also add f16 functions * move math functions from freestanding libc to compiler-rt (#7265) * enable all the f128 and f80 code in the stage2 compiler and behavior tests (#11161). * update std lib to use builtins rather than `std.math`.

78 files changed, 4768 insertions(+), 5020 deletions(-)

CMakeLists.txt+33-1
......@@ -445,7 +445,6 @@ set(ZIG_STAGE2_SOURCES
445445 "${CMAKE_SOURCE_DIR}/lib/std/math/big.zig"
446446 "${CMAKE_SOURCE_DIR}/lib/std/math/big/int.zig"
447447 "${CMAKE_SOURCE_DIR}/lib/std/math/float.zig"
448 "${CMAKE_SOURCE_DIR}/lib/std/math/floor.zig"
449448 "${CMAKE_SOURCE_DIR}/lib/std/math/frexp.zig"
450449 "${CMAKE_SOURCE_DIR}/lib/std/math/isinf.zig"
451450 "${CMAKE_SOURCE_DIR}/lib/std/math/isnan.zig"
......@@ -482,20 +481,40 @@ set(ZIG_STAGE2_SOURCES
482481 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt.zig"
483482 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/absv.zig"
484483 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/addXf3.zig"
484 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/addo.zig"
485 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/arm.zig"
485486 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/atomics.zig"
487 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/aulldiv.zig"
488 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/aullrem.zig"
486489 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/bswap.zig"
490 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/ceil.zig"
487491 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/clear_cache.zig"
488492 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/cmp.zig"
489493 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/compareXf2.zig"
494 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/cos.zig"
490495 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/count0bits.zig"
491496 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/divdf3.zig"
492497 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/divsf3.zig"
493498 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/divtf3.zig"
494499 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/divti3.zig"
500 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/divxf3.zig"
501 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/emutls.zig"
502 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/exp.zig"
503 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/exp2.zig"
495504 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/extendXfYf2.zig"
505 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/extend_f80.zig"
506 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fabs.zig"
496507 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fixXfYi.zig"
497508 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floatXiYf.zig"
509 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/floor.zig"
510 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fma.zig"
511 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fmax.zig"
512 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fmin.zig"
513 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/fmod.zig"
498514 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/int.zig"
515 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/log.zig"
516 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/log10.zig"
517 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/log2.zig"
499518 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/modti3.zig"
500519 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/mulXf3.zig"
501520 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/muldi3.zig"
......@@ -507,9 +526,22 @@ set(ZIG_STAGE2_SOURCES
507526 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/os_version_check.zig"
508527 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/parity.zig"
509528 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/popcount.zig"
529 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/rem_pio2.zig"
530 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/rem_pio2_large.zig"
531 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/rem_pio2f.zig"
532 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/round.zig"
510533 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/shift.zig"
534 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/sin.zig"
535 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/sincos.zig"
536 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/sparc.zig"
537 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/sqrt.zig"
511538 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/stack_probe.zig"
539 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/subo.zig"
540 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/tan.zig"
541 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/trig.zig"
542 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/trunc.zig"
512543 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/truncXfYf2.zig"
544 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/trunc_f80.zig"
513545 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/udivmod.zig"
514546 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/udivmodti4.zig"
515547 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/udivti3.zig"
lib/std/fmt/errol.zig+4-4
......@@ -113,7 +113,7 @@ fn errolSlow(val: f64, buffer: []u8) FloatDecimal {
113113 // normalize the midpoint
114114
115115 const e = math.frexp(val).exponent;
116 var exp = @floatToInt(i16, math.floor(307 + @intToFloat(f64, e) * 0.30103));
116 var exp = @floatToInt(i16, @floor(307 + @intToFloat(f64, e) * 0.30103));
117117 if (exp < 20) {
118118 exp = 20;
119119 } else if (@intCast(usize, exp) >= lookup_table.len) {
......@@ -170,10 +170,10 @@ fn errolSlow(val: f64, buffer: []u8) FloatDecimal {
170170 // digit generation
171171 var buf_index: usize = 0;
172172 while (true) {
173 var hdig = @floatToInt(u8, math.floor(high.val));
173 var hdig = @floatToInt(u8, @floor(high.val));
174174 if ((high.val == @intToFloat(f64, hdig)) and (high.off < 0)) hdig -= 1;
175175
176 var ldig = @floatToInt(u8, math.floor(low.val));
176 var ldig = @floatToInt(u8, @floor(low.val));
177177 if ((low.val == @intToFloat(f64, ldig)) and (low.off < 0)) ldig -= 1;
178178
179179 if (ldig != hdig) break;
......@@ -187,7 +187,7 @@ fn errolSlow(val: f64, buffer: []u8) FloatDecimal {
187187 }
188188
189189 const tmp = (high.val + low.val) / 2.0;
190 var mdig = @floatToInt(u8, math.floor(tmp + 0.5));
190 var mdig = @floatToInt(u8, @floor(tmp + 0.5));
191191 if ((@intToFloat(f64, mdig) - tmp) == 0.5 and (mdig & 0x1) != 0) mdig -= 1;
192192
193193 buffer[buf_index] = mdig + '0';
lib/std/math.zig+2-29
......@@ -138,7 +138,7 @@ pub fn approxEqAbs(comptime T: type, x: T, y: T, tolerance: T) bool {
138138 if (isNan(x) or isNan(y))
139139 return false;
140140
141 return fabs(x - y) <= tolerance;
141 return @fabs(x - y) <= tolerance;
142142}
143143
144144/// Performs an approximate comparison of two floating point values `x` and `y`.
......@@ -166,7 +166,7 @@ pub fn approxEqRel(comptime T: type, x: T, y: T, tolerance: T) bool {
166166 if (isNan(x) or isNan(y))
167167 return false;
168168
169 return fabs(x - y) <= max(fabs(x), fabs(y)) * tolerance;
169 return @fabs(x - y) <= max(@fabs(x), @fabs(y)) * tolerance;
170170}
171171
172172pub fn approxEq(comptime T: type, x: T, y: T, tolerance: T) bool {
......@@ -233,11 +233,6 @@ pub fn raiseDivByZero() void {
233233
234234pub const isNan = @import("math/isnan.zig").isNan;
235235pub const isSignalNan = @import("math/isnan.zig").isSignalNan;
236pub const fabs = @import("math/fabs.zig").fabs;
237pub const ceil = @import("math/ceil.zig").ceil;
238pub const floor = @import("math/floor.zig").floor;
239pub const trunc = @import("math/trunc.zig").trunc;
240pub const round = @import("math/round.zig").round;
241236pub const frexp = @import("math/frexp.zig").frexp;
242237pub const Frexp = @import("math/frexp.zig").Frexp;
243238pub const modf = @import("math/modf.zig").modf;
......@@ -261,8 +256,6 @@ pub const asin = @import("math/asin.zig").asin;
261256pub const atan = @import("math/atan.zig").atan;
262257pub const atan2 = @import("math/atan2.zig").atan2;
263258pub const hypot = @import("math/hypot.zig").hypot;
264pub const exp = @import("math/exp.zig").exp;
265pub const exp2 = @import("math/exp2.zig").exp2;
266259pub const expm1 = @import("math/expm1.zig").expm1;
267260pub const ilogb = @import("math/ilogb.zig").ilogb;
268261pub const ln = @import("math/ln.zig").ln;
......@@ -270,16 +263,12 @@ pub const log = @import("math/log.zig").log;
270263pub const log2 = @import("math/log2.zig").log2;
271264pub const log10 = @import("math/log10.zig").log10;
272265pub const log1p = @import("math/log1p.zig").log1p;
273pub const fma = @import("math/fma.zig").fma;
274266pub const asinh = @import("math/asinh.zig").asinh;
275267pub const acosh = @import("math/acosh.zig").acosh;
276268pub const atanh = @import("math/atanh.zig").atanh;
277269pub const sinh = @import("math/sinh.zig").sinh;
278270pub const cosh = @import("math/cosh.zig").cosh;
279271pub const tanh = @import("math/tanh.zig").tanh;
280pub const cos = @import("math/cos.zig").cos;
281pub const sin = @import("math/sin.zig").sin;
282pub const tan = @import("math/tan.zig").tan;
283272
284273pub const complex = @import("math/complex.zig");
285274pub const Complex = complex.Complex;
......@@ -716,17 +705,6 @@ fn testAbsInt() !void {
716705 try testing.expect((absInt(@as(i32, 10)) catch unreachable) == 10);
717706}
718707
719pub const absFloat = fabs;
720
721test "absFloat" {
722 try testAbsFloat();
723 comptime try testAbsFloat();
724}
725fn testAbsFloat() !void {
726 try testing.expect(absFloat(@as(f32, -10.05)) == 10.05);
727 try testing.expect(absFloat(@as(f32, 10.05)) == 10.05);
728}
729
730708/// Divide numerator by denominator, rounding toward zero. Returns an
731709/// error on overflow or when denominator is zero.
732710pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T {
......@@ -1400,11 +1378,6 @@ test "order.compare" {
14001378 try testing.expect(order(1, 0).compare(.neq));
14011379}
14021380
1403test "comptime sin and ln" {
1404 const v = comptime (sin(@as(f32, 1)) + ln(@as(f32, 5)));
1405 try testing.expect(v == sin(@as(f32, 1)) + ln(@as(f32, 5)));
1406}
1407
14081381/// Returns a mask of all ones if value is true,
14091382/// and a mask of all zeroes if value is false.
14101383/// Compiles to one instruction for register sized integers.
lib/std/math/__rem_pio2.zig deleted-198
......@@ -1,198 +0,0 @@
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_pio2.c
5
6const std = @import("../std.zig");
7const __rem_pio2_large = @import("__rem_pio2_large.zig").__rem_pio2_large;
8const math = std.math;
9
10const toint = 1.5 / math.floatEps(f64);
11// pi/4
12const pio4 = 0x1.921fb54442d18p-1;
13// invpio2: 53 bits of 2/pi
14const invpio2 = 6.36619772367581382433e-01; // 0x3FE45F30, 0x6DC9C883
15// pio2_1: first 33 bit of pi/2
16const pio2_1 = 1.57079632673412561417e+00; // 0x3FF921FB, 0x54400000
17// pio2_1t: pi/2 - pio2_1
18const pio2_1t = 6.07710050650619224932e-11; // 0x3DD0B461, 0x1A626331
19// pio2_2: second 33 bit of pi/2
20const pio2_2 = 6.07710050630396597660e-11; // 0x3DD0B461, 0x1A600000
21// pio2_2t: pi/2 - (pio2_1+pio2_2)
22const pio2_2t = 2.02226624879595063154e-21; // 0x3BA3198A, 0x2E037073
23// pio2_3: third 33 bit of pi/2
24const pio2_3 = 2.02226624871116645580e-21; // 0x3BA3198A, 0x2E000000
25// pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3)
26const pio2_3t = 8.47842766036889956997e-32; // 0x397B839A, 0x252049C1
27
28fn U(x: anytype) usize {
29 return @intCast(usize, x);
30}
31
32fn medium(ix: u32, x: f64, y: *[2]f64) i32 {
33 var w: f64 = undefined;
34 var t: f64 = undefined;
35 var r: f64 = undefined;
36 var @"fn": f64 = undefined;
37 var n: i32 = undefined;
38 var ex: i32 = undefined;
39 var ey: i32 = undefined;
40 var ui: u64 = undefined;
41
42 // rint(x/(pi/2))
43 @"fn" = x * invpio2 + toint - toint;
44 n = @floatToInt(i32, @"fn");
45 r = x - @"fn" * pio2_1;
46 w = @"fn" * pio2_1t; // 1st round, good to 85 bits
47 // Matters with directed rounding.
48 if (r - w < -pio4) {
49 n -= 1;
50 @"fn" -= 1;
51 r = x - @"fn" * pio2_1;
52 w = @"fn" * pio2_1t;
53 } else if (r - w > pio4) {
54 n += 1;
55 @"fn" += 1;
56 r = x - @"fn" * pio2_1;
57 w = @"fn" * pio2_1t;
58 }
59 y[0] = r - w;
60 ui = @bitCast(u64, y[0]);
61 ey = @intCast(i32, (ui >> 52) & 0x7ff);
62 ex = @intCast(i32, ix >> 20);
63 if (ex - ey > 16) { // 2nd round, good to 118 bits
64 t = r;
65 w = @"fn" * pio2_2;
66 r = t - w;
67 w = @"fn" * pio2_2t - ((t - r) - w);
68 y[0] = r - w;
69 ui = @bitCast(u64, y[0]);
70 ey = @intCast(i32, (ui >> 52) & 0x7ff);
71 if (ex - ey > 49) { // 3rd round, good to 151 bits, covers all cases
72 t = r;
73 w = @"fn" * pio2_3;
74 r = t - w;
75 w = @"fn" * pio2_3t - ((t - r) - w);
76 y[0] = r - w;
77 }
78 }
79 y[1] = (r - y[0]) - w;
80 return n;
81}
82
83// Returns the remainder of x rem pi/2 in y[0]+y[1]
84//
85// use __rem_pio2_large() for large x
86//
87// caller must handle the case when reduction is not needed: |x| ~<= pi/4 */
88pub fn __rem_pio2(x: f64, y: *[2]f64) i32 {
89 var z: f64 = undefined;
90 var tx: [3]f64 = undefined;
91 var ty: [2]f64 = undefined;
92 var n: i32 = undefined;
93 var ix: u32 = undefined;
94 var sign: bool = undefined;
95 var i: i32 = undefined;
96 var ui: u64 = undefined;
97
98 ui = @bitCast(u64, x);
99 sign = ui >> 63 != 0;
100 ix = @truncate(u32, (ui >> 32) & 0x7fffffff);
101 if (ix <= 0x400f6a7a) { // |x| ~<= 5pi/4
102 if ((ix & 0xfffff) == 0x921fb) { // |x| ~= pi/2 or 2pi/2
103 return medium(ix, x, y);
104 }
105 if (ix <= 0x4002d97c) { // |x| ~<= 3pi/4
106 if (!sign) {
107 z = x - pio2_1; // one round good to 85 bits
108 y[0] = z - pio2_1t;
109 y[1] = (z - y[0]) - pio2_1t;
110 return 1;
111 } else {
112 z = x + pio2_1;
113 y[0] = z + pio2_1t;
114 y[1] = (z - y[0]) + pio2_1t;
115 return -1;
116 }
117 } else {
118 if (!sign) {
119 z = x - 2 * pio2_1;
120 y[0] = z - 2 * pio2_1t;
121 y[1] = (z - y[0]) - 2 * pio2_1t;
122 return 2;
123 } else {
124 z = x + 2 * pio2_1;
125 y[0] = z + 2 * pio2_1t;
126 y[1] = (z - y[0]) + 2 * pio2_1t;
127 return -2;
128 }
129 }
130 }
131 if (ix <= 0x401c463b) { // |x| ~<= 9pi/4
132 if (ix <= 0x4015fdbc) { // |x| ~<= 7pi/4
133 if (ix == 0x4012d97c) { // |x| ~= 3pi/2
134 return medium(ix, x, y);
135 }
136 if (!sign) {
137 z = x - 3 * pio2_1;
138 y[0] = z - 3 * pio2_1t;
139 y[1] = (z - y[0]) - 3 * pio2_1t;
140 return 3;
141 } else {
142 z = x + 3 * pio2_1;
143 y[0] = z + 3 * pio2_1t;
144 y[1] = (z - y[0]) + 3 * pio2_1t;
145 return -3;
146 }
147 } else {
148 if (ix == 0x401921fb) { // |x| ~= 4pi/2 */
149 return medium(ix, x, y);
150 }
151 if (!sign) {
152 z = x - 4 * pio2_1;
153 y[0] = z - 4 * pio2_1t;
154 y[1] = (z - y[0]) - 4 * pio2_1t;
155 return 4;
156 } else {
157 z = x + 4 * pio2_1;
158 y[0] = z + 4 * pio2_1t;
159 y[1] = (z - y[0]) + 4 * pio2_1t;
160 return -4;
161 }
162 }
163 }
164 if (ix < 0x413921fb) { // |x| ~< 2^20*(pi/2), medium size
165 return medium(ix, x, y);
166 }
167 // all other (large) arguments
168 if (ix >= 0x7ff00000) { // x is inf or NaN
169 y[0] = x - x;
170 y[1] = y[0];
171 return 0;
172 }
173 // set z = scalbn(|x|,-ilogb(x)+23)
174 ui = @bitCast(u64, x);
175 ui &= std.math.maxInt(u64) >> 12;
176 ui |= @as(u64, 0x3ff + 23) << 52;
177 z = @bitCast(f64, ui);
178
179 i = 0;
180 while (i < 2) : (i += 1) {
181 tx[U(i)] = @intToFloat(f64, @floatToInt(i32, z));
182 z = (z - tx[U(i)]) * 0x1p24;
183 }
184 tx[U(i)] = z;
185 // skip zero terms, first term is non-zero
186 while (tx[U(i)] == 0.0) {
187 i -= 1;
188 }
189 n = __rem_pio2_large(tx[0..], ty[0..], @intCast(i32, (ix >> 20)) - (0x3ff + 23), i + 1, 1);
190 if (sign) {
191 y[0] = -ty[0];
192 y[1] = -ty[1];
193 return -n;
194 }
195 y[0] = ty[0];
196 y[1] = ty[1];
197 return n;
198}
lib/std/math/__rem_pio2_large.zig deleted-510
......@@ -1,510 +0,0 @@
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_pio2_large.c
5
6const std = @import("../std.zig");
7const math = std.math;
8
9const init_jk = [_]i32{ 3, 4, 4, 6 }; // initial value for jk
10
11//
12// Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
13//
14// integer array, contains the (24*i)-th to (24*i+23)-th
15// bit of 2/pi after binary point. The corresponding
16// floating value is
17//
18// ipio2[i] * 2^(-24(i+1)).
19//
20// NB: This table must have at least (e0-3)/24 + jk terms.
21// For quad precision (e0 <= 16360, jk = 6), this is 686.
22///
23const ipio2 = [_]i32{
24 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62,
25 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A,
26 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129,
27 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41,
28 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8,
29 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF,
30 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5,
31 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08,
32 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3,
33 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880,
34 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B,
35
36 //#if LDBL_MAX_EXP > 1024
37 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6,
38 0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2,
39 0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35,
40 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30,
41 0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C,
42 0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4,
43 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770,
44 0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7,
45 0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19,
46 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522,
47 0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16,
48 0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6,
49 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E,
50 0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48,
51 0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3,
52 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF,
53 0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55,
54 0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612,
55 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929,
56 0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC,
57 0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B,
58 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C,
59 0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4,
60 0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB,
61 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC,
62 0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C,
63 0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F,
64 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5,
65 0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437,
66 0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B,
67 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA,
68 0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD,
69 0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3,
70 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3,
71 0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717,
72 0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F,
73 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61,
74 0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB,
75 0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51,
76 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0,
77 0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C,
78 0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6,
79 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC,
80 0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED,
81 0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328,
82 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D,
83 0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0,
84 0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B,
85 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4,
86 0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3,
87 0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F,
88 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD,
89 0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B,
90 0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4,
91 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761,
92 0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31,
93 0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30,
94 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262,
95 0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E,
96 0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1,
97 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C,
98 0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4,
99 0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08,
100 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196,
101 0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9,
102 0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4,
103 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC,
104 0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C,
105 0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0,
106 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C,
107 0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0,
108 0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC,
109 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22,
110 0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893,
111 0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7,
112 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5,
113 0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F,
114 0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4,
115 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF,
116 0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B,
117 0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2,
118 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138,
119 0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E,
120 0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569,
121 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34,
122 0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9,
123 0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D,
124 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F,
125 0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855,
126 0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569,
127 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B,
128 0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE,
129 0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41,
130 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49,
131 0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F,
132 0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110,
133 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8,
134 0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365,
135 0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A,
136 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270,
137 0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5,
138 0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616,
139 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B,
140 0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901,
141 0x8071E0,
142 //#endif
143};
144
145const PIo2 = [_]f64{
146 1.57079625129699707031e+00, // 0x3FF921FB, 0x40000000
147 7.54978941586159635335e-08, // 0x3E74442D, 0x00000000
148 5.39030252995776476554e-15, // 0x3CF84698, 0x80000000
149 3.28200341580791294123e-22, // 0x3B78CC51, 0x60000000
150 1.27065575308067607349e-29, // 0x39F01B83, 0x80000000
151 1.22933308981111328932e-36, // 0x387A2520, 0x40000000
152 2.73370053816464559624e-44, // 0x36E38222, 0x80000000
153 2.16741683877804819444e-51, // 0x3569F31D, 0x00000000
154};
155
156fn U(x: anytype) usize {
157 return @intCast(usize, x);
158}
159
160// Returns the last three digits of N with y = x - N*pi/2 so that |y| < pi/2.
161//
162// The method is to compute the integer (mod 8) and fraction parts of
163// (2/pi)*x without doing the full multiplication. In general we
164// skip the part of the product that are known to be a huge integer (
165// more accurately, = 0 mod 8 ). Thus the number of operations are
166// independent of the exponent of the input.
167//
168// (2/pi) is represented by an array of 24-bit integers in ipio2[].
169//
170// Input parameters:
171// x[] The input value (must be positive) is broken into nx
172// pieces of 24-bit integers in double precision format.
173// x[i] will be the i-th 24 bit of x. The scaled exponent
174// of x[0] is given in input parameter e0 (i.e., x[0]*2^e0
175// match x's up to 24 bits.
176//
177// Example of breaking a double positive z into x[0]+x[1]+x[2]:
178// e0 = ilogb(z)-23
179// z = scalbn(z,-e0)
180// for i = 0,1,2
181// x[i] = floor(z)
182// z = (z-x[i])*2**24
183//
184//
185// y[] ouput result in an array of double precision numbers.
186// The dimension of y[] is:
187// 24-bit precision 1
188// 53-bit precision 2
189// 64-bit precision 2
190// 113-bit precision 3
191// The actual value is the sum of them. Thus for 113-bit
192// precison, one may have to do something like:
193//
194// long double t,w,r_head, r_tail;
195// t = (long double)y[2] + (long double)y[1];
196// w = (long double)y[0];
197// r_head = t+w;
198// r_tail = w - (r_head - t);
199//
200// e0 The exponent of x[0]. Must be <= 16360 or you need to
201// expand the ipio2 table.
202//
203// nx dimension of x[]
204//
205// prec an integer indicating the precision:
206// 0 24 bits (single)
207// 1 53 bits (double)
208// 2 64 bits (extended)
209// 3 113 bits (quad)
210//
211// Here is the description of some local variables:
212//
213// jk jk+1 is the initial number of terms of ipio2[] needed
214// in the computation. The minimum and recommended value
215// for jk is 3,4,4,6 for single, double, extended, and quad.
216// jk+1 must be 2 larger than you might expect so that our
217// recomputation test works. (Up to 24 bits in the integer
218// part (the 24 bits of it that we compute) and 23 bits in
219// the fraction part may be lost to cancelation before we
220// recompute.)
221//
222// jz local integer variable indicating the number of
223// terms of ipio2[] used.
224//
225// jx nx - 1
226//
227// jv index for pointing to the suitable ipio2[] for the
228// computation. In general, we want
229// ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8
230// is an integer. Thus
231// e0-3-24*jv >= 0 or (e0-3)/24 >= jv
232// Hence jv = max(0,(e0-3)/24).
233//
234// jp jp+1 is the number of terms in PIo2[] needed, jp = jk.
235//
236// q[] double array with integral value, representing the
237// 24-bits chunk of the product of x and 2/pi.
238//
239// q0 the corresponding exponent of q[0]. Note that the
240// exponent for q[i] would be q0-24*i.
241//
242// PIo2[] double precision array, obtained by cutting pi/2
243// into 24 bits chunks.
244//
245// f[] ipio2[] in floating point
246//
247// iq[] integer array by breaking up q[] in 24-bits chunk.
248//
249// fq[] final product of x*(2/pi) in fq[0],..,fq[jk]
250//
251// ih integer. If >0 it indicates q[] is >= 0.5, hence
252// it also indicates the *sign* of the result.
253//
254///
255//
256// Constants:
257// The hexadecimal values are the intended ones for the following
258// constants. The decimal values may be used, provided that the
259// compiler will convert from decimal to binary accurately enough
260// to produce the hexadecimal values shown.
261///
262pub fn __rem_pio2_large(x: []f64, y: []f64, e0: i32, nx: i32, prec: usize) i32 {
263 var jz: i32 = undefined;
264 var jx: i32 = undefined;
265 var jv: i32 = undefined;
266 var jp: i32 = undefined;
267 var jk: i32 = undefined;
268 var carry: i32 = undefined;
269 var n: i32 = undefined;
270 var iq: [20]i32 = undefined;
271 var i: i32 = undefined;
272 var j: i32 = undefined;
273 var k: i32 = undefined;
274 var m: i32 = undefined;
275 var q0: i32 = undefined;
276 var ih: i32 = undefined;
277
278 var z: f64 = undefined;
279 var fw: f64 = undefined;
280 var f: [20]f64 = undefined;
281 var fq: [20]f64 = undefined;
282 var q: [20]f64 = undefined;
283
284 // initialize jk
285 jk = init_jk[prec];
286 jp = jk;
287
288 // determine jx,jv,q0, note that 3>q0
289 jx = nx - 1;
290 jv = @divFloor(e0 - 3, 24);
291 if (jv < 0) jv = 0;
292 q0 = e0 - 24 * (jv + 1);
293
294 // set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk]
295 j = jv - jx;
296 m = jx + jk;
297 i = 0;
298 while (i <= m) : ({
299 i += 1;
300 j += 1;
301 }) {
302 f[U(i)] = if (j < 0) 0.0 else @intToFloat(f64, ipio2[U(j)]);
303 }
304
305 // compute q[0],q[1],...q[jk]
306 i = 0;
307 while (i <= jk) : (i += 1) {
308 j = 0;
309 fw = 0;
310 while (j <= jx) : (j += 1) {
311 fw += x[U(j)] * f[U(jx + i - j)];
312 }
313 q[U(i)] = fw;
314 }
315
316 jz = jk;
317
318 // This is to handle a non-trivial goto translation from C.
319 // An unconditional return statement is found at the end of this loop.
320 recompute: while (true) {
321 // distill q[] into iq[] reversingly
322 i = 0;
323 j = jz;
324 z = q[U(jz)];
325 while (j > 0) : ({
326 i += 1;
327 j -= 1;
328 }) {
329 fw = @intToFloat(f64, @floatToInt(i32, 0x1p-24 * z));
330 iq[U(i)] = @floatToInt(i32, z - 0x1p24 * fw);
331 z = q[U(j - 1)] + fw;
332 }
333
334 // compute n
335 z = math.scalbn(z, q0); // actual value of z
336 z -= 8.0 * math.floor(z * 0.125); // trim off integer >= 8
337 n = @floatToInt(i32, z);
338 z -= @intToFloat(f64, n);
339 ih = 0;
340 if (q0 > 0) { // need iq[jz-1] to determine n
341 i = iq[U(jz - 1)] >> @intCast(u5, 24 - q0);
342 n += i;
343 iq[U(jz - 1)] -= i << @intCast(u5, 24 - q0);
344 ih = iq[U(jz - 1)] >> @intCast(u5, 23 - q0);
345 } else if (q0 == 0) {
346 ih = iq[U(jz - 1)] >> 23;
347 } else if (z >= 0.5) {
348 ih = 2;
349 }
350
351 if (ih > 0) { // q > 0.5
352 n += 1;
353 carry = 0;
354 i = 0;
355 while (i < jz) : (i += 1) { // compute 1-q
356 j = iq[U(i)];
357 if (carry == 0) {
358 if (j != 0) {
359 carry = 1;
360 iq[U(i)] = 0x1000000 - j;
361 }
362 } else {
363 iq[U(i)] = 0xffffff - j;
364 }
365 }
366 if (q0 > 0) { // rare case: chance is 1 in 12
367 switch (q0) {
368 1 => iq[U(jz - 1)] &= 0x7fffff,
369 2 => iq[U(jz - 1)] &= 0x3fffff,
370 else => unreachable,
371 }
372 }
373 if (ih == 2) {
374 z = 1.0 - z;
375 if (carry != 0) {
376 z -= math.scalbn(@as(f64, 1.0), q0);
377 }
378 }
379 }
380
381 // check if recomputation is needed
382 if (z == 0.0) {
383 j = 0;
384 i = jz - 1;
385 while (i >= jk) : (i -= 1) {
386 j |= iq[U(i)];
387 }
388
389 if (j == 0) { // need recomputation
390 k = 1;
391 while (iq[U(jk - k)] == 0) : (k += 1) {
392 // k = no. of terms needed
393 }
394
395 i = jz + 1;
396 while (i <= jz + k) : (i += 1) { // add q[jz+1] to q[jz+k]
397 f[U(jx + i)] = @intToFloat(f64, ipio2[U(jv + i)]);
398 j = 0;
399 fw = 0;
400 while (j <= jx) : (j += 1) {
401 fw += x[U(j)] * f[U(jx + i - j)];
402 }
403 q[U(i)] = fw;
404 }
405 jz += k;
406 continue :recompute; // mimic goto recompute
407 }
408 }
409
410 // chop off zero terms
411 if (z == 0.0) {
412 jz -= 1;
413 q0 -= 24;
414 while (iq[U(jz)] == 0) {
415 jz -= 1;
416 q0 -= 24;
417 }
418 } else { // break z into 24-bit if necessary
419 z = math.scalbn(z, -q0);
420 if (z >= 0x1p24) {
421 fw = @intToFloat(f64, @floatToInt(i32, 0x1p-24 * z));
422 iq[U(jz)] = @floatToInt(i32, z - 0x1p24 * fw);
423 jz += 1;
424 q0 += 24;
425 iq[U(jz)] = @floatToInt(i32, fw);
426 } else {
427 iq[U(jz)] = @floatToInt(i32, z);
428 }
429 }
430
431 // convert integer "bit" chunk to floating-point value
432 fw = math.scalbn(@as(f64, 1.0), q0);
433 i = jz;
434 while (i >= 0) : (i -= 1) {
435 q[U(i)] = fw * @intToFloat(f64, iq[U(i)]);
436 fw *= 0x1p-24;
437 }
438
439 // compute PIo2[0,...,jp]*q[jz,...,0]
440 i = jz;
441 while (i >= 0) : (i -= 1) {
442 fw = 0;
443 k = 0;
444 while (k <= jp and k <= jz - i) : (k += 1) {
445 fw += PIo2[U(k)] * q[U(i + k)];
446 }
447 fq[U(jz - i)] = fw;
448 }
449
450 // compress fq[] into y[]
451 switch (prec) {
452 0 => {
453 fw = 0.0;
454 i = jz;
455 while (i >= 0) : (i -= 1) {
456 fw += fq[U(i)];
457 }
458 y[0] = if (ih == 0) fw else -fw;
459 },
460
461 1, 2 => {
462 fw = 0.0;
463 i = jz;
464 while (i >= 0) : (i -= 1) {
465 fw += fq[U(i)];
466 }
467 // TODO: drop excess precision here once double_t is used
468 fw = fw;
469 y[0] = if (ih == 0) fw else -fw;
470 fw = fq[0] - fw;
471 i = 1;
472 while (i <= jz) : (i += 1) {
473 fw += fq[U(i)];
474 }
475 y[1] = if (ih == 0) fw else -fw;
476 },
477 3 => { // painful
478 i = jz;
479 while (i > 0) : (i -= 1) {
480 fw = fq[U(i - 1)] + fq[U(i)];
481 fq[U(i)] += fq[U(i - 1)] - fw;
482 fq[U(i - 1)] = fw;
483 }
484 i = jz;
485 while (i > 1) : (i -= 1) {
486 fw = fq[U(i - 1)] + fq[U(i)];
487 fq[U(i)] += fq[U(i - 1)] - fw;
488 fq[U(i - 1)] = fw;
489 }
490 fw = 0;
491 i = jz;
492 while (i >= 2) : (i -= 1) {
493 fw += fq[U(i)];
494 }
495 if (ih == 0) {
496 y[0] = fq[0];
497 y[1] = fq[1];
498 y[2] = fw;
499 } else {
500 y[0] = -fq[0];
501 y[1] = -fq[1];
502 y[2] = -fw;
503 }
504 },
505 else => unreachable,
506 }
507
508 return n & 7;
509 }
510}
lib/std/math/__rem_pio2f.zig deleted-70
......@@ -1,70 +0,0 @@
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_pio2f.c
5
6const std = @import("../std.zig");
7const __rem_pio2_large = @import("__rem_pio2_large.zig").__rem_pio2_large;
8const math = std.math;
9
10const toint = 1.5 / math.floatEps(f64);
11// pi/4
12const pio4 = 0x1.921fb6p-1;
13// invpio2: 53 bits of 2/pi
14const invpio2 = 6.36619772367581382433e-01; // 0x3FE45F30, 0x6DC9C883
15// pio2_1: first 25 bits of pi/2
16const pio2_1 = 1.57079631090164184570e+00; // 0x3FF921FB, 0x50000000
17// pio2_1t: pi/2 - pio2_1
18const pio2_1t = 1.58932547735281966916e-08; // 0x3E5110b4, 0x611A6263
19
20// Returns the remainder of x rem pi/2 in *y
21// use double precision for everything except passing x
22// use __rem_pio2_large() for large x
23pub fn __rem_pio2f(x: f32, y: *f64) i32 {
24 var tx: [1]f64 = undefined;
25 var ty: [1]f64 = undefined;
26 var @"fn": f64 = undefined;
27 var ix: u32 = undefined;
28 var n: i32 = undefined;
29 var sign: bool = undefined;
30 var e0: u32 = undefined;
31 var ui: u32 = undefined;
32
33 ui = @bitCast(u32, x);
34 ix = ui & 0x7fffffff;
35
36 // 25+53 bit pi is good enough for medium size
37 if (ix < 0x4dc90fdb) { // |x| ~< 2^28*(pi/2), medium size
38 // Use a specialized rint() to get fn.
39 @"fn" = @floatCast(f64, x) * invpio2 + toint - toint;
40 n = @floatToInt(i32, @"fn");
41 y.* = x - @"fn" * pio2_1 - @"fn" * pio2_1t;
42 // Matters with directed rounding.
43 if (y.* < -pio4) {
44 n -= 1;
45 @"fn" -= 1;
46 y.* = x - @"fn" * pio2_1 - @"fn" * pio2_1t;
47 } else if (y.* > pio4) {
48 n += 1;
49 @"fn" += 1;
50 y.* = x - @"fn" * pio2_1 - @"fn" * pio2_1t;
51 }
52 return n;
53 }
54 if (ix >= 0x7f800000) { // x is inf or NaN
55 y.* = x - x;
56 return 0;
57 }
58 // scale x into [2^23, 2^24-1]
59 sign = ui >> 31 != 0;
60 e0 = (ix >> 23) - (0x7f + 23); // e0 = ilogb(|x|)-23, positive
61 ui = ix - (e0 << 23);
62 tx[0] = @bitCast(f32, ui);
63 n = __rem_pio2_large(&tx, &ty, @intCast(i32, e0), 1, 0);
64 if (sign) {
65 y.* = -ty[0];
66 return -n;
67 }
68 y.* = ty[0];
69 return n;
70}
lib/std/math/__trig.zig deleted-273
......@@ -1,273 +0,0 @@
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/__cos.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/__cosdf.c
6// https://git.musl-libc.org/cgit/musl/tree/src/math/__sin.c
7// https://git.musl-libc.org/cgit/musl/tree/src/math/__sindf.c
8// https://git.musl-libc.org/cgit/musl/tree/src/math/__tand.c
9// https://git.musl-libc.org/cgit/musl/tree/src/math/__tandf.c
10
11// kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
12// Input x is assumed to be bounded by ~pi/4 in magnitude.
13// Input y is the tail of x.
14//
15// Algorithm
16// 1. Since cos(-x) = cos(x), we need only to consider positive x.
17// 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0.
18// 3. cos(x) is approximated by a polynomial of degree 14 on
19// [0,pi/4]
20// 4 14
21// cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x
22// where the remez error is
23//
24// | 2 4 6 8 10 12 14 | -58
25// |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2
26// | |
27//
28// 4 6 8 10 12 14
29// 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then
30// cos(x) ~ 1 - x*x/2 + r
31// since cos(x+y) ~ cos(x) - sin(x)*y
32// ~ cos(x) - x*y,
33// a correction term is necessary in cos(x) and hence
34// cos(x+y) = 1 - (x*x/2 - (r - x*y))
35// For better accuracy, rearrange to
36// cos(x+y) ~ w + (tmp + (r-x*y))
37// where w = 1 - x*x/2 and tmp is a tiny correction term
38// (1 - x*x/2 == w + tmp exactly in infinite precision).
39// The exactness of w + tmp in infinite precision depends on w
40// and tmp having the same precision as x. If they have extra
41// precision due to compiler bugs, then the extra precision is
42// only good provided it is retained in all terms of the final
43// expression for cos(). Retention happens in all cases tested
44// under FreeBSD, so don't pessimize things by forcibly clipping
45// any extra precision in w.
46pub fn __cos(x: f64, y: f64) f64 {
47 const C1 = 4.16666666666666019037e-02; // 0x3FA55555, 0x5555554C
48 const C2 = -1.38888888888741095749e-03; // 0xBF56C16C, 0x16C15177
49 const C3 = 2.48015872894767294178e-05; // 0x3EFA01A0, 0x19CB1590
50 const C4 = -2.75573143513906633035e-07; // 0xBE927E4F, 0x809C52AD
51 const C5 = 2.08757232129817482790e-09; // 0x3E21EE9E, 0xBDB4B1C4
52 const C6 = -1.13596475577881948265e-11; // 0xBDA8FAE9, 0xBE8838D4
53
54 const z = x * x;
55 const zs = z * z;
56 const r = z * (C1 + z * (C2 + z * C3)) + zs * zs * (C4 + z * (C5 + z * C6));
57 const hz = 0.5 * z;
58 const w = 1.0 - hz;
59 return w + (((1.0 - w) - hz) + (z * r - x * y));
60}
61
62pub fn __cosdf(x: f64) f32 {
63 // |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]).
64 const C0 = -0x1ffffffd0c5e81.0p-54; // -0.499999997251031003120
65 const C1 = 0x155553e1053a42.0p-57; // 0.0416666233237390631894
66 const C2 = -0x16c087e80f1e27.0p-62; // -0.00138867637746099294692
67 const C3 = 0x199342e0ee5069.0p-68; // 0.0000243904487962774090654
68
69 // Try to optimize for parallel evaluation as in __tandf.c.
70 const z = x * x;
71 const w = z * z;
72 const r = C2 + z * C3;
73 return @floatCast(f32, ((1.0 + z * C0) + w * C1) + (w * z) * r);
74}
75
76// kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854
77// Input x is assumed to be bounded by ~pi/4 in magnitude.
78// Input y is the tail of x.
79// Input iy indicates whether y is 0. (if iy=0, y assume to be 0).
80//
81// Algorithm
82// 1. Since sin(-x) = -sin(x), we need only to consider positive x.
83// 2. Callers must return sin(-0) = -0 without calling here since our
84// odd polynomial is not evaluated in a way that preserves -0.
85// Callers may do the optimization sin(x) ~ x for tiny x.
86// 3. sin(x) is approximated by a polynomial of degree 13 on
87// [0,pi/4]
88// 3 13
89// sin(x) ~ x + S1*x + ... + S6*x
90// where
91//
92// |sin(x) 2 4 6 8 10 12 | -58
93// |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2
94// | x |
95//
96// 4. sin(x+y) = sin(x) + sin'(x')*y
97// ~ sin(x) + (1-x*x/2)*y
98// For better accuracy, let
99// 3 2 2 2 2
100// r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6))))
101// then 3 2
102// sin(x) = x + (S1*x + (x *(r-y/2)+y))
103pub fn __sin(x: f64, y: f64, iy: i32) f64 {
104 const S1 = -1.66666666666666324348e-01; // 0xBFC55555, 0x55555549
105 const S2 = 8.33333333332248946124e-03; // 0x3F811111, 0x1110F8A6
106 const S3 = -1.98412698298579493134e-04; // 0xBF2A01A0, 0x19C161D5
107 const S4 = 2.75573137070700676789e-06; // 0x3EC71DE3, 0x57B1FE7D
108 const S5 = -2.50507602534068634195e-08; // 0xBE5AE5E6, 0x8A2B9CEB
109 const S6 = 1.58969099521155010221e-10; // 0x3DE5D93A, 0x5ACFD57C
110
111 const z = x * x;
112 const w = z * z;
113 const r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6);
114 const v = z * x;
115 if (iy == 0) {
116 return x + v * (S1 + z * r);
117 } else {
118 return x - ((z * (0.5 * y - v * r) - y) - v * S1);
119 }
120}
121
122pub fn __sindf(x: f64) f32 {
123 // |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]).
124 const S1 = -0x15555554cbac77.0p-55; // -0.166666666416265235595
125 const S2 = 0x111110896efbb2.0p-59; // 0.0083333293858894631756
126 const S3 = -0x1a00f9e2cae774.0p-65; // -0.000198393348360966317347
127 const S4 = 0x16cd878c3b46a7.0p-71; // 0.0000027183114939898219064
128
129 // Try to optimize for parallel evaluation as in __tandf.c.
130 const z = x * x;
131 const w = z * z;
132 const r = S3 + z * S4;
133 const s = z * x;
134 return @floatCast(f32, (x + s * (S1 + z * S2)) + s * w * r);
135}
136
137// kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854
138// Input x is assumed to be bounded by ~pi/4 in magnitude.
139// Input y is the tail of x.
140// Input odd indicates whether tan (if odd = 0) or -1/tan (if odd = 1) is returned.
141//
142// Algorithm
143// 1. Since tan(-x) = -tan(x), we need only to consider positive x.
144// 2. Callers must return tan(-0) = -0 without calling here since our
145// odd polynomial is not evaluated in a way that preserves -0.
146// Callers may do the optimization tan(x) ~ x for tiny x.
147// 3. tan(x) is approximated by a odd polynomial of degree 27 on
148// [0,0.67434]
149// 3 27
150// tan(x) ~ x + T1*x + ... + T13*x
151// where
152//
153// |tan(x) 2 4 26 | -59.2
154// |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2
155// | x |
156//
157// Note: tan(x+y) = tan(x) + tan'(x)*y
158// ~ tan(x) + (1+x*x)*y
159// Therefore, for better accuracy in computing tan(x+y), let
160// 3 2 2 2 2
161// r = x *(T2+x *(T3+x *(...+x *(T12+x *T13))))
162// then
163// 3 2
164// tan(x+y) = x + (T1*x + (x *(r+y)+y))
165//
166// 4. For x in [0.67434,pi/4], let y = pi/4 - x, then
167// tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y))
168// = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y)))
169pub fn __tan(x_: f64, y_: f64, odd: bool) f64 {
170 var x = x_;
171 var y = y_;
172
173 const T = [_]f64{
174 3.33333333333334091986e-01, // 3FD55555, 55555563
175 1.33333333333201242699e-01, // 3FC11111, 1110FE7A
176 5.39682539762260521377e-02, // 3FABA1BA, 1BB341FE
177 2.18694882948595424599e-02, // 3F9664F4, 8406D637
178 8.86323982359930005737e-03, // 3F8226E3, E96E8493
179 3.59207910759131235356e-03, // 3F6D6D22, C9560328
180 1.45620945432529025516e-03, // 3F57DBC8, FEE08315
181 5.88041240820264096874e-04, // 3F4344D8, F2F26501
182 2.46463134818469906812e-04, // 3F3026F7, 1A8D1068
183 7.81794442939557092300e-05, // 3F147E88, A03792A6
184 7.14072491382608190305e-05, // 3F12B80F, 32F0A7E9
185 -1.85586374855275456654e-05, // BEF375CB, DB605373
186 2.59073051863633712884e-05, // 3EFB2A70, 74BF7AD4
187 };
188 const pio4 = 7.85398163397448278999e-01; // 3FE921FB, 54442D18
189 const pio4lo = 3.06161699786838301793e-17; // 3C81A626, 33145C07
190
191 var z: f64 = undefined;
192 var r: f64 = undefined;
193 var v: f64 = undefined;
194 var w: f64 = undefined;
195 var s: f64 = undefined;
196 var a: f64 = undefined;
197 var w0: f64 = undefined;
198 var a0: f64 = undefined;
199 var hx: u32 = undefined;
200 var sign: bool = undefined;
201
202 hx = @intCast(u32, @bitCast(u64, x) >> 32);
203 const big = (hx & 0x7fffffff) >= 0x3FE59428; // |x| >= 0.6744
204 if (big) {
205 sign = hx >> 31 != 0;
206 if (sign) {
207 x = -x;
208 y = -y;
209 }
210 x = (pio4 - x) + (pio4lo - y);
211 y = 0.0;
212 }
213 z = x * x;
214 w = z * z;
215
216 // Break x^5*(T[1]+x^2*T[2]+...) into
217 // x^5(T[1]+x^4*T[3]+...+x^20*T[11]) +
218 // x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12]))
219 r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] + w * T[11]))));
220 v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] + w * T[12])))));
221 s = z * x;
222 r = y + z * (s * (r + v) + y) + s * T[0];
223 w = x + r;
224 if (big) {
225 s = 1 - 2 * @intToFloat(f64, @boolToInt(odd));
226 v = s - 2.0 * (x + (r - w * w / (w + s)));
227 return if (sign) -v else v;
228 }
229 if (!odd) {
230 return w;
231 }
232 // -1.0/(x+r) has up to 2ulp error, so compute it accurately
233 w0 = w;
234 w0 = @bitCast(f64, @bitCast(u64, w0) & 0xffffffff00000000);
235 v = r - (w0 - x); // w0+v = r+x
236 a = -1.0 / w;
237 a0 = a;
238 a0 = @bitCast(f64, @bitCast(u64, a0) & 0xffffffff00000000);
239 return a0 + a * (1.0 + a0 * w0 + a0 * v);
240}
241
242pub fn __tandf(x: f64, odd: bool) f32 {
243 // |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]).
244 const T = [_]f64{
245 0x15554d3418c99f.0p-54, // 0.333331395030791399758
246 0x1112fd38999f72.0p-55, // 0.133392002712976742718
247 0x1b54c91d865afe.0p-57, // 0.0533812378445670393523
248 0x191df3908c33ce.0p-58, // 0.0245283181166547278873
249 0x185dadfcecf44e.0p-61, // 0.00297435743359967304927
250 0x1362b9bf971bcd.0p-59, // 0.00946564784943673166728
251 };
252
253 const z = x * x;
254 // Split up the polynomial into small independent terms to give
255 // opportunities for parallel evaluation. The chosen splitting is
256 // micro-optimized for Athlons (XP, X64). It costs 2 multiplications
257 // relative to Horner's method on sequential machines.
258 //
259 // We add the small terms from lowest degree up for efficiency on
260 // non-sequential machines (the lowest degree terms tend to be ready
261 // earlier). Apart from this, we don't care about order of
262 // operations, and don't need to to care since we have precision to
263 // spare. However, the chosen splitting is good for accuracy too,
264 // and would give results as accurate as Horner's method if the
265 // small terms were added from highest degree down.
266 const r = T[4] + z * T[5];
267 const t = T[2] + z * T[3];
268 const w = z * z;
269 const s = z * x;
270 const u = T[0] + z * T[1];
271 const r0 = (x + s * u) + (s * w) * (t + w * r);
272 return @floatCast(f32, if (odd) -1.0 / r0 else r0);
273}
lib/std/math/acos.zig+4-4
......@@ -64,14 +64,14 @@ fn acos32(x: f32) f32 {
6464 // x < -0.5
6565 if (hx >> 31 != 0) {
6666 const z = (1 + x) * 0.5;
67 const s = math.sqrt(z);
67 const s = @sqrt(z);
6868 const w = r32(z) * s - pio2_lo;
6969 return 2 * (pio2_hi - (s + w));
7070 }
7171
7272 // x > 0.5
7373 const z = (1.0 - x) * 0.5;
74 const s = math.sqrt(z);
74 const s = @sqrt(z);
7575 const jx = @bitCast(u32, s);
7676 const df = @bitCast(f32, jx & 0xFFFFF000);
7777 const c = (z - df * df) / (s + df);
......@@ -133,14 +133,14 @@ fn acos64(x: f64) f64 {
133133 // x < -0.5
134134 if (hx >> 31 != 0) {
135135 const z = (1.0 + x) * 0.5;
136 const s = math.sqrt(z);
136 const s = @sqrt(z);
137137 const w = r64(z) * s - pio2_lo;
138138 return 2 * (pio2_hi - (s + w));
139139 }
140140
141141 // x > 0.5
142142 const z = (1.0 - x) * 0.5;
143 const s = math.sqrt(z);
143 const s = @sqrt(z);
144144 const jx = @bitCast(u64, s);
145145 const df = @bitCast(f64, jx & 0xFFFFFFFF00000000);
146146 const c = (z - df * df) / (s + df);
lib/std/math/acosh.zig+6-6
......@@ -29,15 +29,15 @@ fn acosh32(x: f32) f32 {
2929
3030 // |x| < 2, invalid if x < 1 or nan
3131 if (i < 0x3F800000 + (1 << 23)) {
32 return math.log1p(x - 1 + math.sqrt((x - 1) * (x - 1) + 2 * (x - 1)));
32 return math.log1p(x - 1 + @sqrt((x - 1) * (x - 1) + 2 * (x - 1)));
3333 }
3434 // |x| < 0x1p12
3535 else if (i < 0x3F800000 + (12 << 23)) {
36 return math.ln(2 * x - 1 / (x + math.sqrt(x * x - 1)));
36 return @log(2 * x - 1 / (x + @sqrt(x * x - 1)));
3737 }
3838 // |x| >= 0x1p12
3939 else {
40 return math.ln(x) + 0.693147180559945309417232121458176568;
40 return @log(x) + 0.693147180559945309417232121458176568;
4141 }
4242}
4343
......@@ -47,15 +47,15 @@ fn acosh64(x: f64) f64 {
4747
4848 // |x| < 2, invalid if x < 1 or nan
4949 if (e < 0x3FF + 1) {
50 return math.log1p(x - 1 + math.sqrt((x - 1) * (x - 1) + 2 * (x - 1)));
50 return math.log1p(x - 1 + @sqrt((x - 1) * (x - 1) + 2 * (x - 1)));
5151 }
5252 // |x| < 0x1p26
5353 else if (e < 0x3FF + 26) {
54 return math.ln(2 * x - 1 / (x + math.sqrt(x * x - 1)));
54 return @log(2 * x - 1 / (x + @sqrt(x * x - 1)));
5555 }
5656 // |x| >= 0x1p26 or nan
5757 else {
58 return math.ln(x) + 0.693147180559945309417232121458176568;
58 return @log(x) + 0.693147180559945309417232121458176568;
5959 }
6060}
6161
lib/std/math/asin.zig+4-4
......@@ -60,8 +60,8 @@ fn asin32(x: f32) f32 {
6060 }
6161
6262 // 1 > |x| >= 0.5
63 const z = (1 - math.fabs(x)) * 0.5;
64 const s = math.sqrt(z);
63 const z = (1 - @fabs(x)) * 0.5;
64 const s = @sqrt(z);
6565 const fx = pio2 - 2 * (s + s * r32(z));
6666
6767 if (hx >> 31 != 0) {
......@@ -119,8 +119,8 @@ fn asin64(x: f64) f64 {
119119 }
120120
121121 // 1 > |x| >= 0.5
122 const z = (1 - math.fabs(x)) * 0.5;
123 const s = math.sqrt(z);
122 const z = (1 - @fabs(x)) * 0.5;
123 const s = @sqrt(z);
124124 const r = r64(z);
125125 var fx: f64 = undefined;
126126
lib/std/math/asinh.zig+6-6
......@@ -39,15 +39,15 @@ fn asinh32(x: f32) f32 {
3939
4040 // |x| >= 0x1p12 or inf or nan
4141 if (i >= 0x3F800000 + (12 << 23)) {
42 rx = math.ln(rx) + 0.69314718055994530941723212145817656;
42 rx = @log(rx) + 0.69314718055994530941723212145817656;
4343 }
4444 // |x| >= 2
4545 else if (i >= 0x3F800000 + (1 << 23)) {
46 rx = math.ln(2 * x + 1 / (math.sqrt(x * x + 1) + x));
46 rx = @log(2 * x + 1 / (@sqrt(x * x + 1) + x));
4747 }
4848 // |x| >= 0x1p-12, up to 1.6ulp error
4949 else if (i >= 0x3F800000 - (12 << 23)) {
50 rx = math.log1p(x + x * x / (math.sqrt(x * x + 1) + 1));
50 rx = math.log1p(x + x * x / (@sqrt(x * x + 1) + 1));
5151 }
5252 // |x| < 0x1p-12, inexact if x != 0
5353 else {
......@@ -70,15 +70,15 @@ fn asinh64(x: f64) f64 {
7070
7171 // |x| >= 0x1p26 or inf or nan
7272 if (e >= 0x3FF + 26) {
73 rx = math.ln(rx) + 0.693147180559945309417232121458176568;
73 rx = @log(rx) + 0.693147180559945309417232121458176568;
7474 }
7575 // |x| >= 2
7676 else if (e >= 0x3FF + 1) {
77 rx = math.ln(2 * x + 1 / (math.sqrt(x * x + 1) + x));
77 rx = @log(2 * x + 1 / (@sqrt(x * x + 1) + x));
7878 }
7979 // |x| >= 0x1p-12, up to 1.6ulp error
8080 else if (e >= 0x3FF - 26) {
81 rx = math.log1p(x + x * x / (math.sqrt(x * x + 1) + 1));
81 rx = math.log1p(x + x * x / (@sqrt(x * x + 1) + 1));
8282 }
8383 // |x| < 0x1p-12, inexact if x != 0
8484 else {
lib/std/math/atan.zig+2-2
......@@ -73,7 +73,7 @@ fn atan32(x_: f32) f32 {
7373 }
7474 id = null;
7575 } else {
76 x = math.fabs(x);
76 x = @fabs(x);
7777 // |x| < 1.1875
7878 if (ix < 0x3F980000) {
7979 // 7/16 <= |x| < 11/16
......@@ -171,7 +171,7 @@ fn atan64(x_: f64) f64 {
171171 }
172172 id = null;
173173 } else {
174 x = math.fabs(x);
174 x = @fabs(x);
175175 // |x| < 1.1875
176176 if (ix < 0x3FF30000) {
177177 // 7/16 <= |x| < 11/16
lib/std/math/atan2.zig+2-2
......@@ -108,7 +108,7 @@ fn atan2_32(y: f32, x: f32) f32 {
108108 if ((m & 2) != 0 and iy + (26 << 23) < ix) {
109109 break :z 0.0;
110110 } else {
111 break :z math.atan(math.fabs(y / x));
111 break :z math.atan(@fabs(y / x));
112112 }
113113 };
114114
......@@ -198,7 +198,7 @@ fn atan2_64(y: f64, x: f64) f64 {
198198 if ((m & 2) != 0 and iy +% (64 << 20) < ix) {
199199 break :z 0.0;
200200 } else {
201 break :z math.atan(math.fabs(y / x));
201 break :z math.atan(@fabs(y / x));
202202 }
203203 };
204204
lib/std/math/ceil.zig deleted-170
......@@ -1,170 +0,0 @@
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/ceilf.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/ceil.c
6
7const std = @import("../std.zig");
8const math = std.math;
9const expect = std.testing.expect;
10
11/// Returns the least integer value greater than of equal to x.
12///
13/// Special Cases:
14/// - ceil(+-0) = +-0
15/// - ceil(+-inf) = +-inf
16/// - ceil(nan) = nan
17pub fn ceil(x: anytype) @TypeOf(x) {
18 const T = @TypeOf(x);
19 return switch (T) {
20 f32 => ceil32(x),
21 f64 => ceil64(x),
22 f128 => ceil128(x),
23
24 // TODO this is not correct for some targets
25 c_longdouble => @floatCast(c_longdouble, ceil128(x)),
26
27 else => @compileError("ceil not implemented for " ++ @typeName(T)),
28 };
29}
30
31fn ceil32(x: f32) f32 {
32 var u = @bitCast(u32, x);
33 var e = @intCast(i32, (u >> 23) & 0xFF) - 0x7F;
34 var m: u32 = undefined;
35
36 // TODO: Shouldn't need this explicit check.
37 if (x == 0.0) {
38 return x;
39 }
40
41 if (e >= 23) {
42 return x;
43 } else if (e >= 0) {
44 m = @as(u32, 0x007FFFFF) >> @intCast(u5, e);
45 if (u & m == 0) {
46 return x;
47 }
48 math.doNotOptimizeAway(x + 0x1.0p120);
49 if (u >> 31 == 0) {
50 u += m;
51 }
52 u &= ~m;
53 return @bitCast(f32, u);
54 } else {
55 math.doNotOptimizeAway(x + 0x1.0p120);
56 if (u >> 31 != 0) {
57 return -0.0;
58 } else {
59 return 1.0;
60 }
61 }
62}
63
64fn ceil64(x: f64) f64 {
65 const f64_toint = 1.0 / math.floatEps(f64);
66
67 const u = @bitCast(u64, x);
68 const e = (u >> 52) & 0x7FF;
69 var y: f64 = undefined;
70
71 if (e >= 0x3FF + 52 or x == 0) {
72 return x;
73 }
74
75 if (u >> 63 != 0) {
76 y = x - f64_toint + f64_toint - x;
77 } else {
78 y = x + f64_toint - f64_toint - x;
79 }
80
81 if (e <= 0x3FF - 1) {
82 math.doNotOptimizeAway(y);
83 if (u >> 63 != 0) {
84 return -0.0;
85 } else {
86 return 1.0;
87 }
88 } else if (y < 0) {
89 return x + y + 1;
90 } else {
91 return x + y;
92 }
93}
94
95fn ceil128(x: f128) f128 {
96 const f128_toint = 1.0 / math.floatEps(f128);
97
98 const u = @bitCast(u128, x);
99 const e = (u >> 112) & 0x7FFF;
100 var y: f128 = undefined;
101
102 if (e >= 0x3FFF + 112 or x == 0) return x;
103
104 if (u >> 127 != 0) {
105 y = x - f128_toint + f128_toint - x;
106 } else {
107 y = x + f128_toint - f128_toint - x;
108 }
109
110 if (e <= 0x3FFF - 1) {
111 math.doNotOptimizeAway(y);
112 if (u >> 127 != 0) {
113 return -0.0;
114 } else {
115 return 1.0;
116 }
117 } else if (y < 0) {
118 return x + y + 1;
119 } else {
120 return x + y;
121 }
122}
123
124test "math.ceil" {
125 try expect(ceil(@as(f32, 0.0)) == ceil32(0.0));
126 try expect(ceil(@as(f64, 0.0)) == ceil64(0.0));
127 try expect(ceil(@as(f128, 0.0)) == ceil128(0.0));
128}
129
130test "math.ceil32" {
131 try expect(ceil32(1.3) == 2.0);
132 try expect(ceil32(-1.3) == -1.0);
133 try expect(ceil32(0.2) == 1.0);
134}
135
136test "math.ceil64" {
137 try expect(ceil64(1.3) == 2.0);
138 try expect(ceil64(-1.3) == -1.0);
139 try expect(ceil64(0.2) == 1.0);
140}
141
142test "math.ceil128" {
143 try expect(ceil128(1.3) == 2.0);
144 try expect(ceil128(-1.3) == -1.0);
145 try expect(ceil128(0.2) == 1.0);
146}
147
148test "math.ceil32.special" {
149 try expect(ceil32(0.0) == 0.0);
150 try expect(ceil32(-0.0) == -0.0);
151 try expect(math.isPositiveInf(ceil32(math.inf(f32))));
152 try expect(math.isNegativeInf(ceil32(-math.inf(f32))));
153 try expect(math.isNan(ceil32(math.nan(f32))));
154}
155
156test "math.ceil64.special" {
157 try expect(ceil64(0.0) == 0.0);
158 try expect(ceil64(-0.0) == -0.0);
159 try expect(math.isPositiveInf(ceil64(math.inf(f64))));
160 try expect(math.isNegativeInf(ceil64(-math.inf(f64))));
161 try expect(math.isNan(ceil64(math.nan(f64))));
162}
163
164test "math.ceil128.special" {
165 try expect(ceil128(0.0) == 0.0);
166 try expect(ceil128(-0.0) == -0.0);
167 try expect(math.isPositiveInf(ceil128(math.inf(f128))));
168 try expect(math.isNegativeInf(ceil128(-math.inf(f128))));
169 try expect(math.isNan(ceil128(math.nan(f128))));
170}
lib/std/math/complex.zig+1-1
......@@ -115,7 +115,7 @@ pub fn Complex(comptime T: type) type {
115115
116116 /// Returns the magnitude of a complex number.
117117 pub fn magnitude(self: Self) T {
118 return math.sqrt(self.re * self.re + self.im * self.im);
118 return @sqrt(self.re * self.re + self.im * self.im);
119119 }
120120 };
121121}
lib/std/math/complex/atan.zig+2-2
......@@ -66,7 +66,7 @@ fn atan32(z: Complex(f32)) Complex(f32) {
6666
6767 t = y + 1.0;
6868 a = (x2 + (t * t)) / a;
69 return Complex(f32).init(w, 0.25 * math.ln(a));
69 return Complex(f32).init(w, 0.25 * @log(a));
7070}
7171
7272fn redupif64(x: f64) f64 {
......@@ -115,7 +115,7 @@ fn atan64(z: Complex(f64)) Complex(f64) {
115115
116116 t = y + 1.0;
117117 a = (x2 + (t * t)) / a;
118 return Complex(f64).init(w, 0.25 * math.ln(a));
118 return Complex(f64).init(w, 0.25 * @log(a));
119119}
120120
121121const epsilon = 0.0001;
lib/std/math/complex/cosh.zig+4-4
......@@ -44,12 +44,12 @@ fn cosh32(z: Complex(f32)) Complex(f32) {
4444 // |x|>= 9, so cosh(x) ~= exp(|x|)
4545 if (ix < 0x42b17218) {
4646 // x < 88.7: exp(|x|) won't overflow
47 const h = math.exp(math.fabs(x)) * 0.5;
47 const h = @exp(@fabs(x)) * 0.5;
4848 return Complex(f32).init(math.copysign(f32, h, x) * math.cos(y), h * math.sin(y));
4949 }
5050 // x < 192.7: scale to avoid overflow
5151 else if (ix < 0x4340b1e7) {
52 const v = Complex(f32).init(math.fabs(x), y);
52 const v = Complex(f32).init(@fabs(x), y);
5353 const r = ldexp_cexp(v, -1);
5454 return Complex(f32).init(r.re, r.im * math.copysign(f32, 1, x));
5555 }
......@@ -112,12 +112,12 @@ fn cosh64(z: Complex(f64)) Complex(f64) {
112112 // |x|>= 22, so cosh(x) ~= exp(|x|)
113113 if (ix < 0x40862e42) {
114114 // x < 710: exp(|x|) won't overflow
115 const h = math.exp(math.fabs(x)) * 0.5;
115 const h = @exp(@fabs(x)) * 0.5;
116116 return Complex(f64).init(h * math.cos(y), math.copysign(f64, h, x) * math.sin(y));
117117 }
118118 // x < 1455: scale to avoid overflow
119119 else if (ix < 0x4096bbaa) {
120 const v = Complex(f64).init(math.fabs(x), y);
120 const v = Complex(f64).init(@fabs(x), y);
121121 const r = ldexp_cexp(v, -1);
122122 return Complex(f64).init(r.re, r.im * math.copysign(f64, 1, x));
123123 }
lib/std/math/complex/exp.zig+6-6
......@@ -33,7 +33,7 @@ fn exp32(z: Complex(f32)) Complex(f32) {
3333 const hy = @bitCast(u32, y) & 0x7fffffff;
3434 // cexp(x + i0) = exp(x) + i0
3535 if (hy == 0) {
36 return Complex(f32).init(math.exp(x), y);
36 return Complex(f32).init(@exp(x), y);
3737 }
3838
3939 const hx = @bitCast(u32, x);
......@@ -63,7 +63,7 @@ fn exp32(z: Complex(f32)) Complex(f32) {
6363 // - x = +-inf
6464 // - x = nan
6565 else {
66 const exp_x = math.exp(x);
66 const exp_x = @exp(x);
6767 return Complex(f32).init(exp_x * math.cos(y), exp_x * math.sin(y));
6868 }
6969}
......@@ -81,7 +81,7 @@ fn exp64(z: Complex(f64)) Complex(f64) {
8181
8282 // cexp(x + i0) = exp(x) + i0
8383 if (hy | ly == 0) {
84 return Complex(f64).init(math.exp(x), y);
84 return Complex(f64).init(@exp(x), y);
8585 }
8686
8787 const fx = @bitCast(u64, x);
......@@ -114,13 +114,13 @@ fn exp64(z: Complex(f64)) Complex(f64) {
114114 // - x = +-inf
115115 // - x = nan
116116 else {
117 const exp_x = math.exp(x);
117 const exp_x = @exp(x);
118118 return Complex(f64).init(exp_x * math.cos(y), exp_x * math.sin(y));
119119 }
120120}
121121
122122test "complex.cexp32" {
123 const tolerance_f32 = math.sqrt(math.floatEps(f32));
123 const tolerance_f32 = @sqrt(math.floatEps(f32));
124124
125125 {
126126 const a = Complex(f32).init(5, 3);
......@@ -140,7 +140,7 @@ test "complex.cexp32" {
140140}
141141
142142test "complex.cexp64" {
143 const tolerance_f64 = math.sqrt(math.floatEps(f64));
143 const tolerance_f64 = @sqrt(math.floatEps(f64));
144144
145145 {
146146 const a = Complex(f64).init(5, 3);
lib/std/math/complex/ldexp.zig+2-2
......@@ -26,7 +26,7 @@ fn frexp_exp32(x: f32, expt: *i32) f32 {
2626 const k = 235; // reduction constant
2727 const kln2 = 162.88958740; // k * ln2
2828
29 const exp_x = math.exp(x - kln2);
29 const exp_x = @exp(x - kln2);
3030 const hx = @bitCast(u32, exp_x);
3131 // TODO zig should allow this cast implicitly because it should know the value is in range
3232 expt.* = @intCast(i32, hx >> 23) - (0x7f + 127) + k;
......@@ -54,7 +54,7 @@ fn frexp_exp64(x: f64, expt: *i32) f64 {
5454 const k = 1799; // reduction constant
5555 const kln2 = 1246.97177782734161156; // k * ln2
5656
57 const exp_x = math.exp(x - kln2);
57 const exp_x = @exp(x - kln2);
5858
5959 const fx = @bitCast(u64, exp_x);
6060 const hx = @intCast(u32, fx >> 32);
lib/std/math/complex/log.zig+1-1
......@@ -10,7 +10,7 @@ pub fn log(z: anytype) Complex(@TypeOf(z.re)) {
1010 const r = cmath.abs(z);
1111 const phi = cmath.arg(z);
1212
13 return Complex(T).init(math.ln(r), phi);
13 return Complex(T).init(@log(r), phi);
1414}
1515
1616const epsilon = 0.0001;
lib/std/math/complex/sinh.zig+4-4
......@@ -44,12 +44,12 @@ fn sinh32(z: Complex(f32)) Complex(f32) {
4444 // |x|>= 9, so cosh(x) ~= exp(|x|)
4545 if (ix < 0x42b17218) {
4646 // x < 88.7: exp(|x|) won't overflow
47 const h = math.exp(math.fabs(x)) * 0.5;
47 const h = @exp(@fabs(x)) * 0.5;
4848 return Complex(f32).init(math.copysign(f32, h, x) * math.cos(y), h * math.sin(y));
4949 }
5050 // x < 192.7: scale to avoid overflow
5151 else if (ix < 0x4340b1e7) {
52 const v = Complex(f32).init(math.fabs(x), y);
52 const v = Complex(f32).init(@fabs(x), y);
5353 const r = ldexp_cexp(v, -1);
5454 return Complex(f32).init(r.re * math.copysign(f32, 1, x), r.im);
5555 }
......@@ -111,12 +111,12 @@ fn sinh64(z: Complex(f64)) Complex(f64) {
111111 // |x|>= 22, so cosh(x) ~= exp(|x|)
112112 if (ix < 0x40862e42) {
113113 // x < 710: exp(|x|) won't overflow
114 const h = math.exp(math.fabs(x)) * 0.5;
114 const h = @exp(@fabs(x)) * 0.5;
115115 return Complex(f64).init(math.copysign(f64, h, x) * math.cos(y), h * math.sin(y));
116116 }
117117 // x < 1455: scale to avoid overflow
118118 else if (ix < 0x4096bbaa) {
119 const v = Complex(f64).init(math.fabs(x), y);
119 const v = Complex(f64).init(@fabs(x), y);
120120 const r = ldexp_cexp(v, -1);
121121 return Complex(f64).init(r.re * math.copysign(f64, 1, x), r.im);
122122 }
lib/std/math/complex/sqrt.zig+9-9
......@@ -43,7 +43,7 @@ fn sqrt32(z: Complex(f32)) Complex(f32) {
4343 // sqrt(-inf + i nan) = nan +- inf i
4444 // sqrt(-inf + iy) = 0 + inf i
4545 if (math.signbit(x)) {
46 return Complex(f32).init(math.fabs(x - y), math.copysign(f32, x, y));
46 return Complex(f32).init(@fabs(x - y), math.copysign(f32, x, y));
4747 } else {
4848 return Complex(f32).init(x, math.copysign(f32, y - y, y));
4949 }
......@@ -56,15 +56,15 @@ fn sqrt32(z: Complex(f32)) Complex(f32) {
5656 const dy = @as(f64, y);
5757
5858 if (dx >= 0) {
59 const t = math.sqrt((dx + math.hypot(f64, dx, dy)) * 0.5);
59 const t = @sqrt((dx + math.hypot(f64, dx, dy)) * 0.5);
6060 return Complex(f32).init(
6161 @floatCast(f32, t),
6262 @floatCast(f32, dy / (2.0 * t)),
6363 );
6464 } else {
65 const t = math.sqrt((-dx + math.hypot(f64, dx, dy)) * 0.5);
65 const t = @sqrt((-dx + math.hypot(f64, dx, dy)) * 0.5);
6666 return Complex(f32).init(
67 @floatCast(f32, math.fabs(y) / (2.0 * t)),
67 @floatCast(f32, @fabs(y) / (2.0 * t)),
6868 @floatCast(f32, math.copysign(f64, t, y)),
6969 );
7070 }
......@@ -94,7 +94,7 @@ fn sqrt64(z: Complex(f64)) Complex(f64) {
9494 // sqrt(-inf + i nan) = nan +- inf i
9595 // sqrt(-inf + iy) = 0 + inf i
9696 if (math.signbit(x)) {
97 return Complex(f64).init(math.fabs(x - y), math.copysign(f64, x, y));
97 return Complex(f64).init(@fabs(x - y), math.copysign(f64, x, y));
9898 } else {
9999 return Complex(f64).init(x, math.copysign(f64, y - y, y));
100100 }
......@@ -104,7 +104,7 @@ fn sqrt64(z: Complex(f64)) Complex(f64) {
104104
105105 // scale to avoid overflow
106106 var scale = false;
107 if (math.fabs(x) >= threshold or math.fabs(y) >= threshold) {
107 if (@fabs(x) >= threshold or @fabs(y) >= threshold) {
108108 x *= 0.25;
109109 y *= 0.25;
110110 scale = true;
......@@ -112,11 +112,11 @@ fn sqrt64(z: Complex(f64)) Complex(f64) {
112112
113113 var result: Complex(f64) = undefined;
114114 if (x >= 0) {
115 const t = math.sqrt((x + math.hypot(f64, x, y)) * 0.5);
115 const t = @sqrt((x + math.hypot(f64, x, y)) * 0.5);
116116 result = Complex(f64).init(t, y / (2.0 * t));
117117 } else {
118 const t = math.sqrt((-x + math.hypot(f64, x, y)) * 0.5);
119 result = Complex(f64).init(math.fabs(y) / (2.0 * t), math.copysign(f64, t, y));
118 const t = @sqrt((-x + math.hypot(f64, x, y)) * 0.5);
119 result = Complex(f64).init(@fabs(y) / (2.0 * t), math.copysign(f64, t, y));
120120 }
121121
122122 if (scale) {
lib/std/math/complex/tanh.zig+4-4
......@@ -44,7 +44,7 @@ fn tanh32(z: Complex(f32)) Complex(f32) {
4444
4545 // x >= 11
4646 if (ix >= 0x41300000) {
47 const exp_mx = math.exp(-math.fabs(x));
47 const exp_mx = @exp(-@fabs(x));
4848 return Complex(f32).init(math.copysign(f32, 1, x), 4 * math.sin(y) * math.cos(y) * exp_mx * exp_mx);
4949 }
5050
......@@ -52,7 +52,7 @@ fn tanh32(z: Complex(f32)) Complex(f32) {
5252 const t = math.tan(y);
5353 const beta = 1.0 + t * t;
5454 const s = math.sinh(x);
55 const rho = math.sqrt(1 + s * s);
55 const rho = @sqrt(1 + s * s);
5656 const den = 1 + beta * s * s;
5757
5858 return Complex(f32).init((beta * rho * s) / den, t / den);
......@@ -87,7 +87,7 @@ fn tanh64(z: Complex(f64)) Complex(f64) {
8787
8888 // x >= 22
8989 if (ix >= 0x40360000) {
90 const exp_mx = math.exp(-math.fabs(x));
90 const exp_mx = @exp(-@fabs(x));
9191 return Complex(f64).init(math.copysign(f64, 1, x), 4 * math.sin(y) * math.cos(y) * exp_mx * exp_mx);
9292 }
9393
......@@ -95,7 +95,7 @@ fn tanh64(z: Complex(f64)) Complex(f64) {
9595 const t = math.tan(y);
9696 const beta = 1.0 + t * t;
9797 const s = math.sinh(x);
98 const rho = math.sqrt(1 + s * s);
98 const rho = @sqrt(1 + s * s);
9999 const den = 1 + beta * s * s;
100100
101101 return Complex(f64).init((beta * rho * s) / den, t / den);
lib/std/math/cos.zig deleted-154
......@@ -1,154 +0,0 @@
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
7const std = @import("../std.zig");
8const math = std.math;
9const expect = std.testing.expect;
10
11const kernel = @import("__trig.zig");
12const __rem_pio2 = @import("__rem_pio2.zig").__rem_pio2;
13const __rem_pio2f = @import("__rem_pio2f.zig").__rem_pio2f;
14
15/// Returns the cosine of the radian value x.
16///
17/// Special Cases:
18/// - cos(+-inf) = nan
19/// - cos(nan) = nan
20pub fn cos(x: anytype) @TypeOf(x) {
21 const T = @TypeOf(x);
22 return switch (T) {
23 f32 => cos32(x),
24 f64 => cos64(x),
25 else => @compileError("cos not implemented for " ++ @typeName(T)),
26 };
27}
28
29fn cos32(x: f32) f32 {
30 // Small multiples of pi/2 rounded to double precision.
31 const c1pio2: f64 = 1.0 * math.pi / 2.0; // 0x3FF921FB, 0x54442D18
32 const c2pio2: f64 = 2.0 * math.pi / 2.0; // 0x400921FB, 0x54442D18
33 const c3pio2: f64 = 3.0 * math.pi / 2.0; // 0x4012D97C, 0x7F3321D2
34 const c4pio2: f64 = 4.0 * math.pi / 2.0; // 0x401921FB, 0x54442D18
35
36 var ix = @bitCast(u32, x);
37 const sign = ix >> 31 != 0;
38 ix &= 0x7fffffff;
39
40 if (ix <= 0x3f490fda) { // |x| ~<= pi/4
41 if (ix < 0x39800000) { // |x| < 2**-12
42 // raise inexact if x != 0
43 math.doNotOptimizeAway(x + 0x1p120);
44 return 1.0;
45 }
46 return kernel.__cosdf(x);
47 }
48 if (ix <= 0x407b53d1) { // |x| ~<= 5*pi/4
49 if (ix > 0x4016cbe3) { // |x| ~> 3*pi/4
50 return -kernel.__cosdf(if (sign) x + c2pio2 else x - c2pio2);
51 } else {
52 if (sign) {
53 return kernel.__sindf(x + c1pio2);
54 } else {
55 return kernel.__sindf(c1pio2 - x);
56 }
57 }
58 }
59 if (ix <= 0x40e231d5) { // |x| ~<= 9*pi/4
60 if (ix > 0x40afeddf) { // |x| ~> 7*pi/4
61 return kernel.__cosdf(if (sign) x + c4pio2 else x - c4pio2);
62 } else {
63 if (sign) {
64 return kernel.__sindf(-x - c3pio2);
65 } else {
66 return kernel.__sindf(x - c3pio2);
67 }
68 }
69 }
70
71 // cos(Inf or NaN) is NaN
72 if (ix >= 0x7f800000) {
73 return x - x;
74 }
75
76 var y: f64 = undefined;
77 const n = __rem_pio2f(x, &y);
78 return switch (n & 3) {
79 0 => kernel.__cosdf(y),
80 1 => kernel.__sindf(-y),
81 2 => -kernel.__cosdf(y),
82 else => kernel.__sindf(y),
83 };
84}
85
86fn cos64(x: f64) f64 {
87 var ix = @bitCast(u64, x) >> 32;
88 ix &= 0x7fffffff;
89
90 // |x| ~< pi/4
91 if (ix <= 0x3fe921fb) {
92 if (ix < 0x3e46a09e) { // |x| < 2**-27 * sqrt(2)
93 // raise inexact if x!=0
94 math.doNotOptimizeAway(x + 0x1p120);
95 return 1.0;
96 }
97 return kernel.__cos(x, 0);
98 }
99
100 // cos(Inf or NaN) is NaN
101 if (ix >= 0x7ff00000) {
102 return x - x;
103 }
104
105 var y: [2]f64 = undefined;
106 const n = __rem_pio2(x, &y);
107 return switch (n & 3) {
108 0 => kernel.__cos(y[0], y[1]),
109 1 => -kernel.__sin(y[0], y[1], 1),
110 2 => -kernel.__cos(y[0], y[1]),
111 else => kernel.__sin(y[0], y[1], 1),
112 };
113}
114
115test "math.cos" {
116 try expect(cos(@as(f32, 0.0)) == cos32(0.0));
117 try expect(cos(@as(f64, 0.0)) == cos64(0.0));
118}
119
120test "math.cos32" {
121 const epsilon = 0.00001;
122
123 try expect(math.approxEqAbs(f32, cos32(0.0), 1.0, epsilon));
124 try expect(math.approxEqAbs(f32, cos32(0.2), 0.980067, epsilon));
125 try expect(math.approxEqAbs(f32, cos32(0.8923), 0.627623, epsilon));
126 try expect(math.approxEqAbs(f32, cos32(1.5), 0.070737, epsilon));
127 try expect(math.approxEqAbs(f32, cos32(-1.5), 0.070737, epsilon));
128 try expect(math.approxEqAbs(f32, cos32(37.45), 0.969132, epsilon));
129 try expect(math.approxEqAbs(f32, cos32(89.123), 0.400798, epsilon));
130}
131
132test "math.cos64" {
133 const epsilon = 0.000001;
134
135 try expect(math.approxEqAbs(f64, cos64(0.0), 1.0, epsilon));
136 try expect(math.approxEqAbs(f64, cos64(0.2), 0.980067, epsilon));
137 try expect(math.approxEqAbs(f64, cos64(0.8923), 0.627623, epsilon));
138 try expect(math.approxEqAbs(f64, cos64(1.5), 0.070737, epsilon));
139 try expect(math.approxEqAbs(f64, cos64(-1.5), 0.070737, epsilon));
140 try expect(math.approxEqAbs(f64, cos64(37.45), 0.969132, epsilon));
141 try expect(math.approxEqAbs(f64, cos64(89.123), 0.40080, epsilon));
142}
143
144test "math.cos32.special" {
145 try expect(math.isNan(cos32(math.inf(f32))));
146 try expect(math.isNan(cos32(-math.inf(f32))));
147 try expect(math.isNan(cos32(math.nan(f32))));
148}
149
150test "math.cos64.special" {
151 try expect(math.isNan(cos64(math.inf(f64))));
152 try expect(math.isNan(cos64(-math.inf(f64))));
153 try expect(math.isNan(cos64(math.nan(f64))));
154}
lib/std/math/cosh.zig+2-2
......@@ -45,7 +45,7 @@ fn cosh32(x: f32) f32 {
4545
4646 // |x| < log(FLT_MAX)
4747 if (ux < 0x42B17217) {
48 const t = math.exp(ax);
48 const t = @exp(ax);
4949 return 0.5 * (t + 1 / t);
5050 }
5151
......@@ -77,7 +77,7 @@ fn cosh64(x: f64) f64 {
7777
7878 // |x| < log(DBL_MAX)
7979 if (w < 0x40862E42) {
80 const t = math.exp(ax);
80 const t = @exp(ax);
8181 // NOTE: If x > log(0x1p26) then 1/t is not required.
8282 return 0.5 * (t + 1 / t);
8383 }
lib/std/math/exp.zig deleted-217
......@@ -1,217 +0,0 @@
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/expf.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/exp.c
6
7const std = @import("../std.zig");
8const math = std.math;
9const expect = std.testing.expect;
10
11/// Returns e raised to the power of x (e^x).
12///
13/// Special Cases:
14/// - exp(+inf) = +inf
15/// - exp(nan) = nan
16pub fn exp(x: anytype) @TypeOf(x) {
17 const T = @TypeOf(x);
18 return switch (T) {
19 f32 => exp32(x),
20 f64 => exp64(x),
21 else => @compileError("exp not implemented for " ++ @typeName(T)),
22 };
23}
24
25fn exp32(x_: f32) f32 {
26 const half = [_]f32{ 0.5, -0.5 };
27 const ln2hi = 6.9314575195e-1;
28 const ln2lo = 1.4286067653e-6;
29 const invln2 = 1.4426950216e+0;
30 const P1 = 1.6666625440e-1;
31 const P2 = -2.7667332906e-3;
32
33 var x = x_;
34 var hx = @bitCast(u32, x);
35 const sign = @intCast(i32, hx >> 31);
36 hx &= 0x7FFFFFFF;
37
38 if (math.isNan(x)) {
39 return x;
40 }
41
42 // |x| >= -87.33655 or nan
43 if (hx >= 0x42AEAC50) {
44 // nan
45 if (hx > 0x7F800000) {
46 return x;
47 }
48 // x >= 88.722839
49 if (hx >= 0x42b17218 and sign == 0) {
50 return x * 0x1.0p127;
51 }
52 if (sign != 0) {
53 math.doNotOptimizeAway(-0x1.0p-149 / x); // overflow
54 // x <= -103.972084
55 if (hx >= 0x42CFF1B5) {
56 return 0;
57 }
58 }
59 }
60
61 var k: i32 = undefined;
62 var hi: f32 = undefined;
63 var lo: f32 = undefined;
64
65 // |x| > 0.5 * ln2
66 if (hx > 0x3EB17218) {
67 // |x| > 1.5 * ln2
68 if (hx > 0x3F851592) {
69 k = @floatToInt(i32, invln2 * x + half[@intCast(usize, sign)]);
70 } else {
71 k = 1 - sign - sign;
72 }
73
74 const fk = @intToFloat(f32, k);
75 hi = x - fk * ln2hi;
76 lo = fk * ln2lo;
77 x = hi - lo;
78 }
79 // |x| > 2^(-14)
80 else if (hx > 0x39000000) {
81 k = 0;
82 hi = x;
83 lo = 0;
84 } else {
85 math.doNotOptimizeAway(0x1.0p127 + x); // inexact
86 return 1 + x;
87 }
88
89 const xx = x * x;
90 const c = x - xx * (P1 + xx * P2);
91 const y = 1 + (x * c / (2 - c) - lo + hi);
92
93 if (k == 0) {
94 return y;
95 } else {
96 return math.scalbn(y, k);
97 }
98}
99
100fn exp64(x_: f64) f64 {
101 const half = [_]f64{ 0.5, -0.5 };
102 const ln2hi: f64 = 6.93147180369123816490e-01;
103 const ln2lo: f64 = 1.90821492927058770002e-10;
104 const invln2: f64 = 1.44269504088896338700e+00;
105 const P1: f64 = 1.66666666666666019037e-01;
106 const P2: f64 = -2.77777777770155933842e-03;
107 const P3: f64 = 6.61375632143793436117e-05;
108 const P4: f64 = -1.65339022054652515390e-06;
109 const P5: f64 = 4.13813679705723846039e-08;
110
111 var x = x_;
112 var ux = @bitCast(u64, x);
113 var hx = ux >> 32;
114 const sign = @intCast(i32, hx >> 31);
115 hx &= 0x7FFFFFFF;
116
117 if (math.isNan(x)) {
118 return x;
119 }
120
121 // |x| >= 708.39 or nan
122 if (hx >= 0x4086232B) {
123 // nan
124 if (hx > 0x7FF00000) {
125 return x;
126 }
127 if (x > 709.782712893383973096) {
128 // overflow if x != inf
129 if (!math.isInf(x)) {
130 math.raiseOverflow();
131 }
132 return math.inf(f64);
133 }
134 if (x < -708.39641853226410622) {
135 // underflow if x != -inf
136 // math.doNotOptimizeAway(@as(f32, -0x1.0p-149 / x));
137 if (x < -745.13321910194110842) {
138 return 0;
139 }
140 }
141 }
142
143 // argument reduction
144 var k: i32 = undefined;
145 var hi: f64 = undefined;
146 var lo: f64 = undefined;
147
148 // |x| > 0.5 * ln2
149 if (hx > 0x3FD62E42) {
150 // |x| >= 1.5 * ln2
151 if (hx > 0x3FF0A2B2) {
152 k = @floatToInt(i32, invln2 * x + half[@intCast(usize, sign)]);
153 } else {
154 k = 1 - sign - sign;
155 }
156
157 const dk = @intToFloat(f64, k);
158 hi = x - dk * ln2hi;
159 lo = dk * ln2lo;
160 x = hi - lo;
161 }
162 // |x| > 2^(-28)
163 else if (hx > 0x3E300000) {
164 k = 0;
165 hi = x;
166 lo = 0;
167 } else {
168 // inexact if x != 0
169 // math.doNotOptimizeAway(0x1.0p1023 + x);
170 return 1 + x;
171 }
172
173 const xx = x * x;
174 const c = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5))));
175 const y = 1 + (x * c / (2 - c) - lo + hi);
176
177 if (k == 0) {
178 return y;
179 } else {
180 return math.scalbn(y, k);
181 }
182}
183
184test "math.exp" {
185 try expect(exp(@as(f32, 0.0)) == exp32(0.0));
186 try expect(exp(@as(f64, 0.0)) == exp64(0.0));
187}
188
189test "math.exp32" {
190 const epsilon = 0.000001;
191
192 try expect(exp32(0.0) == 1.0);
193 try expect(math.approxEqAbs(f32, exp32(0.0), 1.0, epsilon));
194 try expect(math.approxEqAbs(f32, exp32(0.2), 1.221403, epsilon));
195 try expect(math.approxEqAbs(f32, exp32(0.8923), 2.440737, epsilon));
196 try expect(math.approxEqAbs(f32, exp32(1.5), 4.481689, epsilon));
197}
198
199test "math.exp64" {
200 const epsilon = 0.000001;
201
202 try expect(exp64(0.0) == 1.0);
203 try expect(math.approxEqAbs(f64, exp64(0.0), 1.0, epsilon));
204 try expect(math.approxEqAbs(f64, exp64(0.2), 1.221403, epsilon));
205 try expect(math.approxEqAbs(f64, exp64(0.8923), 2.440737, epsilon));
206 try expect(math.approxEqAbs(f64, exp64(1.5), 4.481689, epsilon));
207}
208
209test "math.exp32.special" {
210 try expect(math.isPositiveInf(exp32(math.inf(f32))));
211 try expect(math.isNan(exp32(math.nan(f32))));
212}
213
214test "math.exp64.special" {
215 try expect(math.isPositiveInf(exp64(math.inf(f64))));
216 try expect(math.isNan(exp64(math.nan(f64))));
217}
lib/std/math/exp2.zig deleted-465
......@@ -1,465 +0,0 @@
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/exp2f.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/exp2.c
6
7const std = @import("../std.zig");
8const math = std.math;
9const expect = std.testing.expect;
10
11/// Returns 2 raised to the power of x (2^x).
12///
13/// Special Cases:
14/// - exp2(+inf) = +inf
15/// - exp2(nan) = nan
16pub fn exp2(x: anytype) @TypeOf(x) {
17 const T = @TypeOf(x);
18 return switch (T) {
19 f32 => exp2_32(x),
20 f64 => exp2_64(x),
21 else => @compileError("exp2 not implemented for " ++ @typeName(T)),
22 };
23}
24
25const exp2ft = [_]f64{
26 0x1.6a09e667f3bcdp-1,
27 0x1.7a11473eb0187p-1,
28 0x1.8ace5422aa0dbp-1,
29 0x1.9c49182a3f090p-1,
30 0x1.ae89f995ad3adp-1,
31 0x1.c199bdd85529cp-1,
32 0x1.d5818dcfba487p-1,
33 0x1.ea4afa2a490dap-1,
34 0x1.0000000000000p+0,
35 0x1.0b5586cf9890fp+0,
36 0x1.172b83c7d517bp+0,
37 0x1.2387a6e756238p+0,
38 0x1.306fe0a31b715p+0,
39 0x1.3dea64c123422p+0,
40 0x1.4bfdad5362a27p+0,
41 0x1.5ab07dd485429p+0,
42};
43
44fn exp2_32(x: f32) f32 {
45 const tblsiz = @intCast(u32, exp2ft.len);
46 const redux: f32 = 0x1.8p23 / @intToFloat(f32, tblsiz);
47 const P1: f32 = 0x1.62e430p-1;
48 const P2: f32 = 0x1.ebfbe0p-3;
49 const P3: f32 = 0x1.c6b348p-5;
50 const P4: f32 = 0x1.3b2c9cp-7;
51
52 var u = @bitCast(u32, x);
53 const ix = u & 0x7FFFFFFF;
54
55 // |x| > 126
56 if (ix > 0x42FC0000) {
57 // nan
58 if (ix > 0x7F800000) {
59 return x;
60 }
61 // x >= 128
62 if (u >= 0x43000000 and u < 0x80000000) {
63 return x * 0x1.0p127;
64 }
65 // x < -126
66 if (u >= 0x80000000) {
67 if (u >= 0xC3160000 or u & 0x000FFFF != 0) {
68 math.doNotOptimizeAway(-0x1.0p-149 / x);
69 }
70 // x <= -150
71 if (u >= 0x3160000) {
72 return 0;
73 }
74 }
75 }
76 // |x| <= 0x1p-25
77 else if (ix <= 0x33000000) {
78 return 1.0 + x;
79 }
80
81 // NOTE: musl relies on unsafe behaviours which are replicated below
82 // (addition/bit-shift overflow). Appears that this produces the
83 // intended result but should confirm how GCC/Clang handle this to ensure.
84
85 var uf = x + redux;
86 var i_0 = @bitCast(u32, uf);
87 i_0 +%= tblsiz / 2;
88
89 const k = i_0 / tblsiz;
90 const uk = @bitCast(f64, @as(u64, 0x3FF + k) << 52);
91 i_0 &= tblsiz - 1;
92 uf -= redux;
93
94 const z: f64 = x - uf;
95 var r: f64 = exp2ft[@intCast(usize, i_0)];
96 const t: f64 = r * z;
97 r = r + t * (P1 + z * P2) + t * (z * z) * (P3 + z * P4);
98 return @floatCast(f32, r * uk);
99}
100
101const exp2dt = [_]f64{
102 // exp2(z + eps) eps
103 0x1.6a09e667f3d5dp-1, 0x1.9880p-44,
104 0x1.6b052fa751744p-1, 0x1.8000p-50,
105 0x1.6c012750bd9fep-1, -0x1.8780p-45,
106 0x1.6cfdcddd476bfp-1, 0x1.ec00p-46,
107 0x1.6dfb23c651a29p-1, -0x1.8000p-50,
108 0x1.6ef9298593ae3p-1, -0x1.c000p-52,
109 0x1.6ff7df9519386p-1, -0x1.fd80p-45,
110 0x1.70f7466f42da3p-1, -0x1.c880p-45,
111 0x1.71f75e8ec5fc3p-1, 0x1.3c00p-46,
112 0x1.72f8286eacf05p-1, -0x1.8300p-44,
113 0x1.73f9a48a58152p-1, -0x1.0c00p-47,
114 0x1.74fbd35d7ccfcp-1, 0x1.f880p-45,
115 0x1.75feb564267f1p-1, 0x1.3e00p-47,
116 0x1.77024b1ab6d48p-1, -0x1.7d00p-45,
117 0x1.780694fde5d38p-1, -0x1.d000p-50,
118 0x1.790b938ac1d00p-1, 0x1.3000p-49,
119 0x1.7a11473eb0178p-1, -0x1.d000p-49,
120 0x1.7b17b0976d060p-1, 0x1.0400p-45,
121 0x1.7c1ed0130c133p-1, 0x1.0000p-53,
122 0x1.7d26a62ff8636p-1, -0x1.6900p-45,
123 0x1.7e2f336cf4e3bp-1, -0x1.2e00p-47,
124 0x1.7f3878491c3e8p-1, -0x1.4580p-45,
125 0x1.80427543e1b4ep-1, 0x1.3000p-44,
126 0x1.814d2add1071ap-1, 0x1.f000p-47,
127 0x1.82589994ccd7ep-1, -0x1.1c00p-45,
128 0x1.8364c1eb942d0p-1, 0x1.9d00p-45,
129 0x1.8471a4623cab5p-1, 0x1.7100p-43,
130 0x1.857f4179f5bbcp-1, 0x1.2600p-45,
131 0x1.868d99b4491afp-1, -0x1.2c40p-44,
132 0x1.879cad931a395p-1, -0x1.3000p-45,
133 0x1.88ac7d98a65b8p-1, -0x1.a800p-45,
134 0x1.89bd0a4785800p-1, -0x1.d000p-49,
135 0x1.8ace5422aa223p-1, 0x1.3280p-44,
136 0x1.8be05bad619fap-1, 0x1.2b40p-43,
137 0x1.8cf3216b54383p-1, -0x1.ed00p-45,
138 0x1.8e06a5e08664cp-1, -0x1.0500p-45,
139 0x1.8f1ae99157807p-1, 0x1.8280p-45,
140 0x1.902fed0282c0ep-1, -0x1.cb00p-46,
141 0x1.9145b0b91ff96p-1, -0x1.5e00p-47,
142 0x1.925c353aa2ff9p-1, 0x1.5400p-48,
143 0x1.93737b0cdc64ap-1, 0x1.7200p-46,
144 0x1.948b82b5f98aep-1, -0x1.9000p-47,
145 0x1.95a44cbc852cbp-1, 0x1.5680p-45,
146 0x1.96bdd9a766f21p-1, -0x1.6d00p-44,
147 0x1.97d829fde4e2ap-1, -0x1.1000p-47,
148 0x1.98f33e47a23a3p-1, 0x1.d000p-45,
149 0x1.9a0f170ca0604p-1, -0x1.8a40p-44,
150 0x1.9b2bb4d53ff89p-1, 0x1.55c0p-44,
151 0x1.9c49182a3f15bp-1, 0x1.6b80p-45,
152 0x1.9d674194bb8c5p-1, -0x1.c000p-49,
153 0x1.9e86319e3238ep-1, 0x1.7d00p-46,
154 0x1.9fa5e8d07f302p-1, 0x1.6400p-46,
155 0x1.a0c667b5de54dp-1, -0x1.5000p-48,
156 0x1.a1e7aed8eb8f6p-1, 0x1.9e00p-47,
157 0x1.a309bec4a2e27p-1, 0x1.ad80p-45,
158 0x1.a42c980460a5dp-1, -0x1.af00p-46,
159 0x1.a5503b23e259bp-1, 0x1.b600p-47,
160 0x1.a674a8af46213p-1, 0x1.8880p-44,
161 0x1.a799e1330b3a7p-1, 0x1.1200p-46,
162 0x1.a8bfe53c12e8dp-1, 0x1.6c00p-47,
163 0x1.a9e6b5579fcd2p-1, -0x1.9b80p-45,
164 0x1.ab0e521356fb8p-1, 0x1.b700p-45,
165 0x1.ac36bbfd3f381p-1, 0x1.9000p-50,
166 0x1.ad5ff3a3c2780p-1, 0x1.4000p-49,
167 0x1.ae89f995ad2a3p-1, -0x1.c900p-45,
168 0x1.afb4ce622f367p-1, 0x1.6500p-46,
169 0x1.b0e07298db790p-1, 0x1.fd40p-45,
170 0x1.b20ce6c9a89a9p-1, 0x1.2700p-46,
171 0x1.b33a2b84f1a4bp-1, 0x1.d470p-43,
172 0x1.b468415b747e7p-1, -0x1.8380p-44,
173 0x1.b59728de5593ap-1, 0x1.8000p-54,
174 0x1.b6c6e29f1c56ap-1, 0x1.ad00p-47,
175 0x1.b7f76f2fb5e50p-1, 0x1.e800p-50,
176 0x1.b928cf22749b2p-1, -0x1.4c00p-47,
177 0x1.ba5b030a10603p-1, -0x1.d700p-47,
178 0x1.bb8e0b79a6f66p-1, 0x1.d900p-47,
179 0x1.bcc1e904bc1ffp-1, 0x1.2a00p-47,
180 0x1.bdf69c3f3a16fp-1, -0x1.f780p-46,
181 0x1.bf2c25bd71db8p-1, -0x1.0a00p-46,
182 0x1.c06286141b2e9p-1, -0x1.1400p-46,
183 0x1.c199bdd8552e0p-1, 0x1.be00p-47,
184 0x1.c2d1cd9fa64eep-1, -0x1.9400p-47,
185 0x1.c40ab5fffd02fp-1, -0x1.ed00p-47,
186 0x1.c544778fafd15p-1, 0x1.9660p-44,
187 0x1.c67f12e57d0cbp-1, -0x1.a100p-46,
188 0x1.c7ba88988c1b6p-1, -0x1.8458p-42,
189 0x1.c8f6d9406e733p-1, -0x1.a480p-46,
190 0x1.ca3405751c4dfp-1, 0x1.b000p-51,
191 0x1.cb720dcef9094p-1, 0x1.1400p-47,
192 0x1.ccb0f2e6d1689p-1, 0x1.0200p-48,
193 0x1.cdf0b555dc412p-1, 0x1.3600p-48,
194 0x1.cf3155b5bab3bp-1, -0x1.6900p-47,
195 0x1.d072d4a0789bcp-1, 0x1.9a00p-47,
196 0x1.d1b532b08c8fap-1, -0x1.5e00p-46,
197 0x1.d2f87080d8a85p-1, 0x1.d280p-46,
198 0x1.d43c8eacaa203p-1, 0x1.1a00p-47,
199 0x1.d5818dcfba491p-1, 0x1.f000p-50,
200 0x1.d6c76e862e6a1p-1, -0x1.3a00p-47,
201 0x1.d80e316c9834ep-1, -0x1.cd80p-47,
202 0x1.d955d71ff6090p-1, 0x1.4c00p-48,
203 0x1.da9e603db32aep-1, 0x1.f900p-48,
204 0x1.dbe7cd63a8325p-1, 0x1.9800p-49,
205 0x1.dd321f301b445p-1, -0x1.5200p-48,
206 0x1.de7d5641c05bfp-1, -0x1.d700p-46,
207 0x1.dfc97337b9aecp-1, -0x1.6140p-46,
208 0x1.e11676b197d5ep-1, 0x1.b480p-47,
209 0x1.e264614f5a3e7p-1, 0x1.0ce0p-43,
210 0x1.e3b333b16ee5cp-1, 0x1.c680p-47,
211 0x1.e502ee78b3fb4p-1, -0x1.9300p-47,
212 0x1.e653924676d68p-1, -0x1.5000p-49,
213 0x1.e7a51fbc74c44p-1, -0x1.7f80p-47,
214 0x1.e8f7977cdb726p-1, -0x1.3700p-48,
215 0x1.ea4afa2a490e8p-1, 0x1.5d00p-49,
216 0x1.eb9f4867ccae4p-1, 0x1.61a0p-46,
217 0x1.ecf482d8e680dp-1, 0x1.5500p-48,
218 0x1.ee4aaa2188514p-1, 0x1.6400p-51,
219 0x1.efa1bee615a13p-1, -0x1.e800p-49,
220 0x1.f0f9c1cb64106p-1, -0x1.a880p-48,
221 0x1.f252b376bb963p-1, -0x1.c900p-45,
222 0x1.f3ac948dd7275p-1, 0x1.a000p-53,
223 0x1.f50765b6e4524p-1, -0x1.4f00p-48,
224 0x1.f6632798844fdp-1, 0x1.a800p-51,
225 0x1.f7bfdad9cbe38p-1, 0x1.abc0p-48,
226 0x1.f91d802243c82p-1, -0x1.4600p-50,
227 0x1.fa7c1819e908ep-1, -0x1.b0c0p-47,
228 0x1.fbdba3692d511p-1, -0x1.0e00p-51,
229 0x1.fd3c22b8f7194p-1, -0x1.0de8p-46,
230 0x1.fe9d96b2a23eep-1, 0x1.e430p-49,
231 0x1.0000000000000p+0, 0x0.0000p+0,
232 0x1.00b1afa5abcbep+0, -0x1.3400p-52,
233 0x1.0163da9fb3303p+0, -0x1.2170p-46,
234 0x1.02168143b0282p+0, 0x1.a400p-52,
235 0x1.02c9a3e77806cp+0, 0x1.f980p-49,
236 0x1.037d42e11bbcap+0, -0x1.7400p-51,
237 0x1.04315e86e7f89p+0, 0x1.8300p-50,
238 0x1.04e5f72f65467p+0, -0x1.a3f0p-46,
239 0x1.059b0d315855ap+0, -0x1.2840p-47,
240 0x1.0650a0e3c1f95p+0, 0x1.1600p-48,
241 0x1.0706b29ddf71ap+0, 0x1.5240p-46,
242 0x1.07bd42b72a82dp+0, -0x1.9a00p-49,
243 0x1.0874518759bd0p+0, 0x1.6400p-49,
244 0x1.092bdf66607c8p+0, -0x1.0780p-47,
245 0x1.09e3ecac6f383p+0, -0x1.8000p-54,
246 0x1.0a9c79b1f3930p+0, 0x1.fa00p-48,
247 0x1.0b5586cf988fcp+0, -0x1.ac80p-48,
248 0x1.0c0f145e46c8ap+0, 0x1.9c00p-50,
249 0x1.0cc922b724816p+0, 0x1.5200p-47,
250 0x1.0d83b23395dd8p+0, -0x1.ad00p-48,
251 0x1.0e3ec32d3d1f3p+0, 0x1.bac0p-46,
252 0x1.0efa55fdfa9a6p+0, -0x1.4e80p-47,
253 0x1.0fb66affed2f0p+0, -0x1.d300p-47,
254 0x1.1073028d7234bp+0, 0x1.1500p-48,
255 0x1.11301d0125b5bp+0, 0x1.c000p-49,
256 0x1.11edbab5e2af9p+0, 0x1.6bc0p-46,
257 0x1.12abdc06c31d5p+0, 0x1.8400p-49,
258 0x1.136a814f2047dp+0, -0x1.ed00p-47,
259 0x1.1429aaea92de9p+0, 0x1.8e00p-49,
260 0x1.14e95934f3138p+0, 0x1.b400p-49,
261 0x1.15a98c8a58e71p+0, 0x1.5300p-47,
262 0x1.166a45471c3dfp+0, 0x1.3380p-47,
263 0x1.172b83c7d5211p+0, 0x1.8d40p-45,
264 0x1.17ed48695bb9fp+0, -0x1.5d00p-47,
265 0x1.18af9388c8d93p+0, -0x1.c880p-46,
266 0x1.1972658375d66p+0, 0x1.1f00p-46,
267 0x1.1a35beb6fcba7p+0, 0x1.0480p-46,
268 0x1.1af99f81387e3p+0, -0x1.7390p-43,
269 0x1.1bbe084045d54p+0, 0x1.4e40p-45,
270 0x1.1c82f95281c43p+0, -0x1.a200p-47,
271 0x1.1d4873168b9b2p+0, 0x1.3800p-49,
272 0x1.1e0e75eb44031p+0, 0x1.ac00p-49,
273 0x1.1ed5022fcd938p+0, 0x1.1900p-47,
274 0x1.1f9c18438cdf7p+0, -0x1.b780p-46,
275 0x1.2063b88628d8fp+0, 0x1.d940p-45,
276 0x1.212be3578a81ep+0, 0x1.8000p-50,
277 0x1.21f49917ddd41p+0, 0x1.b340p-45,
278 0x1.22bdda2791323p+0, 0x1.9f80p-46,
279 0x1.2387a6e7561e7p+0, -0x1.9c80p-46,
280 0x1.2451ffb821427p+0, 0x1.2300p-47,
281 0x1.251ce4fb2a602p+0, -0x1.3480p-46,
282 0x1.25e85711eceb0p+0, 0x1.2700p-46,
283 0x1.26b4565e27d16p+0, 0x1.1d00p-46,
284 0x1.2780e341de00fp+0, 0x1.1ee0p-44,
285 0x1.284dfe1f5633ep+0, -0x1.4c00p-46,
286 0x1.291ba7591bb30p+0, -0x1.3d80p-46,
287 0x1.29e9df51fdf09p+0, 0x1.8b00p-47,
288 0x1.2ab8a66d10e9bp+0, -0x1.27c0p-45,
289 0x1.2b87fd0dada3ap+0, 0x1.a340p-45,
290 0x1.2c57e39771af9p+0, -0x1.0800p-46,
291 0x1.2d285a6e402d9p+0, -0x1.ed00p-47,
292 0x1.2df961f641579p+0, -0x1.4200p-48,
293 0x1.2ecafa93e2ecfp+0, -0x1.4980p-45,
294 0x1.2f9d24abd8822p+0, -0x1.6300p-46,
295 0x1.306fe0a31b625p+0, -0x1.2360p-44,
296 0x1.31432edeea50bp+0, -0x1.0df8p-40,
297 0x1.32170fc4cd7b8p+0, -0x1.2480p-45,
298 0x1.32eb83ba8e9a2p+0, -0x1.5980p-45,
299 0x1.33c08b2641766p+0, 0x1.ed00p-46,
300 0x1.3496266e3fa27p+0, -0x1.c000p-50,
301 0x1.356c55f929f0fp+0, -0x1.0d80p-44,
302 0x1.36431a2de88b9p+0, 0x1.2c80p-45,
303 0x1.371a7373aaa39p+0, 0x1.0600p-45,
304 0x1.37f26231e74fep+0, -0x1.6600p-46,
305 0x1.38cae6d05d838p+0, -0x1.ae00p-47,
306 0x1.39a401b713ec3p+0, -0x1.4720p-43,
307 0x1.3a7db34e5a020p+0, 0x1.8200p-47,
308 0x1.3b57fbfec6e95p+0, 0x1.e800p-44,
309 0x1.3c32dc313a8f2p+0, 0x1.f800p-49,
310 0x1.3d0e544ede122p+0, -0x1.7a00p-46,
311 0x1.3dea64c1234bbp+0, 0x1.6300p-45,
312 0x1.3ec70df1c4eccp+0, -0x1.8a60p-43,
313 0x1.3fa4504ac7e8cp+0, -0x1.cdc0p-44,
314 0x1.40822c367a0bbp+0, 0x1.5b80p-45,
315 0x1.4160a21f72e95p+0, 0x1.ec00p-46,
316 0x1.423fb27094646p+0, -0x1.3600p-46,
317 0x1.431f5d950a920p+0, 0x1.3980p-45,
318 0x1.43ffa3f84b9ebp+0, 0x1.a000p-48,
319 0x1.44e0860618919p+0, -0x1.6c00p-48,
320 0x1.45c2042a7d201p+0, -0x1.bc00p-47,
321 0x1.46a41ed1d0016p+0, -0x1.2800p-46,
322 0x1.4786d668b3326p+0, 0x1.0e00p-44,
323 0x1.486a2b5c13c00p+0, -0x1.d400p-45,
324 0x1.494e1e192af04p+0, 0x1.c200p-47,
325 0x1.4a32af0d7d372p+0, -0x1.e500p-46,
326 0x1.4b17dea6db801p+0, 0x1.7800p-47,
327 0x1.4bfdad53629e1p+0, -0x1.3800p-46,
328 0x1.4ce41b817c132p+0, 0x1.0800p-47,
329 0x1.4dcb299fddddbp+0, 0x1.c700p-45,
330 0x1.4eb2d81d8ab96p+0, -0x1.ce00p-46,
331 0x1.4f9b2769d2d02p+0, 0x1.9200p-46,
332 0x1.508417f4531c1p+0, -0x1.8c00p-47,
333 0x1.516daa2cf662ap+0, -0x1.a000p-48,
334 0x1.5257de83f51eap+0, 0x1.a080p-43,
335 0x1.5342b569d4edap+0, -0x1.6d80p-45,
336 0x1.542e2f4f6ac1ap+0, -0x1.2440p-44,
337 0x1.551a4ca5d94dbp+0, 0x1.83c0p-43,
338 0x1.56070dde9116bp+0, 0x1.4b00p-45,
339 0x1.56f4736b529dep+0, 0x1.15a0p-43,
340 0x1.57e27dbe2c40ep+0, -0x1.9e00p-45,
341 0x1.58d12d497c76fp+0, -0x1.3080p-45,
342 0x1.59c0827ff0b4cp+0, 0x1.dec0p-43,
343 0x1.5ab07dd485427p+0, -0x1.4000p-51,
344 0x1.5ba11fba87af4p+0, 0x1.0080p-44,
345 0x1.5c9268a59460bp+0, -0x1.6c80p-45,
346 0x1.5d84590998e3fp+0, 0x1.69a0p-43,
347 0x1.5e76f15ad20e1p+0, -0x1.b400p-46,
348 0x1.5f6a320dcebcap+0, 0x1.7700p-46,
349 0x1.605e1b976dcb8p+0, 0x1.6f80p-45,
350 0x1.6152ae6cdf715p+0, 0x1.1000p-47,
351 0x1.6247eb03a5531p+0, -0x1.5d00p-46,
352 0x1.633dd1d1929b5p+0, -0x1.2d00p-46,
353 0x1.6434634ccc313p+0, -0x1.a800p-49,
354 0x1.652b9febc8efap+0, -0x1.8600p-45,
355 0x1.6623882553397p+0, 0x1.1fe0p-40,
356 0x1.671c1c708328ep+0, -0x1.7200p-44,
357 0x1.68155d44ca97ep+0, 0x1.6800p-49,
358 0x1.690f4b19e9471p+0, -0x1.9780p-45,
359};
360
361fn exp2_64(x: f64) f64 {
362 const tblsiz: u32 = @intCast(u32, exp2dt.len / 2);
363 const redux: f64 = 0x1.8p52 / @intToFloat(f64, tblsiz);
364 const P1: f64 = 0x1.62e42fefa39efp-1;
365 const P2: f64 = 0x1.ebfbdff82c575p-3;
366 const P3: f64 = 0x1.c6b08d704a0a6p-5;
367 const P4: f64 = 0x1.3b2ab88f70400p-7;
368 const P5: f64 = 0x1.5d88003875c74p-10;
369
370 const ux = @bitCast(u64, x);
371 const ix = @intCast(u32, ux >> 32) & 0x7FFFFFFF;
372
373 // TODO: This should be handled beneath.
374 if (math.isNan(x)) {
375 return math.nan(f64);
376 }
377
378 // |x| >= 1022 or nan
379 if (ix >= 0x408FF000) {
380 // x >= 1024 or nan
381 if (ix >= 0x40900000 and ux >> 63 == 0) {
382 math.raiseOverflow();
383 return math.inf(f64);
384 }
385 // -inf or -nan
386 if (ix >= 0x7FF00000) {
387 return -1 / x;
388 }
389 // x <= -1022
390 if (ux >> 63 != 0) {
391 // underflow
392 if (x <= -1075 or x - 0x1.0p52 + 0x1.0p52 != x) {
393 math.doNotOptimizeAway(@floatCast(f32, -0x1.0p-149 / x));
394 }
395 if (x <= -1075) {
396 return 0;
397 }
398 }
399 }
400 // |x| < 0x1p-54
401 else if (ix < 0x3C900000) {
402 return 1.0 + x;
403 }
404
405 // NOTE: musl relies on unsafe behaviours which are replicated below
406 // (addition overflow, division truncation, casting). Appears that this
407 // produces the intended result but should confirm how GCC/Clang handle this
408 // to ensure.
409
410 // reduce x
411 var uf: f64 = x + redux;
412 // NOTE: musl performs an implicit 64-bit to 32-bit u32 truncation here
413 var i_0: u32 = @truncate(u32, @bitCast(u64, uf));
414 i_0 +%= tblsiz / 2;
415
416 const k: u32 = i_0 / tblsiz * tblsiz;
417 const ik: i32 = @divTrunc(@bitCast(i32, k), tblsiz);
418 i_0 %= tblsiz;
419 uf -= redux;
420
421 // r = exp2(y) = exp2t[i_0] * p(z - eps[i])
422 var z: f64 = x - uf;
423 const t: f64 = exp2dt[@intCast(usize, 2 * i_0)];
424 z -= exp2dt[@intCast(usize, 2 * i_0 + 1)];
425 const r: f64 = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5))));
426
427 return math.scalbn(r, ik);
428}
429
430test "math.exp2" {
431 try expect(exp2(@as(f32, 0.8923)) == exp2_32(0.8923));
432 try expect(exp2(@as(f64, 0.8923)) == exp2_64(0.8923));
433}
434
435test "math.exp2_32" {
436 const epsilon = 0.000001;
437
438 try expect(exp2_32(0.0) == 1.0);
439 try expect(math.approxEqAbs(f32, exp2_32(0.2), 1.148698, epsilon));
440 try expect(math.approxEqAbs(f32, exp2_32(0.8923), 1.856133, epsilon));
441 try expect(math.approxEqAbs(f32, exp2_32(1.5), 2.828427, epsilon));
442 try expect(math.approxEqAbs(f32, exp2_32(37.45), 187747237888, epsilon));
443 try expect(math.approxEqAbs(f32, exp2_32(-1), 0.5, epsilon));
444}
445
446test "math.exp2_64" {
447 const epsilon = 0.000001;
448
449 try expect(exp2_64(0.0) == 1.0);
450 try expect(math.approxEqAbs(f64, exp2_64(0.2), 1.148698, epsilon));
451 try expect(math.approxEqAbs(f64, exp2_64(0.8923), 1.856133, epsilon));
452 try expect(math.approxEqAbs(f64, exp2_64(1.5), 2.828427, epsilon));
453 try expect(math.approxEqAbs(f64, exp2_64(-1), 0.5, epsilon));
454 try expect(math.approxEqAbs(f64, exp2_64(-0x1.a05cc754481d1p-2), 0x1.824056efc687cp-1, epsilon));
455}
456
457test "math.exp2_32.special" {
458 try expect(math.isPositiveInf(exp2_32(math.inf(f32))));
459 try expect(math.isNan(exp2_32(math.nan(f32))));
460}
461
462test "math.exp2_64.special" {
463 try expect(math.isPositiveInf(exp2_64(math.inf(f64))));
464 try expect(math.isNan(exp2_64(math.nan(f64))));
465}
lib/std/math/expo2.zig+2-2
......@@ -22,7 +22,7 @@ fn expo2f(x: f32) f32 {
2222
2323 const u = (0x7F + k / 2) << 23;
2424 const scale = @bitCast(f32, u);
25 return math.exp(x - kln2) * scale * scale;
25 return @exp(x - kln2) * scale * scale;
2626}
2727
2828fn expo2d(x: f64) f64 {
......@@ -31,5 +31,5 @@ fn expo2d(x: f64) f64 {
3131
3232 const u = (0x3FF + k / 2) << 20;
3333 const scale = @bitCast(f64, @as(u64, u) << 32);
34 return math.exp(x - kln2) * scale * scale;
34 return @exp(x - kln2) * scale * scale;
3535}
lib/std/math/fabs.zig deleted-45
......@@ -1,45 +0,0 @@
1const std = @import("../std.zig");
2const math = std.math;
3const expect = std.testing.expect;
4
5/// Returns the absolute value of x.
6///
7/// Special Cases:
8/// - fabs(+-inf) = +inf
9/// - fabs(nan) = nan
10pub fn fabs(x: anytype) @TypeOf(x) {
11 const T = @TypeOf(x);
12 const TBits = std.meta.Int(.unsigned, @bitSizeOf(T));
13 if (@typeInfo(T) != .Float) {
14 @compileError("fabs not implemented for " ++ @typeName(T));
15 }
16
17 const float_bits = @bitCast(TBits, x);
18 const remove_sign = ~@as(TBits, 0) >> 1;
19
20 return @bitCast(T, float_bits & remove_sign);
21}
22
23test "math.fabs" {
24 // TODO add support for c_longdouble here
25 inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| {
26 // normals
27 try expect(fabs(@as(T, 1.0)) == 1.0);
28 try expect(fabs(@as(T, -1.0)) == 1.0);
29 try expect(fabs(math.floatMin(T)) == math.floatMin(T));
30 try expect(fabs(-math.floatMin(T)) == math.floatMin(T));
31 try expect(fabs(math.floatMax(T)) == math.floatMax(T));
32 try expect(fabs(-math.floatMax(T)) == math.floatMax(T));
33
34 // subnormals
35 try expect(fabs(@as(T, 0.0)) == 0.0);
36 try expect(fabs(@as(T, -0.0)) == 0.0);
37 try expect(fabs(math.floatTrueMin(T)) == math.floatTrueMin(T));
38 try expect(fabs(-math.floatTrueMin(T)) == math.floatTrueMin(T));
39
40 // non-finite numbers
41 try expect(math.isPositiveInf(fabs(math.inf(T))));
42 try expect(math.isPositiveInf(fabs(-math.inf(T))));
43 try expect(math.isNan(fabs(math.nan(T))));
44 }
45}
lib/std/math/floor.zig deleted-221
......@@ -1,221 +0,0 @@
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/floorf.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/floor.c
6
7const expect = std.testing.expect;
8const std = @import("../std.zig");
9const math = std.math;
10
11/// Returns the greatest integer value less than or equal to x.
12///
13/// Special Cases:
14/// - floor(+-0) = +-0
15/// - floor(+-inf) = +-inf
16/// - floor(nan) = nan
17pub fn floor(x: anytype) @TypeOf(x) {
18 const T = @TypeOf(x);
19 return switch (T) {
20 f16 => floor16(x),
21 f32 => floor32(x),
22 f64 => floor64(x),
23 f128 => floor128(x),
24
25 // TODO this is not correct for some targets
26 c_longdouble => @floatCast(c_longdouble, floor128(x)),
27
28 else => @compileError("floor not implemented for " ++ @typeName(T)),
29 };
30}
31
32fn floor16(x: f16) f16 {
33 var u = @bitCast(u16, x);
34 const e = @intCast(i16, (u >> 10) & 31) - 15;
35 var m: u16 = undefined;
36
37 // TODO: Shouldn't need this explicit check.
38 if (x == 0.0) {
39 return x;
40 }
41
42 if (e >= 10) {
43 return x;
44 }
45
46 if (e >= 0) {
47 m = @as(u16, 1023) >> @intCast(u4, e);
48 if (u & m == 0) {
49 return x;
50 }
51 math.doNotOptimizeAway(x + 0x1.0p120);
52 if (u >> 15 != 0) {
53 u += m;
54 }
55 return @bitCast(f16, u & ~m);
56 } else {
57 math.doNotOptimizeAway(x + 0x1.0p120);
58 if (u >> 15 == 0) {
59 return 0.0;
60 } else {
61 return -1.0;
62 }
63 }
64}
65
66fn floor32(x: f32) f32 {
67 var u = @bitCast(u32, x);
68 const e = @intCast(i32, (u >> 23) & 0xFF) - 0x7F;
69 var m: u32 = undefined;
70
71 // TODO: Shouldn't need this explicit check.
72 if (x == 0.0) {
73 return x;
74 }
75
76 if (e >= 23) {
77 return x;
78 }
79
80 if (e >= 0) {
81 m = @as(u32, 0x007FFFFF) >> @intCast(u5, e);
82 if (u & m == 0) {
83 return x;
84 }
85 math.doNotOptimizeAway(x + 0x1.0p120);
86 if (u >> 31 != 0) {
87 u += m;
88 }
89 return @bitCast(f32, u & ~m);
90 } else {
91 math.doNotOptimizeAway(x + 0x1.0p120);
92 if (u >> 31 == 0) {
93 return 0.0;
94 } else {
95 return -1.0;
96 }
97 }
98}
99
100fn floor64(x: f64) f64 {
101 const f64_toint = 1.0 / math.floatEps(f64);
102
103 const u = @bitCast(u64, x);
104 const e = (u >> 52) & 0x7FF;
105 var y: f64 = undefined;
106
107 if (e >= 0x3FF + 52 or x == 0) {
108 return x;
109 }
110
111 if (u >> 63 != 0) {
112 y = x - f64_toint + f64_toint - x;
113 } else {
114 y = x + f64_toint - f64_toint - x;
115 }
116
117 if (e <= 0x3FF - 1) {
118 math.doNotOptimizeAway(y);
119 if (u >> 63 != 0) {
120 return -1.0;
121 } else {
122 return 0.0;
123 }
124 } else if (y > 0) {
125 return x + y - 1;
126 } else {
127 return x + y;
128 }
129}
130
131fn floor128(x: f128) f128 {
132 const f128_toint = 1.0 / math.floatEps(f128);
133
134 const u = @bitCast(u128, x);
135 const e = (u >> 112) & 0x7FFF;
136 var y: f128 = undefined;
137
138 if (e >= 0x3FFF + 112 or x == 0) return x;
139
140 if (u >> 127 != 0) {
141 y = x - f128_toint + f128_toint - x;
142 } else {
143 y = x + f128_toint - f128_toint - x;
144 }
145
146 if (e <= 0x3FFF - 1) {
147 math.doNotOptimizeAway(y);
148 if (u >> 127 != 0) {
149 return -1.0;
150 } else {
151 return 0.0;
152 }
153 } else if (y > 0) {
154 return x + y - 1;
155 } else {
156 return x + y;
157 }
158}
159
160test "math.floor" {
161 try expect(floor(@as(f16, 1.3)) == floor16(1.3));
162 try expect(floor(@as(f32, 1.3)) == floor32(1.3));
163 try expect(floor(@as(f64, 1.3)) == floor64(1.3));
164 try expect(floor(@as(f128, 1.3)) == floor128(1.3));
165}
166
167test "math.floor16" {
168 try expect(floor16(1.3) == 1.0);
169 try expect(floor16(-1.3) == -2.0);
170 try expect(floor16(0.2) == 0.0);
171}
172
173test "math.floor32" {
174 try expect(floor32(1.3) == 1.0);
175 try expect(floor32(-1.3) == -2.0);
176 try expect(floor32(0.2) == 0.0);
177}
178
179test "math.floor64" {
180 try expect(floor64(1.3) == 1.0);
181 try expect(floor64(-1.3) == -2.0);
182 try expect(floor64(0.2) == 0.0);
183}
184
185test "math.floor128" {
186 try expect(floor128(1.3) == 1.0);
187 try expect(floor128(-1.3) == -2.0);
188 try expect(floor128(0.2) == 0.0);
189}
190
191test "math.floor16.special" {
192 try expect(floor16(0.0) == 0.0);
193 try expect(floor16(-0.0) == -0.0);
194 try expect(math.isPositiveInf(floor16(math.inf(f16))));
195 try expect(math.isNegativeInf(floor16(-math.inf(f16))));
196 try expect(math.isNan(floor16(math.nan(f16))));
197}
198
199test "math.floor32.special" {
200 try expect(floor32(0.0) == 0.0);
201 try expect(floor32(-0.0) == -0.0);
202 try expect(math.isPositiveInf(floor32(math.inf(f32))));
203 try expect(math.isNegativeInf(floor32(-math.inf(f32))));
204 try expect(math.isNan(floor32(math.nan(f32))));
205}
206
207test "math.floor64.special" {
208 try expect(floor64(0.0) == 0.0);
209 try expect(floor64(-0.0) == -0.0);
210 try expect(math.isPositiveInf(floor64(math.inf(f64))));
211 try expect(math.isNegativeInf(floor64(-math.inf(f64))));
212 try expect(math.isNan(floor64(math.nan(f64))));
213}
214
215test "math.floor128.special" {
216 try expect(floor128(0.0) == 0.0);
217 try expect(floor128(-0.0) == -0.0);
218 try expect(math.isPositiveInf(floor128(math.inf(f128))));
219 try expect(math.isNegativeInf(floor128(-math.inf(f128))));
220 try expect(math.isNan(floor128(math.nan(f128))));
221}
lib/std/math/fma.zig deleted-339
......@@ -1,339 +0,0 @@
1// Ported from musl, which is MIT licensed:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//
4// https://git.musl-libc.org/cgit/musl/tree/src/math/fmal.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/fmaf.c
6// https://git.musl-libc.org/cgit/musl/tree/src/math/fma.c
7
8const std = @import("../std.zig");
9const math = std.math;
10const expect = std.testing.expect;
11
12/// Returns x * y + z with a single rounding error.
13pub fn fma(comptime T: type, x: T, y: T, z: T) T {
14 return switch (T) {
15 f32 => fma32(x, y, z),
16 f64 => fma64(x, y, z),
17 f128 => fma128(x, y, z),
18
19 // TODO this is not correct for some targets
20 c_longdouble => @floatCast(c_longdouble, fma128(x, y, z)),
21
22 f80 => @floatCast(f80, fma128(x, y, z)),
23
24 else => @compileError("fma not implemented for " ++ @typeName(T)),
25 };
26}
27
28fn fma32(x: f32, y: f32, z: f32) f32 {
29 const xy = @as(f64, x) * y;
30 const xy_z = xy + z;
31 const u = @bitCast(u64, xy_z);
32 const e = (u >> 52) & 0x7FF;
33
34 if ((u & 0x1FFFFFFF) != 0x10000000 or e == 0x7FF or (xy_z - xy == z and xy_z - z == xy)) {
35 return @floatCast(f32, xy_z);
36 } else {
37 // TODO: Handle inexact case with double-rounding
38 return @floatCast(f32, xy_z);
39 }
40}
41
42// NOTE: Upstream fma.c has been rewritten completely to raise fp exceptions more accurately.
43fn fma64(x: f64, y: f64, z: f64) f64 {
44 if (!math.isFinite(x) or !math.isFinite(y)) {
45 return x * y + z;
46 }
47 if (!math.isFinite(z)) {
48 return z;
49 }
50 if (x == 0.0 or y == 0.0) {
51 return x * y + z;
52 }
53 if (z == 0.0) {
54 return x * y;
55 }
56
57 const x1 = math.frexp(x);
58 var ex = x1.exponent;
59 var xs = x1.significand;
60 const x2 = math.frexp(y);
61 var ey = x2.exponent;
62 var ys = x2.significand;
63 const x3 = math.frexp(z);
64 var ez = x3.exponent;
65 var zs = x3.significand;
66
67 var spread = ex + ey - ez;
68 if (spread <= 53 * 2) {
69 zs = math.scalbn(zs, -spread);
70 } else {
71 zs = math.copysign(f64, math.floatMin(f64), zs);
72 }
73
74 const xy = dd_mul(xs, ys);
75 const r = dd_add(xy.hi, zs);
76 spread = ex + ey;
77
78 if (r.hi == 0.0) {
79 return xy.hi + zs + math.scalbn(xy.lo, spread);
80 }
81
82 const adj = add_adjusted(r.lo, xy.lo);
83 if (spread + math.ilogb(r.hi) > -1023) {
84 return math.scalbn(r.hi + adj, spread);
85 } else {
86 return add_and_denorm(r.hi, adj, spread);
87 }
88}
89
90const dd = struct {
91 hi: f64,
92 lo: f64,
93};
94
95fn dd_add(a: f64, b: f64) dd {
96 var ret: dd = undefined;
97 ret.hi = a + b;
98 const s = ret.hi - a;
99 ret.lo = (a - (ret.hi - s)) + (b - s);
100 return ret;
101}
102
103fn dd_mul(a: f64, b: f64) dd {
104 var ret: dd = undefined;
105 const split: f64 = 0x1.0p27 + 1.0;
106
107 var p = a * split;
108 var ha = a - p;
109 ha += p;
110 var la = a - ha;
111
112 p = b * split;
113 var hb = b - p;
114 hb += p;
115 var lb = b - hb;
116
117 p = ha * hb;
118 var q = ha * lb + la * hb;
119
120 ret.hi = p + q;
121 ret.lo = p - ret.hi + q + la * lb;
122 return ret;
123}
124
125fn add_adjusted(a: f64, b: f64) f64 {
126 var sum = dd_add(a, b);
127 if (sum.lo != 0) {
128 var uhii = @bitCast(u64, sum.hi);
129 if (uhii & 1 == 0) {
130 // hibits += copysign(1.0, sum.hi, sum.lo)
131 const uloi = @bitCast(u64, sum.lo);
132 uhii += 1 - ((uhii ^ uloi) >> 62);
133 sum.hi = @bitCast(f64, uhii);
134 }
135 }
136 return sum.hi;
137}
138
139fn add_and_denorm(a: f64, b: f64, scale: i32) f64 {
140 var sum = dd_add(a, b);
141 if (sum.lo != 0) {
142 var uhii = @bitCast(u64, sum.hi);
143 const bits_lost = -@intCast(i32, (uhii >> 52) & 0x7FF) - scale + 1;
144 if ((bits_lost != 1) == (uhii & 1 != 0)) {
145 const uloi = @bitCast(u64, sum.lo);
146 uhii += 1 - (((uhii ^ uloi) >> 62) & 2);
147 sum.hi = @bitCast(f64, uhii);
148 }
149 }
150 return math.scalbn(sum.hi, scale);
151}
152
153/// A struct that represents a floating-point number with twice the precision
154/// of f128. We maintain the invariant that "hi" stores the high-order
155/// bits of the result.
156const dd128 = struct {
157 hi: f128,
158 lo: f128,
159};
160
161/// Compute a+b exactly, returning the exact result in a struct dd. We assume
162/// that both a and b are finite, but make no assumptions about their relative
163/// magnitudes.
164fn dd_add128(a: f128, b: f128) dd128 {
165 var ret: dd128 = undefined;
166 ret.hi = a + b;
167 const s = ret.hi - a;
168 ret.lo = (a - (ret.hi - s)) + (b - s);
169 return ret;
170}
171
172/// Compute a+b, with a small tweak: The least significant bit of the
173/// result is adjusted into a sticky bit summarizing all the bits that
174/// were lost to rounding. This adjustment negates the effects of double
175/// rounding when the result is added to another number with a higher
176/// exponent. For an explanation of round and sticky bits, see any reference
177/// on FPU design, e.g.,
178///
179/// J. Coonen. An Implementation Guide to a Proposed Standard for
180/// Floating-Point Arithmetic. Computer, vol. 13, no. 1, Jan 1980.
181fn add_adjusted128(a: f128, b: f128) f128 {
182 var sum = dd_add128(a, b);
183 if (sum.lo != 0) {
184 var uhii = @bitCast(u128, sum.hi);
185 if (uhii & 1 == 0) {
186 // hibits += copysign(1.0, sum.hi, sum.lo)
187 const uloi = @bitCast(u128, sum.lo);
188 uhii += 1 - ((uhii ^ uloi) >> 126);
189 sum.hi = @bitCast(f128, uhii);
190 }
191 }
192 return sum.hi;
193}
194
195/// Compute ldexp(a+b, scale) with a single rounding error. It is assumed
196/// that the result will be subnormal, and care is taken to ensure that
197/// double rounding does not occur.
198fn add_and_denorm128(a: f128, b: f128, scale: i32) f128 {
199 var sum = dd_add128(a, b);
200 // If we are losing at least two bits of accuracy to denormalization,
201 // then the first lost bit becomes a round bit, and we adjust the
202 // lowest bit of sum.hi to make it a sticky bit summarizing all the
203 // bits in sum.lo. With the sticky bit adjusted, the hardware will
204 // break any ties in the correct direction.
205 //
206 // If we are losing only one bit to denormalization, however, we must
207 // break the ties manually.
208 if (sum.lo != 0) {
209 var uhii = @bitCast(u128, sum.hi);
210 const bits_lost = -@intCast(i32, (uhii >> 112) & 0x7FFF) - scale + 1;
211 if ((bits_lost != 1) == (uhii & 1 != 0)) {
212 const uloi = @bitCast(u128, sum.lo);
213 uhii += 1 - (((uhii ^ uloi) >> 126) & 2);
214 sum.hi = @bitCast(f128, uhii);
215 }
216 }
217 return math.scalbn(sum.hi, scale);
218}
219
220/// Compute a*b exactly, returning the exact result in a struct dd. We assume
221/// that both a and b are normalized, so no underflow or overflow will occur.
222/// The current rounding mode must be round-to-nearest.
223fn dd_mul128(a: f128, b: f128) dd128 {
224 var ret: dd128 = undefined;
225 const split: f128 = 0x1.0p57 + 1.0;
226
227 var p = a * split;
228 var ha = a - p;
229 ha += p;
230 var la = a - ha;
231
232 p = b * split;
233 var hb = b - p;
234 hb += p;
235 var lb = b - hb;
236
237 p = ha * hb;
238 var q = ha * lb + la * hb;
239
240 ret.hi = p + q;
241 ret.lo = p - ret.hi + q + la * lb;
242 return ret;
243}
244
245/// Fused multiply-add: Compute x * y + z with a single rounding error.
246///
247/// We use scaling to avoid overflow/underflow, along with the
248/// canonical precision-doubling technique adapted from:
249///
250/// Dekker, T. A Floating-Point Technique for Extending the
251/// Available Precision. Numer. Math. 18, 224-242 (1971).
252fn fma128(x: f128, y: f128, z: f128) f128 {
253 if (!math.isFinite(x) or !math.isFinite(y)) {
254 return x * y + z;
255 }
256 if (!math.isFinite(z)) {
257 return z;
258 }
259 if (x == 0.0 or y == 0.0) {
260 return x * y + z;
261 }
262 if (z == 0.0) {
263 return x * y;
264 }
265
266 const x1 = math.frexp(x);
267 var ex = x1.exponent;
268 var xs = x1.significand;
269 const x2 = math.frexp(y);
270 var ey = x2.exponent;
271 var ys = x2.significand;
272 const x3 = math.frexp(z);
273 var ez = x3.exponent;
274 var zs = x3.significand;
275
276 var spread = ex + ey - ez;
277 if (spread <= 113 * 2) {
278 zs = math.scalbn(zs, -spread);
279 } else {
280 zs = math.copysign(f128, math.floatMin(f128), zs);
281 }
282
283 const xy = dd_mul128(xs, ys);
284 const r = dd_add128(xy.hi, zs);
285 spread = ex + ey;
286
287 if (r.hi == 0.0) {
288 return xy.hi + zs + math.scalbn(xy.lo, spread);
289 }
290
291 const adj = add_adjusted128(r.lo, xy.lo);
292 if (spread + math.ilogb(r.hi) > -16383) {
293 return math.scalbn(r.hi + adj, spread);
294 } else {
295 return add_and_denorm128(r.hi, adj, spread);
296 }
297}
298
299test "type dispatch" {
300 try expect(fma(f32, 0.0, 1.0, 1.0) == fma32(0.0, 1.0, 1.0));
301 try expect(fma(f64, 0.0, 1.0, 1.0) == fma64(0.0, 1.0, 1.0));
302 try expect(fma(f128, 0.0, 1.0, 1.0) == fma128(0.0, 1.0, 1.0));
303}
304
305test "32" {
306 const epsilon = 0.000001;
307
308 try expect(math.approxEqAbs(f32, fma32(0.0, 5.0, 9.124), 9.124, epsilon));
309 try expect(math.approxEqAbs(f32, fma32(0.2, 5.0, 9.124), 10.124, epsilon));
310 try expect(math.approxEqAbs(f32, fma32(0.8923, 5.0, 9.124), 13.5855, epsilon));
311 try expect(math.approxEqAbs(f32, fma32(1.5, 5.0, 9.124), 16.624, epsilon));
312 try expect(math.approxEqAbs(f32, fma32(37.45, 5.0, 9.124), 196.374004, epsilon));
313 try expect(math.approxEqAbs(f32, fma32(89.123, 5.0, 9.124), 454.739005, epsilon));
314 try expect(math.approxEqAbs(f32, fma32(123123.234375, 5.0, 9.124), 615625.295875, epsilon));
315}
316
317test "64" {
318 const epsilon = 0.000001;
319
320 try expect(math.approxEqAbs(f64, fma64(0.0, 5.0, 9.124), 9.124, epsilon));
321 try expect(math.approxEqAbs(f64, fma64(0.2, 5.0, 9.124), 10.124, epsilon));
322 try expect(math.approxEqAbs(f64, fma64(0.8923, 5.0, 9.124), 13.5855, epsilon));
323 try expect(math.approxEqAbs(f64, fma64(1.5, 5.0, 9.124), 16.624, epsilon));
324 try expect(math.approxEqAbs(f64, fma64(37.45, 5.0, 9.124), 196.374, epsilon));
325 try expect(math.approxEqAbs(f64, fma64(89.123, 5.0, 9.124), 454.739, epsilon));
326 try expect(math.approxEqAbs(f64, fma64(123123.234375, 5.0, 9.124), 615625.295875, epsilon));
327}
328
329test "128" {
330 const epsilon = 0.000001;
331
332 try expect(math.approxEqAbs(f128, fma128(0.0, 5.0, 9.124), 9.124, epsilon));
333 try expect(math.approxEqAbs(f128, fma128(0.2, 5.0, 9.124), 10.124, epsilon));
334 try expect(math.approxEqAbs(f128, fma128(0.8923, 5.0, 9.124), 13.5855, epsilon));
335 try expect(math.approxEqAbs(f128, fma128(1.5, 5.0, 9.124), 16.624, epsilon));
336 try expect(math.approxEqAbs(f128, fma128(37.45, 5.0, 9.124), 196.374, epsilon));
337 try expect(math.approxEqAbs(f128, fma128(89.123, 5.0, 9.124), 454.739, epsilon));
338 try expect(math.approxEqAbs(f128, fma128(123123.234375, 5.0, 9.124), 615625.295875, epsilon));
339}
lib/std/math/hypot.zig+2-2
......@@ -56,7 +56,7 @@ fn hypot32(x: f32, y: f32) f32 {
5656 yy *= 0x1.0p-90;
5757 }
5858
59 return z * math.sqrt(@floatCast(f32, @as(f64, x) * x + @as(f64, y) * y));
59 return z * @sqrt(@floatCast(f32, @as(f64, x) * x + @as(f64, y) * y));
6060}
6161
6262fn sq(hi: *f64, lo: *f64, x: f64) void {
......@@ -117,7 +117,7 @@ fn hypot64(x: f64, y: f64) f64 {
117117 sq(&hx, &lx, x);
118118 sq(&hy, &ly, y);
119119
120 return z * math.sqrt(ly + lx + hy + hx);
120 return z * @sqrt(ly + lx + hy + hx);
121121}
122122
123123test "math.hypot" {
lib/std/math/ln.zig+8-163
......@@ -1,12 +1,6 @@
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/lnf.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/ln.c
6
71const std = @import("../std.zig");
82const math = std.math;
9const expect = std.testing.expect;
3const testing = std.testing;
104
115/// Returns the natural logarithm of x.
126///
......@@ -15,175 +9,26 @@ const expect = std.testing.expect;
159/// - ln(0) = -inf
1610/// - ln(x) = nan if x < 0
1711/// - ln(nan) = nan
12/// TODO remove this in favor of `@log`.
1813pub fn ln(x: anytype) @TypeOf(x) {
1914 const T = @TypeOf(x);
2015 switch (@typeInfo(T)) {
2116 .ComptimeFloat => {
22 return @as(comptime_float, ln_64(x));
23 },
24 .Float => {
25 return switch (T) {
26 f32 => ln_32(x),
27 f64 => ln_64(x),
28 else => @compileError("ln not implemented for " ++ @typeName(T)),
29 };
17 return @as(comptime_float, @log(x));
3018 },
19 .Float => return @log(x),
3120 .ComptimeInt => {
32 return @as(comptime_int, math.floor(ln_64(@as(f64, x))));
21 return @as(comptime_int, @floor(@log(@as(f64, x))));
3322 },
3423 .Int => |IntType| switch (IntType.signedness) {
3524 .signed => @compileError("ln not implemented for signed integers"),
36 .unsigned => return @as(T, math.floor(ln_64(@as(f64, x)))),
25 .unsigned => return @as(T, @floor(@log(@as(f64, x)))),
3726 },
3827 else => @compileError("ln not implemented for " ++ @typeName(T)),
3928 }
4029}
4130
42pub fn ln_32(x_: f32) f32 {
43 const ln2_hi: f32 = 6.9313812256e-01;
44 const ln2_lo: f32 = 9.0580006145e-06;
45 const Lg1: f32 = 0xaaaaaa.0p-24;
46 const Lg2: f32 = 0xccce13.0p-25;
47 const Lg3: f32 = 0x91e9ee.0p-25;
48 const Lg4: f32 = 0xf89e26.0p-26;
49
50 var x = x_;
51 var ix = @bitCast(u32, x);
52 var k: i32 = 0;
53
54 // x < 2^(-126)
55 if (ix < 0x00800000 or ix >> 31 != 0) {
56 // log(+-0) = -inf
57 if (ix << 1 == 0) {
58 return -math.inf(f32);
59 }
60 // log(-#) = nan
61 if (ix >> 31 != 0) {
62 return math.nan(f32);
63 }
64
65 // subnormal, scale x
66 k -= 25;
67 x *= 0x1.0p25;
68 ix = @bitCast(u32, x);
69 } else if (ix >= 0x7F800000) {
70 return x;
71 } else if (ix == 0x3F800000) {
72 return 0;
73 }
74
75 // x into [sqrt(2) / 2, sqrt(2)]
76 ix += 0x3F800000 - 0x3F3504F3;
77 k += @intCast(i32, ix >> 23) - 0x7F;
78 ix = (ix & 0x007FFFFF) + 0x3F3504F3;
79 x = @bitCast(f32, ix);
80
81 const f = x - 1.0;
82 const s = f / (2.0 + f);
83 const z = s * s;
84 const w = z * z;
85 const t1 = w * (Lg2 + w * Lg4);
86 const t2 = z * (Lg1 + w * Lg3);
87 const R = t2 + t1;
88 const hfsq = 0.5 * f * f;
89 const dk = @intToFloat(f32, k);
90
91 return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi;
92}
93
94pub fn ln_64(x_: f64) f64 {
95 const ln2_hi: f64 = 6.93147180369123816490e-01;
96 const ln2_lo: f64 = 1.90821492927058770002e-10;
97 const Lg1: f64 = 6.666666666666735130e-01;
98 const Lg2: f64 = 3.999999999940941908e-01;
99 const Lg3: f64 = 2.857142874366239149e-01;
100 const Lg4: f64 = 2.222219843214978396e-01;
101 const Lg5: f64 = 1.818357216161805012e-01;
102 const Lg6: f64 = 1.531383769920937332e-01;
103 const Lg7: f64 = 1.479819860511658591e-01;
104
105 var x = x_;
106 var ix = @bitCast(u64, x);
107 var hx = @intCast(u32, ix >> 32);
108 var k: i32 = 0;
109
110 if (hx < 0x00100000 or hx >> 31 != 0) {
111 // log(+-0) = -inf
112 if (ix << 1 == 0) {
113 return -math.inf(f64);
114 }
115 // log(-#) = nan
116 if (hx >> 31 != 0) {
117 return math.nan(f64);
118 }
119
120 // subnormal, scale x
121 k -= 54;
122 x *= 0x1.0p54;
123 hx = @intCast(u32, @bitCast(u64, ix) >> 32);
124 } else if (hx >= 0x7FF00000) {
125 return x;
126 } else if (hx == 0x3FF00000 and ix << 32 == 0) {
127 return 0;
128 }
129
130 // x into [sqrt(2) / 2, sqrt(2)]
131 hx += 0x3FF00000 - 0x3FE6A09E;
132 k += @intCast(i32, hx >> 20) - 0x3FF;
133 hx = (hx & 0x000FFFFF) + 0x3FE6A09E;
134 ix = (@as(u64, hx) << 32) | (ix & 0xFFFFFFFF);
135 x = @bitCast(f64, ix);
136
137 const f = x - 1.0;
138 const hfsq = 0.5 * f * f;
139 const s = f / (2.0 + f);
140 const z = s * s;
141 const w = z * z;
142 const t1 = w * (Lg2 + w * (Lg4 + w * Lg6));
143 const t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7)));
144 const R = t2 + t1;
145 const dk = @intToFloat(f64, k);
146
147 return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi;
148}
149
15031test "math.ln" {
151 try expect(ln(@as(f32, 0.2)) == ln_32(0.2));
152 try expect(ln(@as(f64, 0.2)) == ln_64(0.2));
153}
154
155test "math.ln32" {
156 const epsilon = 0.000001;
157
158 try expect(math.approxEqAbs(f32, ln_32(0.2), -1.609438, epsilon));
159 try expect(math.approxEqAbs(f32, ln_32(0.8923), -0.113953, epsilon));
160 try expect(math.approxEqAbs(f32, ln_32(1.5), 0.405465, epsilon));
161 try expect(math.approxEqAbs(f32, ln_32(37.45), 3.623007, epsilon));
162 try expect(math.approxEqAbs(f32, ln_32(89.123), 4.490017, epsilon));
163 try expect(math.approxEqAbs(f32, ln_32(123123.234375), 11.720941, epsilon));
164}
165
166test "math.ln64" {
167 const epsilon = 0.000001;
168
169 try expect(math.approxEqAbs(f64, ln_64(0.2), -1.609438, epsilon));
170 try expect(math.approxEqAbs(f64, ln_64(0.8923), -0.113953, epsilon));
171 try expect(math.approxEqAbs(f64, ln_64(1.5), 0.405465, epsilon));
172 try expect(math.approxEqAbs(f64, ln_64(37.45), 3.623007, epsilon));
173 try expect(math.approxEqAbs(f64, ln_64(89.123), 4.490017, epsilon));
174 try expect(math.approxEqAbs(f64, ln_64(123123.234375), 11.720941, epsilon));
175}
176
177test "math.ln32.special" {
178 try expect(math.isPositiveInf(ln_32(math.inf(f32))));
179 try expect(math.isNegativeInf(ln_32(0.0)));
180 try expect(math.isNan(ln_32(-1.0)));
181 try expect(math.isNan(ln_32(math.nan(f32))));
182}
183
184test "math.ln64.special" {
185 try expect(math.isPositiveInf(ln_64(math.inf(f64))));
186 try expect(math.isNegativeInf(ln_64(0.0)));
187 try expect(math.isNan(ln_64(-1.0)));
188 try expect(math.isNan(ln_64(math.nan(f64))));
32 try testing.expect(ln(@as(f32, 0.2)) == @log(0.2));
33 try testing.expect(ln(@as(f64, 0.2)) == @log(0.2));
18934}
lib/std/math/log.zig+6-6
......@@ -15,28 +15,28 @@ pub fn log(comptime T: type, base: T, x: T) T {
1515 } else if (base == 10) {
1616 return math.log10(x);
1717 } else if ((@typeInfo(T) == .Float or @typeInfo(T) == .ComptimeFloat) and base == math.e) {
18 return math.ln(x);
18 return @log(x);
1919 }
2020
2121 const float_base = math.lossyCast(f64, base);
2222 switch (@typeInfo(T)) {
2323 .ComptimeFloat => {
24 return @as(comptime_float, math.ln(@as(f64, x)) / math.ln(float_base));
24 return @as(comptime_float, @log(@as(f64, x)) / @log(float_base));
2525 },
2626 .ComptimeInt => {
27 return @as(comptime_int, math.floor(math.ln(@as(f64, x)) / math.ln(float_base)));
27 return @as(comptime_int, @floor(@log(@as(f64, x)) / @log(float_base)));
2828 },
2929
3030 // TODO implement integer log without using float math
3131 .Int => |IntType| switch (IntType.signedness) {
3232 .signed => @compileError("log not implemented for signed integers"),
33 .unsigned => return @floatToInt(T, math.floor(math.ln(@intToFloat(f64, x)) / math.ln(float_base))),
33 .unsigned => return @floatToInt(T, @floor(@log(@intToFloat(f64, x)) / @log(float_base))),
3434 },
3535
3636 .Float => {
3737 switch (T) {
38 f32 => return @floatCast(f32, math.ln(@as(f64, x)) / math.ln(float_base)),
39 f64 => return math.ln(x) / math.ln(float_base),
38 f32 => return @floatCast(f32, @log(@as(f64, x)) / @log(float_base)),
39 f64 => return @log(x) / @log(float_base),
4040 else => @compileError("log not implemented for " ++ @typeName(T)),
4141 }
4242 },
lib/std/math/log10.zig+4-192
......@@ -1,9 +1,3 @@
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/log10f.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/log10.c
6
71const std = @import("../std.zig");
82const math = std.math;
93const testing = std.testing;
......@@ -20,198 +14,16 @@ pub fn log10(x: anytype) @TypeOf(x) {
2014 const T = @TypeOf(x);
2115 switch (@typeInfo(T)) {
2216 .ComptimeFloat => {
23 return @as(comptime_float, log10_64(x));
24 },
25 .Float => {
26 return switch (T) {
27 f32 => log10_32(x),
28 f64 => log10_64(x),
29 else => @compileError("log10 not implemented for " ++ @typeName(T)),
30 };
17 return @as(comptime_float, @log10(x));
3118 },
19 .Float => return @log10(x),
3220 .ComptimeInt => {
33 return @as(comptime_int, math.floor(log10_64(@as(f64, x))));
21 return @as(comptime_int, @floor(@log10(@as(f64, x))));
3422 },
3523 .Int => |IntType| switch (IntType.signedness) {
3624 .signed => @compileError("log10 not implemented for signed integers"),
37 .unsigned => return @floatToInt(T, math.floor(log10_64(@intToFloat(f64, x)))),
25 .unsigned => return @floatToInt(T, @floor(@log10(@intToFloat(f64, x)))),
3826 },
3927 else => @compileError("log10 not implemented for " ++ @typeName(T)),
4028 }
4129}
42
43pub fn log10_32(x_: f32) f32 {
44 const ivln10hi: f32 = 4.3432617188e-01;
45 const ivln10lo: f32 = -3.1689971365e-05;
46 const log10_2hi: f32 = 3.0102920532e-01;
47 const log10_2lo: f32 = 7.9034151668e-07;
48 const Lg1: f32 = 0xaaaaaa.0p-24;
49 const Lg2: f32 = 0xccce13.0p-25;
50 const Lg3: f32 = 0x91e9ee.0p-25;
51 const Lg4: f32 = 0xf89e26.0p-26;
52
53 var x = x_;
54 var u = @bitCast(u32, x);
55 var ix = u;
56 var k: i32 = 0;
57
58 // x < 2^(-126)
59 if (ix < 0x00800000 or ix >> 31 != 0) {
60 // log(+-0) = -inf
61 if (ix << 1 == 0) {
62 return -math.inf(f32);
63 }
64 // log(-#) = nan
65 if (ix >> 31 != 0) {
66 return math.nan(f32);
67 }
68
69 k -= 25;
70 x *= 0x1.0p25;
71 ix = @bitCast(u32, x);
72 } else if (ix >= 0x7F800000) {
73 return x;
74 } else if (ix == 0x3F800000) {
75 return 0;
76 }
77
78 // x into [sqrt(2) / 2, sqrt(2)]
79 ix += 0x3F800000 - 0x3F3504F3;
80 k += @intCast(i32, ix >> 23) - 0x7F;
81 ix = (ix & 0x007FFFFF) + 0x3F3504F3;
82 x = @bitCast(f32, ix);
83
84 const f = x - 1.0;
85 const s = f / (2.0 + f);
86 const z = s * s;
87 const w = z * z;
88 const t1 = w * (Lg2 + w * Lg4);
89 const t2 = z * (Lg1 + w * Lg3);
90 const R = t2 + t1;
91 const hfsq = 0.5 * f * f;
92
93 var hi = f - hfsq;
94 u = @bitCast(u32, hi);
95 u &= 0xFFFFF000;
96 hi = @bitCast(f32, u);
97 const lo = f - hi - hfsq + s * (hfsq + R);
98 const dk = @intToFloat(f32, k);
99
100 return dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi;
101}
102
103pub fn log10_64(x_: f64) f64 {
104 const ivln10hi: f64 = 4.34294481878168880939e-01;
105 const ivln10lo: f64 = 2.50829467116452752298e-11;
106 const log10_2hi: f64 = 3.01029995663611771306e-01;
107 const log10_2lo: f64 = 3.69423907715893078616e-13;
108 const Lg1: f64 = 6.666666666666735130e-01;
109 const Lg2: f64 = 3.999999999940941908e-01;
110 const Lg3: f64 = 2.857142874366239149e-01;
111 const Lg4: f64 = 2.222219843214978396e-01;
112 const Lg5: f64 = 1.818357216161805012e-01;
113 const Lg6: f64 = 1.531383769920937332e-01;
114 const Lg7: f64 = 1.479819860511658591e-01;
115
116 var x = x_;
117 var ix = @bitCast(u64, x);
118 var hx = @intCast(u32, ix >> 32);
119 var k: i32 = 0;
120
121 if (hx < 0x00100000 or hx >> 31 != 0) {
122 // log(+-0) = -inf
123 if (ix << 1 == 0) {
124 return -math.inf(f32);
125 }
126 // log(-#) = nan
127 if (hx >> 31 != 0) {
128 return math.nan(f32);
129 }
130
131 // subnormal, scale x
132 k -= 54;
133 x *= 0x1.0p54;
134 hx = @intCast(u32, @bitCast(u64, x) >> 32);
135 } else if (hx >= 0x7FF00000) {
136 return x;
137 } else if (hx == 0x3FF00000 and ix << 32 == 0) {
138 return 0;
139 }
140
141 // x into [sqrt(2) / 2, sqrt(2)]
142 hx += 0x3FF00000 - 0x3FE6A09E;
143 k += @intCast(i32, hx >> 20) - 0x3FF;
144 hx = (hx & 0x000FFFFF) + 0x3FE6A09E;
145 ix = (@as(u64, hx) << 32) | (ix & 0xFFFFFFFF);
146 x = @bitCast(f64, ix);
147
148 const f = x - 1.0;
149 const hfsq = 0.5 * f * f;
150 const s = f / (2.0 + f);
151 const z = s * s;
152 const w = z * z;
153 const t1 = w * (Lg2 + w * (Lg4 + w * Lg6));
154 const t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7)));
155 const R = t2 + t1;
156
157 // hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f)
158 var hi = f - hfsq;
159 var hii = @bitCast(u64, hi);
160 hii &= @as(u64, maxInt(u64)) << 32;
161 hi = @bitCast(f64, hii);
162 const lo = f - hi - hfsq + s * (hfsq + R);
163
164 // val_hi + val_lo ~ log10(1 + f) + k * log10(2)
165 var val_hi = hi * ivln10hi;
166 const dk = @intToFloat(f64, k);
167 const y = dk * log10_2hi;
168 var val_lo = dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi;
169
170 // Extra precision multiplication
171 const ww = y + val_hi;
172 val_lo += (y - ww) + val_hi;
173 val_hi = ww;
174
175 return val_lo + val_hi;
176}
177
178test "math.log10" {
179 try testing.expect(log10(@as(f32, 0.2)) == log10_32(0.2));
180 try testing.expect(log10(@as(f64, 0.2)) == log10_64(0.2));
181}
182
183test "math.log10_32" {
184 const epsilon = 0.000001;
185
186 try testing.expect(math.approxEqAbs(f32, log10_32(0.2), -0.698970, epsilon));
187 try testing.expect(math.approxEqAbs(f32, log10_32(0.8923), -0.049489, epsilon));
188 try testing.expect(math.approxEqAbs(f32, log10_32(1.5), 0.176091, epsilon));
189 try testing.expect(math.approxEqAbs(f32, log10_32(37.45), 1.573452, epsilon));
190 try testing.expect(math.approxEqAbs(f32, log10_32(89.123), 1.94999, epsilon));
191 try testing.expect(math.approxEqAbs(f32, log10_32(123123.234375), 5.09034, epsilon));
192}
193
194test "math.log10_64" {
195 const epsilon = 0.000001;
196
197 try testing.expect(math.approxEqAbs(f64, log10_64(0.2), -0.698970, epsilon));
198 try testing.expect(math.approxEqAbs(f64, log10_64(0.8923), -0.049489, epsilon));
199 try testing.expect(math.approxEqAbs(f64, log10_64(1.5), 0.176091, epsilon));
200 try testing.expect(math.approxEqAbs(f64, log10_64(37.45), 1.573452, epsilon));
201 try testing.expect(math.approxEqAbs(f64, log10_64(89.123), 1.94999, epsilon));
202 try testing.expect(math.approxEqAbs(f64, log10_64(123123.234375), 5.09034, epsilon));
203}
204
205test "math.log10_32.special" {
206 try testing.expect(math.isPositiveInf(log10_32(math.inf(f32))));
207 try testing.expect(math.isNegativeInf(log10_32(0.0)));
208 try testing.expect(math.isNan(log10_32(-1.0)));
209 try testing.expect(math.isNan(log10_32(math.nan(f32))));
210}
211
212test "math.log10_64.special" {
213 try testing.expect(math.isPositiveInf(log10_64(math.inf(f64))));
214 try testing.expect(math.isNegativeInf(log10_64(0.0)));
215 try testing.expect(math.isNan(log10_64(-1.0)));
216 try testing.expect(math.isNan(log10_64(math.nan(f64))));
217}
lib/std/math/log2.zig+5-179
......@@ -1,13 +1,6 @@
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/log2f.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/log2.c
6
71const std = @import("../std.zig");
82const math = std.math;
93const expect = std.testing.expect;
10const maxInt = std.math.maxInt;
114
125/// Returns the base-2 logarithm of x.
136///
......@@ -20,15 +13,9 @@ pub fn log2(x: anytype) @TypeOf(x) {
2013 const T = @TypeOf(x);
2114 switch (@typeInfo(T)) {
2215 .ComptimeFloat => {
23 return @as(comptime_float, log2_64(x));
24 },
25 .Float => {
26 return switch (T) {
27 f32 => log2_32(x),
28 f64 => log2_64(x),
29 else => @compileError("log2 not implemented for " ++ @typeName(T)),
30 };
16 return @as(comptime_float, @log2(x));
3117 },
18 .Float => return @log2(x),
3219 .ComptimeInt => comptime {
3320 var result = 0;
3421 var x_shifted = x;
......@@ -46,168 +33,7 @@ pub fn log2(x: anytype) @TypeOf(x) {
4633 }
4734}
4835
49pub fn log2_32(x_: f32) f32 {
50 const ivln2hi: f32 = 1.4428710938e+00;
51 const ivln2lo: f32 = -1.7605285393e-04;
52 const Lg1: f32 = 0xaaaaaa.0p-24;
53 const Lg2: f32 = 0xccce13.0p-25;
54 const Lg3: f32 = 0x91e9ee.0p-25;
55 const Lg4: f32 = 0xf89e26.0p-26;
56
57 var x = x_;
58 var u = @bitCast(u32, x);
59 var ix = u;
60 var k: i32 = 0;
61
62 // x < 2^(-126)
63 if (ix < 0x00800000 or ix >> 31 != 0) {
64 // log(+-0) = -inf
65 if (ix << 1 == 0) {
66 return -math.inf(f32);
67 }
68 // log(-#) = nan
69 if (ix >> 31 != 0) {
70 return math.nan(f32);
71 }
72
73 k -= 25;
74 x *= 0x1.0p25;
75 ix = @bitCast(u32, x);
76 } else if (ix >= 0x7F800000) {
77 return x;
78 } else if (ix == 0x3F800000) {
79 return 0;
80 }
81
82 // x into [sqrt(2) / 2, sqrt(2)]
83 ix += 0x3F800000 - 0x3F3504F3;
84 k += @intCast(i32, ix >> 23) - 0x7F;
85 ix = (ix & 0x007FFFFF) + 0x3F3504F3;
86 x = @bitCast(f32, ix);
87
88 const f = x - 1.0;
89 const s = f / (2.0 + f);
90 const z = s * s;
91 const w = z * z;
92 const t1 = w * (Lg2 + w * Lg4);
93 const t2 = z * (Lg1 + w * Lg3);
94 const R = t2 + t1;
95 const hfsq = 0.5 * f * f;
96
97 var hi = f - hfsq;
98 u = @bitCast(u32, hi);
99 u &= 0xFFFFF000;
100 hi = @bitCast(f32, u);
101 const lo = f - hi - hfsq + s * (hfsq + R);
102 return (lo + hi) * ivln2lo + lo * ivln2hi + hi * ivln2hi + @intToFloat(f32, k);
103}
104
105pub fn log2_64(x_: f64) f64 {
106 const ivln2hi: f64 = 1.44269504072144627571e+00;
107 const ivln2lo: f64 = 1.67517131648865118353e-10;
108 const Lg1: f64 = 6.666666666666735130e-01;
109 const Lg2: f64 = 3.999999999940941908e-01;
110 const Lg3: f64 = 2.857142874366239149e-01;
111 const Lg4: f64 = 2.222219843214978396e-01;
112 const Lg5: f64 = 1.818357216161805012e-01;
113 const Lg6: f64 = 1.531383769920937332e-01;
114 const Lg7: f64 = 1.479819860511658591e-01;
115
116 var x = x_;
117 var ix = @bitCast(u64, x);
118 var hx = @intCast(u32, ix >> 32);
119 var k: i32 = 0;
120
121 if (hx < 0x00100000 or hx >> 31 != 0) {
122 // log(+-0) = -inf
123 if (ix << 1 == 0) {
124 return -math.inf(f64);
125 }
126 // log(-#) = nan
127 if (hx >> 31 != 0) {
128 return math.nan(f64);
129 }
130
131 // subnormal, scale x
132 k -= 54;
133 x *= 0x1.0p54;
134 hx = @intCast(u32, @bitCast(u64, x) >> 32);
135 } else if (hx >= 0x7FF00000) {
136 return x;
137 } else if (hx == 0x3FF00000 and ix << 32 == 0) {
138 return 0;
139 }
140
141 // x into [sqrt(2) / 2, sqrt(2)]
142 hx += 0x3FF00000 - 0x3FE6A09E;
143 k += @intCast(i32, hx >> 20) - 0x3FF;
144 hx = (hx & 0x000FFFFF) + 0x3FE6A09E;
145 ix = (@as(u64, hx) << 32) | (ix & 0xFFFFFFFF);
146 x = @bitCast(f64, ix);
147
148 const f = x - 1.0;
149 const hfsq = 0.5 * f * f;
150 const s = f / (2.0 + f);
151 const z = s * s;
152 const w = z * z;
153 const t1 = w * (Lg2 + w * (Lg4 + w * Lg6));
154 const t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7)));
155 const R = t2 + t1;
156
157 // hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f)
158 var hi = f - hfsq;
159 var hii = @bitCast(u64, hi);
160 hii &= @as(u64, maxInt(u64)) << 32;
161 hi = @bitCast(f64, hii);
162 const lo = f - hi - hfsq + s * (hfsq + R);
163
164 var val_hi = hi * ivln2hi;
165 var val_lo = (lo + hi) * ivln2lo + lo * ivln2hi;
166
167 // spadd(val_hi, val_lo, y)
168 const y = @intToFloat(f64, k);
169 const ww = y + val_hi;
170 val_lo += (y - ww) + val_hi;
171 val_hi = ww;
172
173 return val_lo + val_hi;
174}
175
176test "math.log2" {
177 try expect(log2(@as(f32, 0.2)) == log2_32(0.2));
178 try expect(log2(@as(f64, 0.2)) == log2_64(0.2));
179}
180
181test "math.log2_32" {
182 const epsilon = 0.000001;
183
184 try expect(math.approxEqAbs(f32, log2_32(0.2), -2.321928, epsilon));
185 try expect(math.approxEqAbs(f32, log2_32(0.8923), -0.164399, epsilon));
186 try expect(math.approxEqAbs(f32, log2_32(1.5), 0.584962, epsilon));
187 try expect(math.approxEqAbs(f32, log2_32(37.45), 5.226894, epsilon));
188 try expect(math.approxEqAbs(f32, log2_32(123123.234375), 16.909744, epsilon));
189}
190
191test "math.log2_64" {
192 const epsilon = 0.000001;
193
194 try expect(math.approxEqAbs(f64, log2_64(0.2), -2.321928, epsilon));
195 try expect(math.approxEqAbs(f64, log2_64(0.8923), -0.164399, epsilon));
196 try expect(math.approxEqAbs(f64, log2_64(1.5), 0.584962, epsilon));
197 try expect(math.approxEqAbs(f64, log2_64(37.45), 5.226894, epsilon));
198 try expect(math.approxEqAbs(f64, log2_64(123123.234375), 16.909744, epsilon));
199}
200
201test "math.log2_32.special" {
202 try expect(math.isPositiveInf(log2_32(math.inf(f32))));
203 try expect(math.isNegativeInf(log2_32(0.0)));
204 try expect(math.isNan(log2_32(-1.0)));
205 try expect(math.isNan(log2_32(math.nan(f32))));
206}
207
208test "math.log2_64.special" {
209 try expect(math.isPositiveInf(log2_64(math.inf(f64))));
210 try expect(math.isNegativeInf(log2_64(0.0)));
211 try expect(math.isNan(log2_64(-1.0)));
212 try expect(math.isNan(log2_64(math.nan(f64))));
36test "log2" {
37 try expect(log2(@as(f32, 0.2)) == @log2(0.2));
38 try expect(log2(@as(f64, 0.2)) == @log2(0.2));
21339}
lib/std/math/nan.zig+14-14
......@@ -2,13 +2,13 @@ const math = @import("../math.zig");
22
33/// Returns the nan representation for type T.
44pub fn nan(comptime T: type) T {
5 return switch (T) {
6 f16 => math.nan_f16,
7 f32 => math.nan_f32,
8 f64 => math.nan_f64,
9 f80 => math.nan_f80,
10 f128 => math.nan_f128,
11 else => @compileError("nan not implemented for " ++ @typeName(T)),
5 return switch (@typeInfo(T).Float.bits) {
6 16 => math.nan_f16,
7 32 => math.nan_f32,
8 64 => math.nan_f64,
9 80 => math.nan_f80,
10 128 => math.nan_f128,
11 else => @compileError("unreachable"),
1212 };
1313}
1414
......@@ -16,12 +16,12 @@ pub fn nan(comptime T: type) T {
1616pub fn snan(comptime T: type) T {
1717 // Note: A signalling nan is identical to a standard right now by may have a different bit
1818 // representation in the future when required.
19 return switch (T) {
20 f16 => @bitCast(f16, math.nan_u16),
21 f32 => @bitCast(f32, math.nan_u32),
22 f64 => @bitCast(f64, math.nan_u64),
23 f80 => @bitCast(f80, math.nan_u80),
24 f128 => @bitCast(f128, math.nan_u128),
25 else => @compileError("snan not implemented for " ++ @typeName(T)),
19 return switch (@typeInfo(T).Float.bits) {
20 16 => math.nan_u16,
21 32 => math.nan_u32,
22 64 => math.nan_u64,
23 80 => math.nan_u80,
24 128 => math.nan_u128,
25 else => @compileError("unreachable"),
2626 };
2727}
lib/std/math/pow.zig+6-6
......@@ -82,7 +82,7 @@ pub fn pow(comptime T: type, x: T, y: T) T {
8282 }
8383 // pow(x, +inf) = +0 for |x| < 1
8484 // pow(x, -inf) = +0 for |x| > 1
85 else if ((math.fabs(x) < 1) == math.isPositiveInf(y)) {
85 else if ((@fabs(x) < 1) == math.isPositiveInf(y)) {
8686 return 0;
8787 }
8888 // pow(x, -inf) = +inf for |x| < 1
......@@ -108,14 +108,14 @@ pub fn pow(comptime T: type, x: T, y: T) T {
108108
109109 // special case sqrt
110110 if (y == 0.5) {
111 return math.sqrt(x);
111 return @sqrt(x);
112112 }
113113
114114 if (y == -0.5) {
115 return 1 / math.sqrt(x);
115 return 1 / @sqrt(x);
116116 }
117117
118 const r1 = math.modf(math.fabs(y));
118 const r1 = math.modf(@fabs(y));
119119 var yi = r1.ipart;
120120 var yf = r1.fpart;
121121
......@@ -123,7 +123,7 @@ pub fn pow(comptime T: type, x: T, y: T) T {
123123 return math.nan(T);
124124 }
125125 if (yi >= 1 << (@typeInfo(T).Float.bits - 1)) {
126 return math.exp(y * math.ln(x));
126 return @exp(y * @log(x));
127127 }
128128
129129 // a = a1 * 2^ae
......@@ -136,7 +136,7 @@ pub fn pow(comptime T: type, x: T, y: T) T {
136136 yf -= 1;
137137 yi += 1;
138138 }
139 a1 = math.exp(yf * math.ln(x));
139 a1 = @exp(yf * @log(x));
140140 }
141141
142142 // a *= x^yi
lib/std/math/round.zig deleted-185
......@@ -1,185 +0,0 @@
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/roundf.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/round.c
6
7const expect = std.testing.expect;
8const std = @import("../std.zig");
9const math = std.math;
10
11/// Returns x rounded to the nearest integer, rounding half away from zero.
12///
13/// Special Cases:
14/// - round(+-0) = +-0
15/// - round(+-inf) = +-inf
16/// - round(nan) = nan
17pub fn round(x: anytype) @TypeOf(x) {
18 const T = @TypeOf(x);
19 return switch (T) {
20 f32 => round32(x),
21 f64 => round64(x),
22 f128 => round128(x),
23
24 // TODO this is not correct for some targets
25 c_longdouble => @floatCast(c_longdouble, round128(x)),
26
27 else => @compileError("round not implemented for " ++ @typeName(T)),
28 };
29}
30
31fn round32(x_: f32) f32 {
32 const f32_toint = 1.0 / math.floatEps(f32);
33
34 var x = x_;
35 const u = @bitCast(u32, x);
36 const e = (u >> 23) & 0xFF;
37 var y: f32 = undefined;
38
39 if (e >= 0x7F + 23) {
40 return x;
41 }
42 if (u >> 31 != 0) {
43 x = -x;
44 }
45 if (e < 0x7F - 1) {
46 math.doNotOptimizeAway(x + f32_toint);
47 return 0 * @bitCast(f32, u);
48 }
49
50 y = x + f32_toint - f32_toint - x;
51 if (y > 0.5) {
52 y = y + x - 1;
53 } else if (y <= -0.5) {
54 y = y + x + 1;
55 } else {
56 y = y + x;
57 }
58
59 if (u >> 31 != 0) {
60 return -y;
61 } else {
62 return y;
63 }
64}
65
66fn round64(x_: f64) f64 {
67 const f64_toint = 1.0 / math.floatEps(f64);
68
69 var x = x_;
70 const u = @bitCast(u64, x);
71 const e = (u >> 52) & 0x7FF;
72 var y: f64 = undefined;
73
74 if (e >= 0x3FF + 52) {
75 return x;
76 }
77 if (u >> 63 != 0) {
78 x = -x;
79 }
80 if (e < 0x3ff - 1) {
81 math.doNotOptimizeAway(x + f64_toint);
82 return 0 * @bitCast(f64, u);
83 }
84
85 y = x + f64_toint - f64_toint - x;
86 if (y > 0.5) {
87 y = y + x - 1;
88 } else if (y <= -0.5) {
89 y = y + x + 1;
90 } else {
91 y = y + x;
92 }
93
94 if (u >> 63 != 0) {
95 return -y;
96 } else {
97 return y;
98 }
99}
100
101fn round128(x_: f128) f128 {
102 const f128_toint = 1.0 / math.floatEps(f128);
103
104 var x = x_;
105 const u = @bitCast(u128, x);
106 const e = (u >> 112) & 0x7FFF;
107 var y: f128 = undefined;
108
109 if (e >= 0x3FFF + 112) {
110 return x;
111 }
112 if (u >> 127 != 0) {
113 x = -x;
114 }
115 if (e < 0x3FFF - 1) {
116 math.doNotOptimizeAway(x + f128_toint);
117 return 0 * @bitCast(f128, u);
118 }
119
120 y = x + f128_toint - f128_toint - x;
121 if (y > 0.5) {
122 y = y + x - 1;
123 } else if (y <= -0.5) {
124 y = y + x + 1;
125 } else {
126 y = y + x;
127 }
128
129 if (u >> 127 != 0) {
130 return -y;
131 } else {
132 return y;
133 }
134}
135
136test "math.round" {
137 try expect(round(@as(f32, 1.3)) == round32(1.3));
138 try expect(round(@as(f64, 1.3)) == round64(1.3));
139 try expect(round(@as(f128, 1.3)) == round128(1.3));
140}
141
142test "math.round32" {
143 try expect(round32(1.3) == 1.0);
144 try expect(round32(-1.3) == -1.0);
145 try expect(round32(0.2) == 0.0);
146 try expect(round32(1.8) == 2.0);
147}
148
149test "math.round64" {
150 try expect(round64(1.3) == 1.0);
151 try expect(round64(-1.3) == -1.0);
152 try expect(round64(0.2) == 0.0);
153 try expect(round64(1.8) == 2.0);
154}
155
156test "math.round128" {
157 try expect(round128(1.3) == 1.0);
158 try expect(round128(-1.3) == -1.0);
159 try expect(round128(0.2) == 0.0);
160 try expect(round128(1.8) == 2.0);
161}
162
163test "math.round32.special" {
164 try expect(round32(0.0) == 0.0);
165 try expect(round32(-0.0) == -0.0);
166 try expect(math.isPositiveInf(round32(math.inf(f32))));
167 try expect(math.isNegativeInf(round32(-math.inf(f32))));
168 try expect(math.isNan(round32(math.nan(f32))));
169}
170
171test "math.round64.special" {
172 try expect(round64(0.0) == 0.0);
173 try expect(round64(-0.0) == -0.0);
174 try expect(math.isPositiveInf(round64(math.inf(f64))));
175 try expect(math.isNegativeInf(round64(-math.inf(f64))));
176 try expect(math.isNan(round64(math.nan(f64))));
177}
178
179test "math.round128.special" {
180 try expect(round128(0.0) == 0.0);
181 try expect(round128(-0.0) == -0.0);
182 try expect(math.isPositiveInf(round128(math.inf(f128))));
183 try expect(math.isNegativeInf(round128(-math.inf(f128))));
184 try expect(math.isNan(round128(math.nan(f128))));
185}
lib/std/math/sin.zig deleted-168
......@@ -1,168 +0,0 @@
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/sinf.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/sin.c
6//
7const std = @import("../std.zig");
8const math = std.math;
9const expect = std.testing.expect;
10
11const kernel = @import("__trig.zig");
12const __rem_pio2 = @import("__rem_pio2.zig").__rem_pio2;
13const __rem_pio2f = @import("__rem_pio2f.zig").__rem_pio2f;
14
15/// Returns the sine of the radian value x.
16///
17/// Special Cases:
18/// - sin(+-0) = +-0
19/// - sin(+-inf) = nan
20/// - sin(nan) = nan
21pub fn sin(x: anytype) @TypeOf(x) {
22 const T = @TypeOf(x);
23 return switch (T) {
24 f32 => sin32(x),
25 f64 => sin64(x),
26 else => @compileError("sin not implemented for " ++ @typeName(T)),
27 };
28}
29
30fn sin32(x: f32) f32 {
31 // Small multiples of pi/2 rounded to double precision.
32 const s1pio2: f64 = 1.0 * math.pi / 2.0; // 0x3FF921FB, 0x54442D18
33 const s2pio2: f64 = 2.0 * math.pi / 2.0; // 0x400921FB, 0x54442D18
34 const s3pio2: f64 = 3.0 * math.pi / 2.0; // 0x4012D97C, 0x7F3321D2
35 const s4pio2: f64 = 4.0 * math.pi / 2.0; // 0x401921FB, 0x54442D18
36
37 var ix = @bitCast(u32, x);
38 const sign = ix >> 31 != 0;
39 ix &= 0x7fffffff;
40
41 if (ix <= 0x3f490fda) { // |x| ~<= pi/4
42 if (ix < 0x39800000) { // |x| < 2**-12
43 // raise inexact if x!=0 and underflow if subnormal
44 math.doNotOptimizeAway(if (ix < 0x00800000) x / 0x1p120 else x + 0x1p120);
45 return x;
46 }
47 return kernel.__sindf(x);
48 }
49 if (ix <= 0x407b53d1) { // |x| ~<= 5*pi/4
50 if (ix <= 0x4016cbe3) { // |x| ~<= 3pi/4
51 if (sign) {
52 return -kernel.__cosdf(x + s1pio2);
53 } else {
54 return kernel.__cosdf(x - s1pio2);
55 }
56 }
57 return kernel.__sindf(if (sign) -(x + s2pio2) else -(x - s2pio2));
58 }
59 if (ix <= 0x40e231d5) { // |x| ~<= 9*pi/4
60 if (ix <= 0x40afeddf) { // |x| ~<= 7*pi/4
61 if (sign) {
62 return kernel.__cosdf(x + s3pio2);
63 } else {
64 return -kernel.__cosdf(x - s3pio2);
65 }
66 }
67 return kernel.__sindf(if (sign) x + s4pio2 else x - s4pio2);
68 }
69
70 // sin(Inf or NaN) is NaN
71 if (ix >= 0x7f800000) {
72 return x - x;
73 }
74
75 var y: f64 = undefined;
76 const n = __rem_pio2f(x, &y);
77 return switch (n & 3) {
78 0 => kernel.__sindf(y),
79 1 => kernel.__cosdf(y),
80 2 => kernel.__sindf(-y),
81 else => -kernel.__cosdf(y),
82 };
83}
84
85fn sin64(x: f64) f64 {
86 var ix = @bitCast(u64, x) >> 32;
87 ix &= 0x7fffffff;
88
89 // |x| ~< pi/4
90 if (ix <= 0x3fe921fb) {
91 if (ix < 0x3e500000) { // |x| < 2**-26
92 // raise inexact if x != 0 and underflow if subnormal
93 math.doNotOptimizeAway(if (ix < 0x00100000) x / 0x1p120 else x + 0x1p120);
94 return x;
95 }
96 return kernel.__sin(x, 0.0, 0);
97 }
98
99 // sin(Inf or NaN) is NaN
100 if (ix >= 0x7ff00000) {
101 return x - x;
102 }
103
104 var y: [2]f64 = undefined;
105 const n = __rem_pio2(x, &y);
106 return switch (n & 3) {
107 0 => kernel.__sin(y[0], y[1], 1),
108 1 => kernel.__cos(y[0], y[1]),
109 2 => -kernel.__sin(y[0], y[1], 1),
110 else => -kernel.__cos(y[0], y[1]),
111 };
112}
113
114test "math.sin" {
115 try expect(sin(@as(f32, 0.0)) == sin32(0.0));
116 try expect(sin(@as(f64, 0.0)) == sin64(0.0));
117 try expect(comptime (math.sin(@as(f64, 2))) == math.sin(@as(f64, 2)));
118}
119
120test "math.sin32" {
121 const epsilon = 0.00001;
122
123 try expect(math.approxEqAbs(f32, sin32(0.0), 0.0, epsilon));
124 try expect(math.approxEqAbs(f32, sin32(0.2), 0.198669, epsilon));
125 try expect(math.approxEqAbs(f32, sin32(0.8923), 0.778517, epsilon));
126 try expect(math.approxEqAbs(f32, sin32(1.5), 0.997495, epsilon));
127 try expect(math.approxEqAbs(f32, sin32(-1.5), -0.997495, epsilon));
128 try expect(math.approxEqAbs(f32, sin32(37.45), -0.246544, epsilon));
129 try expect(math.approxEqAbs(f32, sin32(89.123), 0.916166, epsilon));
130}
131
132test "math.sin64" {
133 const epsilon = 0.000001;
134
135 try expect(math.approxEqAbs(f64, sin64(0.0), 0.0, epsilon));
136 try expect(math.approxEqAbs(f64, sin64(0.2), 0.198669, epsilon));
137 try expect(math.approxEqAbs(f64, sin64(0.8923), 0.778517, epsilon));
138 try expect(math.approxEqAbs(f64, sin64(1.5), 0.997495, epsilon));
139 try expect(math.approxEqAbs(f64, sin64(-1.5), -0.997495, epsilon));
140 try expect(math.approxEqAbs(f64, sin64(37.45), -0.246543, epsilon));
141 try expect(math.approxEqAbs(f64, sin64(89.123), 0.916166, epsilon));
142}
143
144test "math.sin32.special" {
145 try expect(sin32(0.0) == 0.0);
146 try expect(sin32(-0.0) == -0.0);
147 try expect(math.isNan(sin32(math.inf(f32))));
148 try expect(math.isNan(sin32(-math.inf(f32))));
149 try expect(math.isNan(sin32(math.nan(f32))));
150}
151
152test "math.sin64.special" {
153 try expect(sin64(0.0) == 0.0);
154 try expect(sin64(-0.0) == -0.0);
155 try expect(math.isNan(sin64(math.inf(f64))));
156 try expect(math.isNan(sin64(-math.inf(f64))));
157 try expect(math.isNan(sin64(math.nan(f64))));
158}
159
160test "math.sin32 #9901" {
161 const float = @bitCast(f32, @as(u32, 0b11100011111111110000000000000000));
162 _ = std.math.sin(float);
163}
164
165test "math.sin64 #9901" {
166 const float = @bitCast(f64, @as(u64, 0b1111111101000001000000001111110111111111100000000000000000000001));
167 _ = std.math.sin(float);
168}
lib/std/math/tan.zig deleted-140
......@@ -1,140 +0,0 @@
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/tanf.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/tan.c
6// https://golang.org/src/math/tan.go
7
8const std = @import("../std.zig");
9const math = std.math;
10const expect = std.testing.expect;
11
12const kernel = @import("__trig.zig");
13const __rem_pio2 = @import("__rem_pio2.zig").__rem_pio2;
14const __rem_pio2f = @import("__rem_pio2f.zig").__rem_pio2f;
15
16/// Returns the tangent of the radian value x.
17///
18/// Special Cases:
19/// - tan(+-0) = +-0
20/// - tan(+-inf) = nan
21/// - tan(nan) = nan
22pub fn tan(x: anytype) @TypeOf(x) {
23 const T = @TypeOf(x);
24 return switch (T) {
25 f32 => tan32(x),
26 f64 => tan64(x),
27 else => @compileError("tan not implemented for " ++ @typeName(T)),
28 };
29}
30
31fn tan32(x: f32) f32 {
32 // Small multiples of pi/2 rounded to double precision.
33 const t1pio2: f64 = 1.0 * math.pi / 2.0; // 0x3FF921FB, 0x54442D18
34 const t2pio2: f64 = 2.0 * math.pi / 2.0; // 0x400921FB, 0x54442D18
35 const t3pio2: f64 = 3.0 * math.pi / 2.0; // 0x4012D97C, 0x7F3321D2
36 const t4pio2: f64 = 4.0 * math.pi / 2.0; // 0x401921FB, 0x54442D18
37
38 var ix = @bitCast(u32, x);
39 const sign = ix >> 31 != 0;
40 ix &= 0x7fffffff;
41
42 if (ix <= 0x3f490fda) { // |x| ~<= pi/4
43 if (ix < 0x39800000) { // |x| < 2**-12
44 // raise inexact if x!=0 and underflow if subnormal
45 math.doNotOptimizeAway(if (ix < 0x00800000) x / 0x1p120 else x + 0x1p120);
46 return x;
47 }
48 return kernel.__tandf(x, false);
49 }
50 if (ix <= 0x407b53d1) { // |x| ~<= 5*pi/4
51 if (ix <= 0x4016cbe3) { // |x| ~<= 3pi/4
52 return kernel.__tandf((if (sign) x + t1pio2 else x - t1pio2), true);
53 } else {
54 return kernel.__tandf((if (sign) x + t2pio2 else x - t2pio2), false);
55 }
56 }
57 if (ix <= 0x40e231d5) { // |x| ~<= 9*pi/4
58 if (ix <= 0x40afeddf) { // |x| ~<= 7*pi/4
59 return kernel.__tandf((if (sign) x + t3pio2 else x - t3pio2), true);
60 } else {
61 return kernel.__tandf((if (sign) x + t4pio2 else x - t4pio2), false);
62 }
63 }
64
65 // tan(Inf or NaN) is NaN
66 if (ix >= 0x7f800000) {
67 return x - x;
68 }
69
70 var y: f64 = undefined;
71 const n = __rem_pio2f(x, &y);
72 return kernel.__tandf(y, n & 1 != 0);
73}
74
75fn tan64(x: f64) f64 {
76 var ix = @bitCast(u64, x) >> 32;
77 ix &= 0x7fffffff;
78
79 // |x| ~< pi/4
80 if (ix <= 0x3fe921fb) {
81 if (ix < 0x3e400000) { // |x| < 2**-27
82 // raise inexact if x!=0 and underflow if subnormal
83 math.doNotOptimizeAway(if (ix < 0x00100000) x / 0x1p120 else x + 0x1p120);
84 return x;
85 }
86 return kernel.__tan(x, 0.0, false);
87 }
88
89 // tan(Inf or NaN) is NaN
90 if (ix >= 0x7ff00000) {
91 return x - x;
92 }
93
94 var y: [2]f64 = undefined;
95 const n = __rem_pio2(x, &y);
96 return kernel.__tan(y[0], y[1], n & 1 != 0);
97}
98
99test "math.tan" {
100 try expect(tan(@as(f32, 0.0)) == tan32(0.0));
101 try expect(tan(@as(f64, 0.0)) == tan64(0.0));
102}
103
104test "math.tan32" {
105 const epsilon = 0.00001;
106
107 try expect(math.approxEqAbs(f32, tan32(0.0), 0.0, epsilon));
108 try expect(math.approxEqAbs(f32, tan32(0.2), 0.202710, epsilon));
109 try expect(math.approxEqAbs(f32, tan32(0.8923), 1.240422, epsilon));
110 try expect(math.approxEqAbs(f32, tan32(1.5), 14.101420, epsilon));
111 try expect(math.approxEqAbs(f32, tan32(37.45), -0.254397, epsilon));
112 try expect(math.approxEqAbs(f32, tan32(89.123), 2.285852, epsilon));
113}
114
115test "math.tan64" {
116 const epsilon = 0.000001;
117
118 try expect(math.approxEqAbs(f64, tan64(0.0), 0.0, epsilon));
119 try expect(math.approxEqAbs(f64, tan64(0.2), 0.202710, epsilon));
120 try expect(math.approxEqAbs(f64, tan64(0.8923), 1.240422, epsilon));
121 try expect(math.approxEqAbs(f64, tan64(1.5), 14.101420, epsilon));
122 try expect(math.approxEqAbs(f64, tan64(37.45), -0.254397, epsilon));
123 try expect(math.approxEqAbs(f64, tan64(89.123), 2.2858376, epsilon));
124}
125
126test "math.tan32.special" {
127 try expect(tan32(0.0) == 0.0);
128 try expect(tan32(-0.0) == -0.0);
129 try expect(math.isNan(tan32(math.inf(f32))));
130 try expect(math.isNan(tan32(-math.inf(f32))));
131 try expect(math.isNan(tan32(math.nan(f32))));
132}
133
134test "math.tan64.special" {
135 try expect(tan64(0.0) == 0.0);
136 try expect(tan64(-0.0) == -0.0);
137 try expect(math.isNan(tan64(math.inf(f64))));
138 try expect(math.isNan(tan64(-math.inf(f64))));
139 try expect(math.isNan(tan64(math.nan(f64))));
140}
lib/std/math/trunc.zig deleted-141
......@@ -1,141 +0,0 @@
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/truncf.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/trunc.c
6
7const std = @import("../std.zig");
8const math = std.math;
9const expect = std.testing.expect;
10const maxInt = std.math.maxInt;
11
12/// Returns the integer value of x.
13///
14/// Special Cases:
15/// - trunc(+-0) = +-0
16/// - trunc(+-inf) = +-inf
17/// - trunc(nan) = nan
18pub fn trunc(x: anytype) @TypeOf(x) {
19 const T = @TypeOf(x);
20 return switch (T) {
21 f32 => trunc32(x),
22 f64 => trunc64(x),
23 f128 => trunc128(x),
24
25 // TODO this is not correct for some targets
26 c_longdouble => @floatCast(c_longdouble, trunc128(x)),
27
28 else => @compileError("trunc not implemented for " ++ @typeName(T)),
29 };
30}
31
32fn trunc32(x: f32) f32 {
33 const u = @bitCast(u32, x);
34 var e = @intCast(i32, ((u >> 23) & 0xFF)) - 0x7F + 9;
35 var m: u32 = undefined;
36
37 if (e >= 23 + 9) {
38 return x;
39 }
40 if (e < 9) {
41 e = 1;
42 }
43
44 m = @as(u32, maxInt(u32)) >> @intCast(u5, e);
45 if (u & m == 0) {
46 return x;
47 } else {
48 math.doNotOptimizeAway(x + 0x1p120);
49 return @bitCast(f32, u & ~m);
50 }
51}
52
53fn trunc64(x: f64) f64 {
54 const u = @bitCast(u64, x);
55 var e = @intCast(i32, ((u >> 52) & 0x7FF)) - 0x3FF + 12;
56 var m: u64 = undefined;
57
58 if (e >= 52 + 12) {
59 return x;
60 }
61 if (e < 12) {
62 e = 1;
63 }
64
65 m = @as(u64, maxInt(u64)) >> @intCast(u6, e);
66 if (u & m == 0) {
67 return x;
68 } else {
69 math.doNotOptimizeAway(x + 0x1p120);
70 return @bitCast(f64, u & ~m);
71 }
72}
73
74fn trunc128(x: f128) f128 {
75 const u = @bitCast(u128, x);
76 var e = @intCast(i32, ((u >> 112) & 0x7FFF)) - 0x3FFF + 16;
77 var m: u128 = undefined;
78
79 if (e >= 112 + 16) {
80 return x;
81 }
82 if (e < 16) {
83 e = 1;
84 }
85
86 m = @as(u128, maxInt(u128)) >> @intCast(u7, e);
87 if (u & m == 0) {
88 return x;
89 } else {
90 math.doNotOptimizeAway(x + 0x1p120);
91 return @bitCast(f128, u & ~m);
92 }
93}
94
95test "math.trunc" {
96 try expect(trunc(@as(f32, 1.3)) == trunc32(1.3));
97 try expect(trunc(@as(f64, 1.3)) == trunc64(1.3));
98 try expect(trunc(@as(f128, 1.3)) == trunc128(1.3));
99}
100
101test "math.trunc32" {
102 try expect(trunc32(1.3) == 1.0);
103 try expect(trunc32(-1.3) == -1.0);
104 try expect(trunc32(0.2) == 0.0);
105}
106
107test "math.trunc64" {
108 try expect(trunc64(1.3) == 1.0);
109 try expect(trunc64(-1.3) == -1.0);
110 try expect(trunc64(0.2) == 0.0);
111}
112
113test "math.trunc128" {
114 try expect(trunc128(1.3) == 1.0);
115 try expect(trunc128(-1.3) == -1.0);
116 try expect(trunc128(0.2) == 0.0);
117}
118
119test "math.trunc32.special" {
120 try expect(trunc32(0.0) == 0.0); // 0x3F800000
121 try expect(trunc32(-0.0) == -0.0);
122 try expect(math.isPositiveInf(trunc32(math.inf(f32))));
123 try expect(math.isNegativeInf(trunc32(-math.inf(f32))));
124 try expect(math.isNan(trunc32(math.nan(f32))));
125}
126
127test "math.trunc64.special" {
128 try expect(trunc64(0.0) == 0.0);
129 try expect(trunc64(-0.0) == -0.0);
130 try expect(math.isPositiveInf(trunc64(math.inf(f64))));
131 try expect(math.isNegativeInf(trunc64(-math.inf(f64))));
132 try expect(math.isNan(trunc64(math.nan(f64))));
133}
134
135test "math.trunc128.special" {
136 try expect(trunc128(0.0) == 0.0);
137 try expect(trunc128(-0.0) == -0.0);
138 try expect(math.isPositiveInf(trunc128(math.inf(f128))));
139 try expect(math.isNegativeInf(trunc128(-math.inf(f128))));
140 try expect(math.isNan(trunc128(math.nan(f128))));
141}
lib/std/rand/ziggurat.zig+8-8
......@@ -33,7 +33,7 @@ pub fn next_f64(random: Random, comptime tables: ZigTable) f64 {
3333 };
3434
3535 const x = u * tables.x[i];
36 const test_x = if (tables.is_symmetric) math.fabs(x) else x;
36 const test_x = if (tables.is_symmetric) @fabs(x) else x;
3737
3838 // equivalent to |u| < tables.x[i+1] / tables.x[i] (or u < tables.x[i+1] / tables.x[i])
3939 if (test_x < tables.x[i + 1]) {
......@@ -106,18 +106,18 @@ const norm_r = 3.6541528853610088;
106106const norm_v = 0.00492867323399;
107107
108108fn norm_f(x: f64) f64 {
109 return math.exp(-x * x / 2.0);
109 return @exp(-x * x / 2.0);
110110}
111111fn norm_f_inv(y: f64) f64 {
112 return math.sqrt(-2.0 * math.ln(y));
112 return @sqrt(-2.0 * @log(y));
113113}
114114fn norm_zero_case(random: Random, u: f64) f64 {
115115 var x: f64 = 1;
116116 var y: f64 = 0;
117117
118118 while (-2.0 * y < x * x) {
119 x = math.ln(random.float(f64)) / norm_r;
120 y = math.ln(random.float(f64));
119 x = @log(random.float(f64)) / norm_r;
120 y = @log(random.float(f64));
121121 }
122122
123123 if (u < 0) {
......@@ -151,13 +151,13 @@ const exp_r = 7.69711747013104972;
151151const exp_v = 0.0039496598225815571993;
152152
153153fn exp_f(x: f64) f64 {
154 return math.exp(-x);
154 return @exp(-x);
155155}
156156fn exp_f_inv(y: f64) f64 {
157 return -math.ln(y);
157 return -@log(y);
158158}
159159fn exp_zero_case(random: Random, _: f64) f64 {
160 return exp_r - math.ln(random.float(f64));
160 return exp_r - @log(random.float(f64));
161161}
162162
163163test "exp dist sanity" {
lib/std/special/c.zig-591
......@@ -12,7 +12,6 @@ const maxInt = std.math.maxInt;
1212const native_os = builtin.os.tag;
1313const native_arch = builtin.cpu.arch;
1414const native_abi = builtin.abi;
15const long_double_is_f128 = builtin.target.longDoubleIs(f128);
1615
1716const is_wasm = switch (native_arch) {
1817 .wasm32, .wasm64 => true,
......@@ -55,53 +54,6 @@ comptime {
5554 } else if (is_msvc) {
5655 @export(_fltused, .{ .name = "_fltused", .linkage = .Strong });
5756 }
58
59 @export(trunc, .{ .name = "trunc", .linkage = .Strong });
60 @export(truncf, .{ .name = "truncf", .linkage = .Strong });
61 @export(truncl, .{ .name = "truncl", .linkage = .Strong });
62
63 @export(log, .{ .name = "log", .linkage = .Strong });
64 @export(logf, .{ .name = "logf", .linkage = .Strong });
65
66 @export(sin, .{ .name = "sin", .linkage = .Strong });
67 @export(sinf, .{ .name = "sinf", .linkage = .Strong });
68
69 @export(cos, .{ .name = "cos", .linkage = .Strong });
70 @export(cosf, .{ .name = "cosf", .linkage = .Strong });
71
72 @export(exp, .{ .name = "exp", .linkage = .Strong });
73 @export(expf, .{ .name = "expf", .linkage = .Strong });
74
75 @export(exp2, .{ .name = "exp2", .linkage = .Strong });
76 @export(exp2f, .{ .name = "exp2f", .linkage = .Strong });
77
78 @export(log2, .{ .name = "log2", .linkage = .Strong });
79 @export(log2f, .{ .name = "log2f", .linkage = .Strong });
80
81 @export(log10, .{ .name = "log10", .linkage = .Strong });
82 @export(log10f, .{ .name = "log10f", .linkage = .Strong });
83
84 @export(fmod, .{ .name = "fmod", .linkage = .Strong });
85 @export(fmodf, .{ .name = "fmodf", .linkage = .Strong });
86
87 @export(sincos, .{ .name = "sincos", .linkage = .Strong });
88 @export(sincosf, .{ .name = "sincosf", .linkage = .Strong });
89
90 @export(fabs, .{ .name = "fabs", .linkage = .Strong });
91 @export(fabsf, .{ .name = "fabsf", .linkage = .Strong });
92
93 @export(round, .{ .name = "round", .linkage = .Strong });
94 @export(roundf, .{ .name = "roundf", .linkage = .Strong });
95 @export(roundl, .{ .name = "roundl", .linkage = .Strong });
96
97 @export(fmin, .{ .name = "fmin", .linkage = .Strong });
98 @export(fminf, .{ .name = "fminf", .linkage = .Strong });
99
100 @export(fmax, .{ .name = "fmax", .linkage = .Strong });
101 @export(fmaxf, .{ .name = "fmaxf", .linkage = .Strong });
102
103 @export(sqrt, .{ .name = "sqrt", .linkage = .Strong });
104 @export(sqrtf, .{ .name = "sqrtf", .linkage = .Strong });
10557}
10658
10759// Avoid dragging in the runtime safety mechanisms into this .o file,
......@@ -352,549 +304,6 @@ test "strncmp" {
352304 try std.testing.expect(strncmp("\xff", "\x02", 1) == 253);
353305}
354306
355fn trunc(a: f64) callconv(.C) f64 {
356 return math.trunc(a);
357}
358
359fn truncf(a: f32) callconv(.C) f32 {
360 return math.trunc(a);
361}
362
363fn truncl(a: c_longdouble) callconv(.C) c_longdouble {
364 if (!long_double_is_f128) {
365 @panic("TODO implement this");
366 }
367 return math.trunc(a);
368}
369
370fn log(a: f64) callconv(.C) f64 {
371 return math.ln(a);
372}
373
374fn logf(a: f32) callconv(.C) f32 {
375 return math.ln(a);
376}
377
378fn sin(a: f64) callconv(.C) f64 {
379 return math.sin(a);
380}
381
382fn sinf(a: f32) callconv(.C) f32 {
383 return math.sin(a);
384}
385
386fn cos(a: f64) callconv(.C) f64 {
387 return math.cos(a);
388}
389
390fn cosf(a: f32) callconv(.C) f32 {
391 return math.cos(a);
392}
393
394fn exp(a: f64) callconv(.C) f64 {
395 return math.exp(a);
396}
397
398fn expf(a: f32) callconv(.C) f32 {
399 return math.exp(a);
400}
401
402fn exp2(a: f64) callconv(.C) f64 {
403 return math.exp2(a);
404}
405
406fn exp2f(a: f32) callconv(.C) f32 {
407 return math.exp2(a);
408}
409
410fn log2(a: f64) callconv(.C) f64 {
411 return math.log2(a);
412}
413
414fn log2f(a: f32) callconv(.C) f32 {
415 return math.log2(a);
416}
417
418fn log10(a: f64) callconv(.C) f64 {
419 return math.log10(a);
420}
421
422fn log10f(a: f32) callconv(.C) f32 {
423 return math.log10(a);
424}
425
426fn fmodf(x: f32, y: f32) callconv(.C) f32 {
427 return generic_fmod(f32, x, y);
428}
429fn fmod(x: f64, y: f64) callconv(.C) f64 {
430 return generic_fmod(f64, x, y);
431}
432
433fn generic_fmod(comptime T: type, x: T, y: T) T {
434 @setRuntimeSafety(false);
435
436 const bits = @typeInfo(T).Float.bits;
437 const uint = std.meta.Int(.unsigned, bits);
438 const log2uint = math.Log2Int(uint);
439 const digits = if (T == f32) 23 else 52;
440 const exp_bits = if (T == f32) 9 else 12;
441 const bits_minus_1 = bits - 1;
442 const mask = if (T == f32) 0xff else 0x7ff;
443 var ux = @bitCast(uint, x);
444 var uy = @bitCast(uint, y);
445 var ex = @intCast(i32, (ux >> digits) & mask);
446 var ey = @intCast(i32, (uy >> digits) & mask);
447 const sx = if (T == f32) @intCast(u32, ux & 0x80000000) else @intCast(i32, ux >> bits_minus_1);
448 var i: uint = undefined;
449
450 if (uy << 1 == 0 or isNan(@bitCast(T, uy)) or ex == mask)
451 return (x * y) / (x * y);
452
453 if (ux << 1 <= uy << 1) {
454 if (ux << 1 == uy << 1)
455 return 0 * x;
456 return x;
457 }
458
459 // normalize x and y
460 if (ex == 0) {
461 i = ux << exp_bits;
462 while (i >> bits_minus_1 == 0) : ({
463 ex -= 1;
464 i <<= 1;
465 }) {}
466 ux <<= @intCast(log2uint, @bitCast(u32, -ex + 1));
467 } else {
468 ux &= maxInt(uint) >> exp_bits;
469 ux |= 1 << digits;
470 }
471 if (ey == 0) {
472 i = uy << exp_bits;
473 while (i >> bits_minus_1 == 0) : ({
474 ey -= 1;
475 i <<= 1;
476 }) {}
477 uy <<= @intCast(log2uint, @bitCast(u32, -ey + 1));
478 } else {
479 uy &= maxInt(uint) >> exp_bits;
480 uy |= 1 << digits;
481 }
482
483 // x mod y
484 while (ex > ey) : (ex -= 1) {
485 i = ux -% uy;
486 if (i >> bits_minus_1 == 0) {
487 if (i == 0)
488 return 0 * x;
489 ux = i;
490 }
491 ux <<= 1;
492 }
493 i = ux -% uy;
494 if (i >> bits_minus_1 == 0) {
495 if (i == 0)
496 return 0 * x;
497 ux = i;
498 }
499 while (ux >> digits == 0) : ({
500 ux <<= 1;
501 ex -= 1;
502 }) {}
503
504 // scale result up
505 if (ex > 0) {
506 ux -%= 1 << digits;
507 ux |= @as(uint, @bitCast(u32, ex)) << digits;
508 } else {
509 ux >>= @intCast(log2uint, @bitCast(u32, -ex + 1));
510 }
511 if (T == f32) {
512 ux |= sx;
513 } else {
514 ux |= @intCast(uint, sx) << bits_minus_1;
515 }
516 return @bitCast(T, ux);
517}
518
519test "fmod, fmodf" {
520 inline for ([_]type{ f32, f64 }) |T| {
521 const nan_val = math.nan(T);
522 const inf_val = math.inf(T);
523
524 try std.testing.expect(isNan(generic_fmod(T, nan_val, 1.0)));
525 try std.testing.expect(isNan(generic_fmod(T, 1.0, nan_val)));
526 try std.testing.expect(isNan(generic_fmod(T, inf_val, 1.0)));
527 try std.testing.expect(isNan(generic_fmod(T, 0.0, 0.0)));
528 try std.testing.expect(isNan(generic_fmod(T, 1.0, 0.0)));
529
530 try std.testing.expectEqual(@as(T, 0.0), generic_fmod(T, 0.0, 2.0));
531 try std.testing.expectEqual(@as(T, -0.0), generic_fmod(T, -0.0, 2.0));
532
533 try std.testing.expectEqual(@as(T, -2.0), generic_fmod(T, -32.0, 10.0));
534 try std.testing.expectEqual(@as(T, -2.0), generic_fmod(T, -32.0, -10.0));
535 try std.testing.expectEqual(@as(T, 2.0), generic_fmod(T, 32.0, 10.0));
536 try std.testing.expectEqual(@as(T, 2.0), generic_fmod(T, 32.0, -10.0));
537 }
538}
539
540fn sincos(a: f64, r_sin: *f64, r_cos: *f64) callconv(.C) void {
541 r_sin.* = math.sin(a);
542 r_cos.* = math.cos(a);
543}
544
545fn sincosf(a: f32, r_sin: *f32, r_cos: *f32) callconv(.C) void {
546 r_sin.* = math.sin(a);
547 r_cos.* = math.cos(a);
548}
549
550fn fabs(a: f64) callconv(.C) f64 {
551 return math.fabs(a);
552}
553
554fn fabsf(a: f32) callconv(.C) f32 {
555 return math.fabs(a);
556}
557
558fn roundf(a: f32) callconv(.C) f32 {
559 return math.round(a);
560}
561
562fn round(a: f64) callconv(.C) f64 {
563 return math.round(a);
564}
565
566fn roundl(a: c_longdouble) callconv(.C) c_longdouble {
567 if (!long_double_is_f128) {
568 @panic("TODO implement this");
569 }
570 return math.round(a);
571}
572
573fn fminf(x: f32, y: f32) callconv(.C) f32 {
574 return generic_fmin(f32, x, y);
575}
576
577fn fmin(x: f64, y: f64) callconv(.C) f64 {
578 return generic_fmin(f64, x, y);
579}
580
581fn generic_fmin(comptime T: type, x: T, y: T) T {
582 if (isNan(x))
583 return y;
584 if (isNan(y))
585 return x;
586 return if (x < y) x else y;
587}
588
589test "fmin, fminf" {
590 inline for ([_]type{ f32, f64 }) |T| {
591 const nan_val = math.nan(T);
592
593 try std.testing.expect(isNan(generic_fmin(T, nan_val, nan_val)));
594 try std.testing.expectEqual(@as(T, 1.0), generic_fmin(T, nan_val, 1.0));
595 try std.testing.expectEqual(@as(T, 1.0), generic_fmin(T, 1.0, nan_val));
596
597 try std.testing.expectEqual(@as(T, 1.0), generic_fmin(T, 1.0, 10.0));
598 try std.testing.expectEqual(@as(T, -1.0), generic_fmin(T, 1.0, -1.0));
599 }
600}
601
602fn fmaxf(x: f32, y: f32) callconv(.C) f32 {
603 return generic_fmax(f32, x, y);
604}
605
606fn fmax(x: f64, y: f64) callconv(.C) f64 {
607 return generic_fmax(f64, x, y);
608}
609
610fn generic_fmax(comptime T: type, x: T, y: T) T {
611 if (isNan(x))
612 return y;
613 if (isNan(y))
614 return x;
615 return if (x < y) y else x;
616}
617
618test "fmax, fmaxf" {
619 inline for ([_]type{ f32, f64 }) |T| {
620 const nan_val = math.nan(T);
621
622 try std.testing.expect(isNan(generic_fmax(T, nan_val, nan_val)));
623 try std.testing.expectEqual(@as(T, 1.0), generic_fmax(T, nan_val, 1.0));
624 try std.testing.expectEqual(@as(T, 1.0), generic_fmax(T, 1.0, nan_val));
625
626 try std.testing.expectEqual(@as(T, 10.0), generic_fmax(T, 1.0, 10.0));
627 try std.testing.expectEqual(@as(T, 1.0), generic_fmax(T, 1.0, -1.0));
628 }
629}
630
631// NOTE: The original code is full of implicit signed -> unsigned assumptions and u32 wraparound
632// behaviour. Most intermediate i32 values are changed to u32 where appropriate but there are
633// potentially some edge cases remaining that are not handled in the same way.
634fn sqrt(x: f64) callconv(.C) f64 {
635 const tiny: f64 = 1.0e-300;
636 const sign: u32 = 0x80000000;
637 const u = @bitCast(u64, x);
638
639 var ix0 = @intCast(u32, u >> 32);
640 var ix1 = @intCast(u32, u & 0xFFFFFFFF);
641
642 // sqrt(nan) = nan, sqrt(+inf) = +inf, sqrt(-inf) = nan
643 if (ix0 & 0x7FF00000 == 0x7FF00000) {
644 return x * x + x;
645 }
646
647 // sqrt(+-0) = +-0
648 if (x == 0.0) {
649 return x;
650 }
651 // sqrt(-ve) = snan
652 if (ix0 & sign != 0) {
653 return math.snan(f64);
654 }
655
656 // normalize x
657 var m = @intCast(i32, ix0 >> 20);
658 if (m == 0) {
659 // subnormal
660 while (ix0 == 0) {
661 m -= 21;
662 ix0 |= ix1 >> 11;
663 ix1 <<= 21;
664 }
665
666 // subnormal
667 var i: u32 = 0;
668 while (ix0 & 0x00100000 == 0) : (i += 1) {
669 ix0 <<= 1;
670 }
671 m -= @intCast(i32, i) - 1;
672 ix0 |= ix1 >> @intCast(u5, 32 - i);
673 ix1 <<= @intCast(u5, i);
674 }
675
676 // unbias exponent
677 m -= 1023;
678 ix0 = (ix0 & 0x000FFFFF) | 0x00100000;
679 if (m & 1 != 0) {
680 ix0 += ix0 + (ix1 >> 31);
681 ix1 = ix1 +% ix1;
682 }
683 m >>= 1;
684
685 // sqrt(x) bit by bit
686 ix0 += ix0 + (ix1 >> 31);
687 ix1 = ix1 +% ix1;
688
689 var q: u32 = 0;
690 var q1: u32 = 0;
691 var s0: u32 = 0;
692 var s1: u32 = 0;
693 var r: u32 = 0x00200000;
694 var t: u32 = undefined;
695 var t1: u32 = undefined;
696
697 while (r != 0) {
698 t = s0 +% r;
699 if (t <= ix0) {
700 s0 = t + r;
701 ix0 -= t;
702 q += r;
703 }
704 ix0 = ix0 +% ix0 +% (ix1 >> 31);
705 ix1 = ix1 +% ix1;
706 r >>= 1;
707 }
708
709 r = sign;
710 while (r != 0) {
711 t1 = s1 +% r;
712 t = s0;
713 if (t < ix0 or (t == ix0 and t1 <= ix1)) {
714 s1 = t1 +% r;
715 if (t1 & sign == sign and s1 & sign == 0) {
716 s0 += 1;
717 }
718 ix0 -= t;
719 if (ix1 < t1) {
720 ix0 -= 1;
721 }
722 ix1 = ix1 -% t1;
723 q1 += r;
724 }
725 ix0 = ix0 +% ix0 +% (ix1 >> 31);
726 ix1 = ix1 +% ix1;
727 r >>= 1;
728 }
729
730 // rounding direction
731 if (ix0 | ix1 != 0) {
732 var z = 1.0 - tiny; // raise inexact
733 if (z >= 1.0) {
734 z = 1.0 + tiny;
735 if (q1 == 0xFFFFFFFF) {
736 q1 = 0;
737 q += 1;
738 } else if (z > 1.0) {
739 if (q1 == 0xFFFFFFFE) {
740 q += 1;
741 }
742 q1 += 2;
743 } else {
744 q1 += q1 & 1;
745 }
746 }
747 }
748
749 ix0 = (q >> 1) + 0x3FE00000;
750 ix1 = q1 >> 1;
751 if (q & 1 != 0) {
752 ix1 |= 0x80000000;
753 }
754
755 // NOTE: musl here appears to rely on signed twos-complement wraparound. +% has the same
756 // behaviour at least.
757 var iix0 = @intCast(i32, ix0);
758 iix0 = iix0 +% (m << 20);
759
760 const uz = (@intCast(u64, iix0) << 32) | ix1;
761 return @bitCast(f64, uz);
762}
763
764test "sqrt" {
765 const V = [_]f64{
766 0.0,
767 4.089288054930154,
768 7.538757127071935,
769 8.97780793672623,
770 5.304443821913729,
771 5.682408965311888,
772 0.5846878579110049,
773 3.650338664297043,
774 0.3178091951800732,
775 7.1505232436382835,
776 3.6589165881946464,
777 };
778
779 // Note that @sqrt will either generate the sqrt opcode (if supported by the
780 // target ISA) or a call to `sqrtf` otherwise.
781 for (V) |val|
782 try std.testing.expectEqual(@sqrt(val), sqrt(val));
783}
784
785test "sqrt special" {
786 try std.testing.expect(std.math.isPositiveInf(sqrt(std.math.inf(f64))));
787 try std.testing.expect(sqrt(0.0) == 0.0);
788 try std.testing.expect(sqrt(-0.0) == -0.0);
789 try std.testing.expect(isNan(sqrt(-1.0)));
790 try std.testing.expect(isNan(sqrt(std.math.nan(f64))));
791}
792
793fn sqrtf(x: f32) callconv(.C) f32 {
794 const tiny: f32 = 1.0e-30;
795 const sign: i32 = @bitCast(i32, @as(u32, 0x80000000));
796 var ix: i32 = @bitCast(i32, x);
797
798 if ((ix & 0x7F800000) == 0x7F800000) {
799 return x * x + x; // sqrt(nan) = nan, sqrt(+inf) = +inf, sqrt(-inf) = snan
800 }
801
802 // zero
803 if (ix <= 0) {
804 if (ix & ~sign == 0) {
805 return x; // sqrt (+-0) = +-0
806 }
807 if (ix < 0) {
808 return math.snan(f32);
809 }
810 }
811
812 // normalize
813 var m = ix >> 23;
814 if (m == 0) {
815 // subnormal
816 var i: i32 = 0;
817 while (ix & 0x00800000 == 0) : (i += 1) {
818 ix <<= 1;
819 }
820 m -= i - 1;
821 }
822
823 m -= 127; // unbias exponent
824 ix = (ix & 0x007FFFFF) | 0x00800000;
825
826 if (m & 1 != 0) { // odd m, double x to even
827 ix += ix;
828 }
829
830 m >>= 1; // m = [m / 2]
831
832 // sqrt(x) bit by bit
833 ix += ix;
834 var q: i32 = 0; // q = sqrt(x)
835 var s: i32 = 0;
836 var r: i32 = 0x01000000; // r = moving bit right -> left
837
838 while (r != 0) {
839 const t = s + r;
840 if (t <= ix) {
841 s = t + r;
842 ix -= t;
843 q += r;
844 }
845 ix += ix;
846 r >>= 1;
847 }
848
849 // floating add to find rounding direction
850 if (ix != 0) {
851 var z = 1.0 - tiny; // inexact
852 if (z >= 1.0) {
853 z = 1.0 + tiny;
854 if (z > 1.0) {
855 q += 2;
856 } else {
857 if (q & 1 != 0) {
858 q += 1;
859 }
860 }
861 }
862 }
863
864 ix = (q >> 1) + 0x3f000000;
865 ix += m << 23;
866 return @bitCast(f32, ix);
867}
868
869test "sqrtf" {
870 const V = [_]f32{
871 0.0,
872 4.089288054930154,
873 7.538757127071935,
874 8.97780793672623,
875 5.304443821913729,
876 5.682408965311888,
877 0.5846878579110049,
878 3.650338664297043,
879 0.3178091951800732,
880 7.1505232436382835,
881 3.6589165881946464,
882 };
883
884 // Note that @sqrt will either generate the sqrt opcode (if supported by the
885 // target ISA) or a call to `sqrtf` otherwise.
886 for (V) |val|
887 try std.testing.expectEqual(@sqrt(val), sqrtf(val));
888}
889
890test "sqrtf special" {
891 try std.testing.expect(std.math.isPositiveInf(sqrtf(std.math.inf(f32))));
892 try std.testing.expect(sqrtf(0.0) == 0.0);
893 try std.testing.expect(sqrtf(-0.0) == -0.0);
894 try std.testing.expect(isNan(sqrtf(-1.0)));
895 try std.testing.expect(isNan(sqrtf(std.math.nan(f32))));
896}
897
898307// TODO we should be able to put this directly in std/linux/x86_64.zig but
899308// it causes a segfault in release mode. this is a workaround of calling it
900309// across .o file boundaries. fix comptime @ptrCast of nakedcc functions.
lib/std/special/compiler_rt.zig+53-92
......@@ -19,9 +19,6 @@ const strong_linkage = if (is_test)
1919else
2020 std.builtin.GlobalLinkage.Strong;
2121
22const long_double_is_f80 = builtin.target.longDoubleIs(f80);
23const long_double_is_f128 = builtin.target.longDoubleIs(f128);
24
2522comptime {
2623 // These files do their own comptime exporting logic.
2724 _ = @import("compiler_rt/atomics.zig");
......@@ -726,42 +723,25 @@ comptime {
726723 @export(_aullrem, .{ .name = "\x01__aullrem", .linkage = strong_linkage });
727724 }
728725
729 if (!is_test) {
730 if (long_double_is_f80) {
731 @export(fmodx, .{ .name = "fmodl", .linkage = linkage });
732 } else if (long_double_is_f128) {
733 @export(fmodq, .{ .name = "fmodl", .linkage = linkage });
734 } else {
735 @export(fmodl, .{ .name = "fmodl", .linkage = linkage });
736 }
737 if (long_double_is_f80 or builtin.zig_backend == .stage1) {
738 // TODO: https://github.com/ziglang/zig/issues/11161
739 @export(fmodx, .{ .name = "fmodx", .linkage = linkage });
740 }
741 @export(fmodq, .{ .name = "fmodq", .linkage = linkage });
742
743 @export(floorf, .{ .name = "floorf", .linkage = linkage });
744 @export(floor, .{ .name = "floor", .linkage = linkage });
745 @export(floorl, .{ .name = "floorl", .linkage = linkage });
746
747 @export(ceilf, .{ .name = "ceilf", .linkage = linkage });
748 @export(ceil, .{ .name = "ceil", .linkage = linkage });
749 @export(ceill, .{ .name = "ceill", .linkage = linkage });
750
751 @export(fma, .{ .name = "fma", .linkage = linkage });
752 @export(fmaf, .{ .name = "fmaf", .linkage = linkage });
753 @export(fmal, .{ .name = "fmal", .linkage = linkage });
754 if (long_double_is_f80) {
755 @export(fmal, .{ .name = "__fmax", .linkage = linkage });
756 } else {
757 @export(__fmax, .{ .name = "__fmax", .linkage = linkage });
758 }
759 if (long_double_is_f128) {
760 @export(fmal, .{ .name = "fmaq", .linkage = linkage });
761 } else {
762 @export(fmaq, .{ .name = "fmaq", .linkage = linkage });
763 }
764 }
726 mathExport("ceil", @import("./compiler_rt/ceil.zig"));
727 mathExport("cos", @import("./compiler_rt/cos.zig"));
728 mathExport("exp", @import("./compiler_rt/exp.zig"));
729 mathExport("exp2", @import("./compiler_rt/exp2.zig"));
730 mathExport("fabs", @import("./compiler_rt/fabs.zig"));
731 mathExport("floor", @import("./compiler_rt/floor.zig"));
732 mathExport("fma", @import("./compiler_rt/fma.zig"));
733 mathExport("fmax", @import("./compiler_rt/fmax.zig"));
734 mathExport("fmin", @import("./compiler_rt/fmin.zig"));
735 mathExport("fmod", @import("./compiler_rt/fmod.zig"));
736 mathExport("log", @import("./compiler_rt/log.zig"));
737 mathExport("log10", @import("./compiler_rt/log10.zig"));
738 mathExport("log2", @import("./compiler_rt/log2.zig"));
739 mathExport("round", @import("./compiler_rt/round.zig"));
740 mathExport("sin", @import("./compiler_rt/sin.zig"));
741 mathExport("sincos", @import("./compiler_rt/sincos.zig"));
742 mathExport("sqrt", @import("./compiler_rt/sqrt.zig"));
743 mathExport("tan", @import("./compiler_rt/tan.zig"));
744 mathExport("trunc", @import("./compiler_rt/trunc.zig"));
765745
766746 if (arch.isSPARC()) {
767747 // SPARC systems use a different naming scheme
......@@ -842,63 +822,44 @@ comptime {
842822 @export(__unordtf2, .{ .name = "__unordkf2", .linkage = linkage });
843823
844824 // LLVM PPC backend lowers f128 fma to `fmaf128`.
845 @export(fmal, .{ .name = "fmaf128", .linkage = linkage });
825 const fmaq = @import("./compiler_rt/fma.zig").fmaq;
826 @export(fmaq, .{ .name = "fmaf128", .linkage = linkage });
846827 }
847828}
848829
849const math = std.math;
850
851fn fmaf(a: f32, b: f32, c: f32) callconv(.C) f32 {
852 return math.fma(f32, a, b, c);
853}
854fn fma(a: f64, b: f64, c: f64) callconv(.C) f64 {
855 return math.fma(f64, a, b, c);
856}
857fn __fmax(a: f80, b: f80, c: f80) callconv(.C) f80 {
858 return math.fma(f80, a, b, c);
859}
860fn fmaq(a: f128, b: f128, c: f128) callconv(.C) f128 {
861 return math.fma(f128, a, b, c);
862}
863fn fmal(a: c_longdouble, b: c_longdouble, c: c_longdouble) callconv(.C) c_longdouble {
864 return math.fma(c_longdouble, a, b, c);
865}
866
867// TODO add intrinsics for these (and probably the double version too)
868// and have the math stuff use the intrinsic. same as @mod and @rem
869fn floorf(x: f32) callconv(.C) f32 {
870 return math.floor(x);
871}
872fn floor(x: f64) callconv(.C) f64 {
873 return math.floor(x);
874}
875fn floorl(x: c_longdouble) callconv(.C) c_longdouble {
876 if (!long_double_is_f128) {
877 @panic("TODO implement this");
878 }
879 return math.floor(x);
880}
881
882fn ceilf(x: f32) callconv(.C) f32 {
883 return math.ceil(x);
884}
885fn ceil(x: f64) callconv(.C) f64 {
886 return math.ceil(x);
887}
888fn ceill(x: c_longdouble) callconv(.C) c_longdouble {
889 if (!long_double_is_f128) {
890 @panic("TODO implement this");
891 }
892 return math.ceil(x);
893}
894
895const fmodq = @import("compiler_rt/fmodq.zig").fmodq;
896const fmodx = @import("compiler_rt/fmodx.zig").fmodx;
897fn fmodl(x: c_longdouble, y: c_longdouble) callconv(.C) c_longdouble {
898 if (!long_double_is_f128) {
899 @panic("TODO implement this");
830inline fn mathExport(double_name: []const u8, comptime import: type) void {
831 const half_name = "__" ++ double_name ++ "h";
832 const half_fn = @field(import, half_name);
833 const float_name = double_name ++ "f";
834 const float_fn = @field(import, float_name);
835 const double_fn = @field(import, double_name);
836 const long_double_name = double_name ++ "l";
837 const xf80_name = "__" ++ double_name ++ "x";
838 const xf80_fn = @field(import, xf80_name);
839 const quad_name = double_name ++ "q";
840 const quad_fn = @field(import, quad_name);
841
842 @export(half_fn, .{ .name = half_name, .linkage = linkage });
843 @export(float_fn, .{ .name = float_name, .linkage = linkage });
844 @export(double_fn, .{ .name = double_name, .linkage = linkage });
845 @export(xf80_fn, .{ .name = xf80_name, .linkage = linkage });
846 @export(quad_fn, .{ .name = quad_name, .linkage = linkage });
847
848 const pairs = .{
849 .{ f16, half_fn },
850 .{ f32, float_fn },
851 .{ f64, double_fn },
852 .{ f80, xf80_fn },
853 .{ f128, quad_fn },
854 };
855
856 inline for (pairs) |pair| {
857 const F = pair[0];
858 const func = pair[1];
859 if (builtin.target.longDoubleIs(F)) {
860 @export(func, .{ .name = long_double_name, .linkage = linkage });
861 }
900862 }
901 return @floatCast(c_longdouble, fmodq(x, y));
902863}
903864
904865// Avoid dragging in the runtime safety mechanisms into this .o file,
lib/std/special/compiler_rt/ceil.zig created+154
......@@ -0,0 +1,154 @@
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/ceilf.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/ceil.c
6
7const std = @import("std");
8const math = std.math;
9const expect = std.testing.expect;
10
11pub fn __ceilh(x: f16) callconv(.C) f16 {
12 // TODO: more efficient implementation
13 return @floatCast(f16, ceilf(x));
14}
15
16pub fn ceilf(x: f32) callconv(.C) f32 {
17 var u = @bitCast(u32, x);
18 var e = @intCast(i32, (u >> 23) & 0xFF) - 0x7F;
19 var m: u32 = undefined;
20
21 // TODO: Shouldn't need this explicit check.
22 if (x == 0.0) {
23 return x;
24 }
25
26 if (e >= 23) {
27 return x;
28 } else if (e >= 0) {
29 m = @as(u32, 0x007FFFFF) >> @intCast(u5, e);
30 if (u & m == 0) {
31 return x;
32 }
33 math.doNotOptimizeAway(x + 0x1.0p120);
34 if (u >> 31 == 0) {
35 u += m;
36 }
37 u &= ~m;
38 return @bitCast(f32, u);
39 } else {
40 math.doNotOptimizeAway(x + 0x1.0p120);
41 if (u >> 31 != 0) {
42 return -0.0;
43 } else {
44 return 1.0;
45 }
46 }
47}
48
49pub fn ceil(x: f64) callconv(.C) f64 {
50 const f64_toint = 1.0 / math.floatEps(f64);
51
52 const u = @bitCast(u64, x);
53 const e = (u >> 52) & 0x7FF;
54 var y: f64 = undefined;
55
56 if (e >= 0x3FF + 52 or x == 0) {
57 return x;
58 }
59
60 if (u >> 63 != 0) {
61 y = x - f64_toint + f64_toint - x;
62 } else {
63 y = x + f64_toint - f64_toint - x;
64 }
65
66 if (e <= 0x3FF - 1) {
67 math.doNotOptimizeAway(y);
68 if (u >> 63 != 0) {
69 return -0.0;
70 } else {
71 return 1.0;
72 }
73 } else if (y < 0) {
74 return x + y + 1;
75 } else {
76 return x + y;
77 }
78}
79
80pub fn __ceilx(x: f80) callconv(.C) f80 {
81 // TODO: more efficient implementation
82 return @floatCast(f80, ceilq(x));
83}
84
85pub fn ceilq(x: f128) callconv(.C) f128 {
86 const f128_toint = 1.0 / math.floatEps(f128);
87
88 const u = @bitCast(u128, x);
89 const e = (u >> 112) & 0x7FFF;
90 var y: f128 = undefined;
91
92 if (e >= 0x3FFF + 112 or x == 0) return x;
93
94 if (u >> 127 != 0) {
95 y = x - f128_toint + f128_toint - x;
96 } else {
97 y = x + f128_toint - f128_toint - x;
98 }
99
100 if (e <= 0x3FFF - 1) {
101 math.doNotOptimizeAway(y);
102 if (u >> 127 != 0) {
103 return -0.0;
104 } else {
105 return 1.0;
106 }
107 } else if (y < 0) {
108 return x + y + 1;
109 } else {
110 return x + y;
111 }
112}
113
114test "ceil32" {
115 try expect(ceilf(1.3) == 2.0);
116 try expect(ceilf(-1.3) == -1.0);
117 try expect(ceilf(0.2) == 1.0);
118}
119
120test "ceil64" {
121 try expect(ceil(1.3) == 2.0);
122 try expect(ceil(-1.3) == -1.0);
123 try expect(ceil(0.2) == 1.0);
124}
125
126test "ceil128" {
127 try expect(ceilq(1.3) == 2.0);
128 try expect(ceilq(-1.3) == -1.0);
129 try expect(ceilq(0.2) == 1.0);
130}
131
132test "ceil32.special" {
133 try expect(ceilf(0.0) == 0.0);
134 try expect(ceilf(-0.0) == -0.0);
135 try expect(math.isPositiveInf(ceilf(math.inf(f32))));
136 try expect(math.isNegativeInf(ceilf(-math.inf(f32))));
137 try expect(math.isNan(ceilf(math.nan(f32))));
138}
139
140test "ceil64.special" {
141 try expect(ceil(0.0) == 0.0);
142 try expect(ceil(-0.0) == -0.0);
143 try expect(math.isPositiveInf(ceil(math.inf(f64))));
144 try expect(math.isNegativeInf(ceil(-math.inf(f64))));
145 try expect(math.isNan(ceil(math.nan(f64))));
146}
147
148test "ceil128.special" {
149 try expect(ceilq(0.0) == 0.0);
150 try expect(ceilq(-0.0) == -0.0);
151 try expect(math.isPositiveInf(ceilq(math.inf(f128))));
152 try expect(math.isNegativeInf(ceilq(-math.inf(f128))));
153 try expect(math.isNan(ceilq(math.nan(f128))));
154}
lib/std/special/compiler_rt/cos.zig created+144
......@@ -0,0 +1,144 @@
1const std = @import("std");
2const math = std.math;
3const expect = std.testing.expect;
4
5const kernel = @import("trig.zig");
6const rem_pio2 = @import("rem_pio2.zig").rem_pio2;
7const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f;
8
9pub fn __cosh(a: f16) callconv(.C) f16 {
10 // TODO: more efficient implementation
11 return @floatCast(f16, cosf(a));
12}
13
14pub fn cosf(x: f32) callconv(.C) f32 {
15 // Small multiples of pi/2 rounded to double precision.
16 const c1pio2: f64 = 1.0 * math.pi / 2.0; // 0x3FF921FB, 0x54442D18
17 const c2pio2: f64 = 2.0 * math.pi / 2.0; // 0x400921FB, 0x54442D18
18 const c3pio2: f64 = 3.0 * math.pi / 2.0; // 0x4012D97C, 0x7F3321D2
19 const c4pio2: f64 = 4.0 * math.pi / 2.0; // 0x401921FB, 0x54442D18
20
21 var ix = @bitCast(u32, x);
22 const sign = ix >> 31 != 0;
23 ix &= 0x7fffffff;
24
25 if (ix <= 0x3f490fda) { // |x| ~<= pi/4
26 if (ix < 0x39800000) { // |x| < 2**-12
27 // raise inexact if x != 0
28 math.doNotOptimizeAway(x + 0x1p120);
29 return 1.0;
30 }
31 return kernel.__cosdf(x);
32 }
33 if (ix <= 0x407b53d1) { // |x| ~<= 5*pi/4
34 if (ix > 0x4016cbe3) { // |x| ~> 3*pi/4
35 return -kernel.__cosdf(if (sign) x + c2pio2 else x - c2pio2);
36 } else {
37 if (sign) {
38 return kernel.__sindf(x + c1pio2);
39 } else {
40 return kernel.__sindf(c1pio2 - x);
41 }
42 }
43 }
44 if (ix <= 0x40e231d5) { // |x| ~<= 9*pi/4
45 if (ix > 0x40afeddf) { // |x| ~> 7*pi/4
46 return kernel.__cosdf(if (sign) x + c4pio2 else x - c4pio2);
47 } else {
48 if (sign) {
49 return kernel.__sindf(-x - c3pio2);
50 } else {
51 return kernel.__sindf(x - c3pio2);
52 }
53 }
54 }
55
56 // cos(Inf or NaN) is NaN
57 if (ix >= 0x7f800000) {
58 return x - x;
59 }
60
61 var y: f64 = undefined;
62 const n = rem_pio2f(x, &y);
63 return switch (n & 3) {
64 0 => kernel.__cosdf(y),
65 1 => kernel.__sindf(-y),
66 2 => -kernel.__cosdf(y),
67 else => kernel.__sindf(y),
68 };
69}
70
71pub fn cos(x: f64) callconv(.C) f64 {
72 var ix = @bitCast(u64, x) >> 32;
73 ix &= 0x7fffffff;
74
75 // |x| ~< pi/4
76 if (ix <= 0x3fe921fb) {
77 if (ix < 0x3e46a09e) { // |x| < 2**-27 * sqrt(2)
78 // raise inexact if x!=0
79 math.doNotOptimizeAway(x + 0x1p120);
80 return 1.0;
81 }
82 return kernel.__cos(x, 0);
83 }
84
85 // cos(Inf or NaN) is NaN
86 if (ix >= 0x7ff00000) {
87 return x - x;
88 }
89
90 var y: [2]f64 = undefined;
91 const n = rem_pio2(x, &y);
92 return switch (n & 3) {
93 0 => kernel.__cos(y[0], y[1]),
94 1 => -kernel.__sin(y[0], y[1], 1),
95 2 => -kernel.__cos(y[0], y[1]),
96 else => kernel.__sin(y[0], y[1], 1),
97 };
98}
99
100pub fn __cosx(a: f80) callconv(.C) f80 {
101 // TODO: more efficient implementation
102 return @floatCast(f80, cosq(a));
103}
104
105pub fn cosq(a: f128) callconv(.C) f128 {
106 // TODO: more correct implementation
107 return cos(@floatCast(f64, a));
108}
109
110test "cos32" {
111 const epsilon = 0.00001;
112
113 try expect(math.approxEqAbs(f32, cosf(0.0), 1.0, epsilon));
114 try expect(math.approxEqAbs(f32, cosf(0.2), 0.980067, epsilon));
115 try expect(math.approxEqAbs(f32, cosf(0.8923), 0.627623, epsilon));
116 try expect(math.approxEqAbs(f32, cosf(1.5), 0.070737, epsilon));
117 try expect(math.approxEqAbs(f32, cosf(-1.5), 0.070737, epsilon));
118 try expect(math.approxEqAbs(f32, cosf(37.45), 0.969132, epsilon));
119 try expect(math.approxEqAbs(f32, cosf(89.123), 0.400798, epsilon));
120}
121
122test "cos64" {
123 const epsilon = 0.000001;
124
125 try expect(math.approxEqAbs(f64, cos(0.0), 1.0, epsilon));
126 try expect(math.approxEqAbs(f64, cos(0.2), 0.980067, epsilon));
127 try expect(math.approxEqAbs(f64, cos(0.8923), 0.627623, epsilon));
128 try expect(math.approxEqAbs(f64, cos(1.5), 0.070737, epsilon));
129 try expect(math.approxEqAbs(f64, cos(-1.5), 0.070737, epsilon));
130 try expect(math.approxEqAbs(f64, cos(37.45), 0.969132, epsilon));
131 try expect(math.approxEqAbs(f64, cos(89.123), 0.40080, epsilon));
132}
133
134test "cos32.special" {
135 try expect(math.isNan(cosf(math.inf(f32))));
136 try expect(math.isNan(cosf(-math.inf(f32))));
137 try expect(math.isNan(cosf(math.nan(f32))));
138}
139
140test "cos64.special" {
141 try expect(math.isNan(cos(math.inf(f64))));
142 try expect(math.isNan(cos(-math.inf(f64))));
143 try expect(math.isNan(cos(math.nan(f64))));
144}
lib/std/special/compiler_rt/divxf3_test.zig+3-3
......@@ -30,9 +30,9 @@ fn test__divxf3(a: f80, b: f80) !void {
3030 const x_minus_eps = @bitCast(f80, (@bitCast(u80, x) - 1) | integerBit);
3131
3232 // Make sure result is more accurate than the adjacent floats
33 const err_x = std.math.fabs(@mulAdd(f80, x, b, -a));
34 const err_x_plus_eps = std.math.fabs(@mulAdd(f80, x_plus_eps, b, -a));
35 const err_x_minus_eps = std.math.fabs(@mulAdd(f80, x_minus_eps, b, -a));
33 const err_x = @fabs(@mulAdd(f80, x, b, -a));
34 const err_x_plus_eps = @fabs(@mulAdd(f80, x_plus_eps, b, -a));
35 const err_x_minus_eps = @fabs(@mulAdd(f80, x_minus_eps, b, -a));
3636
3737 try testing.expect(err_x_minus_eps > err_x);
3838 try testing.expect(err_x_plus_eps > err_x);
lib/std/special/compiler_rt/exp.zig created+213
......@@ -0,0 +1,213 @@
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/expf.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/exp.c
6
7const std = @import("std");
8const math = std.math;
9const expect = std.testing.expect;
10
11pub fn __exph(a: f16) callconv(.C) f16 {
12 // TODO: more efficient implementation
13 return @floatCast(f16, expf(a));
14}
15
16pub fn expf(x_: f32) callconv(.C) f32 {
17 const half = [_]f32{ 0.5, -0.5 };
18 const ln2hi = 6.9314575195e-1;
19 const ln2lo = 1.4286067653e-6;
20 const invln2 = 1.4426950216e+0;
21 const P1 = 1.6666625440e-1;
22 const P2 = -2.7667332906e-3;
23
24 var x = x_;
25 var hx = @bitCast(u32, x);
26 const sign = @intCast(i32, hx >> 31);
27 hx &= 0x7FFFFFFF;
28
29 if (math.isNan(x)) {
30 return x;
31 }
32
33 // |x| >= -87.33655 or nan
34 if (hx >= 0x42AEAC50) {
35 // nan
36 if (hx > 0x7F800000) {
37 return x;
38 }
39 // x >= 88.722839
40 if (hx >= 0x42b17218 and sign == 0) {
41 return x * 0x1.0p127;
42 }
43 if (sign != 0) {
44 math.doNotOptimizeAway(-0x1.0p-149 / x); // overflow
45 // x <= -103.972084
46 if (hx >= 0x42CFF1B5) {
47 return 0;
48 }
49 }
50 }
51
52 var k: i32 = undefined;
53 var hi: f32 = undefined;
54 var lo: f32 = undefined;
55
56 // |x| > 0.5 * ln2
57 if (hx > 0x3EB17218) {
58 // |x| > 1.5 * ln2
59 if (hx > 0x3F851592) {
60 k = @floatToInt(i32, invln2 * x + half[@intCast(usize, sign)]);
61 } else {
62 k = 1 - sign - sign;
63 }
64
65 const fk = @intToFloat(f32, k);
66 hi = x - fk * ln2hi;
67 lo = fk * ln2lo;
68 x = hi - lo;
69 }
70 // |x| > 2^(-14)
71 else if (hx > 0x39000000) {
72 k = 0;
73 hi = x;
74 lo = 0;
75 } else {
76 math.doNotOptimizeAway(0x1.0p127 + x); // inexact
77 return 1 + x;
78 }
79
80 const xx = x * x;
81 const c = x - xx * (P1 + xx * P2);
82 const y = 1 + (x * c / (2 - c) - lo + hi);
83
84 if (k == 0) {
85 return y;
86 } else {
87 return math.scalbn(y, k);
88 }
89}
90
91pub fn exp(x_: f64) callconv(.C) f64 {
92 const half = [_]f64{ 0.5, -0.5 };
93 const ln2hi: f64 = 6.93147180369123816490e-01;
94 const ln2lo: f64 = 1.90821492927058770002e-10;
95 const invln2: f64 = 1.44269504088896338700e+00;
96 const P1: f64 = 1.66666666666666019037e-01;
97 const P2: f64 = -2.77777777770155933842e-03;
98 const P3: f64 = 6.61375632143793436117e-05;
99 const P4: f64 = -1.65339022054652515390e-06;
100 const P5: f64 = 4.13813679705723846039e-08;
101
102 var x = x_;
103 var ux = @bitCast(u64, x);
104 var hx = ux >> 32;
105 const sign = @intCast(i32, hx >> 31);
106 hx &= 0x7FFFFFFF;
107
108 if (math.isNan(x)) {
109 return x;
110 }
111
112 // |x| >= 708.39 or nan
113 if (hx >= 0x4086232B) {
114 // nan
115 if (hx > 0x7FF00000) {
116 return x;
117 }
118 if (x > 709.782712893383973096) {
119 // overflow if x != inf
120 if (!math.isInf(x)) {
121 math.raiseOverflow();
122 }
123 return math.inf(f64);
124 }
125 if (x < -708.39641853226410622) {
126 // underflow if x != -inf
127 // math.doNotOptimizeAway(@as(f32, -0x1.0p-149 / x));
128 if (x < -745.13321910194110842) {
129 return 0;
130 }
131 }
132 }
133
134 // argument reduction
135 var k: i32 = undefined;
136 var hi: f64 = undefined;
137 var lo: f64 = undefined;
138
139 // |x| > 0.5 * ln2
140 if (hx > 0x3FD62E42) {
141 // |x| >= 1.5 * ln2
142 if (hx > 0x3FF0A2B2) {
143 k = @floatToInt(i32, invln2 * x + half[@intCast(usize, sign)]);
144 } else {
145 k = 1 - sign - sign;
146 }
147
148 const dk = @intToFloat(f64, k);
149 hi = x - dk * ln2hi;
150 lo = dk * ln2lo;
151 x = hi - lo;
152 }
153 // |x| > 2^(-28)
154 else if (hx > 0x3E300000) {
155 k = 0;
156 hi = x;
157 lo = 0;
158 } else {
159 // inexact if x != 0
160 // math.doNotOptimizeAway(0x1.0p1023 + x);
161 return 1 + x;
162 }
163
164 const xx = x * x;
165 const c = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5))));
166 const y = 1 + (x * c / (2 - c) - lo + hi);
167
168 if (k == 0) {
169 return y;
170 } else {
171 return math.scalbn(y, k);
172 }
173}
174
175pub fn __expx(a: f80) callconv(.C) f80 {
176 // TODO: more efficient implementation
177 return @floatCast(f80, expq(a));
178}
179
180pub fn expq(a: f128) callconv(.C) f128 {
181 // TODO: more correct implementation
182 return exp(@floatCast(f64, a));
183}
184
185test "exp32" {
186 const epsilon = 0.000001;
187
188 try expect(expf(0.0) == 1.0);
189 try expect(math.approxEqAbs(f32, expf(0.0), 1.0, epsilon));
190 try expect(math.approxEqAbs(f32, expf(0.2), 1.221403, epsilon));
191 try expect(math.approxEqAbs(f32, expf(0.8923), 2.440737, epsilon));
192 try expect(math.approxEqAbs(f32, expf(1.5), 4.481689, epsilon));
193}
194
195test "exp64" {
196 const epsilon = 0.000001;
197
198 try expect(exp(0.0) == 1.0);
199 try expect(math.approxEqAbs(f64, exp(0.0), 1.0, epsilon));
200 try expect(math.approxEqAbs(f64, exp(0.2), 1.221403, epsilon));
201 try expect(math.approxEqAbs(f64, exp(0.8923), 2.440737, epsilon));
202 try expect(math.approxEqAbs(f64, exp(1.5), 4.481689, epsilon));
203}
204
205test "exp32.special" {
206 try expect(math.isPositiveInf(expf(math.inf(f32))));
207 try expect(math.isNan(expf(math.nan(f32))));
208}
209
210test "exp64.special" {
211 try expect(math.isPositiveInf(exp(math.inf(f64))));
212 try expect(math.isNan(exp(math.nan(f64))));
213}
lib/std/special/compiler_rt/exp2.zig created+461
......@@ -0,0 +1,461 @@
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/exp2f.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/exp2.c
6
7const std = @import("std");
8const math = std.math;
9const expect = std.testing.expect;
10
11pub fn __exp2h(x: f16) callconv(.C) f16 {
12 // TODO: more efficient implementation
13 return @floatCast(f16, exp2f(x));
14}
15
16pub fn exp2f(x: f32) callconv(.C) f32 {
17 const tblsiz = @intCast(u32, exp2ft.len);
18 const redux: f32 = 0x1.8p23 / @intToFloat(f32, tblsiz);
19 const P1: f32 = 0x1.62e430p-1;
20 const P2: f32 = 0x1.ebfbe0p-3;
21 const P3: f32 = 0x1.c6b348p-5;
22 const P4: f32 = 0x1.3b2c9cp-7;
23
24 var u = @bitCast(u32, x);
25 const ix = u & 0x7FFFFFFF;
26
27 // |x| > 126
28 if (ix > 0x42FC0000) {
29 // nan
30 if (ix > 0x7F800000) {
31 return x;
32 }
33 // x >= 128
34 if (u >= 0x43000000 and u < 0x80000000) {
35 return x * 0x1.0p127;
36 }
37 // x < -126
38 if (u >= 0x80000000) {
39 if (u >= 0xC3160000 or u & 0x000FFFF != 0) {
40 math.doNotOptimizeAway(-0x1.0p-149 / x);
41 }
42 // x <= -150
43 if (u >= 0x3160000) {
44 return 0;
45 }
46 }
47 }
48 // |x| <= 0x1p-25
49 else if (ix <= 0x33000000) {
50 return 1.0 + x;
51 }
52
53 // NOTE: musl relies on unsafe behaviours which are replicated below
54 // (addition/bit-shift overflow). Appears that this produces the
55 // intended result but should confirm how GCC/Clang handle this to ensure.
56
57 var uf = x + redux;
58 var i_0 = @bitCast(u32, uf);
59 i_0 +%= tblsiz / 2;
60
61 const k = i_0 / tblsiz;
62 const uk = @bitCast(f64, @as(u64, 0x3FF + k) << 52);
63 i_0 &= tblsiz - 1;
64 uf -= redux;
65
66 const z: f64 = x - uf;
67 var r: f64 = exp2ft[@intCast(usize, i_0)];
68 const t: f64 = r * z;
69 r = r + t * (P1 + z * P2) + t * (z * z) * (P3 + z * P4);
70 return @floatCast(f32, r * uk);
71}
72
73pub fn exp2(x: f64) callconv(.C) f64 {
74 const tblsiz: u32 = @intCast(u32, exp2dt.len / 2);
75 const redux: f64 = 0x1.8p52 / @intToFloat(f64, tblsiz);
76 const P1: f64 = 0x1.62e42fefa39efp-1;
77 const P2: f64 = 0x1.ebfbdff82c575p-3;
78 const P3: f64 = 0x1.c6b08d704a0a6p-5;
79 const P4: f64 = 0x1.3b2ab88f70400p-7;
80 const P5: f64 = 0x1.5d88003875c74p-10;
81
82 const ux = @bitCast(u64, x);
83 const ix = @intCast(u32, ux >> 32) & 0x7FFFFFFF;
84
85 // TODO: This should be handled beneath.
86 if (math.isNan(x)) {
87 return math.nan(f64);
88 }
89
90 // |x| >= 1022 or nan
91 if (ix >= 0x408FF000) {
92 // x >= 1024 or nan
93 if (ix >= 0x40900000 and ux >> 63 == 0) {
94 math.raiseOverflow();
95 return math.inf(f64);
96 }
97 // -inf or -nan
98 if (ix >= 0x7FF00000) {
99 return -1 / x;
100 }
101 // x <= -1022
102 if (ux >> 63 != 0) {
103 // underflow
104 if (x <= -1075 or x - 0x1.0p52 + 0x1.0p52 != x) {
105 math.doNotOptimizeAway(@floatCast(f32, -0x1.0p-149 / x));
106 }
107 if (x <= -1075) {
108 return 0;
109 }
110 }
111 }
112 // |x| < 0x1p-54
113 else if (ix < 0x3C900000) {
114 return 1.0 + x;
115 }
116
117 // NOTE: musl relies on unsafe behaviours which are replicated below
118 // (addition overflow, division truncation, casting). Appears that this
119 // produces the intended result but should confirm how GCC/Clang handle this
120 // to ensure.
121
122 // reduce x
123 var uf: f64 = x + redux;
124 // NOTE: musl performs an implicit 64-bit to 32-bit u32 truncation here
125 var i_0: u32 = @truncate(u32, @bitCast(u64, uf));
126 i_0 +%= tblsiz / 2;
127
128 const k: u32 = i_0 / tblsiz * tblsiz;
129 const ik: i32 = @divTrunc(@bitCast(i32, k), tblsiz);
130 i_0 %= tblsiz;
131 uf -= redux;
132
133 // r = exp2(y) = exp2t[i_0] * p(z - eps[i])
134 var z: f64 = x - uf;
135 const t: f64 = exp2dt[@intCast(usize, 2 * i_0)];
136 z -= exp2dt[@intCast(usize, 2 * i_0 + 1)];
137 const r: f64 = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5))));
138
139 return math.scalbn(r, ik);
140}
141
142pub fn __exp2x(x: f80) callconv(.C) f80 {
143 // TODO: more efficient implementation
144 return @floatCast(f80, exp2q(x));
145}
146
147pub fn exp2q(x: f128) callconv(.C) f128 {
148 // TODO: more correct implementation
149 return exp2(@floatCast(f64, x));
150}
151
152const exp2ft = [_]f64{
153 0x1.6a09e667f3bcdp-1,
154 0x1.7a11473eb0187p-1,
155 0x1.8ace5422aa0dbp-1,
156 0x1.9c49182a3f090p-1,
157 0x1.ae89f995ad3adp-1,
158 0x1.c199bdd85529cp-1,
159 0x1.d5818dcfba487p-1,
160 0x1.ea4afa2a490dap-1,
161 0x1.0000000000000p+0,
162 0x1.0b5586cf9890fp+0,
163 0x1.172b83c7d517bp+0,
164 0x1.2387a6e756238p+0,
165 0x1.306fe0a31b715p+0,
166 0x1.3dea64c123422p+0,
167 0x1.4bfdad5362a27p+0,
168 0x1.5ab07dd485429p+0,
169};
170
171const exp2dt = [_]f64{
172 // exp2(z + eps) eps
173 0x1.6a09e667f3d5dp-1, 0x1.9880p-44,
174 0x1.6b052fa751744p-1, 0x1.8000p-50,
175 0x1.6c012750bd9fep-1, -0x1.8780p-45,
176 0x1.6cfdcddd476bfp-1, 0x1.ec00p-46,
177 0x1.6dfb23c651a29p-1, -0x1.8000p-50,
178 0x1.6ef9298593ae3p-1, -0x1.c000p-52,
179 0x1.6ff7df9519386p-1, -0x1.fd80p-45,
180 0x1.70f7466f42da3p-1, -0x1.c880p-45,
181 0x1.71f75e8ec5fc3p-1, 0x1.3c00p-46,
182 0x1.72f8286eacf05p-1, -0x1.8300p-44,
183 0x1.73f9a48a58152p-1, -0x1.0c00p-47,
184 0x1.74fbd35d7ccfcp-1, 0x1.f880p-45,
185 0x1.75feb564267f1p-1, 0x1.3e00p-47,
186 0x1.77024b1ab6d48p-1, -0x1.7d00p-45,
187 0x1.780694fde5d38p-1, -0x1.d000p-50,
188 0x1.790b938ac1d00p-1, 0x1.3000p-49,
189 0x1.7a11473eb0178p-1, -0x1.d000p-49,
190 0x1.7b17b0976d060p-1, 0x1.0400p-45,
191 0x1.7c1ed0130c133p-1, 0x1.0000p-53,
192 0x1.7d26a62ff8636p-1, -0x1.6900p-45,
193 0x1.7e2f336cf4e3bp-1, -0x1.2e00p-47,
194 0x1.7f3878491c3e8p-1, -0x1.4580p-45,
195 0x1.80427543e1b4ep-1, 0x1.3000p-44,
196 0x1.814d2add1071ap-1, 0x1.f000p-47,
197 0x1.82589994ccd7ep-1, -0x1.1c00p-45,
198 0x1.8364c1eb942d0p-1, 0x1.9d00p-45,
199 0x1.8471a4623cab5p-1, 0x1.7100p-43,
200 0x1.857f4179f5bbcp-1, 0x1.2600p-45,
201 0x1.868d99b4491afp-1, -0x1.2c40p-44,
202 0x1.879cad931a395p-1, -0x1.3000p-45,
203 0x1.88ac7d98a65b8p-1, -0x1.a800p-45,
204 0x1.89bd0a4785800p-1, -0x1.d000p-49,
205 0x1.8ace5422aa223p-1, 0x1.3280p-44,
206 0x1.8be05bad619fap-1, 0x1.2b40p-43,
207 0x1.8cf3216b54383p-1, -0x1.ed00p-45,
208 0x1.8e06a5e08664cp-1, -0x1.0500p-45,
209 0x1.8f1ae99157807p-1, 0x1.8280p-45,
210 0x1.902fed0282c0ep-1, -0x1.cb00p-46,
211 0x1.9145b0b91ff96p-1, -0x1.5e00p-47,
212 0x1.925c353aa2ff9p-1, 0x1.5400p-48,
213 0x1.93737b0cdc64ap-1, 0x1.7200p-46,
214 0x1.948b82b5f98aep-1, -0x1.9000p-47,
215 0x1.95a44cbc852cbp-1, 0x1.5680p-45,
216 0x1.96bdd9a766f21p-1, -0x1.6d00p-44,
217 0x1.97d829fde4e2ap-1, -0x1.1000p-47,
218 0x1.98f33e47a23a3p-1, 0x1.d000p-45,
219 0x1.9a0f170ca0604p-1, -0x1.8a40p-44,
220 0x1.9b2bb4d53ff89p-1, 0x1.55c0p-44,
221 0x1.9c49182a3f15bp-1, 0x1.6b80p-45,
222 0x1.9d674194bb8c5p-1, -0x1.c000p-49,
223 0x1.9e86319e3238ep-1, 0x1.7d00p-46,
224 0x1.9fa5e8d07f302p-1, 0x1.6400p-46,
225 0x1.a0c667b5de54dp-1, -0x1.5000p-48,
226 0x1.a1e7aed8eb8f6p-1, 0x1.9e00p-47,
227 0x1.a309bec4a2e27p-1, 0x1.ad80p-45,
228 0x1.a42c980460a5dp-1, -0x1.af00p-46,
229 0x1.a5503b23e259bp-1, 0x1.b600p-47,
230 0x1.a674a8af46213p-1, 0x1.8880p-44,
231 0x1.a799e1330b3a7p-1, 0x1.1200p-46,
232 0x1.a8bfe53c12e8dp-1, 0x1.6c00p-47,
233 0x1.a9e6b5579fcd2p-1, -0x1.9b80p-45,
234 0x1.ab0e521356fb8p-1, 0x1.b700p-45,
235 0x1.ac36bbfd3f381p-1, 0x1.9000p-50,
236 0x1.ad5ff3a3c2780p-1, 0x1.4000p-49,
237 0x1.ae89f995ad2a3p-1, -0x1.c900p-45,
238 0x1.afb4ce622f367p-1, 0x1.6500p-46,
239 0x1.b0e07298db790p-1, 0x1.fd40p-45,
240 0x1.b20ce6c9a89a9p-1, 0x1.2700p-46,
241 0x1.b33a2b84f1a4bp-1, 0x1.d470p-43,
242 0x1.b468415b747e7p-1, -0x1.8380p-44,
243 0x1.b59728de5593ap-1, 0x1.8000p-54,
244 0x1.b6c6e29f1c56ap-1, 0x1.ad00p-47,
245 0x1.b7f76f2fb5e50p-1, 0x1.e800p-50,
246 0x1.b928cf22749b2p-1, -0x1.4c00p-47,
247 0x1.ba5b030a10603p-1, -0x1.d700p-47,
248 0x1.bb8e0b79a6f66p-1, 0x1.d900p-47,
249 0x1.bcc1e904bc1ffp-1, 0x1.2a00p-47,
250 0x1.bdf69c3f3a16fp-1, -0x1.f780p-46,
251 0x1.bf2c25bd71db8p-1, -0x1.0a00p-46,
252 0x1.c06286141b2e9p-1, -0x1.1400p-46,
253 0x1.c199bdd8552e0p-1, 0x1.be00p-47,
254 0x1.c2d1cd9fa64eep-1, -0x1.9400p-47,
255 0x1.c40ab5fffd02fp-1, -0x1.ed00p-47,
256 0x1.c544778fafd15p-1, 0x1.9660p-44,
257 0x1.c67f12e57d0cbp-1, -0x1.a100p-46,
258 0x1.c7ba88988c1b6p-1, -0x1.8458p-42,
259 0x1.c8f6d9406e733p-1, -0x1.a480p-46,
260 0x1.ca3405751c4dfp-1, 0x1.b000p-51,
261 0x1.cb720dcef9094p-1, 0x1.1400p-47,
262 0x1.ccb0f2e6d1689p-1, 0x1.0200p-48,
263 0x1.cdf0b555dc412p-1, 0x1.3600p-48,
264 0x1.cf3155b5bab3bp-1, -0x1.6900p-47,
265 0x1.d072d4a0789bcp-1, 0x1.9a00p-47,
266 0x1.d1b532b08c8fap-1, -0x1.5e00p-46,
267 0x1.d2f87080d8a85p-1, 0x1.d280p-46,
268 0x1.d43c8eacaa203p-1, 0x1.1a00p-47,
269 0x1.d5818dcfba491p-1, 0x1.f000p-50,
270 0x1.d6c76e862e6a1p-1, -0x1.3a00p-47,
271 0x1.d80e316c9834ep-1, -0x1.cd80p-47,
272 0x1.d955d71ff6090p-1, 0x1.4c00p-48,
273 0x1.da9e603db32aep-1, 0x1.f900p-48,
274 0x1.dbe7cd63a8325p-1, 0x1.9800p-49,
275 0x1.dd321f301b445p-1, -0x1.5200p-48,
276 0x1.de7d5641c05bfp-1, -0x1.d700p-46,
277 0x1.dfc97337b9aecp-1, -0x1.6140p-46,
278 0x1.e11676b197d5ep-1, 0x1.b480p-47,
279 0x1.e264614f5a3e7p-1, 0x1.0ce0p-43,
280 0x1.e3b333b16ee5cp-1, 0x1.c680p-47,
281 0x1.e502ee78b3fb4p-1, -0x1.9300p-47,
282 0x1.e653924676d68p-1, -0x1.5000p-49,
283 0x1.e7a51fbc74c44p-1, -0x1.7f80p-47,
284 0x1.e8f7977cdb726p-1, -0x1.3700p-48,
285 0x1.ea4afa2a490e8p-1, 0x1.5d00p-49,
286 0x1.eb9f4867ccae4p-1, 0x1.61a0p-46,
287 0x1.ecf482d8e680dp-1, 0x1.5500p-48,
288 0x1.ee4aaa2188514p-1, 0x1.6400p-51,
289 0x1.efa1bee615a13p-1, -0x1.e800p-49,
290 0x1.f0f9c1cb64106p-1, -0x1.a880p-48,
291 0x1.f252b376bb963p-1, -0x1.c900p-45,
292 0x1.f3ac948dd7275p-1, 0x1.a000p-53,
293 0x1.f50765b6e4524p-1, -0x1.4f00p-48,
294 0x1.f6632798844fdp-1, 0x1.a800p-51,
295 0x1.f7bfdad9cbe38p-1, 0x1.abc0p-48,
296 0x1.f91d802243c82p-1, -0x1.4600p-50,
297 0x1.fa7c1819e908ep-1, -0x1.b0c0p-47,
298 0x1.fbdba3692d511p-1, -0x1.0e00p-51,
299 0x1.fd3c22b8f7194p-1, -0x1.0de8p-46,
300 0x1.fe9d96b2a23eep-1, 0x1.e430p-49,
301 0x1.0000000000000p+0, 0x0.0000p+0,
302 0x1.00b1afa5abcbep+0, -0x1.3400p-52,
303 0x1.0163da9fb3303p+0, -0x1.2170p-46,
304 0x1.02168143b0282p+0, 0x1.a400p-52,
305 0x1.02c9a3e77806cp+0, 0x1.f980p-49,
306 0x1.037d42e11bbcap+0, -0x1.7400p-51,
307 0x1.04315e86e7f89p+0, 0x1.8300p-50,
308 0x1.04e5f72f65467p+0, -0x1.a3f0p-46,
309 0x1.059b0d315855ap+0, -0x1.2840p-47,
310 0x1.0650a0e3c1f95p+0, 0x1.1600p-48,
311 0x1.0706b29ddf71ap+0, 0x1.5240p-46,
312 0x1.07bd42b72a82dp+0, -0x1.9a00p-49,
313 0x1.0874518759bd0p+0, 0x1.6400p-49,
314 0x1.092bdf66607c8p+0, -0x1.0780p-47,
315 0x1.09e3ecac6f383p+0, -0x1.8000p-54,
316 0x1.0a9c79b1f3930p+0, 0x1.fa00p-48,
317 0x1.0b5586cf988fcp+0, -0x1.ac80p-48,
318 0x1.0c0f145e46c8ap+0, 0x1.9c00p-50,
319 0x1.0cc922b724816p+0, 0x1.5200p-47,
320 0x1.0d83b23395dd8p+0, -0x1.ad00p-48,
321 0x1.0e3ec32d3d1f3p+0, 0x1.bac0p-46,
322 0x1.0efa55fdfa9a6p+0, -0x1.4e80p-47,
323 0x1.0fb66affed2f0p+0, -0x1.d300p-47,
324 0x1.1073028d7234bp+0, 0x1.1500p-48,
325 0x1.11301d0125b5bp+0, 0x1.c000p-49,
326 0x1.11edbab5e2af9p+0, 0x1.6bc0p-46,
327 0x1.12abdc06c31d5p+0, 0x1.8400p-49,
328 0x1.136a814f2047dp+0, -0x1.ed00p-47,
329 0x1.1429aaea92de9p+0, 0x1.8e00p-49,
330 0x1.14e95934f3138p+0, 0x1.b400p-49,
331 0x1.15a98c8a58e71p+0, 0x1.5300p-47,
332 0x1.166a45471c3dfp+0, 0x1.3380p-47,
333 0x1.172b83c7d5211p+0, 0x1.8d40p-45,
334 0x1.17ed48695bb9fp+0, -0x1.5d00p-47,
335 0x1.18af9388c8d93p+0, -0x1.c880p-46,
336 0x1.1972658375d66p+0, 0x1.1f00p-46,
337 0x1.1a35beb6fcba7p+0, 0x1.0480p-46,
338 0x1.1af99f81387e3p+0, -0x1.7390p-43,
339 0x1.1bbe084045d54p+0, 0x1.4e40p-45,
340 0x1.1c82f95281c43p+0, -0x1.a200p-47,
341 0x1.1d4873168b9b2p+0, 0x1.3800p-49,
342 0x1.1e0e75eb44031p+0, 0x1.ac00p-49,
343 0x1.1ed5022fcd938p+0, 0x1.1900p-47,
344 0x1.1f9c18438cdf7p+0, -0x1.b780p-46,
345 0x1.2063b88628d8fp+0, 0x1.d940p-45,
346 0x1.212be3578a81ep+0, 0x1.8000p-50,
347 0x1.21f49917ddd41p+0, 0x1.b340p-45,
348 0x1.22bdda2791323p+0, 0x1.9f80p-46,
349 0x1.2387a6e7561e7p+0, -0x1.9c80p-46,
350 0x1.2451ffb821427p+0, 0x1.2300p-47,
351 0x1.251ce4fb2a602p+0, -0x1.3480p-46,
352 0x1.25e85711eceb0p+0, 0x1.2700p-46,
353 0x1.26b4565e27d16p+0, 0x1.1d00p-46,
354 0x1.2780e341de00fp+0, 0x1.1ee0p-44,
355 0x1.284dfe1f5633ep+0, -0x1.4c00p-46,
356 0x1.291ba7591bb30p+0, -0x1.3d80p-46,
357 0x1.29e9df51fdf09p+0, 0x1.8b00p-47,
358 0x1.2ab8a66d10e9bp+0, -0x1.27c0p-45,
359 0x1.2b87fd0dada3ap+0, 0x1.a340p-45,
360 0x1.2c57e39771af9p+0, -0x1.0800p-46,
361 0x1.2d285a6e402d9p+0, -0x1.ed00p-47,
362 0x1.2df961f641579p+0, -0x1.4200p-48,
363 0x1.2ecafa93e2ecfp+0, -0x1.4980p-45,
364 0x1.2f9d24abd8822p+0, -0x1.6300p-46,
365 0x1.306fe0a31b625p+0, -0x1.2360p-44,
366 0x1.31432edeea50bp+0, -0x1.0df8p-40,
367 0x1.32170fc4cd7b8p+0, -0x1.2480p-45,
368 0x1.32eb83ba8e9a2p+0, -0x1.5980p-45,
369 0x1.33c08b2641766p+0, 0x1.ed00p-46,
370 0x1.3496266e3fa27p+0, -0x1.c000p-50,
371 0x1.356c55f929f0fp+0, -0x1.0d80p-44,
372 0x1.36431a2de88b9p+0, 0x1.2c80p-45,
373 0x1.371a7373aaa39p+0, 0x1.0600p-45,
374 0x1.37f26231e74fep+0, -0x1.6600p-46,
375 0x1.38cae6d05d838p+0, -0x1.ae00p-47,
376 0x1.39a401b713ec3p+0, -0x1.4720p-43,
377 0x1.3a7db34e5a020p+0, 0x1.8200p-47,
378 0x1.3b57fbfec6e95p+0, 0x1.e800p-44,
379 0x1.3c32dc313a8f2p+0, 0x1.f800p-49,
380 0x1.3d0e544ede122p+0, -0x1.7a00p-46,
381 0x1.3dea64c1234bbp+0, 0x1.6300p-45,
382 0x1.3ec70df1c4eccp+0, -0x1.8a60p-43,
383 0x1.3fa4504ac7e8cp+0, -0x1.cdc0p-44,
384 0x1.40822c367a0bbp+0, 0x1.5b80p-45,
385 0x1.4160a21f72e95p+0, 0x1.ec00p-46,
386 0x1.423fb27094646p+0, -0x1.3600p-46,
387 0x1.431f5d950a920p+0, 0x1.3980p-45,
388 0x1.43ffa3f84b9ebp+0, 0x1.a000p-48,
389 0x1.44e0860618919p+0, -0x1.6c00p-48,
390 0x1.45c2042a7d201p+0, -0x1.bc00p-47,
391 0x1.46a41ed1d0016p+0, -0x1.2800p-46,
392 0x1.4786d668b3326p+0, 0x1.0e00p-44,
393 0x1.486a2b5c13c00p+0, -0x1.d400p-45,
394 0x1.494e1e192af04p+0, 0x1.c200p-47,
395 0x1.4a32af0d7d372p+0, -0x1.e500p-46,
396 0x1.4b17dea6db801p+0, 0x1.7800p-47,
397 0x1.4bfdad53629e1p+0, -0x1.3800p-46,
398 0x1.4ce41b817c132p+0, 0x1.0800p-47,
399 0x1.4dcb299fddddbp+0, 0x1.c700p-45,
400 0x1.4eb2d81d8ab96p+0, -0x1.ce00p-46,
401 0x1.4f9b2769d2d02p+0, 0x1.9200p-46,
402 0x1.508417f4531c1p+0, -0x1.8c00p-47,
403 0x1.516daa2cf662ap+0, -0x1.a000p-48,
404 0x1.5257de83f51eap+0, 0x1.a080p-43,
405 0x1.5342b569d4edap+0, -0x1.6d80p-45,
406 0x1.542e2f4f6ac1ap+0, -0x1.2440p-44,
407 0x1.551a4ca5d94dbp+0, 0x1.83c0p-43,
408 0x1.56070dde9116bp+0, 0x1.4b00p-45,
409 0x1.56f4736b529dep+0, 0x1.15a0p-43,
410 0x1.57e27dbe2c40ep+0, -0x1.9e00p-45,
411 0x1.58d12d497c76fp+0, -0x1.3080p-45,
412 0x1.59c0827ff0b4cp+0, 0x1.dec0p-43,
413 0x1.5ab07dd485427p+0, -0x1.4000p-51,
414 0x1.5ba11fba87af4p+0, 0x1.0080p-44,
415 0x1.5c9268a59460bp+0, -0x1.6c80p-45,
416 0x1.5d84590998e3fp+0, 0x1.69a0p-43,
417 0x1.5e76f15ad20e1p+0, -0x1.b400p-46,
418 0x1.5f6a320dcebcap+0, 0x1.7700p-46,
419 0x1.605e1b976dcb8p+0, 0x1.6f80p-45,
420 0x1.6152ae6cdf715p+0, 0x1.1000p-47,
421 0x1.6247eb03a5531p+0, -0x1.5d00p-46,
422 0x1.633dd1d1929b5p+0, -0x1.2d00p-46,
423 0x1.6434634ccc313p+0, -0x1.a800p-49,
424 0x1.652b9febc8efap+0, -0x1.8600p-45,
425 0x1.6623882553397p+0, 0x1.1fe0p-40,
426 0x1.671c1c708328ep+0, -0x1.7200p-44,
427 0x1.68155d44ca97ep+0, 0x1.6800p-49,
428 0x1.690f4b19e9471p+0, -0x1.9780p-45,
429};
430
431test "exp2_32" {
432 const epsilon = 0.000001;
433
434 try expect(exp2f(0.0) == 1.0);
435 try expect(math.approxEqAbs(f32, exp2f(0.2), 1.148698, epsilon));
436 try expect(math.approxEqAbs(f32, exp2f(0.8923), 1.856133, epsilon));
437 try expect(math.approxEqAbs(f32, exp2f(1.5), 2.828427, epsilon));
438 try expect(math.approxEqAbs(f32, exp2f(37.45), 187747237888, epsilon));
439 try expect(math.approxEqAbs(f32, exp2f(-1), 0.5, epsilon));
440}
441
442test "exp2_64" {
443 const epsilon = 0.000001;
444
445 try expect(exp2(0.0) == 1.0);
446 try expect(math.approxEqAbs(f64, exp2(0.2), 1.148698, epsilon));
447 try expect(math.approxEqAbs(f64, exp2(0.8923), 1.856133, epsilon));
448 try expect(math.approxEqAbs(f64, exp2(1.5), 2.828427, epsilon));
449 try expect(math.approxEqAbs(f64, exp2(-1), 0.5, epsilon));
450 try expect(math.approxEqAbs(f64, exp2(-0x1.a05cc754481d1p-2), 0x1.824056efc687cp-1, epsilon));
451}
452
453test "exp2_32.special" {
454 try expect(math.isPositiveInf(exp2f(math.inf(f32))));
455 try expect(math.isNan(exp2f(math.nan(f32))));
456}
457
458test "exp2_64.special" {
459 try expect(math.isPositiveInf(exp2(math.inf(f64))));
460 try expect(math.isNan(exp2(math.nan(f64))));
461}
lib/std/special/compiler_rt/fabs.zig created+29
......@@ -0,0 +1,29 @@
1const std = @import("std");
2
3pub fn __fabsh(a: f16) callconv(.C) f16 {
4 return generic_fabs(a);
5}
6
7pub fn fabsf(a: f32) callconv(.C) f32 {
8 return generic_fabs(a);
9}
10
11pub fn fabs(a: f64) callconv(.C) f64 {
12 return generic_fabs(a);
13}
14
15pub fn __fabsx(a: f80) callconv(.C) f80 {
16 return generic_fabs(a);
17}
18
19pub fn fabsq(a: f128) callconv(.C) f128 {
20 return generic_fabs(a);
21}
22
23inline fn generic_fabs(x: anytype) @TypeOf(x) {
24 const T = @TypeOf(x);
25 const TBits = std.meta.Int(.unsigned, @typeInfo(T).Float.bits);
26 const float_bits = @bitCast(TBits, x);
27 const remove_sign = ~@as(TBits, 0) >> 1;
28 return @bitCast(T, float_bits & remove_sign);
29}
lib/std/special/compiler_rt/floor.zig created+198
......@@ -0,0 +1,198 @@
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/floorf.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/floor.c
6
7const std = @import("std");
8const math = std.math;
9const expect = std.testing.expect;
10
11pub fn __floorh(x: f16) callconv(.C) f16 {
12 var u = @bitCast(u16, x);
13 const e = @intCast(i16, (u >> 10) & 31) - 15;
14 var m: u16 = undefined;
15
16 // TODO: Shouldn't need this explicit check.
17 if (x == 0.0) {
18 return x;
19 }
20
21 if (e >= 10) {
22 return x;
23 }
24
25 if (e >= 0) {
26 m = @as(u16, 1023) >> @intCast(u4, e);
27 if (u & m == 0) {
28 return x;
29 }
30 math.doNotOptimizeAway(x + 0x1.0p120);
31 if (u >> 15 != 0) {
32 u += m;
33 }
34 return @bitCast(f16, u & ~m);
35 } else {
36 math.doNotOptimizeAway(x + 0x1.0p120);
37 if (u >> 15 == 0) {
38 return 0.0;
39 } else {
40 return -1.0;
41 }
42 }
43}
44
45pub fn floorf(x: f32) callconv(.C) f32 {
46 var u = @bitCast(u32, x);
47 const e = @intCast(i32, (u >> 23) & 0xFF) - 0x7F;
48 var m: u32 = undefined;
49
50 // TODO: Shouldn't need this explicit check.
51 if (x == 0.0) {
52 return x;
53 }
54
55 if (e >= 23) {
56 return x;
57 }
58
59 if (e >= 0) {
60 m = @as(u32, 0x007FFFFF) >> @intCast(u5, e);
61 if (u & m == 0) {
62 return x;
63 }
64 math.doNotOptimizeAway(x + 0x1.0p120);
65 if (u >> 31 != 0) {
66 u += m;
67 }
68 return @bitCast(f32, u & ~m);
69 } else {
70 math.doNotOptimizeAway(x + 0x1.0p120);
71 if (u >> 31 == 0) {
72 return 0.0;
73 } else {
74 return -1.0;
75 }
76 }
77}
78
79pub fn floor(x: f64) callconv(.C) f64 {
80 const f64_toint = 1.0 / math.floatEps(f64);
81
82 const u = @bitCast(u64, x);
83 const e = (u >> 52) & 0x7FF;
84 var y: f64 = undefined;
85
86 if (e >= 0x3FF + 52 or x == 0) {
87 return x;
88 }
89
90 if (u >> 63 != 0) {
91 y = x - f64_toint + f64_toint - x;
92 } else {
93 y = x + f64_toint - f64_toint - x;
94 }
95
96 if (e <= 0x3FF - 1) {
97 math.doNotOptimizeAway(y);
98 if (u >> 63 != 0) {
99 return -1.0;
100 } else {
101 return 0.0;
102 }
103 } else if (y > 0) {
104 return x + y - 1;
105 } else {
106 return x + y;
107 }
108}
109
110pub fn __floorx(x: f80) callconv(.C) f80 {
111 // TODO: more efficient implementation
112 return @floatCast(f80, floorq(x));
113}
114
115pub fn floorq(x: f128) callconv(.C) f128 {
116 const f128_toint = 1.0 / math.floatEps(f128);
117
118 const u = @bitCast(u128, x);
119 const e = (u >> 112) & 0x7FFF;
120 var y: f128 = undefined;
121
122 if (e >= 0x3FFF + 112 or x == 0) return x;
123
124 if (u >> 127 != 0) {
125 y = x - f128_toint + f128_toint - x;
126 } else {
127 y = x + f128_toint - f128_toint - x;
128 }
129
130 if (e <= 0x3FFF - 1) {
131 math.doNotOptimizeAway(y);
132 if (u >> 127 != 0) {
133 return -1.0;
134 } else {
135 return 0.0;
136 }
137 } else if (y > 0) {
138 return x + y - 1;
139 } else {
140 return x + y;
141 }
142}
143
144test "floor16" {
145 try expect(__floorh(1.3) == 1.0);
146 try expect(__floorh(-1.3) == -2.0);
147 try expect(__floorh(0.2) == 0.0);
148}
149
150test "floor32" {
151 try expect(floorf(1.3) == 1.0);
152 try expect(floorf(-1.3) == -2.0);
153 try expect(floorf(0.2) == 0.0);
154}
155
156test "floor64" {
157 try expect(floor(1.3) == 1.0);
158 try expect(floor(-1.3) == -2.0);
159 try expect(floor(0.2) == 0.0);
160}
161
162test "floor128" {
163 try expect(floorq(1.3) == 1.0);
164 try expect(floorq(-1.3) == -2.0);
165 try expect(floorq(0.2) == 0.0);
166}
167
168test "floor16.special" {
169 try expect(__floorh(0.0) == 0.0);
170 try expect(__floorh(-0.0) == -0.0);
171 try expect(math.isPositiveInf(__floorh(math.inf(f16))));
172 try expect(math.isNegativeInf(__floorh(-math.inf(f16))));
173 try expect(math.isNan(__floorh(math.nan(f16))));
174}
175
176test "floor32.special" {
177 try expect(floorf(0.0) == 0.0);
178 try expect(floorf(-0.0) == -0.0);
179 try expect(math.isPositiveInf(floorf(math.inf(f32))));
180 try expect(math.isNegativeInf(floorf(-math.inf(f32))));
181 try expect(math.isNan(floorf(math.nan(f32))));
182}
183
184test "floor64.special" {
185 try expect(floor(0.0) == 0.0);
186 try expect(floor(-0.0) == -0.0);
187 try expect(math.isPositiveInf(floor(math.inf(f64))));
188 try expect(math.isNegativeInf(floor(-math.inf(f64))));
189 try expect(math.isNan(floor(math.nan(f64))));
190}
191
192test "floor128.special" {
193 try expect(floorq(0.0) == 0.0);
194 try expect(floorq(-0.0) == -0.0);
195 try expect(math.isPositiveInf(floorq(math.inf(f128))));
196 try expect(math.isNegativeInf(floorq(-math.inf(f128))));
197 try expect(math.isNan(floorq(math.nan(f128))));
198}
lib/std/special/compiler_rt/fma.zig created+327
......@@ -0,0 +1,327 @@
1// Ported from musl, which is MIT licensed:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//
4// https://git.musl-libc.org/cgit/musl/tree/src/math/fmal.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/fmaf.c
6// https://git.musl-libc.org/cgit/musl/tree/src/math/fma.c
7
8const std = @import("std");
9const math = std.math;
10const expect = std.testing.expect;
11
12pub fn __fmah(x: f16, y: f16, z: f16) callconv(.C) f16 {
13 // TODO: more efficient implementation
14 return @floatCast(f16, fmaf(x, y, z));
15}
16
17pub fn fmaf(x: f32, y: f32, z: f32) callconv(.C) f32 {
18 const xy = @as(f64, x) * y;
19 const xy_z = xy + z;
20 const u = @bitCast(u64, xy_z);
21 const e = (u >> 52) & 0x7FF;
22
23 if ((u & 0x1FFFFFFF) != 0x10000000 or e == 0x7FF or (xy_z - xy == z and xy_z - z == xy)) {
24 return @floatCast(f32, xy_z);
25 } else {
26 // TODO: Handle inexact case with double-rounding
27 return @floatCast(f32, xy_z);
28 }
29}
30
31/// NOTE: Upstream fma.c has been rewritten completely to raise fp exceptions more accurately.
32pub fn fma(x: f64, y: f64, z: f64) callconv(.C) f64 {
33 if (!math.isFinite(x) or !math.isFinite(y)) {
34 return x * y + z;
35 }
36 if (!math.isFinite(z)) {
37 return z;
38 }
39 if (x == 0.0 or y == 0.0) {
40 return x * y + z;
41 }
42 if (z == 0.0) {
43 return x * y;
44 }
45
46 const x1 = math.frexp(x);
47 var ex = x1.exponent;
48 var xs = x1.significand;
49 const x2 = math.frexp(y);
50 var ey = x2.exponent;
51 var ys = x2.significand;
52 const x3 = math.frexp(z);
53 var ez = x3.exponent;
54 var zs = x3.significand;
55
56 var spread = ex + ey - ez;
57 if (spread <= 53 * 2) {
58 zs = math.scalbn(zs, -spread);
59 } else {
60 zs = math.copysign(f64, math.floatMin(f64), zs);
61 }
62
63 const xy = dd_mul(xs, ys);
64 const r = dd_add(xy.hi, zs);
65 spread = ex + ey;
66
67 if (r.hi == 0.0) {
68 return xy.hi + zs + math.scalbn(xy.lo, spread);
69 }
70
71 const adj = add_adjusted(r.lo, xy.lo);
72 if (spread + math.ilogb(r.hi) > -1023) {
73 return math.scalbn(r.hi + adj, spread);
74 } else {
75 return add_and_denorm(r.hi, adj, spread);
76 }
77}
78
79pub fn __fmax(a: f80, b: f80, c: f80) callconv(.C) f80 {
80 // TODO: more efficient implementation
81 return @floatCast(f80, fmaq(a, b, c));
82}
83
84/// Fused multiply-add: Compute x * y + z with a single rounding error.
85///
86/// We use scaling to avoid overflow/underflow, along with the
87/// canonical precision-doubling technique adapted from:
88///
89/// Dekker, T. A Floating-Point Technique for Extending the
90/// Available Precision. Numer. Math. 18, 224-242 (1971).
91pub fn fmaq(x: f128, y: f128, z: f128) callconv(.C) f128 {
92 if (!math.isFinite(x) or !math.isFinite(y)) {
93 return x * y + z;
94 }
95 if (!math.isFinite(z)) {
96 return z;
97 }
98 if (x == 0.0 or y == 0.0) {
99 return x * y + z;
100 }
101 if (z == 0.0) {
102 return x * y;
103 }
104
105 const x1 = math.frexp(x);
106 var ex = x1.exponent;
107 var xs = x1.significand;
108 const x2 = math.frexp(y);
109 var ey = x2.exponent;
110 var ys = x2.significand;
111 const x3 = math.frexp(z);
112 var ez = x3.exponent;
113 var zs = x3.significand;
114
115 var spread = ex + ey - ez;
116 if (spread <= 113 * 2) {
117 zs = math.scalbn(zs, -spread);
118 } else {
119 zs = math.copysign(f128, math.floatMin(f128), zs);
120 }
121
122 const xy = dd_mul128(xs, ys);
123 const r = dd_add128(xy.hi, zs);
124 spread = ex + ey;
125
126 if (r.hi == 0.0) {
127 return xy.hi + zs + math.scalbn(xy.lo, spread);
128 }
129
130 const adj = add_adjusted128(r.lo, xy.lo);
131 if (spread + math.ilogb(r.hi) > -16383) {
132 return math.scalbn(r.hi + adj, spread);
133 } else {
134 return add_and_denorm128(r.hi, adj, spread);
135 }
136}
137
138const dd = struct {
139 hi: f64,
140 lo: f64,
141};
142
143fn dd_add(a: f64, b: f64) dd {
144 var ret: dd = undefined;
145 ret.hi = a + b;
146 const s = ret.hi - a;
147 ret.lo = (a - (ret.hi - s)) + (b - s);
148 return ret;
149}
150
151fn dd_mul(a: f64, b: f64) dd {
152 var ret: dd = undefined;
153 const split: f64 = 0x1.0p27 + 1.0;
154
155 var p = a * split;
156 var ha = a - p;
157 ha += p;
158 var la = a - ha;
159
160 p = b * split;
161 var hb = b - p;
162 hb += p;
163 var lb = b - hb;
164
165 p = ha * hb;
166 var q = ha * lb + la * hb;
167
168 ret.hi = p + q;
169 ret.lo = p - ret.hi + q + la * lb;
170 return ret;
171}
172
173fn add_adjusted(a: f64, b: f64) f64 {
174 var sum = dd_add(a, b);
175 if (sum.lo != 0) {
176 var uhii = @bitCast(u64, sum.hi);
177 if (uhii & 1 == 0) {
178 // hibits += copysign(1.0, sum.hi, sum.lo)
179 const uloi = @bitCast(u64, sum.lo);
180 uhii += 1 - ((uhii ^ uloi) >> 62);
181 sum.hi = @bitCast(f64, uhii);
182 }
183 }
184 return sum.hi;
185}
186
187fn add_and_denorm(a: f64, b: f64, scale: i32) f64 {
188 var sum = dd_add(a, b);
189 if (sum.lo != 0) {
190 var uhii = @bitCast(u64, sum.hi);
191 const bits_lost = -@intCast(i32, (uhii >> 52) & 0x7FF) - scale + 1;
192 if ((bits_lost != 1) == (uhii & 1 != 0)) {
193 const uloi = @bitCast(u64, sum.lo);
194 uhii += 1 - (((uhii ^ uloi) >> 62) & 2);
195 sum.hi = @bitCast(f64, uhii);
196 }
197 }
198 return math.scalbn(sum.hi, scale);
199}
200
201/// A struct that represents a floating-point number with twice the precision
202/// of f128. We maintain the invariant that "hi" stores the high-order
203/// bits of the result.
204const dd128 = struct {
205 hi: f128,
206 lo: f128,
207};
208
209/// Compute a+b exactly, returning the exact result in a struct dd. We assume
210/// that both a and b are finite, but make no assumptions about their relative
211/// magnitudes.
212fn dd_add128(a: f128, b: f128) dd128 {
213 var ret: dd128 = undefined;
214 ret.hi = a + b;
215 const s = ret.hi - a;
216 ret.lo = (a - (ret.hi - s)) + (b - s);
217 return ret;
218}
219
220/// Compute a+b, with a small tweak: The least significant bit of the
221/// result is adjusted into a sticky bit summarizing all the bits that
222/// were lost to rounding. This adjustment negates the effects of double
223/// rounding when the result is added to another number with a higher
224/// exponent. For an explanation of round and sticky bits, see any reference
225/// on FPU design, e.g.,
226///
227/// J. Coonen. An Implementation Guide to a Proposed Standard for
228/// Floating-Point Arithmetic. Computer, vol. 13, no. 1, Jan 1980.
229fn add_adjusted128(a: f128, b: f128) f128 {
230 var sum = dd_add128(a, b);
231 if (sum.lo != 0) {
232 var uhii = @bitCast(u128, sum.hi);
233 if (uhii & 1 == 0) {
234 // hibits += copysign(1.0, sum.hi, sum.lo)
235 const uloi = @bitCast(u128, sum.lo);
236 uhii += 1 - ((uhii ^ uloi) >> 126);
237 sum.hi = @bitCast(f128, uhii);
238 }
239 }
240 return sum.hi;
241}
242
243/// Compute ldexp(a+b, scale) with a single rounding error. It is assumed
244/// that the result will be subnormal, and care is taken to ensure that
245/// double rounding does not occur.
246fn add_and_denorm128(a: f128, b: f128, scale: i32) f128 {
247 var sum = dd_add128(a, b);
248 // If we are losing at least two bits of accuracy to denormalization,
249 // then the first lost bit becomes a round bit, and we adjust the
250 // lowest bit of sum.hi to make it a sticky bit summarizing all the
251 // bits in sum.lo. With the sticky bit adjusted, the hardware will
252 // break any ties in the correct direction.
253 //
254 // If we are losing only one bit to denormalization, however, we must
255 // break the ties manually.
256 if (sum.lo != 0) {
257 var uhii = @bitCast(u128, sum.hi);
258 const bits_lost = -@intCast(i32, (uhii >> 112) & 0x7FFF) - scale + 1;
259 if ((bits_lost != 1) == (uhii & 1 != 0)) {
260 const uloi = @bitCast(u128, sum.lo);
261 uhii += 1 - (((uhii ^ uloi) >> 126) & 2);
262 sum.hi = @bitCast(f128, uhii);
263 }
264 }
265 return math.scalbn(sum.hi, scale);
266}
267
268/// Compute a*b exactly, returning the exact result in a struct dd. We assume
269/// that both a and b are normalized, so no underflow or overflow will occur.
270/// The current rounding mode must be round-to-nearest.
271fn dd_mul128(a: f128, b: f128) dd128 {
272 var ret: dd128 = undefined;
273 const split: f128 = 0x1.0p57 + 1.0;
274
275 var p = a * split;
276 var ha = a - p;
277 ha += p;
278 var la = a - ha;
279
280 p = b * split;
281 var hb = b - p;
282 hb += p;
283 var lb = b - hb;
284
285 p = ha * hb;
286 var q = ha * lb + la * hb;
287
288 ret.hi = p + q;
289 ret.lo = p - ret.hi + q + la * lb;
290 return ret;
291}
292
293test "32" {
294 const epsilon = 0.000001;
295
296 try expect(math.approxEqAbs(f32, fmaf(0.0, 5.0, 9.124), 9.124, epsilon));
297 try expect(math.approxEqAbs(f32, fmaf(0.2, 5.0, 9.124), 10.124, epsilon));
298 try expect(math.approxEqAbs(f32, fmaf(0.8923, 5.0, 9.124), 13.5855, epsilon));
299 try expect(math.approxEqAbs(f32, fmaf(1.5, 5.0, 9.124), 16.624, epsilon));
300 try expect(math.approxEqAbs(f32, fmaf(37.45, 5.0, 9.124), 196.374004, epsilon));
301 try expect(math.approxEqAbs(f32, fmaf(89.123, 5.0, 9.124), 454.739005, epsilon));
302 try expect(math.approxEqAbs(f32, fmaf(123123.234375, 5.0, 9.124), 615625.295875, epsilon));
303}
304
305test "64" {
306 const epsilon = 0.000001;
307
308 try expect(math.approxEqAbs(f64, fma(0.0, 5.0, 9.124), 9.124, epsilon));
309 try expect(math.approxEqAbs(f64, fma(0.2, 5.0, 9.124), 10.124, epsilon));
310 try expect(math.approxEqAbs(f64, fma(0.8923, 5.0, 9.124), 13.5855, epsilon));
311 try expect(math.approxEqAbs(f64, fma(1.5, 5.0, 9.124), 16.624, epsilon));
312 try expect(math.approxEqAbs(f64, fma(37.45, 5.0, 9.124), 196.374, epsilon));
313 try expect(math.approxEqAbs(f64, fma(89.123, 5.0, 9.124), 454.739, epsilon));
314 try expect(math.approxEqAbs(f64, fma(123123.234375, 5.0, 9.124), 615625.295875, epsilon));
315}
316
317test "128" {
318 const epsilon = 0.000001;
319
320 try expect(math.approxEqAbs(f128, fmaq(0.0, 5.0, 9.124), 9.124, epsilon));
321 try expect(math.approxEqAbs(f128, fmaq(0.2, 5.0, 9.124), 10.124, epsilon));
322 try expect(math.approxEqAbs(f128, fmaq(0.8923, 5.0, 9.124), 13.5855, epsilon));
323 try expect(math.approxEqAbs(f128, fmaq(1.5, 5.0, 9.124), 16.624, epsilon));
324 try expect(math.approxEqAbs(f128, fmaq(37.45, 5.0, 9.124), 196.374, epsilon));
325 try expect(math.approxEqAbs(f128, fmaq(89.123, 5.0, 9.124), 454.739, epsilon));
326 try expect(math.approxEqAbs(f128, fmaq(123123.234375, 5.0, 9.124), 615625.295875, epsilon));
327}
lib/std/special/compiler_rt/fmax.zig created+43
......@@ -0,0 +1,43 @@
1const std = @import("std");
2const math = std.math;
3
4pub fn __fmaxh(x: f16, y: f16) callconv(.C) f16 {
5 return generic_fmax(f16, x, y);
6}
7
8pub fn fmaxf(x: f32, y: f32) callconv(.C) f32 {
9 return generic_fmax(f32, x, y);
10}
11
12pub fn fmax(x: f64, y: f64) callconv(.C) f64 {
13 return generic_fmax(f64, x, y);
14}
15
16pub fn __fmaxx(x: f80, y: f80) callconv(.C) f80 {
17 return generic_fmax(f80, x, y);
18}
19
20pub fn fmaxq(x: f128, y: f128) callconv(.C) f128 {
21 return generic_fmax(f128, x, y);
22}
23
24inline fn generic_fmax(comptime T: type, x: T, y: T) T {
25 if (math.isNan(x))
26 return y;
27 if (math.isNan(y))
28 return x;
29 return if (x < y) y else x;
30}
31
32test "generic_fmax" {
33 inline for ([_]type{ f32, f64, c_longdouble, f80, f128 }) |T| {
34 const nan_val = math.nan(T);
35
36 try std.testing.expect(math.isNan(generic_fmax(T, nan_val, nan_val)));
37 try std.testing.expectEqual(@as(T, 1.0), generic_fmax(T, nan_val, 1.0));
38 try std.testing.expectEqual(@as(T, 1.0), generic_fmax(T, 1.0, nan_val));
39
40 try std.testing.expectEqual(@as(T, 10.0), generic_fmax(T, 1.0, 10.0));
41 try std.testing.expectEqual(@as(T, 1.0), generic_fmax(T, 1.0, -1.0));
42 }
43}
lib/std/special/compiler_rt/fmin.zig created+43
......@@ -0,0 +1,43 @@
1const std = @import("std");
2const math = std.math;
3
4pub fn __fminh(x: f16, y: f16) callconv(.C) f16 {
5 return generic_fmin(f16, x, y);
6}
7
8pub fn fminf(x: f32, y: f32) callconv(.C) f32 {
9 return generic_fmin(f32, x, y);
10}
11
12pub fn fmin(x: f64, y: f64) callconv(.C) f64 {
13 return generic_fmin(f64, x, y);
14}
15
16pub fn __fminx(x: f80, y: f80) callconv(.C) f80 {
17 return generic_fmin(f80, x, y);
18}
19
20pub fn fminq(x: f128, y: f128) callconv(.C) f128 {
21 return generic_fmin(f128, x, y);
22}
23
24inline fn generic_fmin(comptime T: type, x: T, y: T) T {
25 if (math.isNan(x))
26 return y;
27 if (math.isNan(y))
28 return x;
29 return if (x < y) x else y;
30}
31
32test "generic_fmin" {
33 inline for ([_]type{ f32, f64, c_longdouble, f80, f128 }) |T| {
34 const nan_val = math.nan(T);
35
36 try std.testing.expect(math.isNan(generic_fmin(T, nan_val, nan_val)));
37 try std.testing.expectEqual(@as(T, 1.0), generic_fmin(T, nan_val, 1.0));
38 try std.testing.expectEqual(@as(T, 1.0), generic_fmin(T, 1.0, nan_val));
39
40 try std.testing.expectEqual(@as(T, 1.0), generic_fmin(T, 1.0, 10.0));
41 try std.testing.expectEqual(@as(T, -1.0), generic_fmin(T, 1.0, -1.0));
42 }
43}
lib/std/special/compiler_rt/fmod.zig created+351
......@@ -0,0 +1,351 @@
1const builtin = @import("builtin");
2const std = @import("std");
3const math = std.math;
4const assert = std.debug.assert;
5const normalize = @import("divdf3.zig").normalize;
6
7pub fn __fmodh(x: f16, y: f16) callconv(.C) f16 {
8 // TODO: more efficient implementation
9 return @floatCast(f16, fmodf(x, y));
10}
11
12pub fn fmodf(x: f32, y: f32) callconv(.C) f32 {
13 return generic_fmod(f32, x, y);
14}
15
16pub fn fmod(x: f64, y: f64) callconv(.C) f64 {
17 return generic_fmod(f64, x, y);
18}
19
20/// fmodx - floating modulo large, returns the remainder of division for f80 types
21/// Logic and flow heavily inspired by MUSL fmodl for 113 mantissa digits
22pub fn __fmodx(a: f80, b: f80) callconv(.C) f80 {
23 @setRuntimeSafety(builtin.is_test);
24
25 const T = f80;
26 const Z = std.meta.Int(.unsigned, @bitSizeOf(T));
27
28 const significandBits = math.floatMantissaBits(T);
29 const fractionalBits = math.floatFractionalBits(T);
30 const exponentBits = math.floatExponentBits(T);
31
32 const signBit = (@as(Z, 1) << (significandBits + exponentBits));
33 const maxExponent = ((1 << exponentBits) - 1);
34
35 var aRep = @bitCast(Z, a);
36 var bRep = @bitCast(Z, b);
37
38 const signA = aRep & signBit;
39 var expA = @intCast(i32, (@bitCast(Z, a) >> significandBits) & maxExponent);
40 var expB = @intCast(i32, (@bitCast(Z, b) >> significandBits) & maxExponent);
41
42 // There are 3 cases where the answer is undefined, check for:
43 // - fmodx(val, 0)
44 // - fmodx(val, NaN)
45 // - fmodx(inf, val)
46 // The sign on checked values does not matter.
47 // Doing (a * b) / (a * b) procudes undefined results
48 // because the three cases always produce undefined calculations:
49 // - 0 / 0
50 // - val * NaN
51 // - inf / inf
52 if (b == 0 or math.isNan(b) or expA == maxExponent) {
53 return (a * b) / (a * b);
54 }
55
56 // Remove the sign from both
57 aRep &= ~signBit;
58 bRep &= ~signBit;
59 if (aRep <= bRep) {
60 if (aRep == bRep) {
61 return 0 * a;
62 }
63 return a;
64 }
65
66 if (expA == 0) expA = normalize(f80, &aRep);
67 if (expB == 0) expB = normalize(f80, &bRep);
68
69 var highA: u64 = 0;
70 var highB: u64 = 0;
71 var lowA: u64 = @truncate(u64, aRep);
72 var lowB: u64 = @truncate(u64, bRep);
73
74 while (expA > expB) : (expA -= 1) {
75 var high = highA -% highB;
76 var low = lowA -% lowB;
77 if (lowA < lowB) {
78 high -%= 1;
79 }
80 if (high >> 63 == 0) {
81 if ((high | low) == 0) {
82 return 0 * a;
83 }
84 highA = 2 *% high + (low >> 63);
85 lowA = 2 *% low;
86 } else {
87 highA = 2 *% highA + (lowA >> 63);
88 lowA = 2 *% lowA;
89 }
90 }
91
92 var high = highA -% highB;
93 var low = lowA -% lowB;
94 if (lowA < lowB) {
95 high -%= 1;
96 }
97 if (high >> 63 == 0) {
98 if ((high | low) == 0) {
99 return 0 * a;
100 }
101 highA = high;
102 lowA = low;
103 }
104
105 while ((lowA >> fractionalBits) == 0) {
106 lowA = 2 *% lowA;
107 expA = expA - 1;
108 }
109
110 // Combine the exponent with the sign and significand, normalize if happened to be denormalized
111 if (expA < -fractionalBits) {
112 return @bitCast(T, signA);
113 } else if (expA <= 0) {
114 return @bitCast(T, (lowA >> @intCast(math.Log2Int(u64), 1 - expA)) | signA);
115 } else {
116 return @bitCast(T, lowA | (@as(Z, @intCast(u16, expA)) << significandBits) | signA);
117 }
118}
119
120/// fmodq - floating modulo large, returns the remainder of division for f128 types
121/// Logic and flow heavily inspired by MUSL fmodl for 113 mantissa digits
122pub fn fmodq(a: f128, b: f128) callconv(.C) f128 {
123 @setRuntimeSafety(builtin.is_test);
124 var amod = a;
125 var bmod = b;
126 const aPtr_u64 = @ptrCast([*]u64, &amod);
127 const bPtr_u64 = @ptrCast([*]u64, &bmod);
128 const aPtr_u16 = @ptrCast([*]u16, &amod);
129 const bPtr_u16 = @ptrCast([*]u16, &bmod);
130
131 const exp_and_sign_index = comptime switch (builtin.target.cpu.arch.endian()) {
132 .Little => 7,
133 .Big => 0,
134 };
135 const low_index = comptime switch (builtin.target.cpu.arch.endian()) {
136 .Little => 0,
137 .Big => 1,
138 };
139 const high_index = comptime switch (builtin.target.cpu.arch.endian()) {
140 .Little => 1,
141 .Big => 0,
142 };
143
144 const signA = aPtr_u16[exp_and_sign_index] & 0x8000;
145 var expA = @intCast(i32, (aPtr_u16[exp_and_sign_index] & 0x7fff));
146 var expB = @intCast(i32, (bPtr_u16[exp_and_sign_index] & 0x7fff));
147
148 // There are 3 cases where the answer is undefined, check for:
149 // - fmodq(val, 0)
150 // - fmodq(val, NaN)
151 // - fmodq(inf, val)
152 // The sign on checked values does not matter.
153 // Doing (a * b) / (a * b) procudes undefined results
154 // because the three cases always produce undefined calculations:
155 // - 0 / 0
156 // - val * NaN
157 // - inf / inf
158 if (b == 0 or std.math.isNan(b) or expA == 0x7fff) {
159 return (a * b) / (a * b);
160 }
161
162 // Remove the sign from both
163 aPtr_u16[exp_and_sign_index] = @bitCast(u16, @intCast(i16, expA));
164 bPtr_u16[exp_and_sign_index] = @bitCast(u16, @intCast(i16, expB));
165 if (amod <= bmod) {
166 if (amod == bmod) {
167 return 0 * a;
168 }
169 return a;
170 }
171
172 if (expA == 0) {
173 amod *= 0x1p120;
174 expA = @as(i32, aPtr_u16[exp_and_sign_index]) - 120;
175 }
176
177 if (expB == 0) {
178 bmod *= 0x1p120;
179 expB = @as(i32, bPtr_u16[exp_and_sign_index]) - 120;
180 }
181
182 // OR in extra non-stored mantissa digit
183 var highA: u64 = (aPtr_u64[high_index] & (std.math.maxInt(u64) >> 16)) | 1 << 48;
184 var highB: u64 = (bPtr_u64[high_index] & (std.math.maxInt(u64) >> 16)) | 1 << 48;
185 var lowA: u64 = aPtr_u64[low_index];
186 var lowB: u64 = bPtr_u64[low_index];
187
188 while (expA > expB) : (expA -= 1) {
189 var high = highA -% highB;
190 var low = lowA -% lowB;
191 if (lowA < lowB) {
192 high -%= 1;
193 }
194 if (high >> 63 == 0) {
195 if ((high | low) == 0) {
196 return 0 * a;
197 }
198 highA = 2 *% high + (low >> 63);
199 lowA = 2 *% low;
200 } else {
201 highA = 2 *% highA + (lowA >> 63);
202 lowA = 2 *% lowA;
203 }
204 }
205
206 var high = highA -% highB;
207 var low = lowA -% lowB;
208 if (lowA < lowB) {
209 high -= 1;
210 }
211 if (high >> 63 == 0) {
212 if ((high | low) == 0) {
213 return 0 * a;
214 }
215 highA = high;
216 lowA = low;
217 }
218
219 while (highA >> 48 == 0) {
220 highA = 2 *% highA + (lowA >> 63);
221 lowA = 2 *% lowA;
222 expA = expA - 1;
223 }
224
225 // Overwrite the current amod with the values in highA and lowA
226 aPtr_u64[high_index] = highA;
227 aPtr_u64[low_index] = lowA;
228
229 // Combine the exponent with the sign, normalize if happend to be denormalized
230 if (expA <= 0) {
231 aPtr_u16[exp_and_sign_index] = @truncate(u16, @bitCast(u32, (expA +% 120))) | signA;
232 amod *= 0x1p-120;
233 } else {
234 aPtr_u16[exp_and_sign_index] = @truncate(u16, @bitCast(u32, expA)) | signA;
235 }
236
237 return amod;
238}
239
240inline fn generic_fmod(comptime T: type, x: T, y: T) T {
241 @setRuntimeSafety(false);
242
243 const bits = @typeInfo(T).Float.bits;
244 const uint = std.meta.Int(.unsigned, bits);
245 const log2uint = math.Log2Int(uint);
246 comptime assert(T == f32 or T == f64);
247 const digits = if (T == f32) 23 else 52;
248 const exp_bits = if (T == f32) 9 else 12;
249 const bits_minus_1 = bits - 1;
250 const mask = if (T == f32) 0xff else 0x7ff;
251 var ux = @bitCast(uint, x);
252 var uy = @bitCast(uint, y);
253 var ex = @intCast(i32, (ux >> digits) & mask);
254 var ey = @intCast(i32, (uy >> digits) & mask);
255 const sx = if (T == f32) @intCast(u32, ux & 0x80000000) else @intCast(i32, ux >> bits_minus_1);
256 var i: uint = undefined;
257
258 if (uy << 1 == 0 or math.isNan(@bitCast(T, uy)) or ex == mask)
259 return (x * y) / (x * y);
260
261 if (ux << 1 <= uy << 1) {
262 if (ux << 1 == uy << 1)
263 return 0 * x;
264 return x;
265 }
266
267 // normalize x and y
268 if (ex == 0) {
269 i = ux << exp_bits;
270 while (i >> bits_minus_1 == 0) : ({
271 ex -= 1;
272 i <<= 1;
273 }) {}
274 ux <<= @intCast(log2uint, @bitCast(u32, -ex + 1));
275 } else {
276 ux &= math.maxInt(uint) >> exp_bits;
277 ux |= 1 << digits;
278 }
279 if (ey == 0) {
280 i = uy << exp_bits;
281 while (i >> bits_minus_1 == 0) : ({
282 ey -= 1;
283 i <<= 1;
284 }) {}
285 uy <<= @intCast(log2uint, @bitCast(u32, -ey + 1));
286 } else {
287 uy &= math.maxInt(uint) >> exp_bits;
288 uy |= 1 << digits;
289 }
290
291 // x mod y
292 while (ex > ey) : (ex -= 1) {
293 i = ux -% uy;
294 if (i >> bits_minus_1 == 0) {
295 if (i == 0)
296 return 0 * x;
297 ux = i;
298 }
299 ux <<= 1;
300 }
301 i = ux -% uy;
302 if (i >> bits_minus_1 == 0) {
303 if (i == 0)
304 return 0 * x;
305 ux = i;
306 }
307 while (ux >> digits == 0) : ({
308 ux <<= 1;
309 ex -= 1;
310 }) {}
311
312 // scale result up
313 if (ex > 0) {
314 ux -%= 1 << digits;
315 ux |= @as(uint, @bitCast(u32, ex)) << digits;
316 } else {
317 ux >>= @intCast(log2uint, @bitCast(u32, -ex + 1));
318 }
319 if (T == f32) {
320 ux |= sx;
321 } else {
322 ux |= @intCast(uint, sx) << bits_minus_1;
323 }
324 return @bitCast(T, ux);
325}
326
327test "fmod, fmodf" {
328 inline for ([_]type{ f32, f64 }) |T| {
329 const nan_val = math.nan(T);
330 const inf_val = math.inf(T);
331
332 try std.testing.expect(math.isNan(generic_fmod(T, nan_val, 1.0)));
333 try std.testing.expect(math.isNan(generic_fmod(T, 1.0, nan_val)));
334 try std.testing.expect(math.isNan(generic_fmod(T, inf_val, 1.0)));
335 try std.testing.expect(math.isNan(generic_fmod(T, 0.0, 0.0)));
336 try std.testing.expect(math.isNan(generic_fmod(T, 1.0, 0.0)));
337
338 try std.testing.expectEqual(@as(T, 0.0), generic_fmod(T, 0.0, 2.0));
339 try std.testing.expectEqual(@as(T, -0.0), generic_fmod(T, -0.0, 2.0));
340
341 try std.testing.expectEqual(@as(T, -2.0), generic_fmod(T, -32.0, 10.0));
342 try std.testing.expectEqual(@as(T, -2.0), generic_fmod(T, -32.0, -10.0));
343 try std.testing.expectEqual(@as(T, 2.0), generic_fmod(T, 32.0, 10.0));
344 try std.testing.expectEqual(@as(T, 2.0), generic_fmod(T, 32.0, -10.0));
345 }
346}
347
348test {
349 _ = @import("fmodq_test.zig");
350 _ = @import("fmodx_test.zig");
351}
lib/std/special/compiler_rt/fmodq.zig deleted-126
......@@ -1,126 +0,0 @@
1const builtin = @import("builtin");
2const std = @import("std");
3
4// fmodq - floating modulo large, returns the remainder of division for f128 types
5// Logic and flow heavily inspired by MUSL fmodl for 113 mantissa digits
6pub fn fmodq(a: f128, b: f128) callconv(.C) f128 {
7 @setRuntimeSafety(builtin.is_test);
8 var amod = a;
9 var bmod = b;
10 const aPtr_u64 = @ptrCast([*]u64, &amod);
11 const bPtr_u64 = @ptrCast([*]u64, &bmod);
12 const aPtr_u16 = @ptrCast([*]u16, &amod);
13 const bPtr_u16 = @ptrCast([*]u16, &bmod);
14
15 const exp_and_sign_index = comptime switch (builtin.target.cpu.arch.endian()) {
16 .Little => 7,
17 .Big => 0,
18 };
19 const low_index = comptime switch (builtin.target.cpu.arch.endian()) {
20 .Little => 0,
21 .Big => 1,
22 };
23 const high_index = comptime switch (builtin.target.cpu.arch.endian()) {
24 .Little => 1,
25 .Big => 0,
26 };
27
28 const signA = aPtr_u16[exp_and_sign_index] & 0x8000;
29 var expA = @intCast(i32, (aPtr_u16[exp_and_sign_index] & 0x7fff));
30 var expB = @intCast(i32, (bPtr_u16[exp_and_sign_index] & 0x7fff));
31
32 // There are 3 cases where the answer is undefined, check for:
33 // - fmodq(val, 0)
34 // - fmodq(val, NaN)
35 // - fmodq(inf, val)
36 // The sign on checked values does not matter.
37 // Doing (a * b) / (a * b) procudes undefined results
38 // because the three cases always produce undefined calculations:
39 // - 0 / 0
40 // - val * NaN
41 // - inf / inf
42 if (b == 0 or std.math.isNan(b) or expA == 0x7fff) {
43 return (a * b) / (a * b);
44 }
45
46 // Remove the sign from both
47 aPtr_u16[exp_and_sign_index] = @bitCast(u16, @intCast(i16, expA));
48 bPtr_u16[exp_and_sign_index] = @bitCast(u16, @intCast(i16, expB));
49 if (amod <= bmod) {
50 if (amod == bmod) {
51 return 0 * a;
52 }
53 return a;
54 }
55
56 if (expA == 0) {
57 amod *= 0x1p120;
58 expA = @as(i32, aPtr_u16[exp_and_sign_index]) - 120;
59 }
60
61 if (expB == 0) {
62 bmod *= 0x1p120;
63 expB = @as(i32, bPtr_u16[exp_and_sign_index]) - 120;
64 }
65
66 // OR in extra non-stored mantissa digit
67 var highA: u64 = (aPtr_u64[high_index] & (std.math.maxInt(u64) >> 16)) | 1 << 48;
68 var highB: u64 = (bPtr_u64[high_index] & (std.math.maxInt(u64) >> 16)) | 1 << 48;
69 var lowA: u64 = aPtr_u64[low_index];
70 var lowB: u64 = bPtr_u64[low_index];
71
72 while (expA > expB) : (expA -= 1) {
73 var high = highA -% highB;
74 var low = lowA -% lowB;
75 if (lowA < lowB) {
76 high -%= 1;
77 }
78 if (high >> 63 == 0) {
79 if ((high | low) == 0) {
80 return 0 * a;
81 }
82 highA = 2 *% high + (low >> 63);
83 lowA = 2 *% low;
84 } else {
85 highA = 2 *% highA + (lowA >> 63);
86 lowA = 2 *% lowA;
87 }
88 }
89
90 var high = highA -% highB;
91 var low = lowA -% lowB;
92 if (lowA < lowB) {
93 high -= 1;
94 }
95 if (high >> 63 == 0) {
96 if ((high | low) == 0) {
97 return 0 * a;
98 }
99 highA = high;
100 lowA = low;
101 }
102
103 while (highA >> 48 == 0) {
104 highA = 2 *% highA + (lowA >> 63);
105 lowA = 2 *% lowA;
106 expA = expA - 1;
107 }
108
109 // Overwrite the current amod with the values in highA and lowA
110 aPtr_u64[high_index] = highA;
111 aPtr_u64[low_index] = lowA;
112
113 // Combine the exponent with the sign, normalize if happend to be denormalized
114 if (expA <= 0) {
115 aPtr_u16[exp_and_sign_index] = @truncate(u16, @bitCast(u32, (expA +% 120))) | signA;
116 amod *= 0x1p-120;
117 } else {
118 aPtr_u16[exp_and_sign_index] = @truncate(u16, @bitCast(u32, expA)) | signA;
119 }
120
121 return amod;
122}
123
124test {
125 _ = @import("fmodq_test.zig");
126}
lib/std/special/compiler_rt/fmodq_test.zig+10-10
......@@ -1,24 +1,24 @@
11const std = @import("std");
2const fmodq = @import("fmodq.zig");
2const fmod = @import("fmod.zig");
33const testing = std.testing;
44
55fn test_fmodq(a: f128, b: f128, exp: f128) !void {
6 const res = fmodq.fmodq(a, b);
6 const res = fmod.fmodq(a, b);
77 try testing.expect(exp == res);
88}
99
1010fn test_fmodq_nans() !void {
11 try testing.expect(std.math.isNan(fmodq.fmodq(1.0, std.math.nan(f128))));
12 try testing.expect(std.math.isNan(fmodq.fmodq(1.0, -std.math.nan(f128))));
13 try testing.expect(std.math.isNan(fmodq.fmodq(std.math.nan(f128), 1.0)));
14 try testing.expect(std.math.isNan(fmodq.fmodq(-std.math.nan(f128), 1.0)));
11 try testing.expect(std.math.isNan(fmod.fmodq(1.0, std.math.nan(f128))));
12 try testing.expect(std.math.isNan(fmod.fmodq(1.0, -std.math.nan(f128))));
13 try testing.expect(std.math.isNan(fmod.fmodq(std.math.nan(f128), 1.0)));
14 try testing.expect(std.math.isNan(fmod.fmodq(-std.math.nan(f128), 1.0)));
1515}
1616
1717fn test_fmodq_infs() !void {
18 try testing.expect(fmodq.fmodq(1.0, std.math.inf(f128)) == 1.0);
19 try testing.expect(fmodq.fmodq(1.0, -std.math.inf(f128)) == 1.0);
20 try testing.expect(std.math.isNan(fmodq.fmodq(std.math.inf(f128), 1.0)));
21 try testing.expect(std.math.isNan(fmodq.fmodq(-std.math.inf(f128), 1.0)));
18 try testing.expect(fmod.fmodq(1.0, std.math.inf(f128)) == 1.0);
19 try testing.expect(fmod.fmodq(1.0, -std.math.inf(f128)) == 1.0);
20 try testing.expect(std.math.isNan(fmod.fmodq(std.math.inf(f128), 1.0)));
21 try testing.expect(std.math.isNan(fmod.fmodq(-std.math.inf(f128), 1.0)));
2222}
2323
2424test "fmodq" {
lib/std/special/compiler_rt/fmodx.zig deleted-108
......@@ -1,108 +0,0 @@
1const builtin = @import("builtin");
2const std = @import("std");
3const math = std.math;
4const normalize = @import("divdf3.zig").normalize;
5
6// fmodx - floating modulo large, returns the remainder of division for f80 types
7// Logic and flow heavily inspired by MUSL fmodl for 113 mantissa digits
8pub fn fmodx(a: f80, b: f80) callconv(.C) f80 {
9 @setRuntimeSafety(builtin.is_test);
10
11 const T = f80;
12 const Z = std.meta.Int(.unsigned, @bitSizeOf(T));
13
14 const significandBits = math.floatMantissaBits(T);
15 const fractionalBits = math.floatFractionalBits(T);
16 const exponentBits = math.floatExponentBits(T);
17
18 const signBit = (@as(Z, 1) << (significandBits + exponentBits));
19 const maxExponent = ((1 << exponentBits) - 1);
20
21 var aRep = @bitCast(Z, a);
22 var bRep = @bitCast(Z, b);
23
24 const signA = aRep & signBit;
25 var expA = @intCast(i32, (@bitCast(Z, a) >> significandBits) & maxExponent);
26 var expB = @intCast(i32, (@bitCast(Z, b) >> significandBits) & maxExponent);
27
28 // There are 3 cases where the answer is undefined, check for:
29 // - fmodx(val, 0)
30 // - fmodx(val, NaN)
31 // - fmodx(inf, val)
32 // The sign on checked values does not matter.
33 // Doing (a * b) / (a * b) procudes undefined results
34 // because the three cases always produce undefined calculations:
35 // - 0 / 0
36 // - val * NaN
37 // - inf / inf
38 if (b == 0 or math.isNan(b) or expA == maxExponent) {
39 return (a * b) / (a * b);
40 }
41
42 // Remove the sign from both
43 aRep &= ~signBit;
44 bRep &= ~signBit;
45 if (aRep <= bRep) {
46 if (aRep == bRep) {
47 return 0 * a;
48 }
49 return a;
50 }
51
52 if (expA == 0) expA = normalize(f80, &aRep);
53 if (expB == 0) expB = normalize(f80, &bRep);
54
55 var highA: u64 = 0;
56 var highB: u64 = 0;
57 var lowA: u64 = @truncate(u64, aRep);
58 var lowB: u64 = @truncate(u64, bRep);
59
60 while (expA > expB) : (expA -= 1) {
61 var high = highA -% highB;
62 var low = lowA -% lowB;
63 if (lowA < lowB) {
64 high -%= 1;
65 }
66 if (high >> 63 == 0) {
67 if ((high | low) == 0) {
68 return 0 * a;
69 }
70 highA = 2 *% high + (low >> 63);
71 lowA = 2 *% low;
72 } else {
73 highA = 2 *% highA + (lowA >> 63);
74 lowA = 2 *% lowA;
75 }
76 }
77
78 var high = highA -% highB;
79 var low = lowA -% lowB;
80 if (lowA < lowB) {
81 high -%= 1;
82 }
83 if (high >> 63 == 0) {
84 if ((high | low) == 0) {
85 return 0 * a;
86 }
87 highA = high;
88 lowA = low;
89 }
90
91 while ((lowA >> fractionalBits) == 0) {
92 lowA = 2 *% lowA;
93 expA = expA - 1;
94 }
95
96 // Combine the exponent with the sign and significand, normalize if happened to be denormalized
97 if (expA < -fractionalBits) {
98 return @bitCast(T, signA);
99 } else if (expA <= 0) {
100 return @bitCast(T, (lowA >> @intCast(math.Log2Int(u64), 1 - expA)) | signA);
101 } else {
102 return @bitCast(T, lowA | (@as(Z, @intCast(u16, expA)) << significandBits) | signA);
103 }
104}
105
106test {
107 _ = @import("fmodx_test.zig");
108}
lib/std/special/compiler_rt/fmodx_test.zig+10-10
......@@ -1,24 +1,24 @@
11const std = @import("std");
2const fmodx = @import("fmodx.zig");
2const fmod = @import("fmod.zig");
33const testing = std.testing;
44
55fn test_fmodx(a: f80, b: f80, exp: f80) !void {
6 const res = fmodx.fmodx(a, b);
6 const res = fmod.__fmodx(a, b);
77 try testing.expect(exp == res);
88}
99
1010fn test_fmodx_nans() !void {
11 try testing.expect(std.math.isNan(fmodx.fmodx(1.0, std.math.nan(f80))));
12 try testing.expect(std.math.isNan(fmodx.fmodx(1.0, -std.math.nan(f80))));
13 try testing.expect(std.math.isNan(fmodx.fmodx(std.math.nan(f80), 1.0)));
14 try testing.expect(std.math.isNan(fmodx.fmodx(-std.math.nan(f80), 1.0)));
11 try testing.expect(std.math.isNan(fmod.__fmodx(1.0, std.math.nan(f80))));
12 try testing.expect(std.math.isNan(fmod.__fmodx(1.0, -std.math.nan(f80))));
13 try testing.expect(std.math.isNan(fmod.__fmodx(std.math.nan(f80), 1.0)));
14 try testing.expect(std.math.isNan(fmod.__fmodx(-std.math.nan(f80), 1.0)));
1515}
1616
1717fn test_fmodx_infs() !void {
18 try testing.expect(fmodx.fmodx(1.0, std.math.inf(f80)) == 1.0);
19 try testing.expect(fmodx.fmodx(1.0, -std.math.inf(f80)) == 1.0);
20 try testing.expect(std.math.isNan(fmodx.fmodx(std.math.inf(f80), 1.0)));
21 try testing.expect(std.math.isNan(fmodx.fmodx(-std.math.inf(f80), 1.0)));
18 try testing.expect(fmod.__fmodx(1.0, std.math.inf(f80)) == 1.0);
19 try testing.expect(fmod.__fmodx(1.0, -std.math.inf(f80)) == 1.0);
20 try testing.expect(std.math.isNan(fmod.__fmodx(std.math.inf(f80), 1.0)));
21 try testing.expect(std.math.isNan(fmod.__fmodx(-std.math.inf(f80), 1.0)));
2222}
2323
2424test "fmodx" {
lib/std/special/compiler_rt/log.zig created+168
......@@ -0,0 +1,168 @@
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/lnf.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/ln.c
6
7const std = @import("std");
8const math = std.math;
9const testing = std.testing;
10
11pub fn __logh(a: f16) callconv(.C) f16 {
12 // TODO: more efficient implementation
13 return @floatCast(f16, logf(a));
14}
15
16pub fn logf(x_: f32) callconv(.C) f32 {
17 const ln2_hi: f32 = 6.9313812256e-01;
18 const ln2_lo: f32 = 9.0580006145e-06;
19 const Lg1: f32 = 0xaaaaaa.0p-24;
20 const Lg2: f32 = 0xccce13.0p-25;
21 const Lg3: f32 = 0x91e9ee.0p-25;
22 const Lg4: f32 = 0xf89e26.0p-26;
23
24 var x = x_;
25 var ix = @bitCast(u32, x);
26 var k: i32 = 0;
27
28 // x < 2^(-126)
29 if (ix < 0x00800000 or ix >> 31 != 0) {
30 // log(+-0) = -inf
31 if (ix << 1 == 0) {
32 return -math.inf(f32);
33 }
34 // log(-#) = nan
35 if (ix >> 31 != 0) {
36 return math.nan(f32);
37 }
38
39 // subnormal, scale x
40 k -= 25;
41 x *= 0x1.0p25;
42 ix = @bitCast(u32, x);
43 } else if (ix >= 0x7F800000) {
44 return x;
45 } else if (ix == 0x3F800000) {
46 return 0;
47 }
48
49 // x into [sqrt(2) / 2, sqrt(2)]
50 ix += 0x3F800000 - 0x3F3504F3;
51 k += @intCast(i32, ix >> 23) - 0x7F;
52 ix = (ix & 0x007FFFFF) + 0x3F3504F3;
53 x = @bitCast(f32, ix);
54
55 const f = x - 1.0;
56 const s = f / (2.0 + f);
57 const z = s * s;
58 const w = z * z;
59 const t1 = w * (Lg2 + w * Lg4);
60 const t2 = z * (Lg1 + w * Lg3);
61 const R = t2 + t1;
62 const hfsq = 0.5 * f * f;
63 const dk = @intToFloat(f32, k);
64
65 return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi;
66}
67
68pub fn log(x_: f64) callconv(.C) f64 {
69 const ln2_hi: f64 = 6.93147180369123816490e-01;
70 const ln2_lo: f64 = 1.90821492927058770002e-10;
71 const Lg1: f64 = 6.666666666666735130e-01;
72 const Lg2: f64 = 3.999999999940941908e-01;
73 const Lg3: f64 = 2.857142874366239149e-01;
74 const Lg4: f64 = 2.222219843214978396e-01;
75 const Lg5: f64 = 1.818357216161805012e-01;
76 const Lg6: f64 = 1.531383769920937332e-01;
77 const Lg7: f64 = 1.479819860511658591e-01;
78
79 var x = x_;
80 var ix = @bitCast(u64, x);
81 var hx = @intCast(u32, ix >> 32);
82 var k: i32 = 0;
83
84 if (hx < 0x00100000 or hx >> 31 != 0) {
85 // log(+-0) = -inf
86 if (ix << 1 == 0) {
87 return -math.inf(f64);
88 }
89 // log(-#) = nan
90 if (hx >> 31 != 0) {
91 return math.nan(f64);
92 }
93
94 // subnormal, scale x
95 k -= 54;
96 x *= 0x1.0p54;
97 hx = @intCast(u32, @bitCast(u64, ix) >> 32);
98 } else if (hx >= 0x7FF00000) {
99 return x;
100 } else if (hx == 0x3FF00000 and ix << 32 == 0) {
101 return 0;
102 }
103
104 // x into [sqrt(2) / 2, sqrt(2)]
105 hx += 0x3FF00000 - 0x3FE6A09E;
106 k += @intCast(i32, hx >> 20) - 0x3FF;
107 hx = (hx & 0x000FFFFF) + 0x3FE6A09E;
108 ix = (@as(u64, hx) << 32) | (ix & 0xFFFFFFFF);
109 x = @bitCast(f64, ix);
110
111 const f = x - 1.0;
112 const hfsq = 0.5 * f * f;
113 const s = f / (2.0 + f);
114 const z = s * s;
115 const w = z * z;
116 const t1 = w * (Lg2 + w * (Lg4 + w * Lg6));
117 const t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7)));
118 const R = t2 + t1;
119 const dk = @intToFloat(f64, k);
120
121 return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi;
122}
123
124pub fn __logx(a: f80) callconv(.C) f80 {
125 // TODO: more efficient implementation
126 return @floatCast(f80, logq(a));
127}
128
129pub fn logq(a: f128) callconv(.C) f128 {
130 // TODO: more correct implementation
131 return log(@floatCast(f64, a));
132}
133
134test "ln32" {
135 const epsilon = 0.000001;
136
137 try testing.expect(math.approxEqAbs(f32, logf(0.2), -1.609438, epsilon));
138 try testing.expect(math.approxEqAbs(f32, logf(0.8923), -0.113953, epsilon));
139 try testing.expect(math.approxEqAbs(f32, logf(1.5), 0.405465, epsilon));
140 try testing.expect(math.approxEqAbs(f32, logf(37.45), 3.623007, epsilon));
141 try testing.expect(math.approxEqAbs(f32, logf(89.123), 4.490017, epsilon));
142 try testing.expect(math.approxEqAbs(f32, logf(123123.234375), 11.720941, epsilon));
143}
144
145test "ln64" {
146 const epsilon = 0.000001;
147
148 try testing.expect(math.approxEqAbs(f64, log(0.2), -1.609438, epsilon));
149 try testing.expect(math.approxEqAbs(f64, log(0.8923), -0.113953, epsilon));
150 try testing.expect(math.approxEqAbs(f64, log(1.5), 0.405465, epsilon));
151 try testing.expect(math.approxEqAbs(f64, log(37.45), 3.623007, epsilon));
152 try testing.expect(math.approxEqAbs(f64, log(89.123), 4.490017, epsilon));
153 try testing.expect(math.approxEqAbs(f64, log(123123.234375), 11.720941, epsilon));
154}
155
156test "ln32.special" {
157 try testing.expect(math.isPositiveInf(logf(math.inf(f32))));
158 try testing.expect(math.isNegativeInf(logf(0.0)));
159 try testing.expect(math.isNan(logf(-1.0)));
160 try testing.expect(math.isNan(logf(math.nan(f32))));
161}
162
163test "ln64.special" {
164 try testing.expect(math.isPositiveInf(log(math.inf(f64))));
165 try testing.expect(math.isNegativeInf(log(0.0)));
166 try testing.expect(math.isNan(log(-1.0)));
167 try testing.expect(math.isNan(log(math.nan(f64))));
168}
lib/std/special/compiler_rt/log10.zig created+196
......@@ -0,0 +1,196 @@
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/log10f.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/log10.c
6
7const std = @import("std");
8const math = std.math;
9const testing = std.testing;
10const maxInt = std.math.maxInt;
11
12pub fn __log10h(a: f16) callconv(.C) f16 {
13 // TODO: more efficient implementation
14 return @floatCast(f16, log10f(a));
15}
16
17pub fn log10f(x_: f32) callconv(.C) f32 {
18 const ivln10hi: f32 = 4.3432617188e-01;
19 const ivln10lo: f32 = -3.1689971365e-05;
20 const log10_2hi: f32 = 3.0102920532e-01;
21 const log10_2lo: f32 = 7.9034151668e-07;
22 const Lg1: f32 = 0xaaaaaa.0p-24;
23 const Lg2: f32 = 0xccce13.0p-25;
24 const Lg3: f32 = 0x91e9ee.0p-25;
25 const Lg4: f32 = 0xf89e26.0p-26;
26
27 var x = x_;
28 var u = @bitCast(u32, x);
29 var ix = u;
30 var k: i32 = 0;
31
32 // x < 2^(-126)
33 if (ix < 0x00800000 or ix >> 31 != 0) {
34 // log(+-0) = -inf
35 if (ix << 1 == 0) {
36 return -math.inf(f32);
37 }
38 // log(-#) = nan
39 if (ix >> 31 != 0) {
40 return math.nan(f32);
41 }
42
43 k -= 25;
44 x *= 0x1.0p25;
45 ix = @bitCast(u32, x);
46 } else if (ix >= 0x7F800000) {
47 return x;
48 } else if (ix == 0x3F800000) {
49 return 0;
50 }
51
52 // x into [sqrt(2) / 2, sqrt(2)]
53 ix += 0x3F800000 - 0x3F3504F3;
54 k += @intCast(i32, ix >> 23) - 0x7F;
55 ix = (ix & 0x007FFFFF) + 0x3F3504F3;
56 x = @bitCast(f32, ix);
57
58 const f = x - 1.0;
59 const s = f / (2.0 + f);
60 const z = s * s;
61 const w = z * z;
62 const t1 = w * (Lg2 + w * Lg4);
63 const t2 = z * (Lg1 + w * Lg3);
64 const R = t2 + t1;
65 const hfsq = 0.5 * f * f;
66
67 var hi = f - hfsq;
68 u = @bitCast(u32, hi);
69 u &= 0xFFFFF000;
70 hi = @bitCast(f32, u);
71 const lo = f - hi - hfsq + s * (hfsq + R);
72 const dk = @intToFloat(f32, k);
73
74 return dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi;
75}
76
77pub fn log10(x_: f64) callconv(.C) f64 {
78 const ivln10hi: f64 = 4.34294481878168880939e-01;
79 const ivln10lo: f64 = 2.50829467116452752298e-11;
80 const log10_2hi: f64 = 3.01029995663611771306e-01;
81 const log10_2lo: f64 = 3.69423907715893078616e-13;
82 const Lg1: f64 = 6.666666666666735130e-01;
83 const Lg2: f64 = 3.999999999940941908e-01;
84 const Lg3: f64 = 2.857142874366239149e-01;
85 const Lg4: f64 = 2.222219843214978396e-01;
86 const Lg5: f64 = 1.818357216161805012e-01;
87 const Lg6: f64 = 1.531383769920937332e-01;
88 const Lg7: f64 = 1.479819860511658591e-01;
89
90 var x = x_;
91 var ix = @bitCast(u64, x);
92 var hx = @intCast(u32, ix >> 32);
93 var k: i32 = 0;
94
95 if (hx < 0x00100000 or hx >> 31 != 0) {
96 // log(+-0) = -inf
97 if (ix << 1 == 0) {
98 return -math.inf(f32);
99 }
100 // log(-#) = nan
101 if (hx >> 31 != 0) {
102 return math.nan(f32);
103 }
104
105 // subnormal, scale x
106 k -= 54;
107 x *= 0x1.0p54;
108 hx = @intCast(u32, @bitCast(u64, x) >> 32);
109 } else if (hx >= 0x7FF00000) {
110 return x;
111 } else if (hx == 0x3FF00000 and ix << 32 == 0) {
112 return 0;
113 }
114
115 // x into [sqrt(2) / 2, sqrt(2)]
116 hx += 0x3FF00000 - 0x3FE6A09E;
117 k += @intCast(i32, hx >> 20) - 0x3FF;
118 hx = (hx & 0x000FFFFF) + 0x3FE6A09E;
119 ix = (@as(u64, hx) << 32) | (ix & 0xFFFFFFFF);
120 x = @bitCast(f64, ix);
121
122 const f = x - 1.0;
123 const hfsq = 0.5 * f * f;
124 const s = f / (2.0 + f);
125 const z = s * s;
126 const w = z * z;
127 const t1 = w * (Lg2 + w * (Lg4 + w * Lg6));
128 const t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7)));
129 const R = t2 + t1;
130
131 // hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f)
132 var hi = f - hfsq;
133 var hii = @bitCast(u64, hi);
134 hii &= @as(u64, maxInt(u64)) << 32;
135 hi = @bitCast(f64, hii);
136 const lo = f - hi - hfsq + s * (hfsq + R);
137
138 // val_hi + val_lo ~ log10(1 + f) + k * log10(2)
139 var val_hi = hi * ivln10hi;
140 const dk = @intToFloat(f64, k);
141 const y = dk * log10_2hi;
142 var val_lo = dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi;
143
144 // Extra precision multiplication
145 const ww = y + val_hi;
146 val_lo += (y - ww) + val_hi;
147 val_hi = ww;
148
149 return val_lo + val_hi;
150}
151
152pub fn __log10x(a: f80) callconv(.C) f80 {
153 // TODO: more efficient implementation
154 return @floatCast(f80, log10q(a));
155}
156
157pub fn log10q(a: f128) callconv(.C) f128 {
158 // TODO: more correct implementation
159 return log10(@floatCast(f64, a));
160}
161
162test "log10_32" {
163 const epsilon = 0.000001;
164
165 try testing.expect(math.approxEqAbs(f32, log10f(0.2), -0.698970, epsilon));
166 try testing.expect(math.approxEqAbs(f32, log10f(0.8923), -0.049489, epsilon));
167 try testing.expect(math.approxEqAbs(f32, log10f(1.5), 0.176091, epsilon));
168 try testing.expect(math.approxEqAbs(f32, log10f(37.45), 1.573452, epsilon));
169 try testing.expect(math.approxEqAbs(f32, log10f(89.123), 1.94999, epsilon));
170 try testing.expect(math.approxEqAbs(f32, log10f(123123.234375), 5.09034, epsilon));
171}
172
173test "log10_64" {
174 const epsilon = 0.000001;
175
176 try testing.expect(math.approxEqAbs(f64, log10(0.2), -0.698970, epsilon));
177 try testing.expect(math.approxEqAbs(f64, log10(0.8923), -0.049489, epsilon));
178 try testing.expect(math.approxEqAbs(f64, log10(1.5), 0.176091, epsilon));
179 try testing.expect(math.approxEqAbs(f64, log10(37.45), 1.573452, epsilon));
180 try testing.expect(math.approxEqAbs(f64, log10(89.123), 1.94999, epsilon));
181 try testing.expect(math.approxEqAbs(f64, log10(123123.234375), 5.09034, epsilon));
182}
183
184test "log10_32.special" {
185 try testing.expect(math.isPositiveInf(log10f(math.inf(f32))));
186 try testing.expect(math.isNegativeInf(log10f(0.0)));
187 try testing.expect(math.isNan(log10f(-1.0)));
188 try testing.expect(math.isNan(log10f(math.nan(f32))));
189}
190
191test "log10_64.special" {
192 try testing.expect(math.isPositiveInf(log10(math.inf(f64))));
193 try testing.expect(math.isNegativeInf(log10(0.0)));
194 try testing.expect(math.isNan(log10(-1.0)));
195 try testing.expect(math.isNan(log10(math.nan(f64))));
196}
lib/std/special/compiler_rt/log2.zig created+185
......@@ -0,0 +1,185 @@
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/log2f.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/log2.c
6
7const std = @import("std");
8const math = std.math;
9const expect = std.testing.expect;
10const maxInt = std.math.maxInt;
11
12pub fn __log2h(a: f16) callconv(.C) f16 {
13 // TODO: more efficient implementation
14 return @floatCast(f16, log2f(a));
15}
16
17pub fn log2f(x_: f32) callconv(.C) f32 {
18 const ivln2hi: f32 = 1.4428710938e+00;
19 const ivln2lo: f32 = -1.7605285393e-04;
20 const Lg1: f32 = 0xaaaaaa.0p-24;
21 const Lg2: f32 = 0xccce13.0p-25;
22 const Lg3: f32 = 0x91e9ee.0p-25;
23 const Lg4: f32 = 0xf89e26.0p-26;
24
25 var x = x_;
26 var u = @bitCast(u32, x);
27 var ix = u;
28 var k: i32 = 0;
29
30 // x < 2^(-126)
31 if (ix < 0x00800000 or ix >> 31 != 0) {
32 // log(+-0) = -inf
33 if (ix << 1 == 0) {
34 return -math.inf(f32);
35 }
36 // log(-#) = nan
37 if (ix >> 31 != 0) {
38 return math.nan(f32);
39 }
40
41 k -= 25;
42 x *= 0x1.0p25;
43 ix = @bitCast(u32, x);
44 } else if (ix >= 0x7F800000) {
45 return x;
46 } else if (ix == 0x3F800000) {
47 return 0;
48 }
49
50 // x into [sqrt(2) / 2, sqrt(2)]
51 ix += 0x3F800000 - 0x3F3504F3;
52 k += @intCast(i32, ix >> 23) - 0x7F;
53 ix = (ix & 0x007FFFFF) + 0x3F3504F3;
54 x = @bitCast(f32, ix);
55
56 const f = x - 1.0;
57 const s = f / (2.0 + f);
58 const z = s * s;
59 const w = z * z;
60 const t1 = w * (Lg2 + w * Lg4);
61 const t2 = z * (Lg1 + w * Lg3);
62 const R = t2 + t1;
63 const hfsq = 0.5 * f * f;
64
65 var hi = f - hfsq;
66 u = @bitCast(u32, hi);
67 u &= 0xFFFFF000;
68 hi = @bitCast(f32, u);
69 const lo = f - hi - hfsq + s * (hfsq + R);
70 return (lo + hi) * ivln2lo + lo * ivln2hi + hi * ivln2hi + @intToFloat(f32, k);
71}
72
73pub fn log2(x_: f64) callconv(.C) f64 {
74 const ivln2hi: f64 = 1.44269504072144627571e+00;
75 const ivln2lo: f64 = 1.67517131648865118353e-10;
76 const Lg1: f64 = 6.666666666666735130e-01;
77 const Lg2: f64 = 3.999999999940941908e-01;
78 const Lg3: f64 = 2.857142874366239149e-01;
79 const Lg4: f64 = 2.222219843214978396e-01;
80 const Lg5: f64 = 1.818357216161805012e-01;
81 const Lg6: f64 = 1.531383769920937332e-01;
82 const Lg7: f64 = 1.479819860511658591e-01;
83
84 var x = x_;
85 var ix = @bitCast(u64, x);
86 var hx = @intCast(u32, ix >> 32);
87 var k: i32 = 0;
88
89 if (hx < 0x00100000 or hx >> 31 != 0) {
90 // log(+-0) = -inf
91 if (ix << 1 == 0) {
92 return -math.inf(f64);
93 }
94 // log(-#) = nan
95 if (hx >> 31 != 0) {
96 return math.nan(f64);
97 }
98
99 // subnormal, scale x
100 k -= 54;
101 x *= 0x1.0p54;
102 hx = @intCast(u32, @bitCast(u64, x) >> 32);
103 } else if (hx >= 0x7FF00000) {
104 return x;
105 } else if (hx == 0x3FF00000 and ix << 32 == 0) {
106 return 0;
107 }
108
109 // x into [sqrt(2) / 2, sqrt(2)]
110 hx += 0x3FF00000 - 0x3FE6A09E;
111 k += @intCast(i32, hx >> 20) - 0x3FF;
112 hx = (hx & 0x000FFFFF) + 0x3FE6A09E;
113 ix = (@as(u64, hx) << 32) | (ix & 0xFFFFFFFF);
114 x = @bitCast(f64, ix);
115
116 const f = x - 1.0;
117 const hfsq = 0.5 * f * f;
118 const s = f / (2.0 + f);
119 const z = s * s;
120 const w = z * z;
121 const t1 = w * (Lg2 + w * (Lg4 + w * Lg6));
122 const t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7)));
123 const R = t2 + t1;
124
125 // hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f)
126 var hi = f - hfsq;
127 var hii = @bitCast(u64, hi);
128 hii &= @as(u64, maxInt(u64)) << 32;
129 hi = @bitCast(f64, hii);
130 const lo = f - hi - hfsq + s * (hfsq + R);
131
132 var val_hi = hi * ivln2hi;
133 var val_lo = (lo + hi) * ivln2lo + lo * ivln2hi;
134
135 // spadd(val_hi, val_lo, y)
136 const y = @intToFloat(f64, k);
137 const ww = y + val_hi;
138 val_lo += (y - ww) + val_hi;
139 val_hi = ww;
140
141 return val_lo + val_hi;
142}
143
144pub fn __log2x(a: f80) callconv(.C) f80 {
145 // TODO: more efficient implementation
146 return @floatCast(f80, log2q(a));
147}
148
149pub fn log2q(a: f128) callconv(.C) f128 {
150 return math.log2(a);
151}
152
153test "log2_32" {
154 const epsilon = 0.000001;
155
156 try expect(math.approxEqAbs(f32, log2f(0.2), -2.321928, epsilon));
157 try expect(math.approxEqAbs(f32, log2f(0.8923), -0.164399, epsilon));
158 try expect(math.approxEqAbs(f32, log2f(1.5), 0.584962, epsilon));
159 try expect(math.approxEqAbs(f32, log2f(37.45), 5.226894, epsilon));
160 try expect(math.approxEqAbs(f32, log2f(123123.234375), 16.909744, epsilon));
161}
162
163test "log2_64" {
164 const epsilon = 0.000001;
165
166 try expect(math.approxEqAbs(f64, log2(0.2), -2.321928, epsilon));
167 try expect(math.approxEqAbs(f64, log2(0.8923), -0.164399, epsilon));
168 try expect(math.approxEqAbs(f64, log2(1.5), 0.584962, epsilon));
169 try expect(math.approxEqAbs(f64, log2(37.45), 5.226894, epsilon));
170 try expect(math.approxEqAbs(f64, log2(123123.234375), 16.909744, epsilon));
171}
172
173test "log2_32.special" {
174 try expect(math.isPositiveInf(log2f(math.inf(f32))));
175 try expect(math.isNegativeInf(log2f(0.0)));
176 try expect(math.isNan(log2f(-1.0)));
177 try expect(math.isNan(log2f(math.nan(f32))));
178}
179
180test "log2_64.special" {
181 try expect(math.isPositiveInf(log2(math.inf(f64))));
182 try expect(math.isNegativeInf(log2(0.0)));
183 try expect(math.isNan(log2(-1.0)));
184 try expect(math.isNan(log2(math.nan(f64))));
185}
lib/std/special/compiler_rt/rem_pio2.zig created+198
......@@ -0,0 +1,198 @@
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_pio2.c
5
6const std = @import("std");
7const rem_pio2_large = @import("rem_pio2_large.zig").rem_pio2_large;
8const math = std.math;
9
10const toint = 1.5 / math.floatEps(f64);
11// pi/4
12const pio4 = 0x1.921fb54442d18p-1;
13// invpio2: 53 bits of 2/pi
14const invpio2 = 6.36619772367581382433e-01; // 0x3FE45F30, 0x6DC9C883
15// pio2_1: first 33 bit of pi/2
16const pio2_1 = 1.57079632673412561417e+00; // 0x3FF921FB, 0x54400000
17// pio2_1t: pi/2 - pio2_1
18const pio2_1t = 6.07710050650619224932e-11; // 0x3DD0B461, 0x1A626331
19// pio2_2: second 33 bit of pi/2
20const pio2_2 = 6.07710050630396597660e-11; // 0x3DD0B461, 0x1A600000
21// pio2_2t: pi/2 - (pio2_1+pio2_2)
22const pio2_2t = 2.02226624879595063154e-21; // 0x3BA3198A, 0x2E037073
23// pio2_3: third 33 bit of pi/2
24const pio2_3 = 2.02226624871116645580e-21; // 0x3BA3198A, 0x2E000000
25// pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3)
26const pio2_3t = 8.47842766036889956997e-32; // 0x397B839A, 0x252049C1
27
28fn U(x: anytype) usize {
29 return @intCast(usize, x);
30}
31
32fn medium(ix: u32, x: f64, y: *[2]f64) i32 {
33 var w: f64 = undefined;
34 var t: f64 = undefined;
35 var r: f64 = undefined;
36 var @"fn": f64 = undefined;
37 var n: i32 = undefined;
38 var ex: i32 = undefined;
39 var ey: i32 = undefined;
40 var ui: u64 = undefined;
41
42 // rint(x/(pi/2))
43 @"fn" = x * invpio2 + toint - toint;
44 n = @floatToInt(i32, @"fn");
45 r = x - @"fn" * pio2_1;
46 w = @"fn" * pio2_1t; // 1st round, good to 85 bits
47 // Matters with directed rounding.
48 if (r - w < -pio4) {
49 n -= 1;
50 @"fn" -= 1;
51 r = x - @"fn" * pio2_1;
52 w = @"fn" * pio2_1t;
53 } else if (r - w > pio4) {
54 n += 1;
55 @"fn" += 1;
56 r = x - @"fn" * pio2_1;
57 w = @"fn" * pio2_1t;
58 }
59 y[0] = r - w;
60 ui = @bitCast(u64, y[0]);
61 ey = @intCast(i32, (ui >> 52) & 0x7ff);
62 ex = @intCast(i32, ix >> 20);
63 if (ex - ey > 16) { // 2nd round, good to 118 bits
64 t = r;
65 w = @"fn" * pio2_2;
66 r = t - w;
67 w = @"fn" * pio2_2t - ((t - r) - w);
68 y[0] = r - w;
69 ui = @bitCast(u64, y[0]);
70 ey = @intCast(i32, (ui >> 52) & 0x7ff);
71 if (ex - ey > 49) { // 3rd round, good to 151 bits, covers all cases
72 t = r;
73 w = @"fn" * pio2_3;
74 r = t - w;
75 w = @"fn" * pio2_3t - ((t - r) - w);
76 y[0] = r - w;
77 }
78 }
79 y[1] = (r - y[0]) - w;
80 return n;
81}
82
83// Returns the remainder of x rem pi/2 in y[0]+y[1]
84//
85// use rem_pio2_large() for large x
86//
87// caller must handle the case when reduction is not needed: |x| ~<= pi/4 */
88pub fn rem_pio2(x: f64, y: *[2]f64) i32 {
89 var z: f64 = undefined;
90 var tx: [3]f64 = undefined;
91 var ty: [2]f64 = undefined;
92 var n: i32 = undefined;
93 var ix: u32 = undefined;
94 var sign: bool = undefined;
95 var i: i32 = undefined;
96 var ui: u64 = undefined;
97
98 ui = @bitCast(u64, x);
99 sign = ui >> 63 != 0;
100 ix = @truncate(u32, (ui >> 32) & 0x7fffffff);
101 if (ix <= 0x400f6a7a) { // |x| ~<= 5pi/4
102 if ((ix & 0xfffff) == 0x921fb) { // |x| ~= pi/2 or 2pi/2
103 return medium(ix, x, y);
104 }
105 if (ix <= 0x4002d97c) { // |x| ~<= 3pi/4
106 if (!sign) {
107 z = x - pio2_1; // one round good to 85 bits
108 y[0] = z - pio2_1t;
109 y[1] = (z - y[0]) - pio2_1t;
110 return 1;
111 } else {
112 z = x + pio2_1;
113 y[0] = z + pio2_1t;
114 y[1] = (z - y[0]) + pio2_1t;
115 return -1;
116 }
117 } else {
118 if (!sign) {
119 z = x - 2 * pio2_1;
120 y[0] = z - 2 * pio2_1t;
121 y[1] = (z - y[0]) - 2 * pio2_1t;
122 return 2;
123 } else {
124 z = x + 2 * pio2_1;
125 y[0] = z + 2 * pio2_1t;
126 y[1] = (z - y[0]) + 2 * pio2_1t;
127 return -2;
128 }
129 }
130 }
131 if (ix <= 0x401c463b) { // |x| ~<= 9pi/4
132 if (ix <= 0x4015fdbc) { // |x| ~<= 7pi/4
133 if (ix == 0x4012d97c) { // |x| ~= 3pi/2
134 return medium(ix, x, y);
135 }
136 if (!sign) {
137 z = x - 3 * pio2_1;
138 y[0] = z - 3 * pio2_1t;
139 y[1] = (z - y[0]) - 3 * pio2_1t;
140 return 3;
141 } else {
142 z = x + 3 * pio2_1;
143 y[0] = z + 3 * pio2_1t;
144 y[1] = (z - y[0]) + 3 * pio2_1t;
145 return -3;
146 }
147 } else {
148 if (ix == 0x401921fb) { // |x| ~= 4pi/2 */
149 return medium(ix, x, y);
150 }
151 if (!sign) {
152 z = x - 4 * pio2_1;
153 y[0] = z - 4 * pio2_1t;
154 y[1] = (z - y[0]) - 4 * pio2_1t;
155 return 4;
156 } else {
157 z = x + 4 * pio2_1;
158 y[0] = z + 4 * pio2_1t;
159 y[1] = (z - y[0]) + 4 * pio2_1t;
160 return -4;
161 }
162 }
163 }
164 if (ix < 0x413921fb) { // |x| ~< 2^20*(pi/2), medium size
165 return medium(ix, x, y);
166 }
167 // all other (large) arguments
168 if (ix >= 0x7ff00000) { // x is inf or NaN
169 y[0] = x - x;
170 y[1] = y[0];
171 return 0;
172 }
173 // set z = scalbn(|x|,-ilogb(x)+23)
174 ui = @bitCast(u64, x);
175 ui &= std.math.maxInt(u64) >> 12;
176 ui |= @as(u64, 0x3ff + 23) << 52;
177 z = @bitCast(f64, ui);
178
179 i = 0;
180 while (i < 2) : (i += 1) {
181 tx[U(i)] = @intToFloat(f64, @floatToInt(i32, z));
182 z = (z - tx[U(i)]) * 0x1p24;
183 }
184 tx[U(i)] = z;
185 // skip zero terms, first term is non-zero
186 while (tx[U(i)] == 0.0) {
187 i -= 1;
188 }
189 n = rem_pio2_large(tx[0..], ty[0..], @intCast(i32, (ix >> 20)) - (0x3ff + 23), i + 1, 1);
190 if (sign) {
191 y[0] = -ty[0];
192 y[1] = -ty[1];
193 return -n;
194 }
195 y[0] = ty[0];
196 y[1] = ty[1];
197 return n;
198}
lib/std/special/compiler_rt/rem_pio2_large.zig created+506
......@@ -0,0 +1,506 @@
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_pio2_large.c
5
6const std = @import("std");
7const math = std.math;
8
9const init_jk = [_]i32{ 3, 4, 4, 6 }; // initial value for jk
10
11///
12/// Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
13///
14/// integer array, contains the (24*i)-th to (24*i+23)-th
15/// bit of 2/pi after binary point. The corresponding
16/// floating value is
17///
18/// ipio2[i] * 2^(-24(i+1)).
19///
20/// NB: This table must have at least (e0-3)/24 + jk terms.
21/// For quad precision (e0 <= 16360, jk = 6), this is 686.
22const ipio2 = [_]i32{
23 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62,
24 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A,
25 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129,
26 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41,
27 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8,
28 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF,
29 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5,
30 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08,
31 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3,
32 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880,
33 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B,
34
35 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6,
36 0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2,
37 0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35,
38 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30,
39 0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C,
40 0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4,
41 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770,
42 0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7,
43 0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19,
44 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522,
45 0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16,
46 0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6,
47 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E,
48 0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48,
49 0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3,
50 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF,
51 0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55,
52 0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612,
53 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929,
54 0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC,
55 0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B,
56 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C,
57 0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4,
58 0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB,
59 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC,
60 0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C,
61 0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F,
62 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5,
63 0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437,
64 0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B,
65 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA,
66 0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD,
67 0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3,
68 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3,
69 0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717,
70 0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F,
71 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61,
72 0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB,
73 0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51,
74 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0,
75 0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C,
76 0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6,
77 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC,
78 0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED,
79 0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328,
80 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D,
81 0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0,
82 0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B,
83 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4,
84 0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3,
85 0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F,
86 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD,
87 0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B,
88 0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4,
89 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761,
90 0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31,
91 0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30,
92 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262,
93 0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E,
94 0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1,
95 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C,
96 0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4,
97 0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08,
98 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196,
99 0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9,
100 0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4,
101 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC,
102 0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C,
103 0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0,
104 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C,
105 0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0,
106 0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC,
107 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22,
108 0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893,
109 0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7,
110 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5,
111 0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F,
112 0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4,
113 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF,
114 0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B,
115 0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2,
116 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138,
117 0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E,
118 0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569,
119 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34,
120 0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9,
121 0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D,
122 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F,
123 0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855,
124 0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569,
125 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B,
126 0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE,
127 0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41,
128 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49,
129 0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F,
130 0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110,
131 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8,
132 0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365,
133 0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A,
134 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270,
135 0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5,
136 0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616,
137 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B,
138 0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0,
139};
140
141const PIo2 = [_]f64{
142 1.57079625129699707031e+00, // 0x3FF921FB, 0x40000000
143 7.54978941586159635335e-08, // 0x3E74442D, 0x00000000
144 5.39030252995776476554e-15, // 0x3CF84698, 0x80000000
145 3.28200341580791294123e-22, // 0x3B78CC51, 0x60000000
146 1.27065575308067607349e-29, // 0x39F01B83, 0x80000000
147 1.22933308981111328932e-36, // 0x387A2520, 0x40000000
148 2.73370053816464559624e-44, // 0x36E38222, 0x80000000
149 2.16741683877804819444e-51, // 0x3569F31D, 0x00000000
150};
151
152fn U(x: anytype) usize {
153 return @intCast(usize, x);
154}
155
156/// Returns the last three digits of N with y = x - N*pi/2 so that |y| < pi/2.
157///
158/// The method is to compute the integer (mod 8) and fraction parts of
159/// (2/pi)*x without doing the full multiplication. In general we
160/// skip the part of the product that are known to be a huge integer (
161/// more accurately, = 0 mod 8 ). Thus the number of operations are
162/// independent of the exponent of the input.
163///
164/// (2/pi) is represented by an array of 24-bit integers in ipio2[].
165///
166/// Input parameters:
167/// x[] The input value (must be positive) is broken into nx
168/// pieces of 24-bit integers in double precision format.
169/// x[i] will be the i-th 24 bit of x. The scaled exponent
170/// of x[0] is given in input parameter e0 (i.e., x[0]*2^e0
171/// match x's up to 24 bits.
172///
173/// Example of breaking a double positive z into x[0]+x[1]+x[2]:
174/// e0 = ilogb(z)-23
175/// z = scalbn(z,-e0)
176/// for i = 0,1,2
177/// x[i] = floor(z)
178/// z = (z-x[i])*2**24
179///
180///
181/// y[] ouput result in an array of double precision numbers.
182/// The dimension of y[] is:
183/// 24-bit precision 1
184/// 53-bit precision 2
185/// 64-bit precision 2
186/// 113-bit precision 3
187/// The actual value is the sum of them. Thus for 113-bit
188/// precison, one may have to do something like:
189///
190/// long double t,w,r_head, r_tail;
191/// t = (long double)y[2] + (long double)y[1];
192/// w = (long double)y[0];
193/// r_head = t+w;
194/// r_tail = w - (r_head - t);
195///
196/// e0 The exponent of x[0]. Must be <= 16360 or you need to
197/// expand the ipio2 table.
198///
199/// nx dimension of x[]
200///
201/// prec an integer indicating the precision:
202/// 0 24 bits (single)
203/// 1 53 bits (double)
204/// 2 64 bits (extended)
205/// 3 113 bits (quad)
206///
207/// Here is the description of some local variables:
208///
209/// jk jk+1 is the initial number of terms of ipio2[] needed
210/// in the computation. The minimum and recommended value
211/// for jk is 3,4,4,6 for single, double, extended, and quad.
212/// jk+1 must be 2 larger than you might expect so that our
213/// recomputation test works. (Up to 24 bits in the integer
214/// part (the 24 bits of it that we compute) and 23 bits in
215/// the fraction part may be lost to cancelation before we
216/// recompute.)
217///
218/// jz local integer variable indicating the number of
219/// terms of ipio2[] used.
220///
221/// jx nx - 1
222///
223/// jv index for pointing to the suitable ipio2[] for the
224/// computation. In general, we want
225/// ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8
226/// is an integer. Thus
227/// e0-3-24*jv >= 0 or (e0-3)/24 >= jv
228/// Hence jv = max(0,(e0-3)/24).
229///
230/// jp jp+1 is the number of terms in PIo2[] needed, jp = jk.
231///
232/// q[] double array with integral value, representing the
233/// 24-bits chunk of the product of x and 2/pi.
234///
235/// q0 the corresponding exponent of q[0]. Note that the
236/// exponent for q[i] would be q0-24*i.
237///
238/// PIo2[] double precision array, obtained by cutting pi/2
239/// into 24 bits chunks.
240///
241/// f[] ipio2[] in floating point
242///
243/// iq[] integer array by breaking up q[] in 24-bits chunk.
244///
245/// fq[] final product of x*(2/pi) in fq[0],..,fq[jk]
246///
247/// ih integer. If >0 it indicates q[] is >= 0.5, hence
248/// it also indicates the *sign* of the result.
249///
250///
251///
252/// Constants:
253/// The hexadecimal values are the intended ones for the following
254/// constants. The decimal values may be used, provided that the
255/// compiler will convert from decimal to binary accurately enough
256/// to produce the hexadecimal values shown.
257///
258pub fn rem_pio2_large(x: []f64, y: []f64, e0: i32, nx: i32, prec: usize) i32 {
259 var jz: i32 = undefined;
260 var jx: i32 = undefined;
261 var jv: i32 = undefined;
262 var jp: i32 = undefined;
263 var jk: i32 = undefined;
264 var carry: i32 = undefined;
265 var n: i32 = undefined;
266 var iq: [20]i32 = undefined;
267 var i: i32 = undefined;
268 var j: i32 = undefined;
269 var k: i32 = undefined;
270 var m: i32 = undefined;
271 var q0: i32 = undefined;
272 var ih: i32 = undefined;
273
274 var z: f64 = undefined;
275 var fw: f64 = undefined;
276 var f: [20]f64 = undefined;
277 var fq: [20]f64 = undefined;
278 var q: [20]f64 = undefined;
279
280 // initialize jk
281 jk = init_jk[prec];
282 jp = jk;
283
284 // determine jx,jv,q0, note that 3>q0
285 jx = nx - 1;
286 jv = @divFloor(e0 - 3, 24);
287 if (jv < 0) jv = 0;
288 q0 = e0 - 24 * (jv + 1);
289
290 // set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk]
291 j = jv - jx;
292 m = jx + jk;
293 i = 0;
294 while (i <= m) : ({
295 i += 1;
296 j += 1;
297 }) {
298 f[U(i)] = if (j < 0) 0.0 else @intToFloat(f64, ipio2[U(j)]);
299 }
300
301 // compute q[0],q[1],...q[jk]
302 i = 0;
303 while (i <= jk) : (i += 1) {
304 j = 0;
305 fw = 0;
306 while (j <= jx) : (j += 1) {
307 fw += x[U(j)] * f[U(jx + i - j)];
308 }
309 q[U(i)] = fw;
310 }
311
312 jz = jk;
313
314 // This is to handle a non-trivial goto translation from C.
315 // An unconditional return statement is found at the end of this loop.
316 recompute: while (true) {
317 // distill q[] into iq[] reversingly
318 i = 0;
319 j = jz;
320 z = q[U(jz)];
321 while (j > 0) : ({
322 i += 1;
323 j -= 1;
324 }) {
325 fw = @intToFloat(f64, @floatToInt(i32, 0x1p-24 * z));
326 iq[U(i)] = @floatToInt(i32, z - 0x1p24 * fw);
327 z = q[U(j - 1)] + fw;
328 }
329
330 // compute n
331 z = math.scalbn(z, q0); // actual value of z
332 z -= 8.0 * @floor(z * 0.125); // trim off integer >= 8
333 n = @floatToInt(i32, z);
334 z -= @intToFloat(f64, n);
335 ih = 0;
336 if (q0 > 0) { // need iq[jz-1] to determine n
337 i = iq[U(jz - 1)] >> @intCast(u5, 24 - q0);
338 n += i;
339 iq[U(jz - 1)] -= i << @intCast(u5, 24 - q0);
340 ih = iq[U(jz - 1)] >> @intCast(u5, 23 - q0);
341 } else if (q0 == 0) {
342 ih = iq[U(jz - 1)] >> 23;
343 } else if (z >= 0.5) {
344 ih = 2;
345 }
346
347 if (ih > 0) { // q > 0.5
348 n += 1;
349 carry = 0;
350 i = 0;
351 while (i < jz) : (i += 1) { // compute 1-q
352 j = iq[U(i)];
353 if (carry == 0) {
354 if (j != 0) {
355 carry = 1;
356 iq[U(i)] = 0x1000000 - j;
357 }
358 } else {
359 iq[U(i)] = 0xffffff - j;
360 }
361 }
362 if (q0 > 0) { // rare case: chance is 1 in 12
363 switch (q0) {
364 1 => iq[U(jz - 1)] &= 0x7fffff,
365 2 => iq[U(jz - 1)] &= 0x3fffff,
366 else => unreachable,
367 }
368 }
369 if (ih == 2) {
370 z = 1.0 - z;
371 if (carry != 0) {
372 z -= math.scalbn(@as(f64, 1.0), q0);
373 }
374 }
375 }
376
377 // check if recomputation is needed
378 if (z == 0.0) {
379 j = 0;
380 i = jz - 1;
381 while (i >= jk) : (i -= 1) {
382 j |= iq[U(i)];
383 }
384
385 if (j == 0) { // need recomputation
386 k = 1;
387 while (iq[U(jk - k)] == 0) : (k += 1) {
388 // k = no. of terms needed
389 }
390
391 i = jz + 1;
392 while (i <= jz + k) : (i += 1) { // add q[jz+1] to q[jz+k]
393 f[U(jx + i)] = @intToFloat(f64, ipio2[U(jv + i)]);
394 j = 0;
395 fw = 0;
396 while (j <= jx) : (j += 1) {
397 fw += x[U(j)] * f[U(jx + i - j)];
398 }
399 q[U(i)] = fw;
400 }
401 jz += k;
402 continue :recompute; // mimic goto recompute
403 }
404 }
405
406 // chop off zero terms
407 if (z == 0.0) {
408 jz -= 1;
409 q0 -= 24;
410 while (iq[U(jz)] == 0) {
411 jz -= 1;
412 q0 -= 24;
413 }
414 } else { // break z into 24-bit if necessary
415 z = math.scalbn(z, -q0);
416 if (z >= 0x1p24) {
417 fw = @intToFloat(f64, @floatToInt(i32, 0x1p-24 * z));
418 iq[U(jz)] = @floatToInt(i32, z - 0x1p24 * fw);
419 jz += 1;
420 q0 += 24;
421 iq[U(jz)] = @floatToInt(i32, fw);
422 } else {
423 iq[U(jz)] = @floatToInt(i32, z);
424 }
425 }
426
427 // convert integer "bit" chunk to floating-point value
428 fw = math.scalbn(@as(f64, 1.0), q0);
429 i = jz;
430 while (i >= 0) : (i -= 1) {
431 q[U(i)] = fw * @intToFloat(f64, iq[U(i)]);
432 fw *= 0x1p-24;
433 }
434
435 // compute PIo2[0,...,jp]*q[jz,...,0]
436 i = jz;
437 while (i >= 0) : (i -= 1) {
438 fw = 0;
439 k = 0;
440 while (k <= jp and k <= jz - i) : (k += 1) {
441 fw += PIo2[U(k)] * q[U(i + k)];
442 }
443 fq[U(jz - i)] = fw;
444 }
445
446 // compress fq[] into y[]
447 switch (prec) {
448 0 => {
449 fw = 0.0;
450 i = jz;
451 while (i >= 0) : (i -= 1) {
452 fw += fq[U(i)];
453 }
454 y[0] = if (ih == 0) fw else -fw;
455 },
456
457 1, 2 => {
458 fw = 0.0;
459 i = jz;
460 while (i >= 0) : (i -= 1) {
461 fw += fq[U(i)];
462 }
463 // TODO: drop excess precision here once double_t is used
464 fw = fw;
465 y[0] = if (ih == 0) fw else -fw;
466 fw = fq[0] - fw;
467 i = 1;
468 while (i <= jz) : (i += 1) {
469 fw += fq[U(i)];
470 }
471 y[1] = if (ih == 0) fw else -fw;
472 },
473 3 => { // painful
474 i = jz;
475 while (i > 0) : (i -= 1) {
476 fw = fq[U(i - 1)] + fq[U(i)];
477 fq[U(i)] += fq[U(i - 1)] - fw;
478 fq[U(i - 1)] = fw;
479 }
480 i = jz;
481 while (i > 1) : (i -= 1) {
482 fw = fq[U(i - 1)] + fq[U(i)];
483 fq[U(i)] += fq[U(i - 1)] - fw;
484 fq[U(i - 1)] = fw;
485 }
486 fw = 0;
487 i = jz;
488 while (i >= 2) : (i -= 1) {
489 fw += fq[U(i)];
490 }
491 if (ih == 0) {
492 y[0] = fq[0];
493 y[1] = fq[1];
494 y[2] = fw;
495 } else {
496 y[0] = -fq[0];
497 y[1] = -fq[1];
498 y[2] = -fw;
499 }
500 },
501 else => unreachable,
502 }
503
504 return n & 7;
505 }
506}
lib/std/special/compiler_rt/rem_pio2f.zig created+70
......@@ -0,0 +1,70 @@
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_pio2f.c
5
6const std = @import("std");
7const rem_pio2_large = @import("rem_pio2_large.zig").rem_pio2_large;
8const math = std.math;
9
10const toint = 1.5 / math.floatEps(f64);
11// pi/4
12const pio4 = 0x1.921fb6p-1;
13// invpio2: 53 bits of 2/pi
14const invpio2 = 6.36619772367581382433e-01; // 0x3FE45F30, 0x6DC9C883
15// pio2_1: first 25 bits of pi/2
16const pio2_1 = 1.57079631090164184570e+00; // 0x3FF921FB, 0x50000000
17// pio2_1t: pi/2 - pio2_1
18const pio2_1t = 1.58932547735281966916e-08; // 0x3E5110b4, 0x611A6263
19
20// Returns the remainder of x rem pi/2 in *y
21// use double precision for everything except passing x
22// use rem_pio2_large() for large x
23pub fn rem_pio2f(x: f32, y: *f64) i32 {
24 var tx: [1]f64 = undefined;
25 var ty: [1]f64 = undefined;
26 var @"fn": f64 = undefined;
27 var ix: u32 = undefined;
28 var n: i32 = undefined;
29 var sign: bool = undefined;
30 var e0: u32 = undefined;
31 var ui: u32 = undefined;
32
33 ui = @bitCast(u32, x);
34 ix = ui & 0x7fffffff;
35
36 // 25+53 bit pi is good enough for medium size
37 if (ix < 0x4dc90fdb) { // |x| ~< 2^28*(pi/2), medium size
38 // Use a specialized rint() to get fn.
39 @"fn" = @floatCast(f64, x) * invpio2 + toint - toint;
40 n = @floatToInt(i32, @"fn");
41 y.* = x - @"fn" * pio2_1 - @"fn" * pio2_1t;
42 // Matters with directed rounding.
43 if (y.* < -pio4) {
44 n -= 1;
45 @"fn" -= 1;
46 y.* = x - @"fn" * pio2_1 - @"fn" * pio2_1t;
47 } else if (y.* > pio4) {
48 n += 1;
49 @"fn" += 1;
50 y.* = x - @"fn" * pio2_1 - @"fn" * pio2_1t;
51 }
52 return n;
53 }
54 if (ix >= 0x7f800000) { // x is inf or NaN
55 y.* = x - x;
56 return 0;
57 }
58 // scale x into [2^23, 2^24-1]
59 sign = ui >> 31 != 0;
60 e0 = (ix >> 23) - (0x7f + 23); // e0 = ilogb(|x|)-23, positive
61 ui = ix - (e0 << 23);
62 tx[0] = @bitCast(f32, ui);
63 n = rem_pio2_large(&tx, &ty, @intCast(i32, e0), 1, 0);
64 if (sign) {
65 y.* = -ty[0];
66 return -n;
67 }
68 y.* = ty[0];
69 return n;
70}
lib/std/special/compiler_rt/round.zig created+169
......@@ -0,0 +1,169 @@
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/roundf.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/round.c
6
7const std = @import("std");
8const math = std.math;
9const expect = std.testing.expect;
10
11pub fn __roundh(x: f16) callconv(.C) f16 {
12 // TODO: more efficient implementation
13 return @floatCast(f16, roundf(x));
14}
15
16pub fn roundf(x_: f32) callconv(.C) f32 {
17 const f32_toint = 1.0 / math.floatEps(f32);
18
19 var x = x_;
20 const u = @bitCast(u32, x);
21 const e = (u >> 23) & 0xFF;
22 var y: f32 = undefined;
23
24 if (e >= 0x7F + 23) {
25 return x;
26 }
27 if (u >> 31 != 0) {
28 x = -x;
29 }
30 if (e < 0x7F - 1) {
31 math.doNotOptimizeAway(x + f32_toint);
32 return 0 * @bitCast(f32, u);
33 }
34
35 y = x + f32_toint - f32_toint - x;
36 if (y > 0.5) {
37 y = y + x - 1;
38 } else if (y <= -0.5) {
39 y = y + x + 1;
40 } else {
41 y = y + x;
42 }
43
44 if (u >> 31 != 0) {
45 return -y;
46 } else {
47 return y;
48 }
49}
50
51pub fn round(x_: f64) callconv(.C) f64 {
52 const f64_toint = 1.0 / math.floatEps(f64);
53
54 var x = x_;
55 const u = @bitCast(u64, x);
56 const e = (u >> 52) & 0x7FF;
57 var y: f64 = undefined;
58
59 if (e >= 0x3FF + 52) {
60 return x;
61 }
62 if (u >> 63 != 0) {
63 x = -x;
64 }
65 if (e < 0x3ff - 1) {
66 math.doNotOptimizeAway(x + f64_toint);
67 return 0 * @bitCast(f64, u);
68 }
69
70 y = x + f64_toint - f64_toint - x;
71 if (y > 0.5) {
72 y = y + x - 1;
73 } else if (y <= -0.5) {
74 y = y + x + 1;
75 } else {
76 y = y + x;
77 }
78
79 if (u >> 63 != 0) {
80 return -y;
81 } else {
82 return y;
83 }
84}
85
86pub fn __roundx(x: f80) callconv(.C) f80 {
87 // TODO: more efficient implementation
88 return @floatCast(f80, roundq(x));
89}
90
91pub fn roundq(x_: f128) callconv(.C) f128 {
92 const f128_toint = 1.0 / math.floatEps(f128);
93
94 var x = x_;
95 const u = @bitCast(u128, x);
96 const e = (u >> 112) & 0x7FFF;
97 var y: f128 = undefined;
98
99 if (e >= 0x3FFF + 112) {
100 return x;
101 }
102 if (u >> 127 != 0) {
103 x = -x;
104 }
105 if (e < 0x3FFF - 1) {
106 math.doNotOptimizeAway(x + f128_toint);
107 return 0 * @bitCast(f128, u);
108 }
109
110 y = x + f128_toint - f128_toint - x;
111 if (y > 0.5) {
112 y = y + x - 1;
113 } else if (y <= -0.5) {
114 y = y + x + 1;
115 } else {
116 y = y + x;
117 }
118
119 if (u >> 127 != 0) {
120 return -y;
121 } else {
122 return y;
123 }
124}
125
126test "round32" {
127 try expect(roundf(1.3) == 1.0);
128 try expect(roundf(-1.3) == -1.0);
129 try expect(roundf(0.2) == 0.0);
130 try expect(roundf(1.8) == 2.0);
131}
132
133test "round64" {
134 try expect(round(1.3) == 1.0);
135 try expect(round(-1.3) == -1.0);
136 try expect(round(0.2) == 0.0);
137 try expect(round(1.8) == 2.0);
138}
139
140test "round128" {
141 try expect(roundq(1.3) == 1.0);
142 try expect(roundq(-1.3) == -1.0);
143 try expect(roundq(0.2) == 0.0);
144 try expect(roundq(1.8) == 2.0);
145}
146
147test "round32.special" {
148 try expect(roundf(0.0) == 0.0);
149 try expect(roundf(-0.0) == -0.0);
150 try expect(math.isPositiveInf(roundf(math.inf(f32))));
151 try expect(math.isNegativeInf(roundf(-math.inf(f32))));
152 try expect(math.isNan(roundf(math.nan(f32))));
153}
154
155test "round64.special" {
156 try expect(round(0.0) == 0.0);
157 try expect(round(-0.0) == -0.0);
158 try expect(math.isPositiveInf(round(math.inf(f64))));
159 try expect(math.isNegativeInf(round(-math.inf(f64))));
160 try expect(math.isNan(round(math.nan(f64))));
161}
162
163test "round128.special" {
164 try expect(roundq(0.0) == 0.0);
165 try expect(roundq(-0.0) == -0.0);
166 try expect(math.isPositiveInf(roundq(math.inf(f128))));
167 try expect(math.isNegativeInf(roundq(-math.inf(f128))));
168 try expect(math.isNan(roundq(math.nan(f128))));
169}
lib/std/special/compiler_rt/sin.zig created+168
......@@ -0,0 +1,168 @@
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/sinf.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/sin.c
6
7const std = @import("std");
8const math = std.math;
9const expect = std.testing.expect;
10
11const kernel = @import("trig.zig");
12const rem_pio2 = @import("rem_pio2.zig").rem_pio2;
13const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f;
14
15pub fn __sinh(x: f16) callconv(.C) f16 {
16 // TODO: more efficient implementation
17 return @floatCast(f16, sinf(x));
18}
19
20pub fn sinf(x: f32) callconv(.C) f32 {
21 // Small multiples of pi/2 rounded to double precision.
22 const s1pio2: f64 = 1.0 * math.pi / 2.0; // 0x3FF921FB, 0x54442D18
23 const s2pio2: f64 = 2.0 * math.pi / 2.0; // 0x400921FB, 0x54442D18
24 const s3pio2: f64 = 3.0 * math.pi / 2.0; // 0x4012D97C, 0x7F3321D2
25 const s4pio2: f64 = 4.0 * math.pi / 2.0; // 0x401921FB, 0x54442D18
26
27 var ix = @bitCast(u32, x);
28 const sign = ix >> 31 != 0;
29 ix &= 0x7fffffff;
30
31 if (ix <= 0x3f490fda) { // |x| ~<= pi/4
32 if (ix < 0x39800000) { // |x| < 2**-12
33 // raise inexact if x!=0 and underflow if subnormal
34 math.doNotOptimizeAway(if (ix < 0x00800000) x / 0x1p120 else x + 0x1p120);
35 return x;
36 }
37 return kernel.__sindf(x);
38 }
39 if (ix <= 0x407b53d1) { // |x| ~<= 5*pi/4
40 if (ix <= 0x4016cbe3) { // |x| ~<= 3pi/4
41 if (sign) {
42 return -kernel.__cosdf(x + s1pio2);
43 } else {
44 return kernel.__cosdf(x - s1pio2);
45 }
46 }
47 return kernel.__sindf(if (sign) -(x + s2pio2) else -(x - s2pio2));
48 }
49 if (ix <= 0x40e231d5) { // |x| ~<= 9*pi/4
50 if (ix <= 0x40afeddf) { // |x| ~<= 7*pi/4
51 if (sign) {
52 return kernel.__cosdf(x + s3pio2);
53 } else {
54 return -kernel.__cosdf(x - s3pio2);
55 }
56 }
57 return kernel.__sindf(if (sign) x + s4pio2 else x - s4pio2);
58 }
59
60 // sin(Inf or NaN) is NaN
61 if (ix >= 0x7f800000) {
62 return x - x;
63 }
64
65 var y: f64 = undefined;
66 const n = rem_pio2f(x, &y);
67 return switch (n & 3) {
68 0 => kernel.__sindf(y),
69 1 => kernel.__cosdf(y),
70 2 => kernel.__sindf(-y),
71 else => -kernel.__cosdf(y),
72 };
73}
74
75pub fn sin(x: f64) callconv(.C) f64 {
76 var ix = @bitCast(u64, x) >> 32;
77 ix &= 0x7fffffff;
78
79 // |x| ~< pi/4
80 if (ix <= 0x3fe921fb) {
81 if (ix < 0x3e500000) { // |x| < 2**-26
82 // raise inexact if x != 0 and underflow if subnormal
83 math.doNotOptimizeAway(if (ix < 0x00100000) x / 0x1p120 else x + 0x1p120);
84 return x;
85 }
86 return kernel.__sin(x, 0.0, 0);
87 }
88
89 // sin(Inf or NaN) is NaN
90 if (ix >= 0x7ff00000) {
91 return x - x;
92 }
93
94 var y: [2]f64 = undefined;
95 const n = rem_pio2(x, &y);
96 return switch (n & 3) {
97 0 => kernel.__sin(y[0], y[1], 1),
98 1 => kernel.__cos(y[0], y[1]),
99 2 => -kernel.__sin(y[0], y[1], 1),
100 else => -kernel.__cos(y[0], y[1]),
101 };
102}
103
104pub fn __sinx(x: f80) callconv(.C) f80 {
105 // TODO: more efficient implementation
106 return @floatCast(f80, sinq(x));
107}
108
109pub fn sinq(x: f128) callconv(.C) f128 {
110 // TODO: more correct implementation
111 return sin(@floatCast(f64, x));
112}
113
114test "sin" {
115 try expect(sin(@as(f32, 0.0)) == sinf(0.0));
116 try expect(sin(@as(f64, 0.0)) == sin(0.0));
117 try expect(comptime (math.sin(@as(f64, 2))) == math.sin(@as(f64, 2)));
118}
119
120test "sin32" {
121 const epsilon = 0.00001;
122
123 try expect(math.approxEqAbs(f32, sinf(0.0), 0.0, epsilon));
124 try expect(math.approxEqAbs(f32, sinf(0.2), 0.198669, epsilon));
125 try expect(math.approxEqAbs(f32, sinf(0.8923), 0.778517, epsilon));
126 try expect(math.approxEqAbs(f32, sinf(1.5), 0.997495, epsilon));
127 try expect(math.approxEqAbs(f32, sinf(-1.5), -0.997495, epsilon));
128 try expect(math.approxEqAbs(f32, sinf(37.45), -0.246544, epsilon));
129 try expect(math.approxEqAbs(f32, sinf(89.123), 0.916166, epsilon));
130}
131
132test "sin64" {
133 const epsilon = 0.000001;
134
135 try expect(math.approxEqAbs(f64, sin(0.0), 0.0, epsilon));
136 try expect(math.approxEqAbs(f64, sin(0.2), 0.198669, epsilon));
137 try expect(math.approxEqAbs(f64, sin(0.8923), 0.778517, epsilon));
138 try expect(math.approxEqAbs(f64, sin(1.5), 0.997495, epsilon));
139 try expect(math.approxEqAbs(f64, sin(-1.5), -0.997495, epsilon));
140 try expect(math.approxEqAbs(f64, sin(37.45), -0.246543, epsilon));
141 try expect(math.approxEqAbs(f64, sin(89.123), 0.916166, epsilon));
142}
143
144test "sin32.special" {
145 try expect(sinf(0.0) == 0.0);
146 try expect(sinf(-0.0) == -0.0);
147 try expect(math.isNan(sinf(math.inf(f32))));
148 try expect(math.isNan(sinf(-math.inf(f32))));
149 try expect(math.isNan(sinf(math.nan(f32))));
150}
151
152test "sin64.special" {
153 try expect(sin(0.0) == 0.0);
154 try expect(sin(-0.0) == -0.0);
155 try expect(math.isNan(sin(math.inf(f64))));
156 try expect(math.isNan(sin(-math.inf(f64))));
157 try expect(math.isNan(sin(math.nan(f64))));
158}
159
160test "sin32 #9901" {
161 const float = @bitCast(f32, @as(u32, 0b11100011111111110000000000000000));
162 _ = sinf(float);
163}
164
165test "sin64 #9901" {
166 const float = @bitCast(f64, @as(u64, 0b1111111101000001000000001111110111111111100000000000000000000001));
167 _ = sin(float);
168}
lib/std/special/compiler_rt/sincos.zig created+24
......@@ -0,0 +1,24 @@
1pub fn __sincosh(a: f16, r_sin: *f16, r_cos: *f16) callconv(.C) void {
2 r_sin.* = @sin(a);
3 r_cos.* = @cos(a);
4}
5
6pub fn sincosf(a: f32, r_sin: *f32, r_cos: *f32) callconv(.C) void {
7 r_sin.* = @sin(a);
8 r_cos.* = @cos(a);
9}
10
11pub fn sincos(a: f64, r_sin: *f64, r_cos: *f64) callconv(.C) void {
12 r_sin.* = @sin(a);
13 r_cos.* = @cos(a);
14}
15
16pub fn __sincosx(a: f80, r_sin: *f80, r_cos: *f80) callconv(.C) void {
17 r_sin.* = @sin(a);
18 r_cos.* = @cos(a);
19}
20
21pub fn sincosq(a: f128, r_sin: *f128, r_cos: *f128) callconv(.C) void {
22 r_sin.* = @sin(a);
23 r_cos.* = @cos(a);
24}
lib/std/special/compiler_rt/sqrt.zig created+284
......@@ -0,0 +1,284 @@
1const std = @import("std");
2const math = std.math;
3
4pub fn __sqrth(x: f16) callconv(.C) f16 {
5 // TODO: more efficient implementation
6 return @floatCast(f16, sqrtf(x));
7}
8
9pub fn sqrtf(x: f32) callconv(.C) f32 {
10 const tiny: f32 = 1.0e-30;
11 const sign: i32 = @bitCast(i32, @as(u32, 0x80000000));
12 var ix: i32 = @bitCast(i32, x);
13
14 if ((ix & 0x7F800000) == 0x7F800000) {
15 return x * x + x; // sqrt(nan) = nan, sqrt(+inf) = +inf, sqrt(-inf) = snan
16 }
17
18 // zero
19 if (ix <= 0) {
20 if (ix & ~sign == 0) {
21 return x; // sqrt (+-0) = +-0
22 }
23 if (ix < 0) {
24 return math.snan(f32);
25 }
26 }
27
28 // normalize
29 var m = ix >> 23;
30 if (m == 0) {
31 // subnormal
32 var i: i32 = 0;
33 while (ix & 0x00800000 == 0) : (i += 1) {
34 ix <<= 1;
35 }
36 m -= i - 1;
37 }
38
39 m -= 127; // unbias exponent
40 ix = (ix & 0x007FFFFF) | 0x00800000;
41
42 if (m & 1 != 0) { // odd m, double x to even
43 ix += ix;
44 }
45
46 m >>= 1; // m = [m / 2]
47
48 // sqrt(x) bit by bit
49 ix += ix;
50 var q: i32 = 0; // q = sqrt(x)
51 var s: i32 = 0;
52 var r: i32 = 0x01000000; // r = moving bit right -> left
53
54 while (r != 0) {
55 const t = s + r;
56 if (t <= ix) {
57 s = t + r;
58 ix -= t;
59 q += r;
60 }
61 ix += ix;
62 r >>= 1;
63 }
64
65 // floating add to find rounding direction
66 if (ix != 0) {
67 var z = 1.0 - tiny; // inexact
68 if (z >= 1.0) {
69 z = 1.0 + tiny;
70 if (z > 1.0) {
71 q += 2;
72 } else {
73 if (q & 1 != 0) {
74 q += 1;
75 }
76 }
77 }
78 }
79
80 ix = (q >> 1) + 0x3f000000;
81 ix += m << 23;
82 return @bitCast(f32, ix);
83}
84
85/// NOTE: The original code is full of implicit signed -> unsigned assumptions and u32 wraparound
86/// behaviour. Most intermediate i32 values are changed to u32 where appropriate but there are
87/// potentially some edge cases remaining that are not handled in the same way.
88pub fn sqrt(x: f64) callconv(.C) f64 {
89 const tiny: f64 = 1.0e-300;
90 const sign: u32 = 0x80000000;
91 const u = @bitCast(u64, x);
92
93 var ix0 = @intCast(u32, u >> 32);
94 var ix1 = @intCast(u32, u & 0xFFFFFFFF);
95
96 // sqrt(nan) = nan, sqrt(+inf) = +inf, sqrt(-inf) = nan
97 if (ix0 & 0x7FF00000 == 0x7FF00000) {
98 return x * x + x;
99 }
100
101 // sqrt(+-0) = +-0
102 if (x == 0.0) {
103 return x;
104 }
105 // sqrt(-ve) = snan
106 if (ix0 & sign != 0) {
107 return math.snan(f64);
108 }
109
110 // normalize x
111 var m = @intCast(i32, ix0 >> 20);
112 if (m == 0) {
113 // subnormal
114 while (ix0 == 0) {
115 m -= 21;
116 ix0 |= ix1 >> 11;
117 ix1 <<= 21;
118 }
119
120 // subnormal
121 var i: u32 = 0;
122 while (ix0 & 0x00100000 == 0) : (i += 1) {
123 ix0 <<= 1;
124 }
125 m -= @intCast(i32, i) - 1;
126 ix0 |= ix1 >> @intCast(u5, 32 - i);
127 ix1 <<= @intCast(u5, i);
128 }
129
130 // unbias exponent
131 m -= 1023;
132 ix0 = (ix0 & 0x000FFFFF) | 0x00100000;
133 if (m & 1 != 0) {
134 ix0 += ix0 + (ix1 >> 31);
135 ix1 = ix1 +% ix1;
136 }
137 m >>= 1;
138
139 // sqrt(x) bit by bit
140 ix0 += ix0 + (ix1 >> 31);
141 ix1 = ix1 +% ix1;
142
143 var q: u32 = 0;
144 var q1: u32 = 0;
145 var s0: u32 = 0;
146 var s1: u32 = 0;
147 var r: u32 = 0x00200000;
148 var t: u32 = undefined;
149 var t1: u32 = undefined;
150
151 while (r != 0) {
152 t = s0 +% r;
153 if (t <= ix0) {
154 s0 = t + r;
155 ix0 -= t;
156 q += r;
157 }
158 ix0 = ix0 +% ix0 +% (ix1 >> 31);
159 ix1 = ix1 +% ix1;
160 r >>= 1;
161 }
162
163 r = sign;
164 while (r != 0) {
165 t1 = s1 +% r;
166 t = s0;
167 if (t < ix0 or (t == ix0 and t1 <= ix1)) {
168 s1 = t1 +% r;
169 if (t1 & sign == sign and s1 & sign == 0) {
170 s0 += 1;
171 }
172 ix0 -= t;
173 if (ix1 < t1) {
174 ix0 -= 1;
175 }
176 ix1 = ix1 -% t1;
177 q1 += r;
178 }
179 ix0 = ix0 +% ix0 +% (ix1 >> 31);
180 ix1 = ix1 +% ix1;
181 r >>= 1;
182 }
183
184 // rounding direction
185 if (ix0 | ix1 != 0) {
186 var z = 1.0 - tiny; // raise inexact
187 if (z >= 1.0) {
188 z = 1.0 + tiny;
189 if (q1 == 0xFFFFFFFF) {
190 q1 = 0;
191 q += 1;
192 } else if (z > 1.0) {
193 if (q1 == 0xFFFFFFFE) {
194 q += 1;
195 }
196 q1 += 2;
197 } else {
198 q1 += q1 & 1;
199 }
200 }
201 }
202
203 ix0 = (q >> 1) + 0x3FE00000;
204 ix1 = q1 >> 1;
205 if (q & 1 != 0) {
206 ix1 |= 0x80000000;
207 }
208
209 // NOTE: musl here appears to rely on signed twos-complement wraparound. +% has the same
210 // behaviour at least.
211 var iix0 = @intCast(i32, ix0);
212 iix0 = iix0 +% (m << 20);
213
214 const uz = (@intCast(u64, iix0) << 32) | ix1;
215 return @bitCast(f64, uz);
216}
217
218pub fn __sqrtx(x: f80) callconv(.C) f80 {
219 // TODO: more efficient implementation
220 return @floatCast(f80, sqrtq(x));
221}
222
223pub fn sqrtq(x: f128) callconv(.C) f128 {
224 // TODO: more correct implementation
225 return sqrt(@floatCast(f64, x));
226}
227
228test "sqrtf" {
229 const V = [_]f32{
230 0.0,
231 4.089288054930154,
232 7.538757127071935,
233 8.97780793672623,
234 5.304443821913729,
235 5.682408965311888,
236 0.5846878579110049,
237 3.650338664297043,
238 0.3178091951800732,
239 7.1505232436382835,
240 3.6589165881946464,
241 };
242
243 // Note that @sqrt will either generate the sqrt opcode (if supported by the
244 // target ISA) or a call to `sqrtf` otherwise.
245 for (V) |val|
246 try std.testing.expectEqual(@sqrt(val), sqrtf(val));
247}
248
249test "sqrtf special" {
250 try std.testing.expect(math.isPositiveInf(sqrtf(math.inf(f32))));
251 try std.testing.expect(sqrtf(0.0) == 0.0);
252 try std.testing.expect(sqrtf(-0.0) == -0.0);
253 try std.testing.expect(math.isNan(sqrtf(-1.0)));
254 try std.testing.expect(math.isNan(sqrtf(math.nan(f32))));
255}
256
257test "sqrt" {
258 const V = [_]f64{
259 0.0,
260 4.089288054930154,
261 7.538757127071935,
262 8.97780793672623,
263 5.304443821913729,
264 5.682408965311888,
265 0.5846878579110049,
266 3.650338664297043,
267 0.3178091951800732,
268 7.1505232436382835,
269 3.6589165881946464,
270 };
271
272 // Note that @sqrt will either generate the sqrt opcode (if supported by the
273 // target ISA) or a call to `sqrtf` otherwise.
274 for (V) |val|
275 try std.testing.expectEqual(@sqrt(val), sqrt(val));
276}
277
278test "sqrt special" {
279 try std.testing.expect(math.isPositiveInf(sqrt(math.inf(f64))));
280 try std.testing.expect(sqrt(0.0) == 0.0);
281 try std.testing.expect(sqrt(-0.0) == -0.0);
282 try std.testing.expect(math.isNan(sqrt(-1.0)));
283 try std.testing.expect(math.isNan(sqrt(math.nan(f64))));
284}
lib/std/special/compiler_rt/tan.zig created+140
......@@ -0,0 +1,140 @@
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/tanf.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/tan.c
6// https://golang.org/src/math/tan.go
7
8const std = @import("std");
9const math = std.math;
10const expect = std.testing.expect;
11
12const kernel = @import("trig.zig");
13const rem_pio2 = @import("rem_pio2.zig").rem_pio2;
14const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f;
15
16pub fn __tanh(x: f16) callconv(.C) f16 {
17 // TODO: more efficient implementation
18 return @floatCast(f16, tanf(x));
19}
20
21pub fn tanf(x: f32) callconv(.C) f32 {
22 // Small multiples of pi/2 rounded to double precision.
23 const t1pio2: f64 = 1.0 * math.pi / 2.0; // 0x3FF921FB, 0x54442D18
24 const t2pio2: f64 = 2.0 * math.pi / 2.0; // 0x400921FB, 0x54442D18
25 const t3pio2: f64 = 3.0 * math.pi / 2.0; // 0x4012D97C, 0x7F3321D2
26 const t4pio2: f64 = 4.0 * math.pi / 2.0; // 0x401921FB, 0x54442D18
27
28 var ix = @bitCast(u32, x);
29 const sign = ix >> 31 != 0;
30 ix &= 0x7fffffff;
31
32 if (ix <= 0x3f490fda) { // |x| ~<= pi/4
33 if (ix < 0x39800000) { // |x| < 2**-12
34 // raise inexact if x!=0 and underflow if subnormal
35 math.doNotOptimizeAway(if (ix < 0x00800000) x / 0x1p120 else x + 0x1p120);
36 return x;
37 }
38 return kernel.__tandf(x, false);
39 }
40 if (ix <= 0x407b53d1) { // |x| ~<= 5*pi/4
41 if (ix <= 0x4016cbe3) { // |x| ~<= 3pi/4
42 return kernel.__tandf((if (sign) x + t1pio2 else x - t1pio2), true);
43 } else {
44 return kernel.__tandf((if (sign) x + t2pio2 else x - t2pio2), false);
45 }
46 }
47 if (ix <= 0x40e231d5) { // |x| ~<= 9*pi/4
48 if (ix <= 0x40afeddf) { // |x| ~<= 7*pi/4
49 return kernel.__tandf((if (sign) x + t3pio2 else x - t3pio2), true);
50 } else {
51 return kernel.__tandf((if (sign) x + t4pio2 else x - t4pio2), false);
52 }
53 }
54
55 // tan(Inf or NaN) is NaN
56 if (ix >= 0x7f800000) {
57 return x - x;
58 }
59
60 var y: f64 = undefined;
61 const n = rem_pio2f(x, &y);
62 return kernel.__tandf(y, n & 1 != 0);
63}
64
65pub fn tan(x: f64) callconv(.C) f64 {
66 var ix = @bitCast(u64, x) >> 32;
67 ix &= 0x7fffffff;
68
69 // |x| ~< pi/4
70 if (ix <= 0x3fe921fb) {
71 if (ix < 0x3e400000) { // |x| < 2**-27
72 // raise inexact if x!=0 and underflow if subnormal
73 math.doNotOptimizeAway(if (ix < 0x00100000) x / 0x1p120 else x + 0x1p120);
74 return x;
75 }
76 return kernel.__tan(x, 0.0, false);
77 }
78
79 // tan(Inf or NaN) is NaN
80 if (ix >= 0x7ff00000) {
81 return x - x;
82 }
83
84 var y: [2]f64 = undefined;
85 const n = rem_pio2(x, &y);
86 return kernel.__tan(y[0], y[1], n & 1 != 0);
87}
88
89pub fn __tanx(x: f80) callconv(.C) f80 {
90 // TODO: more efficient implementation
91 return @floatCast(f80, tanq(x));
92}
93
94pub fn tanq(x: f128) callconv(.C) f128 {
95 // TODO: more correct implementation
96 return tan(@floatCast(f64, x));
97}
98
99test "tan" {
100 try expect(tan(@as(f32, 0.0)) == tanf(0.0));
101 try expect(tan(@as(f64, 0.0)) == tan(0.0));
102}
103
104test "tan32" {
105 const epsilon = 0.00001;
106
107 try expect(math.approxEqAbs(f32, tanf(0.0), 0.0, epsilon));
108 try expect(math.approxEqAbs(f32, tanf(0.2), 0.202710, epsilon));
109 try expect(math.approxEqAbs(f32, tanf(0.8923), 1.240422, epsilon));
110 try expect(math.approxEqAbs(f32, tanf(1.5), 14.101420, epsilon));
111 try expect(math.approxEqAbs(f32, tanf(37.45), -0.254397, epsilon));
112 try expect(math.approxEqAbs(f32, tanf(89.123), 2.285852, epsilon));
113}
114
115test "tan64" {
116 const epsilon = 0.000001;
117
118 try expect(math.approxEqAbs(f64, tan(0.0), 0.0, epsilon));
119 try expect(math.approxEqAbs(f64, tan(0.2), 0.202710, epsilon));
120 try expect(math.approxEqAbs(f64, tan(0.8923), 1.240422, epsilon));
121 try expect(math.approxEqAbs(f64, tan(1.5), 14.101420, epsilon));
122 try expect(math.approxEqAbs(f64, tan(37.45), -0.254397, epsilon));
123 try expect(math.approxEqAbs(f64, tan(89.123), 2.2858376, epsilon));
124}
125
126test "tan32.special" {
127 try expect(tanf(0.0) == 0.0);
128 try expect(tanf(-0.0) == -0.0);
129 try expect(math.isNan(tanf(math.inf(f32))));
130 try expect(math.isNan(tanf(-math.inf(f32))));
131 try expect(math.isNan(tanf(math.nan(f32))));
132}
133
134test "tan64.special" {
135 try expect(tan(0.0) == 0.0);
136 try expect(tan(-0.0) == -0.0);
137 try expect(math.isNan(tan(math.inf(f64))));
138 try expect(math.isNan(tan(-math.inf(f64))));
139 try expect(math.isNan(tan(math.nan(f64))));
140}
lib/std/special/compiler_rt/trig.zig created+273
......@@ -0,0 +1,273 @@
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/__cos.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/__cosdf.c
6// https://git.musl-libc.org/cgit/musl/tree/src/math/__sin.c
7// https://git.musl-libc.org/cgit/musl/tree/src/math/__sindf.c
8// https://git.musl-libc.org/cgit/musl/tree/src/math/__tand.c
9// https://git.musl-libc.org/cgit/musl/tree/src/math/__tandf.c
10
11/// kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
12/// Input x is assumed to be bounded by ~pi/4 in magnitude.
13/// Input y is the tail of x.
14///
15/// Algorithm
16/// 1. Since cos(-x) = cos(x), we need only to consider positive x.
17/// 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0.
18/// 3. cos(x) is approximated by a polynomial of degree 14 on
19/// [0,pi/4]
20/// 4 14
21/// cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x
22/// where the remez error is
23///
24/// | 2 4 6 8 10 12 14 | -58
25/// |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2
26/// | |
27///
28/// 4 6 8 10 12 14
29/// 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then
30/// cos(x) ~ 1 - x*x/2 + r
31/// since cos(x+y) ~ cos(x) - sin(x)*y
32/// ~ cos(x) - x*y,
33/// a correction term is necessary in cos(x) and hence
34/// cos(x+y) = 1 - (x*x/2 - (r - x*y))
35/// For better accuracy, rearrange to
36/// cos(x+y) ~ w + (tmp + (r-x*y))
37/// where w = 1 - x*x/2 and tmp is a tiny correction term
38/// (1 - x*x/2 == w + tmp exactly in infinite precision).
39/// The exactness of w + tmp in infinite precision depends on w
40/// and tmp having the same precision as x. If they have extra
41/// precision due to compiler bugs, then the extra precision is
42/// only good provided it is retained in all terms of the final
43/// expression for cos(). Retention happens in all cases tested
44/// under FreeBSD, so don't pessimize things by forcibly clipping
45/// any extra precision in w.
46pub fn __cos(x: f64, y: f64) f64 {
47 const C1 = 4.16666666666666019037e-02; // 0x3FA55555, 0x5555554C
48 const C2 = -1.38888888888741095749e-03; // 0xBF56C16C, 0x16C15177
49 const C3 = 2.48015872894767294178e-05; // 0x3EFA01A0, 0x19CB1590
50 const C4 = -2.75573143513906633035e-07; // 0xBE927E4F, 0x809C52AD
51 const C5 = 2.08757232129817482790e-09; // 0x3E21EE9E, 0xBDB4B1C4
52 const C6 = -1.13596475577881948265e-11; // 0xBDA8FAE9, 0xBE8838D4
53
54 const z = x * x;
55 const zs = z * z;
56 const r = z * (C1 + z * (C2 + z * C3)) + zs * zs * (C4 + z * (C5 + z * C6));
57 const hz = 0.5 * z;
58 const w = 1.0 - hz;
59 return w + (((1.0 - w) - hz) + (z * r - x * y));
60}
61
62pub fn __cosdf(x: f64) f32 {
63 // |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]).
64 const C0 = -0x1ffffffd0c5e81.0p-54; // -0.499999997251031003120
65 const C1 = 0x155553e1053a42.0p-57; // 0.0416666233237390631894
66 const C2 = -0x16c087e80f1e27.0p-62; // -0.00138867637746099294692
67 const C3 = 0x199342e0ee5069.0p-68; // 0.0000243904487962774090654
68
69 // Try to optimize for parallel evaluation as in __tandf.c.
70 const z = x * x;
71 const w = z * z;
72 const r = C2 + z * C3;
73 return @floatCast(f32, ((1.0 + z * C0) + w * C1) + (w * z) * r);
74}
75
76/// kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854
77/// Input x is assumed to be bounded by ~pi/4 in magnitude.
78/// Input y is the tail of x.
79/// Input iy indicates whether y is 0. (if iy=0, y assume to be 0).
80///
81/// Algorithm
82/// 1. Since sin(-x) = -sin(x), we need only to consider positive x.
83/// 2. Callers must return sin(-0) = -0 without calling here since our
84/// odd polynomial is not evaluated in a way that preserves -0.
85/// Callers may do the optimization sin(x) ~ x for tiny x.
86/// 3. sin(x) is approximated by a polynomial of degree 13 on
87/// [0,pi/4]
88/// 3 13
89/// sin(x) ~ x + S1*x + ... + S6*x
90/// where
91///
92/// |sin(x) 2 4 6 8 10 12 | -58
93/// |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2
94/// | x |
95///
96/// 4. sin(x+y) = sin(x) + sin'(x')*y
97/// ~ sin(x) + (1-x*x/2)*y
98/// For better accuracy, let
99/// 3 2 2 2 2
100/// r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6))))
101/// then 3 2
102/// sin(x) = x + (S1*x + (x *(r-y/2)+y))
103pub fn __sin(x: f64, y: f64, iy: i32) f64 {
104 const S1 = -1.66666666666666324348e-01; // 0xBFC55555, 0x55555549
105 const S2 = 8.33333333332248946124e-03; // 0x3F811111, 0x1110F8A6
106 const S3 = -1.98412698298579493134e-04; // 0xBF2A01A0, 0x19C161D5
107 const S4 = 2.75573137070700676789e-06; // 0x3EC71DE3, 0x57B1FE7D
108 const S5 = -2.50507602534068634195e-08; // 0xBE5AE5E6, 0x8A2B9CEB
109 const S6 = 1.58969099521155010221e-10; // 0x3DE5D93A, 0x5ACFD57C
110
111 const z = x * x;
112 const w = z * z;
113 const r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6);
114 const v = z * x;
115 if (iy == 0) {
116 return x + v * (S1 + z * r);
117 } else {
118 return x - ((z * (0.5 * y - v * r) - y) - v * S1);
119 }
120}
121
122pub fn __sindf(x: f64) f32 {
123 // |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]).
124 const S1 = -0x15555554cbac77.0p-55; // -0.166666666416265235595
125 const S2 = 0x111110896efbb2.0p-59; // 0.0083333293858894631756
126 const S3 = -0x1a00f9e2cae774.0p-65; // -0.000198393348360966317347
127 const S4 = 0x16cd878c3b46a7.0p-71; // 0.0000027183114939898219064
128
129 // Try to optimize for parallel evaluation as in __tandf.c.
130 const z = x * x;
131 const w = z * z;
132 const r = S3 + z * S4;
133 const s = z * x;
134 return @floatCast(f32, (x + s * (S1 + z * S2)) + s * w * r);
135}
136
137/// kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854
138/// Input x is assumed to be bounded by ~pi/4 in magnitude.
139/// Input y is the tail of x.
140/// Input odd indicates whether tan (if odd = 0) or -1/tan (if odd = 1) is returned.
141///
142/// Algorithm
143/// 1. Since tan(-x) = -tan(x), we need only to consider positive x.
144/// 2. Callers must return tan(-0) = -0 without calling here since our
145/// odd polynomial is not evaluated in a way that preserves -0.
146/// Callers may do the optimization tan(x) ~ x for tiny x.
147/// 3. tan(x) is approximated by a odd polynomial of degree 27 on
148/// [0,0.67434]
149/// 3 27
150/// tan(x) ~ x + T1*x + ... + T13*x
151/// where
152///
153/// |tan(x) 2 4 26 | -59.2
154/// |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2
155/// | x |
156///
157/// Note: tan(x+y) = tan(x) + tan'(x)*y
158/// ~ tan(x) + (1+x*x)*y
159/// Therefore, for better accuracy in computing tan(x+y), let
160/// 3 2 2 2 2
161/// r = x *(T2+x *(T3+x *(...+x *(T12+x *T13))))
162/// then
163/// 3 2
164/// tan(x+y) = x + (T1*x + (x *(r+y)+y))
165///
166/// 4. For x in [0.67434,pi/4], let y = pi/4 - x, then
167/// tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y))
168/// = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y)))
169pub fn __tan(x_: f64, y_: f64, odd: bool) f64 {
170 var x = x_;
171 var y = y_;
172
173 const T = [_]f64{
174 3.33333333333334091986e-01, // 3FD55555, 55555563
175 1.33333333333201242699e-01, // 3FC11111, 1110FE7A
176 5.39682539762260521377e-02, // 3FABA1BA, 1BB341FE
177 2.18694882948595424599e-02, // 3F9664F4, 8406D637
178 8.86323982359930005737e-03, // 3F8226E3, E96E8493
179 3.59207910759131235356e-03, // 3F6D6D22, C9560328
180 1.45620945432529025516e-03, // 3F57DBC8, FEE08315
181 5.88041240820264096874e-04, // 3F4344D8, F2F26501
182 2.46463134818469906812e-04, // 3F3026F7, 1A8D1068
183 7.81794442939557092300e-05, // 3F147E88, A03792A6
184 7.14072491382608190305e-05, // 3F12B80F, 32F0A7E9
185 -1.85586374855275456654e-05, // BEF375CB, DB605373
186 2.59073051863633712884e-05, // 3EFB2A70, 74BF7AD4
187 };
188 const pio4 = 7.85398163397448278999e-01; // 3FE921FB, 54442D18
189 const pio4lo = 3.06161699786838301793e-17; // 3C81A626, 33145C07
190
191 var z: f64 = undefined;
192 var r: f64 = undefined;
193 var v: f64 = undefined;
194 var w: f64 = undefined;
195 var s: f64 = undefined;
196 var a: f64 = undefined;
197 var w0: f64 = undefined;
198 var a0: f64 = undefined;
199 var hx: u32 = undefined;
200 var sign: bool = undefined;
201
202 hx = @intCast(u32, @bitCast(u64, x) >> 32);
203 const big = (hx & 0x7fffffff) >= 0x3FE59428; // |x| >= 0.6744
204 if (big) {
205 sign = hx >> 31 != 0;
206 if (sign) {
207 x = -x;
208 y = -y;
209 }
210 x = (pio4 - x) + (pio4lo - y);
211 y = 0.0;
212 }
213 z = x * x;
214 w = z * z;
215
216 // Break x^5*(T[1]+x^2*T[2]+...) into
217 // x^5(T[1]+x^4*T[3]+...+x^20*T[11]) +
218 // x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12]))
219 r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] + w * T[11]))));
220 v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] + w * T[12])))));
221 s = z * x;
222 r = y + z * (s * (r + v) + y) + s * T[0];
223 w = x + r;
224 if (big) {
225 s = 1 - 2 * @intToFloat(f64, @boolToInt(odd));
226 v = s - 2.0 * (x + (r - w * w / (w + s)));
227 return if (sign) -v else v;
228 }
229 if (!odd) {
230 return w;
231 }
232 // -1.0/(x+r) has up to 2ulp error, so compute it accurately
233 w0 = w;
234 w0 = @bitCast(f64, @bitCast(u64, w0) & 0xffffffff00000000);
235 v = r - (w0 - x); // w0+v = r+x
236 a = -1.0 / w;
237 a0 = a;
238 a0 = @bitCast(f64, @bitCast(u64, a0) & 0xffffffff00000000);
239 return a0 + a * (1.0 + a0 * w0 + a0 * v);
240}
241
242pub fn __tandf(x: f64, odd: bool) f32 {
243 // |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]).
244 const T = [_]f64{
245 0x15554d3418c99f.0p-54, // 0.333331395030791399758
246 0x1112fd38999f72.0p-55, // 0.133392002712976742718
247 0x1b54c91d865afe.0p-57, // 0.0533812378445670393523
248 0x191df3908c33ce.0p-58, // 0.0245283181166547278873
249 0x185dadfcecf44e.0p-61, // 0.00297435743359967304927
250 0x1362b9bf971bcd.0p-59, // 0.00946564784943673166728
251 };
252
253 const z = x * x;
254 // Split up the polynomial into small independent terms to give
255 // opportunities for parallel evaluation. The chosen splitting is
256 // micro-optimized for Athlons (XP, X64). It costs 2 multiplications
257 // relative to Horner's method on sequential machines.
258 //
259 // We add the small terms from lowest degree up for efficiency on
260 // non-sequential machines (the lowest degree terms tend to be ready
261 // earlier). Apart from this, we don't care about order of
262 // operations, and don't need to to care since we have precision to
263 // spare. However, the chosen splitting is good for accuracy too,
264 // and would give results as accurate as Horner's method if the
265 // small terms were added from highest degree down.
266 const r = T[4] + z * T[5];
267 const t = T[2] + z * T[3];
268 const w = z * z;
269 const s = z * x;
270 const u = T[0] + z * T[1];
271 const r0 = (x + s * u) + (s * w) * (t + w * r);
272 return @floatCast(f32, if (odd) -1.0 / r0 else r0);
273}
lib/std/special/compiler_rt/trunc.zig created+124
......@@ -0,0 +1,124 @@
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/truncf.c
5// https://git.musl-libc.org/cgit/musl/tree/src/math/trunc.c
6
7const std = @import("std");
8const math = std.math;
9const expect = std.testing.expect;
10
11pub fn __trunch(x: f16) callconv(.C) f16 {
12 // TODO: more efficient implementation
13 return @floatCast(f16, truncf(x));
14}
15
16pub fn truncf(x: f32) callconv(.C) f32 {
17 const u = @bitCast(u32, x);
18 var e = @intCast(i32, ((u >> 23) & 0xFF)) - 0x7F + 9;
19 var m: u32 = undefined;
20
21 if (e >= 23 + 9) {
22 return x;
23 }
24 if (e < 9) {
25 e = 1;
26 }
27
28 m = @as(u32, math.maxInt(u32)) >> @intCast(u5, e);
29 if (u & m == 0) {
30 return x;
31 } else {
32 math.doNotOptimizeAway(x + 0x1p120);
33 return @bitCast(f32, u & ~m);
34 }
35}
36
37pub fn trunc(x: f64) callconv(.C) f64 {
38 const u = @bitCast(u64, x);
39 var e = @intCast(i32, ((u >> 52) & 0x7FF)) - 0x3FF + 12;
40 var m: u64 = undefined;
41
42 if (e >= 52 + 12) {
43 return x;
44 }
45 if (e < 12) {
46 e = 1;
47 }
48
49 m = @as(u64, math.maxInt(u64)) >> @intCast(u6, e);
50 if (u & m == 0) {
51 return x;
52 } else {
53 math.doNotOptimizeAway(x + 0x1p120);
54 return @bitCast(f64, u & ~m);
55 }
56}
57
58pub fn __truncx(x: f80) callconv(.C) f80 {
59 // TODO: more efficient implementation
60 return @floatCast(f80, truncq(x));
61}
62
63pub fn truncq(x: f128) callconv(.C) f128 {
64 const u = @bitCast(u128, x);
65 var e = @intCast(i32, ((u >> 112) & 0x7FFF)) - 0x3FFF + 16;
66 var m: u128 = undefined;
67
68 if (e >= 112 + 16) {
69 return x;
70 }
71 if (e < 16) {
72 e = 1;
73 }
74
75 m = @as(u128, math.maxInt(u128)) >> @intCast(u7, e);
76 if (u & m == 0) {
77 return x;
78 } else {
79 math.doNotOptimizeAway(x + 0x1p120);
80 return @bitCast(f128, u & ~m);
81 }
82}
83
84test "trunc32" {
85 try expect(truncf(1.3) == 1.0);
86 try expect(truncf(-1.3) == -1.0);
87 try expect(truncf(0.2) == 0.0);
88}
89
90test "trunc64" {
91 try expect(trunc(1.3) == 1.0);
92 try expect(trunc(-1.3) == -1.0);
93 try expect(trunc(0.2) == 0.0);
94}
95
96test "trunc128" {
97 try expect(truncq(1.3) == 1.0);
98 try expect(truncq(-1.3) == -1.0);
99 try expect(truncq(0.2) == 0.0);
100}
101
102test "trunc32.special" {
103 try expect(truncf(0.0) == 0.0); // 0x3F800000
104 try expect(truncf(-0.0) == -0.0);
105 try expect(math.isPositiveInf(truncf(math.inf(f32))));
106 try expect(math.isNegativeInf(truncf(-math.inf(f32))));
107 try expect(math.isNan(truncf(math.nan(f32))));
108}
109
110test "trunc64.special" {
111 try expect(trunc(0.0) == 0.0);
112 try expect(trunc(-0.0) == -0.0);
113 try expect(math.isPositiveInf(trunc(math.inf(f64))));
114 try expect(math.isNegativeInf(trunc(-math.inf(f64))));
115 try expect(math.isNan(trunc(math.nan(f64))));
116}
117
118test "trunc128.special" {
119 try expect(truncq(0.0) == 0.0);
120 try expect(truncq(-0.0) == -0.0);
121 try expect(math.isPositiveInf(truncq(math.inf(f128))));
122 try expect(math.isNegativeInf(truncq(-math.inf(f128))));
123 try expect(math.isNan(truncq(math.nan(f128))));
124}
lib/std/testing.zig+1-1
......@@ -265,7 +265,7 @@ pub fn expectApproxEqRel(expected: anytype, actual: @TypeOf(expected), tolerance
265265test "expectApproxEqRel" {
266266 inline for ([_]type{ f16, f32, f64, f128 }) |T| {
267267 const eps_value = comptime math.epsilon(T);
268 const sqrt_eps_value = comptime math.sqrt(eps_value);
268 const sqrt_eps_value = comptime @sqrt(eps_value);
269269
270270 const pos_x: T = 12.0;
271271 const pos_y: T = pos_x + 2 * eps_value;
src/Sema.zig+2-2
......@@ -14051,7 +14051,7 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
1405114051 const result_val = val.floatToInt(sema.arena, operand_ty, dest_ty, target) catch |err| switch (err) {
1405214052 error.FloatCannotFit => {
1405314053 return sema.fail(block, operand_src, "integer value {d} cannot be stored in type '{}'", .{
14054 std.math.floor(val.toFloat(f64)),
14054 @floor(val.toFloat(f64)),
1405514055 dest_ty.fmt(sema.mod),
1405614056 });
1405714057 },
......@@ -18371,7 +18371,7 @@ fn coerce(
1837118371 }
1837218372 const result_val = val.floatToInt(sema.arena, inst_ty, dest_ty, target) catch |err| switch (err) {
1837318373 error.FloatCannotFit => {
18374 return sema.fail(block, inst_src, "integer value {d} cannot be stored in type '{}'", .{ std.math.floor(val.toFloat(f64)), dest_ty.fmt(sema.mod) });
18374 return sema.fail(block, inst_src, "integer value {d} cannot be stored in type '{}'", .{ @floor(val.toFloat(f64)), dest_ty.fmt(sema.mod) });
1837518375 },
1837618376 else => |e| return e,
1837718377 };
src/translate_c.zig+1-1
......@@ -3998,7 +3998,7 @@ fn transFloatingLiteral(c: *Context, scope: *Scope, expr: *const clang.FloatingL
39983998 var dbl = expr.getValueAsApproximateDouble();
39993999 const is_negative = dbl < 0;
40004000 if (is_negative) dbl = -dbl;
4001 const str = if (dbl == std.math.floor(dbl))
4001 const str = if (dbl == @floor(dbl))
40024002 try std.fmt.allocPrint(c.arena, "{d}.0", .{dbl})
40034003 else
40044004 try std.fmt.allocPrint(c.arena, "{d}", .{dbl});
src/value.zig+13-99
......@@ -1155,6 +1155,7 @@ pub const Value = extern union {
11551155 16 => return floatWriteToMemory(f16, val.toFloat(f16), target, buffer),
11561156 32 => return floatWriteToMemory(f32, val.toFloat(f32), target, buffer),
11571157 64 => return floatWriteToMemory(f64, val.toFloat(f64), target, buffer),
1158 80 => return floatWriteToMemory(f80, val.toFloat(f80), target, buffer),
11581159 128 => return floatWriteToMemory(f128, val.toFloat(f128), target, buffer),
11591160 else => unreachable,
11601161 },
......@@ -1379,25 +1380,21 @@ pub const Value = extern union {
13791380 }
13801381
13811382 fn floatWriteToMemory(comptime F: type, f: F, target: Target, buffer: []u8) void {
1383 const endian = target.cpu.arch.endian();
13821384 if (F == f80) {
1383 switch (target.cpu.arch) {
1384 .i386, .x86_64 => {
1385 const repr = std.math.break_f80(f);
1386 std.mem.writeIntLittle(u64, buffer[0..8], repr.fraction);
1387 std.mem.writeIntLittle(u16, buffer[8..10], repr.exp);
1388 // TODO set the rest of the bytes to undefined. should we use 0xaa
1389 // or is there a different way?
1390 return;
1391 },
1392 else => {},
1393 }
1385 const repr = std.math.break_f80(f);
1386 std.mem.writeInt(u64, buffer[0..8], repr.fraction, endian);
1387 std.mem.writeInt(u16, buffer[8..10], repr.exp, endian);
1388 // TODO set the rest of the bytes to undefined. should we use 0xaa
1389 // or is there a different way?
1390 return;
13941391 }
13951392 const Int = @Type(.{ .Int = .{
13961393 .signedness = .unsigned,
13971394 .bits = @typeInfo(F).Float.bits,
13981395 } });
13991396 const int = @bitCast(Int, f);
1400 std.mem.writeInt(Int, buffer[0..@sizeOf(Int)], int, target.cpu.arch.endian());
1397 std.mem.writeInt(Int, buffer[0..@sizeOf(Int)], int, endian);
14011398 }
14021399
14031400 fn floatReadFromMemory(comptime F: type, target: Target, buffer: []const u8) F {
......@@ -2869,9 +2866,7 @@ pub const Value = extern union {
28692866 16 => return Value.Tag.float_16.create(arena, @intToFloat(f16, x)),
28702867 32 => return Value.Tag.float_32.create(arena, @intToFloat(f32, x)),
28712868 64 => return Value.Tag.float_64.create(arena, @intToFloat(f64, x)),
2872 // We can't lower this properly on non-x86 llvm backends yet
2873 //80 => return Value.Tag.float_80.create(arena, @intToFloat(f80, x)),
2874 80 => @panic("TODO f80 intToFloat"),
2869 80 => return Value.Tag.float_80.create(arena, @intToFloat(f80, x)),
28752870 128 => return Value.Tag.float_128.create(arena, @intToFloat(f128, x)),
28762871 else => unreachable,
28772872 }
......@@ -2908,9 +2903,9 @@ pub const Value = extern union {
29082903 }
29092904
29102905 const isNegative = std.math.signbit(value);
2911 value = std.math.fabs(value);
2906 value = @fabs(value);
29122907
2913 const floored = std.math.floor(value);
2908 const floored = @floor(value);
29142909
29152910 var rational = try std.math.big.Rational.init(arena);
29162911 defer rational.deinit();
......@@ -2941,7 +2936,7 @@ pub const Value = extern union {
29412936 return 1;
29422937 }
29432938
2944 const w_value = std.math.fabs(scalar);
2939 const w_value = @fabs(scalar);
29452940 return @divFloor(@floatToInt(std.math.big.Limb, std.math.log2(w_value)), @typeInfo(std.math.big.Limb).Int.bits) + 1;
29462941 }
29472942
......@@ -3737,9 +3732,6 @@ pub const Value = extern union {
37373732 return Value.Tag.float_64.create(arena, @rem(lhs_val, rhs_val));
37383733 },
37393734 80 => {
3740 if (true) {
3741 @panic("TODO implement compiler_rt __remx");
3742 }
37433735 const lhs_val = lhs.toFloat(f80);
37443736 const rhs_val = rhs.toFloat(f80);
37453737 return Value.Tag.float_80.create(arena, @rem(lhs_val, rhs_val));
......@@ -3782,9 +3774,6 @@ pub const Value = extern union {
37823774 return Value.Tag.float_64.create(arena, @mod(lhs_val, rhs_val));
37833775 },
37843776 80 => {
3785 if (true) {
3786 @panic("TODO implement compiler_rt __modx");
3787 }
37883777 const lhs_val = lhs.toFloat(f80);
37893778 const rhs_val = rhs.toFloat(f80);
37903779 return Value.Tag.float_80.create(arena, @mod(lhs_val, rhs_val));
......@@ -4198,9 +4187,6 @@ pub const Value = extern union {
41984187 return Value.Tag.float_64.create(arena, lhs_val / rhs_val);
41994188 },
42004189 80 => {
4201 if (true) {
4202 @panic("TODO implement compiler_rt __divxf3");
4203 }
42044190 const lhs_val = lhs.toFloat(f80);
42054191 const rhs_val = rhs.toFloat(f80);
42064192 return Value.Tag.float_80.create(arena, lhs_val / rhs_val);
......@@ -4255,9 +4241,6 @@ pub const Value = extern union {
42554241 return Value.Tag.float_64.create(arena, @divFloor(lhs_val, rhs_val));
42564242 },
42574243 80 => {
4258 if (true) {
4259 @panic("TODO implement compiler_rt __floorx");
4260 }
42614244 const lhs_val = lhs.toFloat(f80);
42624245 const rhs_val = rhs.toFloat(f80);
42634246 return Value.Tag.float_80.create(arena, @divFloor(lhs_val, rhs_val));
......@@ -4312,9 +4295,6 @@ pub const Value = extern union {
43124295 return Value.Tag.float_64.create(arena, @divTrunc(lhs_val, rhs_val));
43134296 },
43144297 80 => {
4315 if (true) {
4316 @panic("TODO implement compiler_rt __truncx");
4317 }
43184298 const lhs_val = lhs.toFloat(f80);
43194299 const rhs_val = rhs.toFloat(f80);
43204300 return Value.Tag.float_80.create(arena, @divTrunc(lhs_val, rhs_val));
......@@ -4369,9 +4349,6 @@ pub const Value = extern union {
43694349 return Value.Tag.float_64.create(arena, lhs_val * rhs_val);
43704350 },
43714351 80 => {
4372 if (true) {
4373 @panic("TODO implement compiler_rt __mulxf3");
4374 }
43754352 const lhs_val = lhs.toFloat(f80);
43764353 const rhs_val = rhs.toFloat(f80);
43774354 return Value.Tag.float_80.create(arena, lhs_val * rhs_val);
......@@ -4411,16 +4388,10 @@ pub const Value = extern union {
44114388 return Value.Tag.float_64.create(arena, @sqrt(f));
44124389 },
44134390 80 => {
4414 if (true) {
4415 @panic("TODO implement compiler_rt __sqrtx");
4416 }
44174391 const f = val.toFloat(f80);
44184392 return Value.Tag.float_80.create(arena, @sqrt(f));
44194393 },
44204394 128 => {
4421 if (true) {
4422 @panic("TODO implement compiler_rt sqrtq");
4423 }
44244395 const f = val.toFloat(f128);
44254396 return Value.Tag.float_128.create(arena, @sqrt(f));
44264397 },
......@@ -4454,16 +4425,10 @@ pub const Value = extern union {
44544425 return Value.Tag.float_64.create(arena, @sin(f));
44554426 },
44564427 80 => {
4457 if (true) {
4458 @panic("TODO implement compiler_rt sin for f80");
4459 }
44604428 const f = val.toFloat(f80);
44614429 return Value.Tag.float_80.create(arena, @sin(f));
44624430 },
44634431 128 => {
4464 if (true) {
4465 @panic("TODO implement compiler_rt sin for f128");
4466 }
44674432 const f = val.toFloat(f128);
44684433 return Value.Tag.float_128.create(arena, @sin(f));
44694434 },
......@@ -4497,16 +4462,10 @@ pub const Value = extern union {
44974462 return Value.Tag.float_64.create(arena, @cos(f));
44984463 },
44994464 80 => {
4500 if (true) {
4501 @panic("TODO implement compiler_rt cos for f80");
4502 }
45034465 const f = val.toFloat(f80);
45044466 return Value.Tag.float_80.create(arena, @cos(f));
45054467 },
45064468 128 => {
4507 if (true) {
4508 @panic("TODO implement compiler_rt cos for f128");
4509 }
45104469 const f = val.toFloat(f128);
45114470 return Value.Tag.float_128.create(arena, @cos(f));
45124471 },
......@@ -4540,16 +4499,10 @@ pub const Value = extern union {
45404499 return Value.Tag.float_64.create(arena, @exp(f));
45414500 },
45424501 80 => {
4543 if (true) {
4544 @panic("TODO implement compiler_rt exp for f80");
4545 }
45464502 const f = val.toFloat(f80);
45474503 return Value.Tag.float_80.create(arena, @exp(f));
45484504 },
45494505 128 => {
4550 if (true) {
4551 @panic("TODO implement compiler_rt exp for f128");
4552 }
45534506 const f = val.toFloat(f128);
45544507 return Value.Tag.float_128.create(arena, @exp(f));
45554508 },
......@@ -4583,16 +4536,10 @@ pub const Value = extern union {
45834536 return Value.Tag.float_64.create(arena, @exp2(f));
45844537 },
45854538 80 => {
4586 if (true) {
4587 @panic("TODO implement compiler_rt exp2 for f80");
4588 }
45894539 const f = val.toFloat(f80);
45904540 return Value.Tag.float_80.create(arena, @exp2(f));
45914541 },
45924542 128 => {
4593 if (true) {
4594 @panic("TODO implement compiler_rt exp2 for f128");
4595 }
45964543 const f = val.toFloat(f128);
45974544 return Value.Tag.float_128.create(arena, @exp2(f));
45984545 },
......@@ -4626,16 +4573,10 @@ pub const Value = extern union {
46264573 return Value.Tag.float_64.create(arena, @log(f));
46274574 },
46284575 80 => {
4629 if (true) {
4630 @panic("TODO implement compiler_rt log for f80");
4631 }
46324576 const f = val.toFloat(f80);
46334577 return Value.Tag.float_80.create(arena, @log(f));
46344578 },
46354579 128 => {
4636 if (true) {
4637 @panic("TODO implement compiler_rt log for f128");
4638 }
46394580 const f = val.toFloat(f128);
46404581 return Value.Tag.float_128.create(arena, @log(f));
46414582 },
......@@ -4669,16 +4610,10 @@ pub const Value = extern union {
46694610 return Value.Tag.float_64.create(arena, @log2(f));
46704611 },
46714612 80 => {
4672 if (true) {
4673 @panic("TODO implement compiler_rt log2 for f80");
4674 }
46754613 const f = val.toFloat(f80);
46764614 return Value.Tag.float_80.create(arena, @log2(f));
46774615 },
46784616 128 => {
4679 if (true) {
4680 @panic("TODO implement compiler_rt log2 for f128");
4681 }
46824617 const f = val.toFloat(f128);
46834618 return Value.Tag.float_128.create(arena, @log2(f));
46844619 },
......@@ -4712,16 +4647,10 @@ pub const Value = extern union {
47124647 return Value.Tag.float_64.create(arena, @log10(f));
47134648 },
47144649 80 => {
4715 if (true) {
4716 @panic("TODO implement compiler_rt log10 for f80");
4717 }
47184650 const f = val.toFloat(f80);
47194651 return Value.Tag.float_80.create(arena, @log10(f));
47204652 },
47214653 128 => {
4722 if (true) {
4723 @panic("TODO implement compiler_rt log10 for f128");
4724 }
47254654 const f = val.toFloat(f128);
47264655 return Value.Tag.float_128.create(arena, @log10(f));
47274656 },
......@@ -4755,9 +4684,6 @@ pub const Value = extern union {
47554684 return Value.Tag.float_64.create(arena, @fabs(f));
47564685 },
47574686 80 => {
4758 if (true) {
4759 @panic("TODO implement compiler_rt fabs for f80 (__fabsx)");
4760 }
47614687 const f = val.toFloat(f80);
47624688 return Value.Tag.float_80.create(arena, @fabs(f));
47634689 },
......@@ -4795,9 +4721,6 @@ pub const Value = extern union {
47954721 return Value.Tag.float_64.create(arena, @floor(f));
47964722 },
47974723 80 => {
4798 if (true) {
4799 @panic("TODO implement compiler_rt floor for f80 (__floorx)");
4800 }
48014724 const f = val.toFloat(f80);
48024725 return Value.Tag.float_80.create(arena, @floor(f));
48034726 },
......@@ -4835,9 +4758,6 @@ pub const Value = extern union {
48354758 return Value.Tag.float_64.create(arena, @ceil(f));
48364759 },
48374760 80 => {
4838 if (true) {
4839 @panic("TODO implement compiler_rt ceil for f80");
4840 }
48414761 const f = val.toFloat(f80);
48424762 return Value.Tag.float_80.create(arena, @ceil(f));
48434763 },
......@@ -4875,9 +4795,6 @@ pub const Value = extern union {
48754795 return Value.Tag.float_64.create(arena, @round(f));
48764796 },
48774797 80 => {
4878 if (true) {
4879 @panic("TODO implement compiler_rt round for f80");
4880 }
48814798 const f = val.toFloat(f80);
48824799 return Value.Tag.float_80.create(arena, @round(f));
48834800 },
......@@ -4915,9 +4832,6 @@ pub const Value = extern union {
49154832 return Value.Tag.float_64.create(arena, @trunc(f));
49164833 },
49174834 80 => {
4918 if (true) {
4919 @panic("TODO implement compiler_rt trunc for f80");
4920 }
49214835 const f = val.toFloat(f80);
49224836 return Value.Tag.float_80.create(arena, @trunc(f));
49234837 },
test/behavior/math.zig+54-16
......@@ -6,6 +6,7 @@ const expectEqualSlices = std.testing.expectEqualSlices;
66const maxInt = std.math.maxInt;
77const minInt = std.math.minInt;
88const mem = std.mem;
9const math = std.math;
910
1011test "assignment operators" {
1112 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -947,13 +948,13 @@ fn frem(comptime T: type) !void {
947948 else => unreachable,
948949 };
949950
950 try expect(std.math.fabs(@rem(@as(T, 6.9), @as(T, 4.0)) - @as(T, 2.9)) < epsilon);
951 try expect(std.math.fabs(@rem(@as(T, -6.9), @as(T, 4.0)) - @as(T, -2.9)) < epsilon);
952 try expect(std.math.fabs(@rem(@as(T, -5.0), @as(T, 3.0)) - @as(T, -2.0)) < epsilon);
953 try expect(std.math.fabs(@rem(@as(T, 3.0), @as(T, 2.0)) - @as(T, 1.0)) < epsilon);
954 try expect(std.math.fabs(@rem(@as(T, 1.0), @as(T, 2.0)) - @as(T, 1.0)) < epsilon);
955 try expect(std.math.fabs(@rem(@as(T, 0.0), @as(T, 1.0)) - @as(T, 0.0)) < epsilon);
956 try expect(std.math.fabs(@rem(@as(T, -0.0), @as(T, 1.0)) - @as(T, -0.0)) < epsilon);
951 try expect(@fabs(@rem(@as(T, 6.9), @as(T, 4.0)) - @as(T, 2.9)) < epsilon);
952 try expect(@fabs(@rem(@as(T, -6.9), @as(T, 4.0)) - @as(T, -2.9)) < epsilon);
953 try expect(@fabs(@rem(@as(T, -5.0), @as(T, 3.0)) - @as(T, -2.0)) < epsilon);
954 try expect(@fabs(@rem(@as(T, 3.0), @as(T, 2.0)) - @as(T, 1.0)) < epsilon);
955 try expect(@fabs(@rem(@as(T, 1.0), @as(T, 2.0)) - @as(T, 1.0)) < epsilon);
956 try expect(@fabs(@rem(@as(T, 0.0), @as(T, 1.0)) - @as(T, 0.0)) < epsilon);
957 try expect(@fabs(@rem(@as(T, -0.0), @as(T, 1.0)) - @as(T, -0.0)) < epsilon);
957958}
958959
959960test "float modulo division using @mod" {
......@@ -978,13 +979,13 @@ fn fmod(comptime T: type) !void {
978979 else => unreachable,
979980 };
980981
981 try expect(std.math.fabs(@mod(@as(T, 6.9), @as(T, 4.0)) - @as(T, 2.9)) < epsilon);
982 try expect(std.math.fabs(@mod(@as(T, -6.9), @as(T, 4.0)) - @as(T, 1.1)) < epsilon);
983 try expect(std.math.fabs(@mod(@as(T, -5.0), @as(T, 3.0)) - @as(T, 1.0)) < epsilon);
984 try expect(std.math.fabs(@mod(@as(T, 3.0), @as(T, 2.0)) - @as(T, 1.0)) < epsilon);
985 try expect(std.math.fabs(@mod(@as(T, 1.0), @as(T, 2.0)) - @as(T, 1.0)) < epsilon);
986 try expect(std.math.fabs(@mod(@as(T, 0.0), @as(T, 1.0)) - @as(T, 0.0)) < epsilon);
987 try expect(std.math.fabs(@mod(@as(T, -0.0), @as(T, 1.0)) - @as(T, -0.0)) < epsilon);
982 try expect(@fabs(@mod(@as(T, 6.9), @as(T, 4.0)) - @as(T, 2.9)) < epsilon);
983 try expect(@fabs(@mod(@as(T, -6.9), @as(T, 4.0)) - @as(T, 1.1)) < epsilon);
984 try expect(@fabs(@mod(@as(T, -5.0), @as(T, 3.0)) - @as(T, 1.0)) < epsilon);
985 try expect(@fabs(@mod(@as(T, 3.0), @as(T, 2.0)) - @as(T, 1.0)) < epsilon);
986 try expect(@fabs(@mod(@as(T, 1.0), @as(T, 2.0)) - @as(T, 1.0)) < epsilon);
987 try expect(@fabs(@mod(@as(T, 0.0), @as(T, 1.0)) - @as(T, 0.0)) < epsilon);
988 try expect(@fabs(@mod(@as(T, -0.0), @as(T, 1.0)) - @as(T, -0.0)) < epsilon);
988989}
989990
990991test "@sqrt" {
......@@ -1288,8 +1289,8 @@ test "NaN comparison f80" {
12881289}
12891290
12901291fn testNanEqNan(comptime F: type) !void {
1291 var nan1 = std.math.nan(F);
1292 var nan2 = std.math.nan(F);
1292 var nan1 = math.nan(F);
1293 var nan2 = math.nan(F);
12931294 try expect(nan1 != nan2);
12941295 try expect(!(nan1 == nan2));
12951296 try expect(!(nan1 > nan2));
......@@ -1346,3 +1347,40 @@ test "signed zeros are represented properly" {
13461347 try S.doTheTest();
13471348 comptime try S.doTheTest();
13481349}
1350
1351test "comptime sin and ln" {
1352 const v = comptime (@sin(@as(f32, 1)) + @log(@as(f32, 5)));
1353 try expect(v == @sin(@as(f32, 1)) + @log(@as(f32, 5)));
1354}
1355
1356test "fabs" {
1357 inline for ([_]type{ f16, f32, f64, f80, f128, c_longdouble }) |T| {
1358 // normals
1359 try expect(@fabs(@as(T, 1.0)) == 1.0);
1360 try expect(@fabs(@as(T, -1.0)) == 1.0);
1361 try expect(@fabs(math.floatMin(T)) == math.floatMin(T));
1362 try expect(@fabs(-math.floatMin(T)) == math.floatMin(T));
1363 try expect(@fabs(math.floatMax(T)) == math.floatMax(T));
1364 try expect(@fabs(-math.floatMax(T)) == math.floatMax(T));
1365
1366 // subnormals
1367 try expect(@fabs(@as(T, 0.0)) == 0.0);
1368 try expect(@fabs(@as(T, -0.0)) == 0.0);
1369 try expect(@fabs(math.floatTrueMin(T)) == math.floatTrueMin(T));
1370 try expect(@fabs(-math.floatTrueMin(T)) == math.floatTrueMin(T));
1371
1372 // non-finite numbers
1373 try expect(math.isPositiveInf(@fabs(math.inf(T))));
1374 try expect(math.isPositiveInf(@fabs(-math.inf(T))));
1375 try expect(math.isNan(@fabs(math.nan(T))));
1376 }
1377}
1378
1379test "absFloat" {
1380 try testAbsFloat();
1381 comptime try testAbsFloat();
1382}
1383fn testAbsFloat() !void {
1384 try expect(@fabs(@as(f32, -10.05)) == @as(f32, 10.05));
1385 try expect(@fabs(@as(f32, 10.05)) == @as(f32, 10.05));
1386}