Hi Joel,
I've seen the posts so far and it appears the answer has
been done to death.
Like you, I was taken by surprise when something like this
(/ 1 2) ; returned 1/2. I "knew" it was correct but the
result did not appear as I wanted 0.05.
The issue was my lack of understanding about how Scheme
deals with rationals and integers, not Scheme per se. Think
in terms of formatting (how the result appears) and what we
see makes sense. Scheme is very powerful in terms of it
accuracy - don't know how many numbers after the decimal it
is capable of determining but it is large.
pi ; returns 3.141592653589793 while I was able to coax one
more digit of precision with this
(/ 3 2.12345678912345678 ) ; ==> 1.4127906983397445
(quotient 1 2) should return an integer result 0 and not a
rational like 1/2. This procedure *should* be used
carefully to make certain rounding errors are not
exaggerated. For example:
(* (quotient 3 2) 2) ;==> 2 and not 3 as you might expect.
You can accommodate the appearance of the end computational
result by applying various rounding procedures (help
contains references to many) or by artificially inflating
the values used in certain procedures. Eg:
(/ (* (quotient 30 2) 2) 10) ; ==> 3
The following code is not my all own work (pinched a lot
from QUT lecture material) but it may help you understand
rationals (in Scheme) a little better. At least it did for
me - BTW, the material was presented in the context of data
abstraction. This was a real "lights flashing" moment for
me - I hope it is of some help for you.
Kindest regards,
Mike
; The following procedures represent rational numbers as two
integers
(define [make-rat n d]
(list (/ n (gcd n d)) ; ; Construct rational n/d
(/ d (gcd n d)))) ; gcd = greatest common
denominator
(define [numer x] ; Select numerator of rational x
(first x))
(define [denom x] ; Select denominator of x
(second x))
; Since the procedures above do exactly the same thing
; as the corresponding list operations,
; we can equivalently define them as follows:
(define make-rat list)
(define numer first)
(define denom second)
; Displaying rational numbers
; In the case of rational numbers we can show them as a
string
; consisting of the numerator, followed by a '/',
; followed by the denominator
(define [show-rat x]
(string-append
(number->string (numer x))
"/"
(number->string (denom x))))
; Example:
;(show-rat (make-rat 1 3)) ; returns "1/3"
; I M P O R T A N T B A S I C S
; The rules of rational number arithmetic
; The following equalities describe arithmetic in terms of
; numerators and denominators
; n1/d1 + n2/d2 = (n1d2 + n2d1)/d1*d2
; n1/d1 - n2/d2 = (n1d2 - n2d1)/d1*d2
; (n1/d1)/(n2/d2) = n1*d2/d1*n2
; (n1/d1) * (n2/d2) = n1*n2/d1*d2
; n1/d1 = n2/d2 iff n1d2 = n2d1
; Note the closure property-each operator takes two
; rational numbers and returns a rational number
; Operations for rational number arithmetic
; We can define these operations easily using the
; rational number constructor and selectors we defined
earlier
(define [add-rat x y]
(make-rat (+ (* (numer x) (denom y))
(* (numer y) (denom x)))
(* (denom x) (denom y))))
(define [sub-rat x y]
(make-rat (- (* (numer x) (denom y))
(* (numer y) (denom x)))
(* (denom x) (denom y))))
(define [mul-rat x y]
(make-rat (* (numer x) (numer y))
(* (denom x) (denom y))))
(define [div-rat x y]
(make-rat (* (numer x) (denom y))
(* (numer y) (denom x))))
; A predicate for rational numbers
; The following property defines equality for rational
numbers
; n1/d1 = n2/d2 iff n1d2 = n2d1
; This property can be expressed easily as a
; Boolean-valued procedure
(define [equal-rat? x y]
(= (* (numer x) (denom y))
(* (numer y) (denom x))))
; Representing rational numbers consistently
; Our rational number representations will not
; always be the simplest:
(define one-third (make-rat 1 3))
;(show-rat (add-rat
; one-third one-third)) ;returns "6/9"
; We would prefer the result to be "2/3" in this case
; We can solve this by dividing the numerator and
; denominator by their greatest common divisor (gcd)
; when we construct a rational number:
(define [make-rat n d]
(list (/ n (gcd n d))
(/ d (gcd n d))))
; (The Scheme gcd procedure for calculating greatest
; common divisors using Euclid's algorithm is in
; Structure and Interpretation of Computer Programs, Section
1.2.5)
;(show-rat (add-rat
; one-third one-third)) ;returns "2/3"
; Data abstraction barriers
;
; When designing a data abstraction we should consider
; carefully the interface between the concrete data
; representation and the user of the abstraction
; Well-designed interfaces make programs easier to
; understand because higher levels of abstraction get
; a simplified view of compound data objects
; Well-designed interfaces also make programs easier
; to maintain by isolating the effects of changes to
; concrete data representations.
; For example:
; Data abstraction barriers in the rational number case
study
;
; PROGRAMS THAT USE RATIONAL NUMBERS
; ----------------------------------
; |
; Rational numbers in the problem domain
;
; ADD-RAT SUB-RAT ...
; ----------------------------------
; |
; Rational numbers as numerators and denominators
;
; MAKE-RAT NUMER DENOM
; ----------------------------------
; |
; Rational numbers as lists
;
; CONS FIRST SECOND ...
; ----------------------------------
; |
; Scheme's implentation of lists
;
;-------------------------------------------
; Isolating the effects of change
; (1) Earlier we saw how the make-rat constructor could be
; modified so that the underlying representation of rational
; numbers was always reduced to its lowest terms
; (2) Alternatively, we could leave make-rat in its original
; form and instead calculate the lowest terms in selector
; procedures numer and denom
; (3) The concrete representation of rational numbers
; like 6/9 is different in these two approaches,
; but this difference is invisible to the higher abstraction
level
[...snip...]
| when I divide using
|
| (/ 1 2)
|
| or
|
| (quotient 1 2)
|
| I get 1/2.
|
| When I divide using
|
| (/ 1 2.)
|
| I get 0.5
|
| As I want to use this to calculate Taylor series and other
such
| sequences, I really need the decimal representation. How
do I coerce
| this (do I need to coerce it or is this much simpler)?
|
| For example, if I
|
| (define series
| (lambda (x)
| (/ 1 x)))
|
| and then do
|
| (map series '(1 2 3 4 5))
|
| I get a list of ones as a result. That's not right ;) It
seems as
| though there's a simple concept here that I'm unaware of.
Tell me
| what it is, please!