Zig and Odin produce opposing results for modulo and remainder operations

Hello there.
I’m currently developing a game in Zig and ran into an issue using the % operator with isize. The compiler recommended using either @mod or @rem. Out of curiosity, I looked up the equivalent operators in Odin, since I have more experience with it.

According to the Odin documentation:

% modulo (truncated) integers
%% remainder (floored) integers

However, when I tested them, I noticed that the results were swapped compared to what I expected from Zig.

//zig
@mod(-1, 50) == 49
@rem(-1, 50) == -1
//odin
-1 % 50 == -1
-1 %% 50 == 49

Can someone clear things up?

Odin made a mistake, it’s that simple.

Odin might also have deliberately made a mistake to correspond with C’s common nickname.

In the C standard, % is explicitly defined as the remainder:

The result of the / operator is the quotient from the division of the first operand by the
second; the result of the % operator is the remainder. Inboth operations, if the value of
the second operand is zero, the behavior is undefined.

However, the % in C language is widely and incorrectly referred to as ‘mod’.

Odin might have deliberately reversed their meanings to go along with this mistake.

It’s a typo. Should be @mod(-1, 50) == 49

2 Likes

zig mod is floored, whereas odins mod is truncated
zig’s rem is truncated, whereas odin’s mod is floored.

The reason why the result values don’t match (but swapped) is probably due to semantic differences between them regarding integer literals
I tested it, they have the same results, just swapped as expected.
Did you typo? Or use different types?

1 Like

I certainly did not, copy past from the docs.

I’m just jealous that Odin gets to use operators.

Zig has three operators for addition and “screw you” for division, /- and /% wouldn’t bloat the language. I think %- and %% are less instantly clear, but they suck so much less than “use a function lol, lmao” that it’s worth it.

Now that ‘make things nice for video games’ is a priority, maybe hope is on the horizon.

To translate from the documentation:

// before
(@divTrunc(a, b) * b) + @rem(a, b) == a; // yuck
// after
a /% b * b + a %% b == a; // yes

// likewise:
(@divFloor(a, b) * b) + @mod(a, b) == a; // my eyes!
a /- b * b + a %- b == a; // you know I'm right
2 Likes

Good catch, I’ll ask around in Odin’s forums to make sure.

I agree…
Math and casting are not fun in zig, I hope we can replace some builtin functions with syntax and operators.

2 Likes

Here’s GingerBill’s reply for anyone wondering

2 Likes

Well, I respectfully disagree with it.

In mathematics, modula is well-defined:

x mod y = x − y⌊x/y⌋

However, the mathematical community almost never discusses truncated division, and therefore also does not discuss the remainder of truncated division.

In the programming world, because computers use truncated division rather than floored division at the lower level, it indeed leads to the modulo sometimes being used interchangeably with the remainder of truncated division. However, this phenomenon generally occurs in languages that do not explicitly distinguish between the remainder of truncated division and the modulo of floored division.

All languages that clearly distinguish between the remainder of truncated division and the modulus of floored division almost all correctly use ‘mod’ to represent the mathematical modulus operation, and ‘rem’ to represent the remainder of truncated division. These languages include Ada, Haskell, the Lisp family, and so on.

Based on the Odin documentation you excerpted, I think Odin is still the first language that, while distinguishing between these two types of operations, considers the modulus to be the result of truncated division and the remainder to be the result of floored division.

I fully agree with Odin’s continuation of using C language symbols, using % to express the meaning of truncated division remainder. However, as mentioned before, the C standard correctly uses ‘remainder’ to express the meaning of the % operator, rather than the widely misunderstood ‘modulo operation’. I insist that Odin’s documentation here is a mistake.

Edit: Although the Odin documentation’s explanation of Modulo and remainder is somewhat counterintuitive, the Odin documentation correctly indicates that these two symbols are applicable to truncating division and floored division.

This may be a sense of humor. In my native language, when discussing North Korea(Chosŏn) and South Korea(Han), out of a sense of humor, people often intentionally reverse them, calling North Korea ‘North Han’ and South Korea ‘South Chosŏn’.

2 Likes

This is overconfident:

In mathematics, the result of the modulo operation is an equivalence class, and any member of the class may be chosen as representative; however, the usual representative is the least positive residue, the smallest non-negative integer that belongs to that class (i.e., the remainder of the Euclidean division).[2] However, other conventions are possible.

The most idiomatic use of the term, what would be understood to be meant without further elaboration, is the remainder of Euclidean division, which follows neither floored nor truncated remainder:

If both the dividend and divisor are positive, then the truncated, floored, and Euclidean definitions agree. If the dividend is positive and the divisor is negative, then the truncated and Euclidean definitions agree. If the dividend is negative and the divisor is positive, then the floored and Euclidean definitions agree. If both the dividend and divisor are negative, then the truncated and floored definitions agree.

From perusing the handy chart of programming languages, this is the least popular interpretation by a considerable margin. For a language like Zig I wouldn’t choose it either.

I’m reluctant to quote Wikipedia like Gospel, but for maths it’s pretty accurate. I’m sure you see the distinction I’m drawing: it would be correct to say that the positive root is what is meant by “the square root of” in maths, but of course it’s understood that there are two.

Mathematics is also not the boss of us. We’re programmers, it’s its own thing.

3 Likes

In mathematics, a mod b is not an integer, it’s an equivalence class of integers, there is universal agreement that there is no canonical choice of integer in that class.

4 Likes

Thank you for providing a broader mathematical background, which has broadened my perspective on interpreting these terms. The mathematical definition of “mod” that I provided mainly comes from CONCRETE MATHEMATICS (I am very sorry for not having a public link.).

I agree, but I think from a programmer’s perspective, the handy chart you provided confirms this view: in the programmer’s world, when both “mod” and “rem” operations are provided, “rem” is always used for truncating division, while “mod” is always used for floored division.

Odin’s use of % for truncating division is completely fine, it’s just that the documentation calling truncation ‘modulo’ and floored ‘remainder’ is basically inconsistent with the conventions in the programmer world.

1 Like

Fun fact: the C standard calls %: remainder. ¯\_(ツ)_/¯

Everyone calls it modulus!! Bill’s got an out here with “general naming conventions” but, that’s not what the standard calls it.

1 Like