I am trying to do some mathematics at compile time (towards a library for units of measure) and got an error I don’t understand. I am afraid my attempt to shorten the code to post here is still a little long:
const std = @import("std");
const testing = std.testing;
pub const ComptimeFraction = struct {
numerator: comptime_int,
denominator: comptime_int,
const Self = @This();
pub fn init(top: comptime_int, bottom: comptime_int) Self {
return Self{
.numerator = top,
.denominator = bottom,
};
}
pub fn eq(self: Self, other: Self) bool {
return (self.numerator == other.numerator) and (self.denominator == other.denominator);
}
};
fn distinctPrimeFactorCount(number: comptime_int) comptime_int {
comptime var remaining = number;
comptime var count = 0;
comptime var p = 2;
while (remaining > 1) {
if (remaining % p == 0) {
count += 1;
while (remaining % p == 0) {
remaining /= p;
}
}
p += 1;
}
return count;
}
const Factor = struct { prime: comptime_int, power: ComptimeFraction };
fn primeFactorization(number: comptime_int) [distinctPrimeFactorCount(number)]Factor {
comptime var factorization: [distinctPrimeFactorCount(number)]Factor = undefined;
comptime var remaining = number;
comptime var p = 2;
comptime var i = 0;
while (i < 0) {
if (remaining % p == 0) {
comptime var count = 0;
while (remaining % p == 0) {
remaining /= p;
count += 1;
}
factorization[i] = .{ .prime = p, .power = ComptimeFraction.init(count, 1) };
i += 1;
}
p += 1;
}
return factorization;
}
test "primeFactorization" {
try testing.expect(primeFactorization(2)[0].power.eq(ComptimeFraction.init(1, 1)));
}
zig test on this file failed with
src/comptime_fraction.zig:17:16: error: use of undefined value here causes undefined behavior
return (self.numerator == other.numerator) and (self.denominator == other.denominator);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
referenced by:
test.primeFactorization: src/comptime_fraction.zig:60:57
Probably. I hit some build errors at the very start that seemed to go away when I made comptime more explicit, and decided to do it that way until it builds and does what I intended. Refactoring away unnecessary "comptime"s is in my todos, though.
I was curious so I removed all the comptime definitions and ended up with this error:
frac.zig:42:62: error: unable to resolve comptime value
fn primeFactorization(number: i64) [distinctPrimeFactorCount(number)]Factor {
^~~~~~
frac.zig:42:62: note: argument to function being called at comptime must be comptime-known
If this error prompted you to comptime everything, I think your problem here is your primeFactorization function needs to know the number to factorize at comptime in order to deduce the size of the output array.
In this form this function can only work at comptime. But I think if you change it so it returns a slice instead of an array, the function becomes comptime agnostic, thus simplifying your code.