Working my way through Exercism Zig exercises (and mentoring some) I have noticed that many people make use of @mod/@rem instead of more conventional % for integer divisibility checks. I would like to understand what’s the preferred approach that’s idiomatic for Zig.
In ziglang/zig#217% was removed for signed integers. When attempting to use it the compiler would suggest to use @mod/@rem instead. The documentation only states that for signed unsigned integers both functions behave exactly as % without recommending one over the other.
Following Zig’s principle of “only one obvious way to do things”, I could imagine the following guidance:
use % for unsigned integers
use @mod/@rem for signed integers depending on what behavior is desired
Is this correct understanding? Do I miss any important aspects?
You misread that that. It states that they behave the same for unsigned integers (all values >= 0).
In general I would do the following:
use % for unsigned integers
if you know that your numbers are positive then you should change the types to unsigned
use @rem if you want the same behavior as % in other languages
use @mod if you want the mathematical modulo, aka difference to the next smaller number divisble by y
use @rem if you want the difference to the next number divisble by y that is smaller in absolute value. Note the following relation between the two: @rem(x, y) == math.sign(x)*@mod(@abs(x), y)
Two more things to note with regards to performance: @rem(x, y) is usually implemented in hardware, so it will be faster in most cases.
However if the right hand side is a comptime-known power of 2 then @mod(x, y) will be faster.
No, I think it just comes down to personal preference.
I don’t see any real reason to discourage using @mod/@rem for unsigned integers.
For example for people coming from a math background I think @mod might actually be more readable.