I'm reading R5RS spec and it shows this:
(modulo 13 4) ===> 1
(remainder 13 4) ===> 1
(modulo -13 4) ===> 3
(remainder -13 4) ===> -1
(modulo 13 -4) ===> -3
(remainder 13 -4) ===> 1
(modulo -13 -4) ===> -1
(remainder -13 -4) ===> -1
(remainder -13 -4.0) ===> -1.0 ; inexact
Is this correct? I thought that modulo and remainder differ only in minus sign. And here it shows that (modulo -13 4)
should return 3, in JavaScript it returns 1.
What are proper algorithms to calculate modulo and remainder? I need this for my Scheme in JavaScript implementation.
I've found this code at quora.
function modulo(num1, num2) {
if (num2 === 0 || isNaN(num1) || isNaN(num2)) {
return NaN;
}
var isPositive = num1 >= 0;
num1 = Math.abs(num1);
num2 = Math.abs(num2);
while (num1 >= num2) {
num1 = num1 - num2;
}
return isPositive ? num1 : -num1;
}
but it don't work like in R5RS spec, it returns -1
for modulo(-13, 4)
. Also I thought that JavaScript's %
is the same as remainder
. How to implement both functions in JavaScript or in Scheme?
My exact question is: how the algorithm for both functions should look like or how JavaScript code to calculate them both should look like?
If someone is interested I've asked the same question on Reddit (with link to this question) and got the answer with exact scheme code:
https://www.reddit.com/r/scheme/comments/fpt1b8/help_with_modulo_and_reminder_in_r5rs/
(define (modulo a b)
(- a (* b (floor (/ a b)))))
(define (remainder a b)
(- a (* b (truncate (/ a b)))))
;; as @soegaard show reminder is just JavaScript % so this can be
;; if % is proper function
(define (remainder a b)
(% a b))
it works the same with examples from R5RS:
(list
(= (modulo 13 4) 1)
(= (remainder 13 4) 1) ;; ===> 1
(= (modulo -13 4) 3) ;; ===> 3
(= (remainder -13 4) -1) ;; ===> -1
(= (modulo 13 -4) -3) ;; ===> -3
(= (remainder 13 -4) 1) ;; ===> 1
(= (modulo -13 -4) -1) ;; ===> -1
(= (remainder -13 -4) -1) ;; ===> -1
(= (remainder -13 -4.0) -1.0)) ;; ===> -1.0 ; inexact
floor
is Math.floor
and truncate
is:
var truncate = (function() {
if (Math.trunc) {
return Math.trunc;
} else {
return function(x) {
if (x === 0) {
return 0;
} else if (x < 0) {
return Math.ceil(x);
} else {
return Math.floor(x);
}
};
}
})();