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 }