Replaced Scales.min to helper.finerScales
This commit is contained in:
parent
49b56bda91
commit
ec05b60fc3
@ -134,13 +134,13 @@ test "BaseQuantities - Dynamics (Force and Work)" {
|
||||
|
||||
// Force = mass * acceleration
|
||||
const f = m.mulBy(a);
|
||||
try std.testing.expectEqual(98000, f.value);
|
||||
try std.testing.expectEqual(98, f.value);
|
||||
try std.testing.expect(Force.dims.eql(@TypeOf(f).dims));
|
||||
|
||||
// Energy (Work) = Force * distance
|
||||
const distance = Meter.Of(f32){ .value = 5.0 };
|
||||
const energy = f.mulBy(distance);
|
||||
try std.testing.expectEqual(490000, energy.value);
|
||||
try std.testing.expectEqual(490, energy.value);
|
||||
try std.testing.expect(Energy.dims.eql(@TypeOf(energy).dims));
|
||||
}
|
||||
|
||||
|
||||
@ -29,8 +29,6 @@ pub const Dimension = enum {
|
||||
}
|
||||
};
|
||||
|
||||
// --------- Dimensions struct ---------
|
||||
|
||||
const Self = @This();
|
||||
|
||||
data: std.EnumArray(Dimension, comptime_int),
|
||||
|
||||
@ -7,6 +7,17 @@ const UnitScale = Scales.UnitScale;
|
||||
const Dimensions = @import("Dimensions.zig");
|
||||
const Dimension = Dimensions.Dimension;
|
||||
|
||||
// TODO: Add those operation:
|
||||
// - eq: Equal
|
||||
// - ne: Not equal
|
||||
// - gt: Greather than
|
||||
// - gte: Greather than or equal
|
||||
// - lt: Less than
|
||||
// - lte Less than or equal
|
||||
// - abs: Absolut value
|
||||
// - pow: Scalar power another
|
||||
// - log: Scalar log another
|
||||
|
||||
pub fn Scalar(comptime T: type, comptime d: Dimensions, comptime s: Scales) type {
|
||||
@setEvalBranchQuota(10_000_000);
|
||||
return struct {
|
||||
@ -22,14 +33,14 @@ pub fn Scalar(comptime T: type, comptime d: Dimensions, comptime s: Scales) type
|
||||
pub inline fn add(self: Self, rhs: anytype) Scalar(
|
||||
T,
|
||||
dims,
|
||||
scales.min(@TypeOf(rhs).scales),
|
||||
hlp.finerScales(Self, @TypeOf(rhs)),
|
||||
) {
|
||||
if (comptime !dims.eql(@TypeOf(rhs).dims))
|
||||
@compileError("Dimension mismatch in add: " ++ dims.str() ++ " vs " ++ @TypeOf(rhs).dims.str());
|
||||
if (comptime @TypeOf(rhs) == Self)
|
||||
return .{ .value = self.value + rhs.value };
|
||||
|
||||
const TargetType = Scalar(T, dims, scales.min(@TypeOf(rhs).scales));
|
||||
const TargetType = Scalar(T, dims, hlp.finerScales(Self, @TypeOf(rhs)));
|
||||
const lhs_val = if (comptime @TypeOf(self) == TargetType) self.value else self.to(TargetType).value;
|
||||
const rhs_val = if (comptime @TypeOf(rhs) == TargetType) rhs.value else rhs.to(TargetType).value;
|
||||
|
||||
@ -39,14 +50,14 @@ pub fn Scalar(comptime T: type, comptime d: Dimensions, comptime s: Scales) type
|
||||
pub inline fn sub(self: Self, rhs: anytype) Scalar(
|
||||
T,
|
||||
dims,
|
||||
scales.min(@TypeOf(rhs).scales),
|
||||
hlp.finerScales(Self, @TypeOf(rhs)),
|
||||
) {
|
||||
if (comptime !dims.eql(@TypeOf(rhs).dims))
|
||||
@compileError("Dimension mismatch in sub: " ++ dims.str() ++ " vs " ++ @TypeOf(rhs).dims.str());
|
||||
if (comptime @TypeOf(rhs) == Self)
|
||||
return .{ .value = self.value - rhs.value };
|
||||
|
||||
const TargetType = Scalar(T, dims, scales.min(@TypeOf(rhs).scales));
|
||||
const TargetType = Scalar(T, dims, hlp.finerScales(Self, @TypeOf(rhs)));
|
||||
const lhs_val = if (comptime @TypeOf(self) == TargetType) self.value else self.to(TargetType).value;
|
||||
const rhs_val = if (comptime @TypeOf(rhs) == TargetType) rhs.value else rhs.to(TargetType).value;
|
||||
|
||||
@ -56,11 +67,11 @@ pub fn Scalar(comptime T: type, comptime d: Dimensions, comptime s: Scales) type
|
||||
pub inline fn mulBy(self: Self, rhs: anytype) Scalar(
|
||||
T,
|
||||
dims.add(@TypeOf(rhs).dims),
|
||||
scales.min(@TypeOf(rhs).scales),
|
||||
hlp.finerScales(Self, @TypeOf(rhs)),
|
||||
) {
|
||||
const RhsType = @TypeOf(rhs);
|
||||
const SelfNorm = Scalar(T, dims, scales.min(RhsType.scales));
|
||||
const RhsNorm = Scalar(T, RhsType.dims, scales.min(RhsType.scales));
|
||||
const SelfNorm = Scalar(T, dims, hlp.finerScales(Self, @TypeOf(rhs)));
|
||||
const RhsNorm = Scalar(T, RhsType.dims, hlp.finerScales(Self, @TypeOf(rhs)));
|
||||
if (comptime Self == SelfNorm and RhsType == RhsNorm)
|
||||
return .{ .value = self.value * rhs.value };
|
||||
|
||||
@ -72,11 +83,11 @@ pub fn Scalar(comptime T: type, comptime d: Dimensions, comptime s: Scales) type
|
||||
pub inline fn divBy(self: Self, rhs: anytype) Scalar(
|
||||
T,
|
||||
dims.sub(@TypeOf(rhs).dims),
|
||||
scales.min(@TypeOf(rhs).scales),
|
||||
hlp.finerScales(Self, @TypeOf(rhs)),
|
||||
) {
|
||||
const RhsType = @TypeOf(rhs);
|
||||
const SelfNorm = Scalar(T, dims, scales.min(RhsType.scales));
|
||||
const RhsNorm = Scalar(T, RhsType.dims, scales.min(RhsType.scales));
|
||||
const SelfNorm = Scalar(T, dims, hlp.finerScales(Self, @TypeOf(rhs)));
|
||||
const RhsNorm = Scalar(T, RhsType.dims, hlp.finerScales(Self, @TypeOf(rhs)));
|
||||
const lhs_val = if (comptime Self == SelfNorm) self.value else self.to(SelfNorm).value;
|
||||
const rhs_val = if (comptime RhsType == RhsNorm) rhs.value else rhs.to(RhsNorm).value;
|
||||
if (comptime @typeInfo(T) == .int) {
|
||||
@ -104,7 +115,6 @@ pub fn Scalar(comptime T: type, comptime d: Dimensions, comptime s: Scales) type
|
||||
const div: DestT = comptime @intFromFloat(1.0 / ratio);
|
||||
const val = @as(DestT, @intCast(self.value));
|
||||
const half = comptime div / 2;
|
||||
// Native round-to-nearest
|
||||
const rounded = if (val >= 0) @divTrunc(val + half, div) else @divTrunc(val - half, div);
|
||||
return .{ .value = rounded };
|
||||
}
|
||||
@ -329,6 +339,18 @@ test "DivBy integer exact" {
|
||||
try std.testing.expectEqual(-1, @TypeOf(vel).dims.get(.T));
|
||||
}
|
||||
|
||||
test "Finer scales skip dim 0" {
|
||||
const Dimless = Scalar(i128, Dimensions.init(.{}), Scales.init(.{}));
|
||||
const KiloMetre = Scalar(i128, Dimensions.init(.{ .L = 1 }), Scales.init(.{ .L = .k }));
|
||||
|
||||
const r = Dimless{ .value = 30 };
|
||||
const time = KiloMetre{ .value = 4 };
|
||||
const vel = r.mulBy(time);
|
||||
|
||||
try std.testing.expectEqual(120, vel.value);
|
||||
try std.testing.expectEqual(Scales.UnitScale.k, @TypeOf(vel).scales.get(.L));
|
||||
}
|
||||
|
||||
test "Conversion chain: km -> m -> cm" {
|
||||
const KiloMeter = Scalar(i128, Dimensions.init(.{ .L = 1 }), Scales.init(.{ .L = .k }));
|
||||
const Meter = Scalar(i128, Dimensions.init(.{ .L = 1 }), Scales.init(.{}));
|
||||
|
||||
@ -81,25 +81,17 @@ pub fn set(comptime self: *Scales, comptime key: Dimension, comptime val: UnitSc
|
||||
comptime self.data.set(key, val);
|
||||
}
|
||||
|
||||
pub fn min(comptime s1: Scales, comptime s2: Scales) Scales {
|
||||
comptime var out = Scales.initFill(.none);
|
||||
inline for (std.enums.values(Dimension)) |dim|
|
||||
out.set(dim, if (s1.get(dim).getFactorInt() > s2.get(dim).getFactorInt()) s2.get(dim) else s1.get(dim));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
pub inline fn getFactor(comptime s: Scales, comptime d: Dimensions) comptime_float {
|
||||
comptime var factor: f64 = 1.0;
|
||||
inline for (std.enums.values(Dimension)) |dim| {
|
||||
const power = d.get(dim);
|
||||
if (power == 0) continue;
|
||||
const power = comptime d.get(dim);
|
||||
if (comptime power == 0) continue;
|
||||
|
||||
const base = s.get(dim).getFactor();
|
||||
const base = comptime s.get(dim).getFactor();
|
||||
|
||||
var i: i32 = 0;
|
||||
var i: comptime_int = 0;
|
||||
const abs_power = if (power < 0) -power else power;
|
||||
while (i < abs_power) : (i += 1) {
|
||||
inline while (i < abs_power) : (i += 1) {
|
||||
if (power > 0)
|
||||
factor *= base
|
||||
else
|
||||
|
||||
@ -30,9 +30,13 @@ pub fn Vector(comptime len: usize, comptime Q: type) type {
|
||||
return .{ .data = data };
|
||||
}
|
||||
|
||||
pub inline fn add(self: Self, rhs: anytype) Vector(len, Scalar(T, d, s.min(@TypeOf(rhs).scales))) {
|
||||
pub inline fn add(self: Self, rhs: anytype) Vector(len, Scalar(
|
||||
T,
|
||||
dims,
|
||||
hlp.finerScales(Self, @TypeOf(rhs)),
|
||||
)) {
|
||||
const Tr = @TypeOf(rhs);
|
||||
var res: Vector(len, Scalar(T, d, s.min(Tr.scales))) = undefined;
|
||||
var res: Vector(len, Scalar(T, d, hlp.finerScales(Self, @TypeOf(rhs)))) = undefined;
|
||||
inline for (self.data, 0..) |v, i| {
|
||||
const q = (Q{ .value = v }).add(Tr.ScalarType{ .value = rhs.data[i] });
|
||||
res.data[i] = q.value;
|
||||
@ -40,9 +44,13 @@ pub fn Vector(comptime len: usize, comptime Q: type) type {
|
||||
return res;
|
||||
}
|
||||
|
||||
pub inline fn sub(self: Self, rhs: anytype) Vector(len, Scalar(T, d, s.min(@TypeOf(rhs).scales))) {
|
||||
pub inline fn sub(self: Self, rhs: anytype) Vector(len, Scalar(
|
||||
T,
|
||||
dims,
|
||||
hlp.finerScales(Self, @TypeOf(rhs)),
|
||||
)) {
|
||||
const Tr = @TypeOf(rhs);
|
||||
var res: Vector(len, Scalar(T, d, s.min(Tr.scales))) = undefined;
|
||||
var res: Vector(len, Scalar(T, d, hlp.finerScales(Self, @TypeOf(rhs)))) = undefined;
|
||||
inline for (self.data, 0..) |v, i| {
|
||||
const q = (Q{ .value = v }).sub(Tr.ScalarType{ .value = rhs.data[i] });
|
||||
res.data[i] = q.value;
|
||||
@ -53,9 +61,13 @@ pub fn Vector(comptime len: usize, comptime Q: type) type {
|
||||
pub inline fn divBy(
|
||||
self: Self,
|
||||
rhs: anytype,
|
||||
) Vector(len, Scalar(T, d.sub(@TypeOf(rhs).dims), s.min(@TypeOf(rhs).scales))) {
|
||||
) Vector(len, Scalar(
|
||||
T,
|
||||
dims.sub(@TypeOf(rhs).dims),
|
||||
hlp.finerScales(Self, @TypeOf(rhs)),
|
||||
)) {
|
||||
const Tr = @TypeOf(rhs);
|
||||
var res: Vector(len, Scalar(T, d.sub(Tr.dims), s.min(Tr.scales))) = undefined;
|
||||
var res: Vector(len, Scalar(T, d.sub(Tr.dims), hlp.finerScales(Self, @TypeOf(rhs)))) = undefined;
|
||||
inline for (self.data, 0..) |v, i| {
|
||||
const q = (Q{ .value = v }).divBy(Tr.ScalarType{ .value = rhs.data[i] });
|
||||
res.data[i] = q.value;
|
||||
@ -66,9 +78,13 @@ pub fn Vector(comptime len: usize, comptime Q: type) type {
|
||||
pub inline fn mulBy(
|
||||
self: Self,
|
||||
rhs: anytype,
|
||||
) Vector(len, Scalar(T, d.add(@TypeOf(rhs).dims), s.min(@TypeOf(rhs).scales))) {
|
||||
) Vector(len, Scalar(
|
||||
T,
|
||||
dims.add(@TypeOf(rhs).dims),
|
||||
hlp.finerScales(Self, @TypeOf(rhs)),
|
||||
)) {
|
||||
const Tr = @TypeOf(rhs);
|
||||
var res: Vector(len, Scalar(T, d.add(Tr.dims), s.min(Tr.scales))) = undefined;
|
||||
var res: Vector(len, Scalar(T, d.add(Tr.dims), hlp.finerScales(Self, @TypeOf(rhs)))) = undefined;
|
||||
inline for (self.data, 0..) |v, i| {
|
||||
const q = (Q{ .value = v }).mulBy(Tr.ScalarType{ .value = rhs.data[i] });
|
||||
res.data[i] = q.value;
|
||||
@ -79,8 +95,12 @@ pub fn Vector(comptime len: usize, comptime Q: type) type {
|
||||
pub inline fn divByScalar(
|
||||
self: Self,
|
||||
scalar: anytype,
|
||||
) Vector(len, Scalar(T, d.sub(@TypeOf(scalar).dims), s.min(@TypeOf(scalar).scales))) {
|
||||
var res: Vector(len, Scalar(T, d.sub(@TypeOf(scalar).dims), s.min(@TypeOf(scalar).scales))) = undefined;
|
||||
) Vector(len, Scalar(
|
||||
T,
|
||||
dims.sub(@TypeOf(scalar).dims),
|
||||
hlp.finerScales(Self, @TypeOf(scalar)),
|
||||
)) {
|
||||
var res: Vector(len, Scalar(T, d.sub(@TypeOf(scalar).dims), hlp.finerScales(Self, @TypeOf(scalar)))) = undefined;
|
||||
inline for (self.data, 0..) |v, i| {
|
||||
const q = Q{ .value = v };
|
||||
res.data[i] = q.divBy(scalar).value;
|
||||
@ -91,8 +111,12 @@ pub fn Vector(comptime len: usize, comptime Q: type) type {
|
||||
pub inline fn mulByScalar(
|
||||
self: Self,
|
||||
scalar: anytype,
|
||||
) Vector(len, Scalar(T, d.add(@TypeOf(scalar).dims), s.min(@TypeOf(scalar).scales))) {
|
||||
var res: Vector(len, Scalar(T, d.add(@TypeOf(scalar).dims), s.min(@TypeOf(scalar).scales))) = undefined;
|
||||
) Vector(len, Scalar(
|
||||
T,
|
||||
dims.add(@TypeOf(scalar).dims),
|
||||
hlp.finerScales(Self, @TypeOf(scalar)),
|
||||
)) {
|
||||
var res: Vector(len, Scalar(T, d.add(@TypeOf(scalar).dims), hlp.finerScales(Self, @TypeOf(scalar)))) = undefined;
|
||||
inline for (self.data, 0..) |v, i| {
|
||||
const q = Q{ .value = v };
|
||||
res.data[i] = q.mulBy(scalar).value;
|
||||
@ -102,25 +126,22 @@ pub fn Vector(comptime len: usize, comptime Q: type) type {
|
||||
|
||||
pub fn negate(self: Self) Self {
|
||||
var res: Self = undefined;
|
||||
inline for (self.data, 0..) |v, i| {
|
||||
inline for (self.data, 0..) |v, i|
|
||||
res.data[i] = -v;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
pub inline fn to(self: Self, comptime DestQ: type) Vector(len, DestQ) {
|
||||
var res: Vector(len, DestQ) = undefined;
|
||||
inline for (self.data, 0..) |v, i| {
|
||||
inline for (self.data, 0..) |v, i|
|
||||
res.data[i] = (Q{ .value = v }).to(DestQ).value;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
pub inline fn lengthSqr(self: Self) T {
|
||||
var sum: T = 0;
|
||||
inline for (self.data) |v| {
|
||||
inline for (self.data) |v|
|
||||
sum += v * v;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
@ -128,10 +149,7 @@ pub fn Vector(comptime len: usize, comptime Q: type) type {
|
||||
const len_sq = self.lengthSqr();
|
||||
|
||||
if (comptime @typeInfo(T) == .int) {
|
||||
// Construct the unsigned equivalent of T at comptime (e.g., i32 -> u32)
|
||||
const UnsignedT = @Int(.unsigned, @typeInfo(T).int.bits);
|
||||
|
||||
// len_sq is always positive, so @intCast is perfectly safe
|
||||
const u_len_sq = @as(UnsignedT, @intCast(len_sq));
|
||||
return @as(T, @intCast(std.math.sqrt(u_len_sq)));
|
||||
} else {
|
||||
|
||||
@ -30,3 +30,30 @@ pub fn printSuperscript(writer: *std.Io.Writer, n: i32) !void {
|
||||
try writer.writeAll(s);
|
||||
}
|
||||
}
|
||||
|
||||
const Scales = @import("Scales.zig");
|
||||
const Dimensions = @import("Dimensions.zig");
|
||||
const Dimension = @import("Dimensions.zig").Dimension;
|
||||
|
||||
pub fn finerScales(comptime T1: type, comptime T2: type) Scales {
|
||||
const d1: Dimensions = T1.dims;
|
||||
const d2: Dimensions = T2.dims;
|
||||
const s1: Scales = T1.scales;
|
||||
const s2: Scales = T2.scales;
|
||||
comptime var out = Scales.initFill(.none);
|
||||
inline for (std.enums.values(Dimension)) |dim| {
|
||||
const scale1 = comptime s1.get(dim);
|
||||
const scale2 = comptime s2.get(dim);
|
||||
out.set(dim, if (comptime d1.get(dim) == 0 and d2.get(dim) == 0)
|
||||
.none
|
||||
else if (comptime d1.get(dim) == 0)
|
||||
scale2
|
||||
else if (comptime d2.get(dim) == 0)
|
||||
scale1
|
||||
else if (comptime scale1.getFactor() > scale2.getFactor())
|
||||
scale2
|
||||
else
|
||||
scale1);
|
||||
}
|
||||
comptime return out;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user