Class: Fraction

Inherits:
Object show all
Includes:
Comparable
Defined in:
lib/epitools/fraction.rb

Overview

A fraction! (Like a Rational, but … uh … in pure Ruby!)

Can be compared, added, multiplied, simplified, “percent”ed, “to_f”ed, and printed/inspected.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(first, last = 1) ⇒ Fraction

‘first` is the top part of the fraction, `last` is the bottom (eg: `first/last`)



19
20
21
22
# File 'lib/epitools/fraction.rb', line 19

def initialize(first, last=1)
  @first = first
  @last = last
end

Instance Attribute Details

#firstObject Also known as: top, numerator

Returns the value of attribute first.



8
9
10
# File 'lib/epitools/fraction.rb', line 8

def first
  @first
end

#lastObject Also known as: bottom, denominator

Returns the value of attribute last.



8
9
10
# File 'lib/epitools/fraction.rb', line 8

def last
  @last
end

Class Method Details

.[](*args) ⇒ Object



24
25
26
# File 'lib/epitools/fraction.rb', line 24

def self.[](*args)
  new(*args)
end

Instance Method Details

#*(v) ⇒ Object

Multiply the fractions



87
88
89
90
91
92
93
94
95
96
# File 'lib/epitools/fraction.rb', line 87

def *(v)
  case v
  when Integer
    Fraction[ v*first, v*last ]
  when Fraction
    Fraction[ v.first*first, v.last*last ]
  else
    raise TypeError.new("I don't know how to multiply a Fraction and a #{v.class}. Sorry. :(")
  end
end

#+(r) ⇒ Object

Adds together the tops and bottoms of the fractions.

Example: For the fractions ‘a/c` and `b/d`, returns `a+b/c+d`



73
74
75
76
77
78
79
80
81
82
# File 'lib/epitools/fraction.rb', line 73

def +(r)
  case r
  when Integer
    self + Fraction[r]
  when Fraction
    Fraction[ r.last*first + r.first*last, r.last*last ]
  else
    raise TypeError.new("Sorry, I can't add a Fraction and a #{r.class}. :(")
  end
end

#<=>(other) ⇒ Object



30
31
32
# File 'lib/epitools/fraction.rb', line 30

def <=>(other)
  to_f <=> other.to_f
end

#inspectObject

“#<Fraction: 1/2>”



64
65
66
# File 'lib/epitools/fraction.rb', line 64

def inspect
  "#<Fraction: #{to_s}>"
end

#percentObject Also known as: to_percent

Returns a string representing the number in percent



56
57
58
# File 'lib/epitools/fraction.rb', line 56

def percent
  "%0.1f%%" % (to_f * 100)
end

#simplifyObject



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/epitools/fraction.rb', line 98

def simplify
  require 'prime'

  # factor the numerator and denominator into hashes of { factor => exponent } pairs
  n_fact, d_fact = [numerator, denominator].map { |n| Prime.prime_division(n).to_h }

  # cancel out common factors by subtracting exponents
  d_fact.each do |v, d_exp|
    if n_exp = n_fact[v]
      if n_exp < d_exp
        d_fact[v] = d_exp - n_exp
        n_fact[v] = 0
      else
        n_fact[v] = n_exp - d_exp # <= if n_exp == d_exp, this is 0, which covers the 3rd case
        d_fact[v] = 0
      end
    end
  end

  # multiply the simplified factors back into full numbers
  simp_n, simp_d = [n_fact, d_fact].map { |h| h.map{ |n, exp| n ** exp }.reduce(:*) }

  Fraction[simp_n, simp_d]
end

#to_fObject

Returns the fraction as a float. (eg: Fraction.to_f == 0.5)



45
46
47
48
49
50
51
# File 'lib/epitools/fraction.rb', line 45

def to_f
  if @last == 0
    raise ZeroDivisionError
  else
    @first.to_f / @last
  end
end

#to_sObject Also known as: fraction

Returns a string representation: “a/b”



37
38
39
# File 'lib/epitools/fraction.rb', line 37

def to_s
  "#{@first}/#{@last}"
end