Added sqrt to Scalar and Vector
This commit is contained in:
parent
0dd9e02f59
commit
a2d46e3f55
@ -68,7 +68,6 @@ pub fn add(comptime a: Self, comptime b: Self) Self {
|
||||
|
||||
/// Subtract exponents component-wise. Used internally by `divBy`.
|
||||
pub fn sub(comptime a: Self, comptime b: Self) Self {
|
||||
@setEvalBranchQuota(10_000);
|
||||
var result = Self.initFill(0);
|
||||
inline for (std.enums.values(Dimension)) |d|
|
||||
result.set(d, a.get(d) - b.get(d));
|
||||
@ -77,13 +76,19 @@ pub fn sub(comptime a: Self, comptime b: Self) Self {
|
||||
|
||||
/// Multiply exponents by a scalar integer. Used internally by `pow` in Scalar.
|
||||
pub fn scale(comptime a: Self, comptime exp: comptime_int) Self {
|
||||
@setEvalBranchQuota(10_000);
|
||||
var result = Self.initFill(0);
|
||||
inline for (std.enums.values(Dimension)) |d|
|
||||
result.set(d, a.get(d) * exp);
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn div(comptime a: Self, comptime exp: comptime_int) Self {
|
||||
var result = Self.initFill(0);
|
||||
inline for (std.enums.values(Dimension)) |d|
|
||||
result.set(d, a.get(d) / exp);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Returns true if every dimension exponent is equal. Used to enforce type compatibility in `add`, `sub`, `to`.
|
||||
pub fn eql(comptime a: Self, comptime b: Self) bool {
|
||||
inline for (std.enums.values(Dimension)) |d|
|
||||
@ -91,6 +96,12 @@ pub fn eql(comptime a: Self, comptime b: Self) bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn isSquare(comptime a: Self) bool {
|
||||
inline for (std.enums.values(Dimension)) |d|
|
||||
if (a.get(d) % 2 != 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn str(comptime a: Self) []const u8 {
|
||||
var out: []const u8 = "";
|
||||
const dims = std.enums.values(Dimension);
|
||||
|
||||
@ -7,10 +7,8 @@ const UnitScale = Scales.UnitScale;
|
||||
const Dimensions = @import("Dimensions.zig");
|
||||
const Dimension = Dimensions.Dimension;
|
||||
|
||||
// TODO: Add those operation:
|
||||
// - abs: Absolut value
|
||||
// - pow: Scalar power another
|
||||
// - log: Scalar log another
|
||||
// TODO: Be able to use comptime float and int and T for mulBy ect
|
||||
// Which endup being Dimension less
|
||||
|
||||
/// A dimensioned scalar value. `T` is the numeric type, `d` the dimension exponents, `s` the SI scales.
|
||||
/// All dimension and unit tracking is resolved at comptime — zero runtime overhead.
|
||||
@ -129,6 +127,24 @@ pub fn Scalar(comptime T: type, comptime d: Dimensions, comptime s: Scales) type
|
||||
return .{ .value = std.math.pow(T, self.value, @as(T, @floatFromInt(exp))) };
|
||||
}
|
||||
|
||||
pub inline fn sqrt(self: Self) Scalar(
|
||||
T,
|
||||
dims.div(2),
|
||||
s,
|
||||
) {
|
||||
if (comptime !dims.isSquare()) // Check if all exponents are divisible by 2
|
||||
@compileError("Cannot take sqrt of " ++ dims.str() ++ ": exponents must be even.");
|
||||
if (self.value < 0) return .{ .value = 0 };
|
||||
|
||||
if (comptime @typeInfo(T) == .int) {
|
||||
const UnsignedT = @Int(.unsigned, @typeInfo(T).int.bits);
|
||||
const u_len_sq = @as(UnsignedT, @intCast(self.value));
|
||||
return .{ .value = @as(T, @intCast(std.math.sqrt(u_len_sq))) };
|
||||
} else {
|
||||
return .{ .value = @sqrt(self.value) };
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert to a compatible unit type. The scale ratio is computed at comptime.
|
||||
/// Compile error if dimensions don't match.
|
||||
pub inline fn to(self: Self, comptime Dest: type) Dest {
|
||||
@ -463,6 +479,26 @@ test "MulBy dimensionless" {
|
||||
try std.testing.expectEqual(1, @TypeOf(scaled).dims.get(.L));
|
||||
}
|
||||
|
||||
test "Sqrt" {
|
||||
const MeterSquare = Scalar(i128, Dimensions.init(.{ .L = 2 }), Scales.init(.{}));
|
||||
|
||||
var d = MeterSquare{ .value = 9 };
|
||||
var scaled = d.sqrt();
|
||||
try std.testing.expectEqual(3, scaled.value);
|
||||
try std.testing.expectEqual(1, @TypeOf(scaled).dims.get(.L));
|
||||
|
||||
d = MeterSquare{ .value = -5 };
|
||||
scaled = d.sqrt();
|
||||
try std.testing.expectEqual(0, scaled.value);
|
||||
try std.testing.expectEqual(1, @TypeOf(scaled).dims.get(.L));
|
||||
|
||||
const MeterSquare_f = Scalar(f64, Dimensions.init(.{ .L = 2 }), Scales.init(.{}));
|
||||
const d2 = MeterSquare_f{ .value = 20 };
|
||||
const scaled2 = d2.sqrt();
|
||||
try std.testing.expectApproxEqAbs(4.472135955, scaled2.value, 1e-4);
|
||||
try std.testing.expectEqual(1, @TypeOf(scaled2).dims.get(.L));
|
||||
}
|
||||
|
||||
test "Chained: velocity and acceleration" {
|
||||
const Meter = Scalar(i128, Dimensions.init(.{ .L = 1 }), Scales.init(.{}));
|
||||
const Second = Scalar(f32, Dimensions.init(.{ .T = 1 }), Scales.init(.{}));
|
||||
|
||||
@ -190,6 +190,16 @@ pub fn Vector(comptime len: usize, comptime Q: type) type {
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Returns a vector where each component is the absolute value of the original.
|
||||
pub inline fn sqrt(self: Self) Self {
|
||||
var res: Self = undefined;
|
||||
inline for (self.data, 0..) |v, i| {
|
||||
const q = Q{ .value = v };
|
||||
res.data[i] = q.sqrt().value;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Multiplies all components of the vector together.
|
||||
/// Resulting dimensions are (Original Dims * len).
|
||||
pub inline fn product(self: Self) Scalar(
|
||||
@ -549,7 +559,7 @@ test "VecX Length" {
|
||||
const MeterInt = Scalar(i32, Dimensions.init(.{ .L = 1 }), Scales.init(.{}));
|
||||
const MeterFloat = Scalar(f32, Dimensions.init(.{ .L = 1 }), Scales.init(.{}));
|
||||
|
||||
// Integer length (using your custom isqrt)
|
||||
// Integer length
|
||||
// 3-4-5 triangle on XY plane
|
||||
const v_int = MeterInt.Vec3{ .data = .{ 3, 4, 0 } };
|
||||
try std.testing.expectEqual(25, v_int.lengthSqr());
|
||||
@ -634,7 +644,7 @@ test "Vector Dot and Cross Products" {
|
||||
try std.testing.expectEqual(2, @TypeOf(torque).dims.get(.L));
|
||||
}
|
||||
|
||||
test "Vector Abs, Pow, and Product" {
|
||||
test "Vector Abs, Pow, Sqrt and Product" {
|
||||
const Meter = Scalar(f32, Dimensions.init(.{ .L = 1 }), Scales.init(.{}));
|
||||
|
||||
const v1 = Meter.Vec3{ .data = .{ -2.0, 3.0, -4.0 } };
|
||||
@ -654,4 +664,10 @@ test "Vector Abs, Pow, and Product" {
|
||||
try std.testing.expectEqual(4.0, area_vec.data[0]);
|
||||
try std.testing.expectEqual(16.0, area_vec.data[2]);
|
||||
try std.testing.expectEqual(2, @TypeOf(area_vec).dims.get(.L));
|
||||
|
||||
// 4. Sqrt
|
||||
const sqrted = area_vec.sqrt();
|
||||
try std.testing.expectEqual(2, sqrted.data[0]);
|
||||
try std.testing.expectEqual(4, sqrted.data[2]);
|
||||
try std.testing.expectEqual(2, @TypeOf(sqrted).dims.get(.L));
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user