lib/fractional.rb in fractional-0.0.3 vs lib/fractional.rb in fractional-0.1.0
- old
+ new
@@ -1,99 +1,119 @@
require 'rational'
-module Fractional
+class Fractional
+ SINGLE_FRACTION = /^\s*(\-?\d+)\/(\-?\d+)\s*$/
+ MIXED_FRACTION = /^\s*(\-?\d*)\s+(\d+)\/(\d+)\s*$/
+ def initialize(value)
+ @value = value
+ end
+
+ def to_s
+ @value
+ end
+
+ def to_f
+ Fractional.to_f(@value)
+ end
+
+ [:+, :-, :*, :/].each do |math_operator|
+ define_method(math_operator) do |another_fractional|
+ Fractional.new(Fractional.to_s(self.to_f.send(math_operator, another_fractional.to_f)))
+ end
+ end
+
def self.to_f(value)
result = 0
-
+
if mixed_fraction?(value)
- whole, numerator, denominator = value.scan(/(\-?\d*)\s(\d+)\/(\d+)/).flatten
-
+ whole, numerator, denominator = value.scan(MIXED_FRACTION).flatten
+
result = (numerator.to_f / denominator.to_f) + whole.to_f.abs
-
+
result = whole.to_f > 0 ? result : -result
elsif single_fraction?(value)
numerator, denominator = value.split("/")
result = numerator.to_f / denominator.to_f
else
result = value.to_f
end
-
+
result
end
def self.to_s(value, args={})
whole_number = value.to_f.truncate.to_i
-
+
if whole_number == 0 # Single fraction
fractional_part_to_string(value, args[:to_nearest])
else # Mixed fraction
decimal_point_value = get_decimal_point_value(value.to_f)
return whole_number.to_s if decimal_point_value == 0
-
+
fractional_part = fractional_part_to_string(decimal_point_value.abs, args[:to_nearest])
-
+
if (fractional_part == "1") || (fractional_part == "0")
(whole_number + fractional_part.to_i).to_s
else
whole_number.to_s + " " + fractional_part
end
- end
+ end
end
-
+
def self.round_to_nearest_fraction(value, to_nearest_fraction)
if value.is_a? String
to_nearest_float = to_f(to_nearest_fraction)
to_s((self.to_f(value) / to_nearest_float).round * to_nearest_float)
else
to_nearest_float = to_f(to_nearest_fraction)
- (value / to_nearest_float).round * to_nearest_float
+ (value / to_nearest_float).round * to_nearest_float
end
-
+
end
private
-
+
def self.fraction?(value)
- value.to_s.count('/') == 1
+ value.is_a? String and (value.match(SINGLE_FRACTION) or value.match(MIXED_FRACTION))
end
def self.single_fraction?(value)
- fraction?(value) and !mixed_fraction?(value)
+ fraction?(value) and value.match(SINGLE_FRACTION)
end
def self.mixed_fraction?(value)
- fraction?(value) and value.match(/\-?\d*\s+\d+\/\d+/)
+ fraction?(value) and value.match(MIXED_FRACTION)
end
-
+
def self.get_decimal_point_value(value)
value - value.truncate
end
-
+
def self.fractional_part_to_string(value, round)
if round
round_to_nearest_fraction(float_to_rational(value.to_f).to_s, round)
else
- float_to_rational(value.to_f).to_s
+ float_to_rational(value.to_f).to_s
end
end
# Whoa this method is crazy
# I nicked it from Jannis Harder at http://markmail.org/message/nqgrsmaixwbrvsno
def self.float_to_rational(value)
- if value.nan?
- return Rational(0,0) # Div by zero error
- elsif value.infinite?
- return Rational(value<0 ? -1 : 1,0) # Div by zero error
- end
- s,e,f = [value].pack("G").unpack("B*").first.unpack("AA11A52")
- s = (-1)**s.to_i
- e = e.to_i(2)
+ if value.nan?
+ return Rational(0,0) # Div by zero error
+ elsif value.infinite?
+ return Rational(value<0 ? -1 : 1,0) # Div by zero error
+ end
+ s,e,f = [value].pack("G").unpack("B*").first.unpack("AA11A52")
+ s = (-1)**s.to_i
+ e = e.to_i(2)
if e.nonzero? and e<2047
- Rational(s)* Rational(2)**(e-1023)*Rational("1#{f}".to_i(2),0x10000000000000)
- elsif e.zero?
- Rational(s)* Rational(2)**(-1024)*Rational("0#{f}".to_i(2),0x10000000000000)
- end
- end
+ Rational(s)* Rational(2)**(e-1023)*Rational("1#{f}".to_i(2),0x10000000000000)
+ elsif e.zero?
+ Rational(s)* Rational(2)**(-1024)*Rational("0#{f}".to_i(2),0x10000000000000)
+ end
+ end
end