module Chapter04 require 'chapter03.rb' include Chapter03 def max_three(a, b, c) max(a, max(b, c)) end def max_four(a, b, c, d) max(max(a, b), max(c, d)) end def max_four2(a, b, c, d) max(a, max(b, max(c, d))) end def max_four3(a, b, c, d) max(a, max_three(b, c, d)) end def between?(a, b, c) (a <= b && b <= c) || (c <= b && b <= a) end def weak_ascending?(a, b, c) a <= b && b <= c end def between2?(a, b, c) weak_acdending?(a, b, c) || weak_ascending?(c, b, a) end def middle_number(a, b, c) return a if between?(b, a, c) return b if between?(a, b, c) return c if between?(a, c, b) end def middle_number2(a, b, c) return a if between2?(b, a, c) return b if between2?(a, b, c) return c if between2?(a, c, b) end def how_many_equal(a, b, c) return 3 if a == b && b == c return 2 if a == b || a == c || b == c 0 end def four_different?(a, b, c, d) how_many_equal(a, b, c) == 0 && how_many_equal(a, b, d) == 0 && how_many_equal(a, c, d) == 0 && how_many_equal(b, c, d) == 0 end def three_of_four_equal?(a, b, c, d) !four_equal?(a, b, c, d) && (three_equal?(a, b, c) || three_equal?(a, b, d) || three_equal?(a, c, d) || three_equal?(b, c, d)) end def how_many_of_four_equal(a, b, c, d) return 4 if four_equal?(a, b, c, d) return 3 if three_of_four_equal?(a, b, c, d) return 0 if four_different?(a, b, c, d) 2 end def range_product(x, y) raise "range_product start is greater than end value" if x > y return y if x == y y * range_product(x, y - 1) end # # Ruby doesn't support tail call optimisation and so there are potential # # problem with stack overflow using recursive methods # # It is much more idiomatic un ruby to use blocks instead of recursion def range_product_idiomatic(x, y) raise "range_product start is greater than end value" if x > y (x..y).inject(1) {|prod, i| prod * i } end def fac(n) raise "fac is only defined on natural numbers" if n < 0 return 1 if n == 0 range_product(1, n) end def mult(a, b) return 0 if a ==0 || b == 0 return a if b == 1 a + mult(a, b - 1) end def mult_idiomatic(a, b) return 0 if a ==0 || b == 0 return a if b == 1 return b if a == 1 (1..b).inject(0){ |sum, i| sum + a } end def sqrt_int(n) raise "sqrt_iter is only defined on positive integers" if n < 1 return 1 if n == 1 sqrt_iter(n, 1) end def max_f(n) return f(0) if n == 0 return max(f(n), max_f(n - 1)) end def max_f_idiomatic(n) (0..n).inject(-99999) {|m,i| fi = f(i); fi>m ? fi : m } end def any_zero?(n) return f2(0) == 0 if n == 0 return f2(n) == 0 || any_zero?(n - 1) end def any_zero_idiomatic?(n) (0..n).each {|i| return true if f2(i)==0 } false end def sum_fun(f, n) return f.call(0) if n == 0 f.call(n) + sum_fun(f, n - 1) end def regions(n) 1 + sum_fun(Proc.new{ |x| id(x) }, n) end def max_pieces(n) (cube(n) + 5 * n + 6) / 6 end def remainder(m, n) return m if m < n remainder(m - n, n) end def divide(m, n) return 0 if m < n 1 + divide(m - n, n) end def hcf(a, b) return a if b ==0 hcf(b, remainder(a, b)) end def two_to_power(n) return 1 if n == 0 return square(two_to_power(divide(n, 2))) if even?(n) 2 * square(two_to_power(divide(n, 2))) end :private def sqrt_iter(n, x) return x if x * x == n return x - 1 if x * x > n sqrt_iter(n, x + 1) end def f(n) return 0 if n == 0 return 44 if n == 1 return 17 if n == 2 0 end def f2(n) return 2 if n == 0 return 3 if n == 1 return 5 if n == 2 return 7 if n == 3 return 11 if n == 4 0 end def id(x) x end def even?(n) remainder(n, 2) == 0 end def square(n) n * n end def cube(n) n * n * n end end