DEV Community

Cover image for Modulo calculation with negative numbers in SASS and JS
Irina Illustrova
Irina Illustrova

Posted on

Modulo calculation with negative numbers in SASS and JS

The reason I wrote this is illustrated with the picture below:

Code playground shows different output for the same modulo calculation in JS and SASS

It's not a bug or mistake, as some might have thought. The modulo operator in SASS does not produce the same result as in JS. This is not that surprising itself, but one might not had ever thought of that, as I haven't.
I learned it the hard way, after 30 mins of searching a bug in my code. The thing is my SASS mixin was actually a translation of Javascript piece of code.

The explanation is simple - as SASS is originally based on Ruby language, it inherits its features. And that's the way modulo in Ruby works, even if some people may complain. Moreover, modulo calculation differs from language to language, Wikipedia provides a great table with data for the most common ones. Actually, if you dig into more, the % operator in Javascript provides a reminder result, and not a mathematical modulo. This is well described in the spec:

The result of an ECMAScript floating-point remainder operation is determined by the rules of IEEE arithmetic:

  • If either operand is NaN, the result is NaN.

  • The sign of the result equals the sign of the dividend.

  • If the dividend is an infinity, or the divisor is a zero, or both, the result is NaN.

  • If the dividend is finite and the divisor is an infinity, the result equals the dividend.

  • If the dividend is a zero and the divisor is nonzero and finite, the result is the same as the dividend.

  • In the remaining cases, where neither an infinity, nor a zero, nor NaN is involved, the floating-point remainder r from a dividend n and a divisor d is defined by the mathematical relation r = n − (d × q) where q is an integer that is negative only if n/d is negative and positive only if n/d is positive, and whose magnitude is as large as possible without exceeding the magnitude of the true mathematical quotient of n and d. r is computed and rounded to the nearest representable value using IEEE 754 round-to-nearest mode.

Following the spec, we can create a similar reminder function for SASS:

@function reminder($origin, $mod){
  $q: if($origin/$mod > 0, floor($origin/$mod), ceil($origin/$mod));
  @return $origin - ($mod * $q);
}

...And now you get the same result as in JS even with negative numbers. Here is my final codepen.

There is one more funny and (I guess?) not intended behaviour I encountered playing with modulos - see the second @debug expression in my codepen. For some reason the result changes, if you include a log string just before the expression, without a space. I don't have explanation for that; would have been great to know.

II


Cover image: dooder - www.freepik.com

Discussion (0)