模数和余数应该如何在 Scheme 中工作?
How modulo and remainder should work in Scheme?
我正在阅读 R5RS 规范并且 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
这是正确的吗?我认为模数和余数仅在负号上有所不同。这里显示 (modulo -13 4)
应该 return 3,在 JavaScript 中它 returns 1.
计算模数和余数的正确算法是什么?我在 JavaScript 实现中需要这个用于我的方案。
我在 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;
}
但它不像 R5RS 规范那样工作,它 returns -1
for modulo(-13, 4)
。我还认为 JavaScript 的 %
与 remainder
相同。如何在JavaScript或Scheme中实现这两个功能?
我的确切问题是:两个函数的算法应该是什么样子,或者 JavaScript 计算它们的代码应该是什么样子?
这是 Chibi 的实现:
remainder
: https://github.com/ashinn/chibi-scheme/blob/12636f4b19e732bcf257ab50808a93c323823099/bignum.c#L1784
-
作者是R7RS的作者之一
以下是我在 Urlang 中实现函数的方式:
(define/export/arity (quotient n m)
(Math.floor (/ n m)))
(define/export/arity (remainder n m)
(% n m))
(define/export/arity (quotient/remainder n m)
(values (quotient n m) (remainder n m)))
(define/export/arity (modulo n m)
(var [who (λ() (string->symbol "modulo"))])
(unless (and (number? n) (not (infinite? n)))
(raise-argument-error (who) "integer?" 1 n m))
(unless (and (number? m) (not (infinite? m)))
(raise-argument-error (who) "integer?" 2 n m))
(% (+ (% n m) m) m))
这里的Math.floor
、%
和+
是标准的JavaScriptfunctions/operators。
出于好奇,这里是 JavaScript 产生的:
function remainder(n,m){if(!((arguments.length===2)===false))VOID;else (raise_arity_error_m((string__gsymbol("remainder")),2,arguments));;return (n%m);};
function quotient_qremainder(n,m){if(!((arguments.length===2)===false))VOID;else (raise_arity_error_m((string__gsymbol("quotient/remainder")),2,arguments));;return (values((quotient(n,m)),(remainder(n,m))));};
function modulo(n,m){if(!((arguments.length===2)===false))VOID;else (raise_arity_error_m((string__gsymbol("modulo")),2,arguments));;var who=(function(){return (string__gsymbol("modulo"));});(((!((number_p(n))&&(!(infinite_p(n)))))===false)?undefined:((function(){return (raise_argument_error((who()),"integer?",1,n,m));})()));(((!((number_p(m))&&(!(infinite_p(m)))))===false)?undefined:((function(){return (raise_argument_error((who()),"integer?",2,n,m));})()));return (((n%m)+m)%m);};
更新
这里有一点背景。该代码为 Scheme 运行时实现余数和取模。运行时在 Urlang 中实现(JavaScript with s-expression-syntax)。
从输出JavaScript中可以看出:
- 方案
remainder
实现为n%m
。
- 方案
modulo
实现为((n%m)+m)%m
这假设 Scheme 编号表示为 JavaScript 个数字(即没有 bignums)。
如果有人感兴趣,我已经在 Reddit 上问了同样的问题(这个问题 link)并得到了带有确切方案代码的答案:
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))
它与 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
是 Math.floor
而 truncate
是:
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);
}
};
}
})();
我正在阅读 R5RS 规范并且 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
这是正确的吗?我认为模数和余数仅在负号上有所不同。这里显示 (modulo -13 4)
应该 return 3,在 JavaScript 中它 returns 1.
计算模数和余数的正确算法是什么?我在 JavaScript 实现中需要这个用于我的方案。
我在 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;
}
但它不像 R5RS 规范那样工作,它 returns -1
for modulo(-13, 4)
。我还认为 JavaScript 的 %
与 remainder
相同。如何在JavaScript或Scheme中实现这两个功能?
我的确切问题是:两个函数的算法应该是什么样子,或者 JavaScript 计算它们的代码应该是什么样子?
这是 Chibi 的实现:
remainder
: https://github.com/ashinn/chibi-scheme/blob/12636f4b19e732bcf257ab50808a93c323823099/bignum.c#L1784
作者是R7RS的作者之一
以下是我在 Urlang 中实现函数的方式:
(define/export/arity (quotient n m)
(Math.floor (/ n m)))
(define/export/arity (remainder n m)
(% n m))
(define/export/arity (quotient/remainder n m)
(values (quotient n m) (remainder n m)))
(define/export/arity (modulo n m)
(var [who (λ() (string->symbol "modulo"))])
(unless (and (number? n) (not (infinite? n)))
(raise-argument-error (who) "integer?" 1 n m))
(unless (and (number? m) (not (infinite? m)))
(raise-argument-error (who) "integer?" 2 n m))
(% (+ (% n m) m) m))
这里的Math.floor
、%
和+
是标准的JavaScriptfunctions/operators。
出于好奇,这里是 JavaScript 产生的:
function remainder(n,m){if(!((arguments.length===2)===false))VOID;else (raise_arity_error_m((string__gsymbol("remainder")),2,arguments));;return (n%m);};
function quotient_qremainder(n,m){if(!((arguments.length===2)===false))VOID;else (raise_arity_error_m((string__gsymbol("quotient/remainder")),2,arguments));;return (values((quotient(n,m)),(remainder(n,m))));};
function modulo(n,m){if(!((arguments.length===2)===false))VOID;else (raise_arity_error_m((string__gsymbol("modulo")),2,arguments));;var who=(function(){return (string__gsymbol("modulo"));});(((!((number_p(n))&&(!(infinite_p(n)))))===false)?undefined:((function(){return (raise_argument_error((who()),"integer?",1,n,m));})()));(((!((number_p(m))&&(!(infinite_p(m)))))===false)?undefined:((function(){return (raise_argument_error((who()),"integer?",2,n,m));})()));return (((n%m)+m)%m);};
更新
这里有一点背景。该代码为 Scheme 运行时实现余数和取模。运行时在 Urlang 中实现(JavaScript with s-expression-syntax)。
从输出JavaScript中可以看出:
- 方案
remainder
实现为n%m
。 - 方案
modulo
实现为((n%m)+m)%m
这假设 Scheme 编号表示为 JavaScript 个数字(即没有 bignums)。
如果有人感兴趣,我已经在 Reddit 上问了同样的问题(这个问题 link)并得到了带有确切方案代码的答案:
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))
它与 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
是 Math.floor
而 truncate
是:
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);
}
};
}
})();