This exercise builds on the integer arithmetic from Leah's Luscious Lasagna. Here you will work with floating- point numbers and pick the right division word for the job.
Factor distinguishes integers (1, 42, 1_000_000) from floating-
point numbers (1.0, 3.14, 6.02e23). If you mix an integer and a
float in one calculation, the result comes out as a float:
2 3 + . ! => 5
2 3.0 + . ! => 5.0
You can put underscores inside a number to group the digits —
1_000_000 — and Factor just ignores them.
Factor has separate division words. They all live in the math
vocabulary.
/ ( x y -- x/y ) ! exact: ratio for two integers, float if either is a float
/f ( x y -- f ) ! always a float
/i ( x y -- q ) ! integer division (truncates toward zero)
mod ( x y -- r ) ! remainder
/mod ( x y -- q r ) ! quotient and remainder together
1 2 / . ! => 1/2 (a proper ratio)
16 3 / . ! => 5+1/3 (an improper ratio, printed as a mixed numeral)
16 3 /f . ! => 5.333333333333333
16 3 /i . ! => 5 (truncated)
16 3 mod . ! => 1
16 3 /mod .s ! quotient and remainder in one pass
! => 5
! => 1
16.0 3 / . ! => 5.333333333333333
/ produces a ratio (Factor's exact rational type) for two integers,
or a float if either input is a float. /f forces a float result
even for two integers. /i always truncates toward zero.
Number predicates from math, math.functions,
and math.primes:
zero? ( x -- ? )
even? ( x -- ? )
odd? ( x -- ? )
prime? ( x -- ? )
divisor? ( m n -- ? ) ! true when n divides m
integer? ( x -- ? ) ! true for ints (fixnum or bignum)
float? ( x -- ? ) ! true for floats
number? ( x -- ? ) ! true for any numeric kind
0 zero? . ! => t
0.0 zero? . ! => t
3 zero? . ! => f
4 even? . ! => t
7 even? . ! => f
7 odd? . ! => t
7 prime? . ! => t
9 prime? . ! => f
15 5 divisor? . ! => t (5 divides 15)
15 4 divisor? . ! => f
floor, ceiling, and round from the
math.functions vocabulary all return a float
(3.0, not 3). To get a true integer, chain >integer:
3.7 floor >integer . ! => 3
3.2 ceiling >integer . ! => 4
sq, ^, and abs (in math.functions)
compute squares, arbitrary powers, and absolute values:
sq ( x -- x*x )
^ ( x y -- x^y )
abs ( x -- |x| )
5 sq . ! => 25
2 10 ^ . ! => 1024
2 0.5 ^ . ! => 1.4142135623730951
-7 abs . ! => 7
3 abs . ! => 3
min ( x y -- z ) and max ( x y -- z ) (in
math.order) return the lesser or greater of two
numbers:
3 7 min . ! => 3
3 7 max . ! => 7
The most common use is clamping — pinning a value to a floor
with max (e.g., 0 max keeps a value non-negative) or to a
ceiling with min.
math.order also provides before?, after?, before=?,
after=? for comparison predicates that work on any orderable
type — numbers, strings, characters:
before? ( obj1 obj2 -- ? ) ! obj1 < obj2
before=? ( obj1 obj2 -- ? ) ! obj1 <= obj2
after? ( obj1 obj2 -- ? ) ! obj1 > obj2
after=? ( obj1 obj2 -- ? ) ! obj1 >= obj2
Use these instead of </<= when the values might be strings —
the arithmetic operators don't dispatch on strings.
Your friend Chandler plans to visit exotic countries all around the world. Sadly, Chandler's math skills aren't good. He's pretty worried about being scammed by currency exchanges during his trip — and he wants you to make a currency calculator for him.
Define exchange-money taking a budget and an exchange-rate and
returning the value of the exchanged currency.
Note: if your currency is USD and you want to exchange USD for EUR
with an exchange rate of 1.20, then 1.20 USD == 1 EUR.
127.5 1.2 exchange-money .
! => 106.25
Define get-change taking a budget (before the exchange) and the
exchanging-value (the amount taken from the budget to be exchanged).
Return the amount of money that is left.
127.5 120 get-change .
! => 7.5
Define value-of-bills taking a denomination (the value of a single
bill) and a number-of-bills. Return the total value of the bills.
5 128 value-of-bills .
! => 640
Define number-of-bills taking an amount and a denomination.
Return the number of whole bills of the given denomination that fit
into the amount. Round down — fractional bills don't exist.
127.5 5 number-of-bills .
! => 25
Define leftover-of-bills taking an amount and a denomination.
Return the leftover amount that cannot be returned as whole bills.
127.5 20 leftover-of-bills .
! => 7.5
Define exchangeable-value taking a denomination, budget,
spread, and exchange-rate.
spread is the percentage taken as an exchange fee, written as an
integer. It needs to be added to the exchange rate as a fraction. If
1.00 EUR == 1.20 USD and the spread is 10, the total exchange rate
is 1.00 EUR == 1.32 USD (10% of 1.20 is 0.12, added to 1.20).
Return the maximum value of the new currency after applying the rate
plus spread, rounded down to whole bills of the given denomination.
The returned value is an integer.
20 127.25 10 1.20 exchangeable-value .
! => 80
5 127.25 10 1.20 exchangeable-value .
! => 95
Like get-change, but if Chandler accidentally typed an
exchanging value larger than his budget, return 0 instead of
a negative number. Define safe-change taking a budget and an
exchanging-value.
127.5 120 safe-change .
! => 7.5
50 100 safe-change .
! => 0
Chandler is haggling for a souvenir. Define cap-spend taking a
budget and a price, and returning whichever is smaller — the
most he can actually pay.
100 30 cap-spend .
! => 30
20 30 cap-spend .
! => 20
Sign up to Exercism to learn and master Factor with 47 concepts163 exercises, and real human mentoring, all for free.