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`.
|
/// Subtract exponents component-wise. Used internally by `divBy`.
|
||||||
pub fn sub(comptime a: Self, comptime b: Self) Self {
|
pub fn sub(comptime a: Self, comptime b: Self) Self {
|
||||||
@setEvalBranchQuota(10_000);
|
|
||||||
var result = Self.initFill(0);
|
var result = Self.initFill(0);
|
||||||
inline for (std.enums.values(Dimension)) |d|
|
inline for (std.enums.values(Dimension)) |d|
|
||||||
result.set(d, a.get(d) - b.get(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.
|
/// Multiply exponents by a scalar integer. Used internally by `pow` in Scalar.
|
||||||
pub fn scale(comptime a: Self, comptime exp: comptime_int) Self {
|
pub fn scale(comptime a: Self, comptime exp: comptime_int) Self {
|
||||||
@setEvalBranchQuota(10_000);
|
|
||||||
var result = Self.initFill(0);
|
var result = Self.initFill(0);
|
||||||
inline for (std.enums.values(Dimension)) |d|
|
inline for (std.enums.values(Dimension)) |d|
|
||||||
result.set(d, a.get(d) * exp);
|
result.set(d, a.get(d) * exp);
|
||||||
return result;
|
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`.
|
/// 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 {
|
pub fn eql(comptime a: Self, comptime b: Self) bool {
|
||||||
inline for (std.enums.values(Dimension)) |d|
|
inline for (std.enums.values(Dimension)) |d|
|
||||||
@ -91,6 +96,12 @@ pub fn eql(comptime a: Self, comptime b: Self) bool {
|
|||||||
return true;
|
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 {
|
pub fn str(comptime a: Self) []const u8 {
|
||||||
var out: []const u8 = "";
|
var out: []const u8 = "";
|
||||||
const dims = std.enums.values(Dimension);
|
const dims = std.enums.values(Dimension);
|
||||||
|
|||||||
@ -7,10 +7,8 @@ const UnitScale = Scales.UnitScale;
|
|||||||
const Dimensions = @import("Dimensions.zig");
|
const Dimensions = @import("Dimensions.zig");
|
||||||
const Dimension = Dimensions.Dimension;
|
const Dimension = Dimensions.Dimension;
|
||||||
|
|
||||||
// TODO: Add those operation:
|
// TODO: Be able to use comptime float and int and T for mulBy ect
|
||||||
// - abs: Absolut value
|
// Which endup being Dimension less
|
||||||
// - pow: Scalar power another
|
|
||||||
// - log: Scalar log another
|
|
||||||
|
|
||||||
/// A dimensioned scalar value. `T` is the numeric type, `d` the dimension exponents, `s` the SI scales.
|
/// 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.
|
/// 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))) };
|
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.
|
/// Convert to a compatible unit type. The scale ratio is computed at comptime.
|
||||||
/// Compile error if dimensions don't match.
|
/// Compile error if dimensions don't match.
|
||||||
pub inline fn to(self: Self, comptime Dest: type) Dest {
|
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));
|
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" {
|
test "Chained: velocity and acceleration" {
|
||||||
const Meter = Scalar(i128, Dimensions.init(.{ .L = 1 }), Scales.init(.{}));
|
const Meter = Scalar(i128, Dimensions.init(.{ .L = 1 }), Scales.init(.{}));
|
||||||
const Second = Scalar(f32, Dimensions.init(.{ .T = 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;
|
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.
|
/// Multiplies all components of the vector together.
|
||||||
/// Resulting dimensions are (Original Dims * len).
|
/// Resulting dimensions are (Original Dims * len).
|
||||||
pub inline fn product(self: Self) Scalar(
|
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 MeterInt = Scalar(i32, Dimensions.init(.{ .L = 1 }), Scales.init(.{}));
|
||||||
const MeterFloat = Scalar(f32, 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
|
// 3-4-5 triangle on XY plane
|
||||||
const v_int = MeterInt.Vec3{ .data = .{ 3, 4, 0 } };
|
const v_int = MeterInt.Vec3{ .data = .{ 3, 4, 0 } };
|
||||||
try std.testing.expectEqual(25, v_int.lengthSqr());
|
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));
|
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 Meter = Scalar(f32, Dimensions.init(.{ .L = 1 }), Scales.init(.{}));
|
||||||
|
|
||||||
const v1 = Meter.Vec3{ .data = .{ -2.0, 3.0, -4.0 } };
|
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(4.0, area_vec.data[0]);
|
||||||
try std.testing.expectEqual(16.0, area_vec.data[2]);
|
try std.testing.expectEqual(16.0, area_vec.data[2]);
|
||||||
try std.testing.expectEqual(2, @TypeOf(area_vec).dims.get(.L));
|
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