Alphish / gm-community-toolbox

A collection of utility functions for GameMaker.
MIT License
35 stars 6 forks source link

Positive modulo #4

Closed Mercerenies closed 1 year ago

Mercerenies commented 1 year ago

Here's a short function that I throw in every project I ever write, pretty much. The built-in Game Maker modulo operator % takes the sign of the dividend, matching the behavior of C. This can cause awkwardness when using % to perform wrapping behavior on a value that might be negative. This is a variant of the modulo function that matches the sign of the result to the sign of the divisor.

function modulo(a, b) {
  return (a % b + b) % b;
}
Alphish commented 1 year ago

Generally in favour of this one, and for the div counterpart as well (i.e. div that rounds towards -infinity, instead of towards 0).

Wondering about the name. modulo doesn't quite show how it's set apart from the mod keyword.

Reading about division, there's apparently the concept of Euclidean division which more or less matches : https://en.wikipedia.org/wiki/Euclidean_division

So I consider function names like:

We might need to accept the fact that there's no super-intuitive name that would make users go "oh, yes, it's the kind of mod/div that handles negative values properly!" and explain things in JSDoc instead. Still, other name suggestions welcome.

JonathanHackerCG commented 1 year ago

I agree with this suggestion. As for name in my own code, I opted for the emod and ediv (even terser).

EDIT: My second suggestion was silly because I misread the post.

A third suggestion is maybe mod_signed and div_signed?

gnysek commented 1 year ago

emod and ediv looks like fast to use

Mercerenies commented 1 year ago

Actually I'm fond of eucmod and eucdiv now that you say that. It's short enough to still type easily, but long enough that anyone who knows what Euclidean division is will immediately recognize the prefix.

Alphish commented 1 year ago

Alright, then maybe let's do some voting on the naming? Since emod/ediv and eucmod/eucdiv seem to be most popular:

People seem to agree that it would be a nice addition, and it seems naming is the only remaining thing to settle before proceeding with implementation.

Alphish commented 1 year ago

Alright, those who voted agreed that eucmod/eucdiv works better, so that's what we're going with. If someone wants to implement it, they can go ahead.

When it comes to eucdiv, I think one of the simplest implementations would be:

function eucdiv(_a, _b) {
    return (a - eucmod(_a, _b)) div _b;
}

Or at least, it matches the definition of Euclidean division.

The tests should verify that:

When it comes to the demonstration, I imagine some grid-snapped input would illustrate it pretty well. So the user moves a mouse around, and there's a comparison between eucdiv and eucmod versus regular div and mod, calculated on (mouse_x - x) and (mouse_y - y), with x and y being coordinates of the grid object and the cell size being the divisor.

If someone does start the implementation work, please tell it here to avoid other people duplicating your work and allow better coordination in general.

devKathy commented 1 year ago

I will go ahead and say that I am starting the implementation work. I will let folks know if any issues arise, or if I am unable to complete it due to schedule conflicts, etc.

I'm adjusting Merc's algorithm to be correct with Euclidian division mods in the case of negative divisors. It seems to me that what he has as of now is based on floor division.

function eucmod(a, b) {
    b = abs(b);
  return (a % b + b) % b;
} 

For more on Euclidian/floor division, see (Look especially at the C implementations!): https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote.pdf

You can see people doing various implementations of floor division here: https://stackoverflow.com/questions/10065080/mod-explanation?rq=3

Take care, folks! :)

Alphish commented 1 year ago

The related PR has been merged, and thus I'm closing this issue.