authorgravatar for r00ster91@proton.meWooster <r00ster91@proton.me> 2023-04-21 00:52:44+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-04-20 18:52:44-04:00
log7d90410b96f4b2393133e184f72b2846d3ff5ac7
tree28cb23ce8505f26f6fb015afa84ec7ee7b1e4679
parentb7c00999be95a72f39c040b9e2a43ccc6100d0a8
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

std.math: add lerp (#13002)


1 files changed, 44 insertions(+), 0 deletions(-)

lib/std/math.zig+44
......@@ -1327,6 +1327,50 @@ test "lossyCast" {
13271327 try testing.expect(lossyCast(u32, @as(f32, maxInt(u32))) == maxInt(u32));
13281328}
13291329
1330/// Performs linear interpolation between *a* and *b* based on *t*.
1331/// *t* must be in range 0.0 to 1.0. Supports floats and vectors of floats.
1332///
1333/// This does not guarantee returning *b* if *t* is 1 due to floating-point errors.
1334/// This is monotonic.
1335pub fn lerp(a: anytype, b: anytype, t: anytype) @TypeOf(a, b, t) {
1336 const Type = @TypeOf(a, b, t);
1337
1338 switch (@typeInfo(Type)) {
1339 .Float, .ComptimeFloat => assert(t >= 0 and t <= 1),
1340 .Vector => |vector| {
1341 const lower_bound = @reduce(.And, t >= @splat(vector.len, @as(vector.child, 0)));
1342 const upper_bound = @reduce(.And, t <= @splat(vector.len, @as(vector.child, 1)));
1343 assert(lower_bound and upper_bound);
1344 },
1345 else => comptime unreachable,
1346 }
1347
1348 return @mulAdd(Type, b - a, t, a);
1349}
1350
1351test "lerp" {
1352 try testing.expectEqual(@as(f64, 75), lerp(50, 100, 0.5));
1353 try testing.expectEqual(@as(f32, 43.75), lerp(50, 25, 0.25));
1354 try testing.expectEqual(@as(f64, -31.25), lerp(-50, 25, 0.25));
1355
1356 try testing.expectApproxEqRel(@as(f32, -7.16067345e+03), lerp(-10000.12345, -5000.12345, 0.56789), 1e-19);
1357 try testing.expectApproxEqRel(@as(f64, 7.010987590521e+62), lerp(0.123456789e-64, 0.123456789e64, 0.56789), 1e-33);
1358
1359 try testing.expectEqual(@as(f32, 0.0), lerp(@as(f32, 1.0e8), 1.0, 1.0));
1360 try testing.expectEqual(@as(f64, 0.0), lerp(@as(f64, 1.0e16), 1.0, 1.0));
1361 try testing.expectEqual(@as(f32, 1.0), lerp(@as(f32, 1.0e7), 1.0, 1.0));
1362 try testing.expectEqual(@as(f64, 1.0), lerp(@as(f64, 1.0e15), 1.0, 1.0));
1363
1364 try testing.expectEqual(
1365 lerp(@splat(3, @as(f32, 0)), @splat(3, @as(f32, 50)), @splat(3, @as(f32, 0.5))),
1366 @Vector(3, f32){ 25, 25, 25 },
1367 );
1368 try testing.expectEqual(
1369 lerp(@splat(3, @as(f64, 50)), @splat(3, @as(f64, 100)), @splat(3, @as(f64, 0.5))),
1370 @Vector(3, f64){ 75, 75, 75 },
1371 );
1372}
1373
13301374/// Returns the maximum value of integer type T.
13311375pub fn maxInt(comptime T: type) comptime_int {
13321376 const info = @typeInfo(T);