mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 14:25:16 +00:00
std.math: add wrap function (#18154)
This commit is contained in:
parent
8afafa717f
commit
1a7a711964
@ -428,6 +428,100 @@ pub const min3 = @compileError("deprecated; use @min instead");
|
||||
pub const max3 = @compileError("deprecated; use @max instead");
|
||||
pub const ln = @compileError("deprecated; use @log instead");
|
||||
|
||||
/// Odd sawtooth function
|
||||
/// ```
|
||||
/// |
|
||||
/// / | / /
|
||||
/// / |/ /
|
||||
/// --/----/----/--
|
||||
/// / /| /
|
||||
/// / / | /
|
||||
/// |
|
||||
/// ```
|
||||
/// Limit x to the half-open interval [-r, r).
|
||||
pub fn wrap(x: anytype, r: anytype) @TypeOf(x) {
|
||||
const info_x = @typeInfo(@TypeOf(x));
|
||||
const info_r = @typeInfo(@TypeOf(r));
|
||||
if (info_x == .Int and info_x.Int.signedness != .signed) {
|
||||
@compileError("x must be floating point, comptime integer, or signed integer.");
|
||||
}
|
||||
switch (info_r) {
|
||||
.Int => {
|
||||
// in the rare usecase of r not being comptime_int or float,
|
||||
// take the penalty of having an intermediary type conversion,
|
||||
// otherwise the alternative is to unwind iteratively to avoid overflow
|
||||
const R = comptime do: {
|
||||
var info = info_r;
|
||||
info.Int.bits += 1;
|
||||
info.Int.signedness = .signed;
|
||||
break :do @Type(info);
|
||||
};
|
||||
const radius: if (info_r.Int.signedness == .signed) @TypeOf(r) else R = r;
|
||||
return @intCast(@mod(x - radius, 2 * @as(R, r)) - r); // provably impossible to overflow
|
||||
},
|
||||
else => {
|
||||
return @mod(x - r, 2 * r) - r;
|
||||
},
|
||||
}
|
||||
}
|
||||
test "wrap" {
|
||||
// Within range
|
||||
try testing.expect(wrap(@as(i32, -75), @as(i32, 180)) == -75);
|
||||
try testing.expect(wrap(@as(i32, -75), @as(i32, -180)) == -75);
|
||||
// Below
|
||||
try testing.expect(wrap(@as(i32, -225), @as(i32, 180)) == 135);
|
||||
try testing.expect(wrap(@as(i32, -225), @as(i32, -180)) == 135);
|
||||
// Above
|
||||
try testing.expect(wrap(@as(i32, 361), @as(i32, 180)) == 1);
|
||||
try testing.expect(wrap(@as(i32, 361), @as(i32, -180)) == 1);
|
||||
|
||||
// One period, right limit, positive r
|
||||
try testing.expect(wrap(@as(i32, 180), @as(i32, 180)) == -180);
|
||||
// One period, left limit, positive r
|
||||
try testing.expect(wrap(@as(i32, -180), @as(i32, 180)) == -180);
|
||||
// One period, right limit, negative r
|
||||
try testing.expect(wrap(@as(i32, 180), @as(i32, -180)) == 180);
|
||||
// One period, left limit, negative r
|
||||
try testing.expect(wrap(@as(i32, -180), @as(i32, -180)) == 180);
|
||||
|
||||
// Two periods, right limit, positive r
|
||||
try testing.expect(wrap(@as(i32, 540), @as(i32, 180)) == -180);
|
||||
// Two periods, left limit, positive r
|
||||
try testing.expect(wrap(@as(i32, -540), @as(i32, 180)) == -180);
|
||||
// Two periods, right limit, negative r
|
||||
try testing.expect(wrap(@as(i32, 540), @as(i32, -180)) == 180);
|
||||
// Two periods, left limit, negative r
|
||||
try testing.expect(wrap(@as(i32, -540), @as(i32, -180)) == 180);
|
||||
|
||||
// Floating point
|
||||
try testing.expect(wrap(@as(f32, 1.125), @as(f32, 1.0)) == -0.875);
|
||||
try testing.expect(wrap(@as(f32, -127.5), @as(f32, 180)) == -127.5);
|
||||
|
||||
// Mix of comptime and non-comptime
|
||||
var i: i32 = 1;
|
||||
_ = &i;
|
||||
try testing.expect(wrap(i, 10) == 1);
|
||||
}
|
||||
test wrap {
|
||||
const limit: i32 = 180;
|
||||
// Within range
|
||||
try testing.expect(wrap(@as(i32, -75), limit) == -75);
|
||||
// Below
|
||||
try testing.expect(wrap(@as(i32, -225), limit) == 135);
|
||||
// Above
|
||||
try testing.expect(wrap(@as(i32, 361), limit) == 1);
|
||||
}
|
||||
|
||||
/// Odd ramp function
|
||||
/// ```
|
||||
/// | _____
|
||||
/// | /
|
||||
/// |/
|
||||
/// -------/-------
|
||||
/// /|
|
||||
/// _____/ |
|
||||
/// |
|
||||
/// ```
|
||||
/// Limit val to the inclusive range [lower, upper].
|
||||
pub fn clamp(val: anytype, lower: anytype, upper: anytype) @TypeOf(val, lower, upper) {
|
||||
assert(lower <= upper);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user