Class: MM::Ratio

Inherits:
Object
  • Object
show all
Includes:
Comparable, Enumerable
Defined in:
lib/mm/ratio.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(n, d) ⇒ Ratio

Returns a new instance of Ratio.



10
11
12
13
14
# File 'lib/mm/ratio.rb', line 10

def initialize n, d
  gcd = n.gcd d
  @numerator = n / gcd
  @denominator = d / gcd
end

Instance Attribute Details

#denominatorObject

Returns the value of attribute denominator.



16
17
18
# File 'lib/mm/ratio.rb', line 16

def denominator
  @denominator
end

#numeratorObject

Returns the value of attribute numerator.



16
17
18
# File 'lib/mm/ratio.rb', line 16

def numerator
  @numerator
end

Class Method Details

.change_interval(point, index, interval) ⇒ Object



147
148
149
150
151
152
153
154
# File 'lib/mm/ratio.rb', line 147

def self.change_interval point, index, interval
  vector = MM::Ratio.to_vector(point)
  if interval == :reciprocal
    interval = vector[index].reciprocal
  end
  vector[index] = interval
  MM::Ratio.from_vector(vector)
end

.from_s(r) ⇒ Object



85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/mm/ratio.rb', line 85

def self.from_s r
  if r.respond_to? :split
    if r =~ /\s/
      r.split(/\s/).inject([]) {|memo, ratio|
        memo << self.from_s(ratio)
      }
    else
      string_to_ratio r
    end
  else
    r.map {|s| self.from_s s}
  end
end

.from_vector(vector) ⇒ Object



143
144
145
# File 'lib/mm/ratio.rb', line 143

def self.from_vector vector
  vector.inject([MM::Ratio.new(1,1)]) {|m, r| m << (m.last / r)}
end

.from_yaml(yaml_string) ⇒ Object

Loads a sequence of MM::Ratios from a YAML file.



105
106
107
# File 'lib/mm/ratio.rb', line 105

def self.from_yaml yaml_string
  YAML.load(yaml_string).map {|r| MM::Ratio.from_s r}
end

.string_to_ratio(string) ⇒ Object



99
100
101
102
# File 'lib/mm/ratio.rb', line 99

def self.string_to_ratio string
  m = string.match(/(\d+)\/(\d+)/)
  MM::Ratio.new(m[1].to_i, m[2].to_i)
end

.to_vector(point) ⇒ Object



139
140
141
# File 'lib/mm/ratio.rb', line 139

def self.to_vector point
  point.each_cons(2).map {|r| r[0] / r[1]}
end

Instance Method Details

#*(other) ⇒ Object



18
19
20
# File 'lib/mm/ratio.rb', line 18

def * other
  MM::Ratio.new(self.numerator * other.numerator, self.denominator * other.denominator)
end

#+(other) ⇒ Object



26
27
28
29
# File 'lib/mm/ratio.rb', line 26

def + other
  MM::Ratio.new(self.numerator*other.denominator + other.numerator*self.denominator,
                self.denominator*other.denominator)
end

#-(other) ⇒ Object



31
32
33
# File 'lib/mm/ratio.rb', line 31

def - other
  self + (other * MM::Ratio.new(-1,1))
end

#/(other) ⇒ Object



22
23
24
# File 'lib/mm/ratio.rb', line 22

def / other
  self * other.reciprocal
end

#<=>(other) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/mm/ratio.rb', line 60

def <=> other
  # Ensure that the comparison makes sense
  return nil unless other.respond_to? :-

  case
  when (self - other).to_f > 0
    return 1
  when (self - other).to_f < 0
    return -1
  end
  return 0
end

#[](i) ⇒ Object



35
36
37
38
39
40
41
# File 'lib/mm/ratio.rb', line 35

def [] i
  if i == 0
    self.numerator
  elsif i == 1
    self.denominator
  end
end

#absObject



52
53
54
55
56
57
58
# File 'lib/mm/ratio.rb', line 52

def abs
  if self < MM::Ratio.new(0, 1)
    self * MM::Ratio.new(-1,1)
  else
    self
  end
end

#centsObject



81
82
83
# File 'lib/mm/ratio.rb', line 81

def cents
  Math.log2(self.to_f) * 1200.0
end

#eachObject



129
130
131
132
133
134
135
136
137
# File 'lib/mm/ratio.rb', line 129

def each
  if block_given?
    [@numerator, @denominator].each do |r|
      yield r
    end
  else
    [@numerator, @denominator].each
  end
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


73
74
75
# File 'lib/mm/ratio.rb', line 73

def eql? other
  other.is_a?(MM::Ratio) && (self == other)
end

#factorsObject

Works very similarly to the Prime::prime_division method, except that factors in the numerator are positive, and factors in the denominator are negative.



46
47
48
49
50
# File 'lib/mm/ratio.rb', line 46

def factors
  n_factors = ::Prime.prime_division(@numerator)
  d_factors = ::Prime.prime_division(@denominator).map {|d| d[1] *= -1; d}
  n_factors.concat(d_factors).sort_by {|x| x[0]}
end

#hashObject



77
78
79
# File 'lib/mm/ratio.rb', line 77

def hash
  [@numerator, @denominator, MM::Ratio].hash
end

#prime_limitObject



121
122
123
124
125
126
127
# File 'lib/mm/ratio.rb', line 121

def prime_limit
  self.map { |r|
    r.prime_division.map { |s|
      s.first
    }.max
  }.compact.max
end

#reciprocalObject



117
118
119
# File 'lib/mm/ratio.rb', line 117

def reciprocal
  MM::Ratio.new(@denominator, @numerator)
end

#to_fObject



109
110
111
# File 'lib/mm/ratio.rb', line 109

def to_f
  @numerator.to_f / @denominator
end

#to_sObject



113
114
115
# File 'lib/mm/ratio.rb', line 113

def to_s
  "#{@numerator}/#{@denominator}"
end