Как должен работать модуль и остаток в схеме? - PullRequest
2 голосов
/ 22 марта 2020

Я читаю R5RS spe c и это показывает :

(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) должно возвращать 3, в JavaScript возвращается 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 spe c, возвращает -1 для modulo(-13, 4). Также я подумал, что JavaScript % такой же, как remainder. Как реализовать обе функции в JavaScript или в Схеме?

Мой точный вопрос: как должен выглядеть алгоритм для обеих функций или как должен выглядеть код JavaScript для их вычисления?

Ответы [ 3 ]

1 голос
/ 27 марта 2020

Вот как я реализовал функции в 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, % и + являются стандартными JavaScript функциями / операторами.

Для любопытных: 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);};

ОБНОВЛЕНИЕ

Вот небольшой контекст. Код реализует остаток и модуль по времени выполнения Схемы. Среда выполнения реализована в Urlang (то есть JavaScript с синтаксисом s-выражения).

Из вывода JavaScript вы можете видеть, что:

  • Схема remainder реализовано как n%m.
  • Схема modulo реализована как ((n%m)+m)%m

Это предполагает, что номера Схемы представлены как JavaScript числа (то есть без бигнумов) .

1 голос
/ 27 марта 2020

Это реализация Чиби:

Автор является одним из авторов R7RS.

0 голосов
/ 27 марта 2020

Если кому-то интересно, я задал тот же вопрос на Reddit (со ссылкой на этот вопрос) и получил ответ с точным кодом схемы:

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 Math.ceil(x);
            } else {
                return Math.floor(x);
            }
        };
    }
})();
...