Skip to content

Commit 67a40c6

Browse files
author
expikr
authored
make math.degreesToRadians and math.radiansToDegrees infer type from argument
1 parent a4508ad commit 67a40c6

File tree

1 file changed

+62
-20
lines changed

1 file changed

+62
-20
lines changed

lib/std/math.zig

Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ pub const sqrt2 = 1.414213562373095048801688724209698079;
3737
/// 1/sqrt(2)
3838
pub const sqrt1_2 = 0.707106781186547524400844362104849039;
3939

40+
/// pi/180.0
41+
pub const rad_per_deg = 0.0174532925199432957692369076848861271344287188854172545609719144;
42+
43+
/// 180.0/pi
44+
pub const deg_per_rad = 57.295779513082320876798154814105170332405472466564321549160243861;
45+
4046
pub const floatExponentBits = @import("math/float.zig").floatExponentBits;
4147
pub const floatMantissaBits = @import("math/float.zig").floatMantissaBits;
4248
pub const floatFractionalBits = @import("math/float.zig").floatFractionalBits;
@@ -293,32 +299,68 @@ pub inline fn tan(value: anytype) @TypeOf(value) {
293299
return @tan(value);
294300
}
295301

296-
/// Converts an angle in radians to degrees. T must be a float type.
297-
pub fn radiansToDegrees(comptime T: type, angle_in_radians: T) T {
298-
if (@typeInfo(T) != .Float and @typeInfo(T) != .ComptimeFloat)
299-
@compileError("T must be a float type");
300-
return angle_in_radians * 180.0 / pi;
302+
/// Converts an angle in radians to degrees. T must be a float or comptime number or a vector of floats.
303+
pub fn radiansToDegrees(ang: anytype) if (@TypeOf(ang) == comptime_int) comptime_float else @TypeOf(ang) {
304+
const T = @TypeOf(ang);
305+
switch (@typeInfo(T)) {
306+
.Float, .ComptimeFloat, .ComptimeInt => return ang * deg_per_rad,
307+
.Vector => |V| if (@typeInfo(V.child) == .Float) return ang * @as(T, @splat(deg_per_rad)),
308+
else => {},
309+
}
310+
@compileError("Input must be float or a comptime number, or a vector of floats.");
301311
}
302312

303313
test "radiansToDegrees" {
304-
try std.testing.expectApproxEqAbs(@as(f32, 0), radiansToDegrees(f32, 0), 1e-6);
305-
try std.testing.expectApproxEqAbs(@as(f32, 90), radiansToDegrees(f32, pi / 2.0), 1e-6);
306-
try std.testing.expectApproxEqAbs(@as(f32, -45), radiansToDegrees(f32, -pi / 4.0), 1e-6);
307-
try std.testing.expectApproxEqAbs(@as(f32, 180), radiansToDegrees(f32, pi), 1e-6);
308-
try std.testing.expectApproxEqAbs(@as(f32, 360), radiansToDegrees(f32, 2.0 * pi), 1e-6);
309-
}
310-
311-
/// Converts an angle in degrees to radians. T must be a float type.
312-
pub fn degreesToRadians(comptime T: type, angle_in_degrees: T) T {
313-
if (@typeInfo(T) != .Float and @typeInfo(T) != .ComptimeFloat)
314-
@compileError("T must be a float type");
315-
return angle_in_degrees * pi / 180.0;
314+
const zero: f32 = 0;
315+
const half_pi: f32 = pi / 2.0;
316+
const neg_quart_pi: f32 = -pi / 4.0;
317+
const one_pi: f32 = pi;
318+
const two_pi: f32 = 2.0 * pi;
319+
try std.testing.expectApproxEqAbs(@as(f32, 0), radiansToDegrees(zero), 1e-6);
320+
try std.testing.expectApproxEqAbs(@as(f32, 90), radiansToDegrees(half_pi), 1e-6);
321+
try std.testing.expectApproxEqAbs(@as(f32, -45), radiansToDegrees(neg_quart_pi), 1e-6);
322+
try std.testing.expectApproxEqAbs(@as(f32, 180), radiansToDegrees(one_pi), 1e-6);
323+
try std.testing.expectApproxEqAbs(@as(f32, 360), radiansToDegrees(two_pi), 1e-6);
324+
325+
const result = radiansToDegrees(@Vector(4, f32){
326+
half_pi,
327+
neg_quart_pi,
328+
one_pi,
329+
two_pi,
330+
});
331+
try std.testing.expectApproxEqAbs(@as(f32, 90), result[0], 1e-6);
332+
try std.testing.expectApproxEqAbs(@as(f32, -45), result[1], 1e-6);
333+
try std.testing.expectApproxEqAbs(@as(f32, 180), result[2], 1e-6);
334+
try std.testing.expectApproxEqAbs(@as(f32, 360), result[3], 1e-6);
335+
}
336+
337+
/// Converts an angle in degrees to radians. T must be a float or comptime number or a vector of floats.
338+
pub fn degreesToRadians(ang: anytype) if (@TypeOf(ang) == comptime_int) comptime_float else @TypeOf(ang) {
339+
const T = @TypeOf(ang);
340+
switch (@typeInfo(T)) {
341+
.Float, .ComptimeFloat, .ComptimeInt => return ang * rad_per_deg,
342+
.Vector => |V| if (@typeInfo(V.child) == .Float) return ang * @as(T, @splat(rad_per_deg)),
343+
else => {},
344+
}
345+
@compileError("Input must be float or a comptime number, or a vector of floats.");
316346
}
317347

318348
test "degreesToRadians" {
319-
try std.testing.expectApproxEqAbs(@as(f32, pi / 2.0), degreesToRadians(f32, 90), 1e-6);
320-
try std.testing.expectApproxEqAbs(@as(f32, -3 * pi / 2.0), degreesToRadians(f32, -270), 1e-6);
321-
try std.testing.expectApproxEqAbs(@as(f32, 2 * pi), degreesToRadians(f32, 360), 1e-6);
349+
const ninety: f32 = 90;
350+
const neg_two_seventy: f32 = -270;
351+
const three_sixty: f32 = 360;
352+
try std.testing.expectApproxEqAbs(@as(f32, pi / 2.0), degreesToRadians(ninety), 1e-6);
353+
try std.testing.expectApproxEqAbs(@as(f32, -3 * pi / 2.0), degreesToRadians(neg_two_seventy), 1e-6);
354+
try std.testing.expectApproxEqAbs(@as(f32, 2 * pi), degreesToRadians(three_sixty), 1e-6);
355+
356+
const result = degreesToRadians(@Vector(3, f32){
357+
ninety,
358+
neg_two_seventy,
359+
three_sixty,
360+
});
361+
try std.testing.expectApproxEqAbs(@as(f32, pi / 2.0), result[0], 1e-6);
362+
try std.testing.expectApproxEqAbs(@as(f32, -3 * pi / 2.0), result[1], 1e-6);
363+
try std.testing.expectApproxEqAbs(@as(f32, 2 * pi), result[2], 1e-6);
322364
}
323365

324366
/// Base-e exponential function on a floating point number.

0 commit comments

Comments
 (0)