diff options
| author | zooster <r00ster91@proton.me> | 2023-04-21 00:52:44 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-04-20 18:52:44 -0400 |
| commit | 7d90410b96f4b2393133e184f72b2846d3ff5ac7 (patch) | |
| tree | 28cb23ce8505f26f6fb015afa84ec7ee7b1e4679 /lib/std/math.zig | |
| parent | b7c00999be95a72f39c040b9e2a43ccc6100d0a8 (diff) | |
| download | zig-7d90410b96f4b2393133e184f72b2846d3ff5ac7.tar.gz zig-7d90410b96f4b2393133e184f72b2846d3ff5ac7.zip | |
std.math: add lerp (#13002)
Diffstat (limited to 'lib/std/math.zig')
| -rw-r--r-- | lib/std/math.zig | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/lib/std/math.zig b/lib/std/math.zig index 65643d92d7..14c71a796f 100644 --- a/lib/std/math.zig +++ b/lib/std/math.zig @@ -1327,6 +1327,50 @@ test "lossyCast" { try testing.expect(lossyCast(u32, @as(f32, maxInt(u32))) == maxInt(u32)); } +/// Performs linear interpolation between *a* and *b* based on *t*. +/// *t* must be in range 0.0 to 1.0. Supports floats and vectors of floats. +/// +/// This does not guarantee returning *b* if *t* is 1 due to floating-point errors. +/// This is monotonic. +pub fn lerp(a: anytype, b: anytype, t: anytype) @TypeOf(a, b, t) { + const Type = @TypeOf(a, b, t); + + switch (@typeInfo(Type)) { + .Float, .ComptimeFloat => assert(t >= 0 and t <= 1), + .Vector => |vector| { + const lower_bound = @reduce(.And, t >= @splat(vector.len, @as(vector.child, 0))); + const upper_bound = @reduce(.And, t <= @splat(vector.len, @as(vector.child, 1))); + assert(lower_bound and upper_bound); + }, + else => comptime unreachable, + } + + return @mulAdd(Type, b - a, t, a); +} + +test "lerp" { + try testing.expectEqual(@as(f64, 75), lerp(50, 100, 0.5)); + try testing.expectEqual(@as(f32, 43.75), lerp(50, 25, 0.25)); + try testing.expectEqual(@as(f64, -31.25), lerp(-50, 25, 0.25)); + + try testing.expectApproxEqRel(@as(f32, -7.16067345e+03), lerp(-10000.12345, -5000.12345, 0.56789), 1e-19); + try testing.expectApproxEqRel(@as(f64, 7.010987590521e+62), lerp(0.123456789e-64, 0.123456789e64, 0.56789), 1e-33); + + try testing.expectEqual(@as(f32, 0.0), lerp(@as(f32, 1.0e8), 1.0, 1.0)); + try testing.expectEqual(@as(f64, 0.0), lerp(@as(f64, 1.0e16), 1.0, 1.0)); + try testing.expectEqual(@as(f32, 1.0), lerp(@as(f32, 1.0e7), 1.0, 1.0)); + try testing.expectEqual(@as(f64, 1.0), lerp(@as(f64, 1.0e15), 1.0, 1.0)); + + try testing.expectEqual( + lerp(@splat(3, @as(f32, 0)), @splat(3, @as(f32, 50)), @splat(3, @as(f32, 0.5))), + @Vector(3, f32){ 25, 25, 25 }, + ); + try testing.expectEqual( + lerp(@splat(3, @as(f64, 50)), @splat(3, @as(f64, 100)), @splat(3, @as(f64, 0.5))), + @Vector(3, f64){ 75, 75, 75 }, + ); +} + /// Returns the maximum value of integer type T. pub fn maxInt(comptime T: type) comptime_int { const info = @typeInfo(T); |
