Skip to content

Commit ebada7c

Browse files
committed
std.math: add lerp
1 parent 9a2f17f commit ebada7c

File tree

1 file changed

+27
-0
lines changed

1 file changed

+27
-0
lines changed

lib/std/math.zig

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,6 +1279,33 @@ test "lossyCast" {
12791279
try testing.expect(lossyCast(u32, @as(f32, maxInt(u32))) == maxInt(u32));
12801280
}
12811281

1282+
/// Performs linear interpolation between *a* and *b* based on *t*.
1283+
/// *t* must be in range 0.0 to 1.0. T must be a float type.
1284+
///
1285+
/// This does not guarantee returning *b* if *t* is 1 due to floating-point errors.
1286+
/// This is monotonic.
1287+
pub fn lerp(comptime T: type, a: T, b: T, t: T) T {
1288+
if (@typeInfo(T) != .Float and @typeInfo(T) != .ComptimeFloat)
1289+
@compileError("T must be a float type");
1290+
1291+
assert(t >= 0 and t <= 1);
1292+
return @mulAdd(T, b - a, t, a);
1293+
}
1294+
1295+
test "lerp" {
1296+
try testing.expectEqual(@as(f16, 75), lerp(f16, 50, 100, 0.5));
1297+
try testing.expectEqual(@as(f32, 43.75), lerp(f32, 50, 25, 0.25));
1298+
try testing.expectEqual(@as(f64, -31.25), lerp(f64, -50, 25, 0.25));
1299+
try testing.expectApproxEqRel(@as(f80, -7.16067345e+03), lerp(f80, -10000.12345, -5000.12345, 0.56789), 1e-19);
1300+
try testing.expectApproxEqRel(@as(f128, 7.010987590521e+62), lerp(f128, 0.123456789e-64, 0.123456789e64, 0.56789), 1e-33);
1301+
1302+
// this highlights the precision
1303+
try testing.expectEqual(@as(f32, 0.0), lerp(f32, 1.0e8, 1.0, 1.0));
1304+
try testing.expectEqual(@as(f16, 0.0), lerp(f16, 1.0e4, 1.0, 1.0));
1305+
try testing.expectEqual(@as(f32, 1.0), lerp(f32, 1.0e7, 1.0, 1.0));
1306+
try testing.expectEqual(@as(f16, 1.0), lerp(f16, 1.0e3, 1.0, 1.0));
1307+
}
1308+
12821309
/// Returns the maximum value of integer type T.
12831310
pub fn maxInt(comptime T: type) comptime_int {
12841311
const info = @typeInfo(T);

0 commit comments

Comments
 (0)