Rebol3 Code Examplex
Fraction reduction
Simplify fractions to lowest terms.
Rebol [
title: "Rosetta code: Fraction reduction"
file: %Fraction_reduction.r3
url: https://rosettacode.org/wiki/Fraction_reduction
needs: 3.21.5 ;= compose map
]
unless native? :idivide [
;; backward compatibility (available since 3.21.14)
idivide: func[a b][to integer! (a / b)]
]
fraction-reduction: function/with [
lo [integer!] "lower bound of range"
hi [integer!] "upper bound of range"
/verbose
][
len: length? form hi ;; number of digits
omitted: array/initial 9 0 ;; ommitted digits counters
n-digits: clear [] ;; digit buffer for numerator
d-digits: clear [] ;; digit buffer for denominator
count: 0
for n lo hi 1 [
unless get-digits n len n-digits [continue] ;; skip numbers that don't qualify
for d n + 1 hi + 1 1 [
;; extract and validate denominator digits
unless get-digits d len d-digits [continue] ;; skip invalid denominators
repeat ni len [
all [
nv: n-digits/:ni ;; get numerator digit
di: index? find d-digits nv ;; find matching digit in denominator
rn: remove-digit n-digits len ni ;; numerator with shared digit removed
rd: remove-digit d-digits len di ;; denominator with shared digit removed
n * rd == (rn * d) ;; cross-multiply to check n/d = rn/rd
++ count ;; increment match counter
omitted/:nv: omitted/:nv + 1 ;; track which digit was cancelled
verbose ;; check if output is needed
prin [CR n "/" d "=" rn "/" rd "by omitting" nv "'s"]
count <= 12 ;; only print first 12 matches
prin LF ;; newline after match
]
]
]
]
if verbose [print "^M^[[K"] ;; clear last line
;; return output as a map
compose/only #[
digit: (len)
count: (count)
omitted: (omitted)
]
][
get-digits: function/with [
;; extract digits of n, reject if invalid (zero digit, repeated digit)
num len digits
][
if invalid/:num [return false]
n: num
append/dup clear digits 0 len ;; reset digit buffer
while [n > 0][
r: n % 10
if find digits r [
invalid/:num: true
return false
]
digits/:len: r
-- len
n: idivide n 10
]
true
][ ;; cache invalid numbers
invalid: make bitset! []
]
remove-digit: function [digits len idx][
sum: 0
pow: pick [1 10 100 1000 10000] len - 1
repeat i len [
if i = idx [continue]
sum: sum + (digits/:i * pow)
pow: idivide pow 10
]
sum
]
]
ranges: [
12 97
123 986
1234 9875
;12345 98764
]
foreach [lo hi] ranges [
print [as-yellow "Using range:" lo "to" hi]
res: fraction-reduction/verbose lo hi
print rejoin ["There are " res/count " " res/digit "-digit fractions of which:"]
repeat i 9 [
unless zero? v: res/omitted/:i [
print rejoin [pad v -6 " have " i "'s omitted"]
]
]
print ""
]