Решение упражнения 2.1 из SICP

16 January, 2008 (21:49) | Решения упражнений

Во-первых, хочу предупредить, что в русском издании (по крайней мере, в моей версии) есть опечатка в условии этого упражнения. На самом деле требуется определить улучшенную версию процедуры make-rat, а не mul-rat. Для этого нам всего лишь необходимо дополнительно разделить числитель и знаменатель на знак знаменателя. На всякий случай, есть смысл при вычислении наибольшего общего делителя вычислять его для модулей числителя и знаменателя, так как НОД определен для неотрицательных чисел.

(define (sign x) 
  (cond ((> x 0) 1) 
        ((< x 0) -1) 
        (else 0)))
(define (make-rat n d) 
  (let ((g (* (gcd (abs n) (abs d)) (sign d)))) 
    (cons (/ n g) (/ d g))))

Comments

Comment from meduza
Date: October 22, 2008, 4:57 pm

У меня прокатывает и такой вариант, gcd работает.

(define (make-rat n d)
(let ((g ((if (negative? d) - +) (gcd n d))))
(cons (/ n g) (/ d g))))

Comment from vovka
Date: March 22, 2010, 5:34 pm

to автор
хм, а если и числитель и знаменатель отрицательны выдает положительное число, так (dr (make-rat2 -6 -9))
выдаст 2/3

Comment from vladimir
Date: November 8, 2011, 8:49 am

(define (make-rat n d)
(let ((g (gcd n d)))
(if (< d 0)
(cons (/ n g) (* -1 (/ d g)))
(cons (/ n g) (/ d g)))))

такое решение корректно?

Comment from vladimir
Date: November 8, 2011, 8:53 am

а все понял. извиняюсь

Comment from Nikolay M
Date: November 14, 2011, 9:58 pm

Если я не ошибаюсь, следующие комбинации должны возвращать (-1 . 9):

(make-rat -1 9)
(make-rat 1 -9)
(make-rat -1 -9)

А код автора на (make-rat -1 -9) вернет (1 . 9)

Я вот так сделал:

(define (make-rat n d)
(let ((sign (if (or (< n 0)(< d 0)) -1 1))
(n (abs n))
(d (abs d)))
(let ((g (gcd n d)))
(cons (* sign (/ n g)) (/ d g)))))

Для надежности 🙂

Comment from Spok
Date: December 19, 2013, 2:17 pm

Я вот не пойму зачем вы такие выверты выдумываете? Деление двух отрицательных чисел в любом случае выдаст положительную натуральную дробь. Задание делается в основном для того, чтоб вывод дробей был корректным. Да и для любых других операций достаточно считать, что только числитель отрицателен, чтоб получить правильный результат. Поэтому нам нужно только проверить знак знаменателя и в случае чего перемножить числитель и знаменатель на -1.

(define (make-rat n d)
(let ((g (Gcd n d)))
(if (< d 0)
(cons (* (/ n g) -1) (* (/ d g) -1))
(cons (/ n g) (/ d g)))))

Comment from Aera
Date: February 23, 2014, 10:09 pm

Рекурсивное определение предыдущего ответа. Здесь я использую встроенную процедуру gcd, которая всегда возвращает положительный результат (исполнительная среда DrRacket).


(define (make-rat n d)
(if (< d 0) (make-rat (- n) (- d))
(let ((g (gcd n d))) (cons (/ n g) (/ d g)))))

Comment from Irv
Date: January 20, 2016, 1:42 pm


(define (make-rat x y)
(if (< y 0)
(make-rat (- x) (- y))
(let ((g (gcd x y)))
(cons (/ x g) (/ y g)))))

Write a comment