The guidance using % vs @rem/@mod

Hi,

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.

6 Likes

Thanks for the detailed response! And sorry for the confusing typo.

Do you think it would make sense to suggest in the documentation for @rem/@mod that % is preferable for unsigned integers?

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.

1 Like

Where’s @divmod? Please don’t say you forgot it.

I haven’t run into @divmod in Zig before nor do I see it in the documentation. Would be happy to learn about it though.