lib/sys/src/math.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const capabilities = @import("capabilities.zig");
3
4 pub const required_capabilities = capabilities.pure();
5
6 pub const MathSymbol = enum {
7 sinf,
8 cosf,
9 tanf,
10 expf,
11 logf,
12 tanhf,
13 floorf,
14 powf,
15 fmaf,
16 sin,
17 cos,
18 tan,
19 exp,
20 log,
21 tanh,
22 floor,
23 pow,
24 fma,
25
26 pub fn name(self: MathSymbol) []const u8 {
27 return @tagName(self);
28 }
29
30 pub fn address(self: MathSymbol) usize {
31 return switch (self) {
32 .sinf => @intFromPtr(&mathSinf),
33 .cosf => @intFromPtr(&mathCosf),
34 .tanf => @intFromPtr(&mathTanf),
35 .expf => @intFromPtr(&mathExpf),
36 .logf => @intFromPtr(&mathLogf),
37 .tanhf => @intFromPtr(&mathTanhf),
38 .floorf => @intFromPtr(&mathFloorf),
39 .powf => @intFromPtr(&mathPowf),
40 .fmaf => @intFromPtr(&mathFmaf),
41 .sin => @intFromPtr(&mathSin),
42 .cos => @intFromPtr(&mathCos),
43 .tan => @intFromPtr(&mathTan),
44 .exp => @intFromPtr(&mathExp),
45 .log => @intFromPtr(&mathLog),
46 .tanh => @intFromPtr(&mathTanh),
47 .floor => @intFromPtr(&mathFloor),
48 .pow => @intFromPtr(&mathPow),
49 .fma => @intFromPtr(&mathFma),
50 };
51 }
52 };
53
54 pub const symbols = [_]MathSymbol{
55 .sinf,
56 .cosf,
57 .tanf,
58 .expf,
59 .logf,
60 .tanhf,
61 .floorf,
62 .powf,
63 .fmaf,
64 .sin,
65 .cos,
66 .tan,
67 .exp,
68 .log,
69 .tanh,
70 .floor,
71 .pow,
72 .fma,
73 };
74
75 fn mathSinf(x: f32) callconv(.c) f32 {
76 return @sin(x);
77 }
78
79 fn mathCosf(x: f32) callconv(.c) f32 {
80 return @cos(x);
81 }
82
83 fn mathTanf(x: f32) callconv(.c) f32 {
84 return @tan(x);
85 }
86
87 fn mathExpf(x: f32) callconv(.c) f32 {
88 return @exp(x);
89 }
90
91 fn mathLogf(x: f32) callconv(.c) f32 {
92 return @log(x);
93 }
94
95 fn mathTanhf(x: f32) callconv(.c) f32 {
96 return std.math.tanh(x);
97 }
98
99 fn mathFloorf(x: f32) callconv(.c) f32 {
100 return @floor(x);
101 }
102
103 fn mathPowf(x: f32, y: f32) callconv(.c) f32 {
104 return std.math.pow(f32, x, y);
105 }
106
107 fn mathFmaf(x: f32, y: f32, z: f32) callconv(.c) f32 {
108 return @mulAdd(f32, x, y, z);
109 }
110
111 fn mathSin(x: f64) callconv(.c) f64 {
112 return @sin(x);
113 }
114
115 fn mathCos(x: f64) callconv(.c) f64 {
116 return @cos(x);
117 }
118
119 fn mathTan(x: f64) callconv(.c) f64 {
120 return @tan(x);
121 }
122
123 fn mathExp(x: f64) callconv(.c) f64 {
124 return @exp(x);
125 }
126
127 fn mathLog(x: f64) callconv(.c) f64 {
128 return @log(x);
129 }
130
131 fn mathTanh(x: f64) callconv(.c) f64 {
132 return std.math.tanh(x);
133 }
134
135 fn mathFloor(x: f64) callconv(.c) f64 {
136 return @floor(x);
137 }
138
139 fn mathPow(x: f64, y: f64) callconv(.c) f64 {
140 return std.math.pow(f64, x, y);
141 }
142
143 fn mathFma(x: f64, y: f64, z: f64) callconv(.c) f64 {
144 return @mulAdd(f64, x, y, z);
145 }
146
147 test "math symbol names remain host-linker names" {
148 const expected = [_][]const u8{
149 "sinf",
150 "cosf",
151 "tanf",
152 "expf",
153 "logf",
154 "tanhf",
155 "floorf",
156 "powf",
157 "fmaf",
158 "sin",
159 "cos",
160 "tan",
161 "exp",
162 "log",
163 "tanh",
164 "floor",
165 "pow",
166 "fma",
167 };
168
169 try std.testing.expectEqual(expected.len, symbols.len);
170 for (symbols, expected) |symbol, name| {
171 try std.testing.expectEqualStrings(name, symbol.name());
172 }
173 }
174
175 test "math symbol addresses call sys implementations" {
176 const Unary32 = *const fn (f32) callconv(.c) f32;
177 const Unary64 = *const fn (f64) callconv(.c) f64;
178 const Binary32 = *const fn (f32, f32) callconv(.c) f32;
179 const Binary64 = *const fn (f64, f64) callconv(.c) f64;
180 const Ternary32 = *const fn (f32, f32, f32) callconv(.c) f32;
181 const Ternary64 = *const fn (f64, f64, f64) callconv(.c) f64;
182
183 const x32: f32 = 0.5;
184 const y32: f32 = 3.0;
185 const z32: f32 = 0.25;
186 const x64: f64 = 0.5;
187 const y64: f64 = 3.0;
188 const z64: f64 = 0.25;
189
190 const sinf_ptr: Unary32 = @ptrFromInt(MathSymbol.sinf.address());
191 const cosf_ptr: Unary32 = @ptrFromInt(MathSymbol.cosf.address());
192 const tanf_ptr: Unary32 = @ptrFromInt(MathSymbol.tanf.address());
193 const expf_ptr: Unary32 = @ptrFromInt(MathSymbol.expf.address());
194 const logf_ptr: Unary32 = @ptrFromInt(MathSymbol.logf.address());
195 const tanhf_ptr: Unary32 = @ptrFromInt(MathSymbol.tanhf.address());
196 const floorf_ptr: Unary32 = @ptrFromInt(MathSymbol.floorf.address());
197 const powf_ptr: Binary32 = @ptrFromInt(MathSymbol.powf.address());
198 const fmaf_ptr: Ternary32 = @ptrFromInt(MathSymbol.fmaf.address());
199 const sin_ptr: Unary64 = @ptrFromInt(MathSymbol.sin.address());
200 const cos_ptr: Unary64 = @ptrFromInt(MathSymbol.cos.address());
201 const tan_ptr: Unary64 = @ptrFromInt(MathSymbol.tan.address());
202 const exp_ptr: Unary64 = @ptrFromInt(MathSymbol.exp.address());
203 const log_ptr: Unary64 = @ptrFromInt(MathSymbol.log.address());
204 const tanh_ptr: Unary64 = @ptrFromInt(MathSymbol.tanh.address());
205 const floor_ptr: Unary64 = @ptrFromInt(MathSymbol.floor.address());
206 const pow_ptr: Binary64 = @ptrFromInt(MathSymbol.pow.address());
207 const fma_ptr: Ternary64 = @ptrFromInt(MathSymbol.fma.address());
208
209 try std.testing.expectApproxEqAbs(@sin(x32), sinf_ptr(x32), 0.000001);
210 try std.testing.expectApproxEqAbs(@cos(x32), cosf_ptr(x32), 0.000001);
211 try std.testing.expectApproxEqAbs(@tan(x32), tanf_ptr(x32), 0.000001);
212 try std.testing.expectApproxEqAbs(@exp(x32), expf_ptr(x32), 0.000001);
213 try std.testing.expectApproxEqAbs(@log(x32), logf_ptr(x32), 0.000001);
214 try std.testing.expectApproxEqAbs(std.math.tanh(x32), tanhf_ptr(x32), 0.000001);
215 try std.testing.expectApproxEqAbs(@floor(x32), floorf_ptr(x32), 0.000001);
216 try std.testing.expectApproxEqAbs(std.math.pow(f32, x32, y32), powf_ptr(x32, y32), 0.000001);
217 try std.testing.expectApproxEqAbs(@mulAdd(f32, x32, y32, z32), fmaf_ptr(x32, y32, z32), 0.000001);
218 try std.testing.expectApproxEqAbs(@sin(x64), sin_ptr(x64), 0.000000000001);
219 try std.testing.expectApproxEqAbs(@cos(x64), cos_ptr(x64), 0.000000000001);
220 try std.testing.expectApproxEqAbs(@tan(x64), tan_ptr(x64), 0.000000000001);
221 try std.testing.expectApproxEqAbs(@exp(x64), exp_ptr(x64), 0.000000000001);
222 try std.testing.expectApproxEqAbs(@log(x64), log_ptr(x64), 0.000000000001);
223 try std.testing.expectApproxEqAbs(std.math.tanh(x64), tanh_ptr(x64), 0.000000000001);
224 try std.testing.expectApproxEqAbs(@floor(x64), floor_ptr(x64), 0.000000000001);
225 try std.testing.expectApproxEqAbs(std.math.pow(f64, x64, y64), pow_ptr(x64, y64), 0.000000000001);
226 try std.testing.expectApproxEqAbs(@mulAdd(f64, x64, y64, z64), fma_ptr(x64, y64, z64), 0.000000000001);
227 }