Formatting floating point number as mixed fractional in Ruby I have to format numbers that are either whole numbers or mixed fractional numbers with quarters (1/4, 1/2, 3/4) or thirds (1/3, 2/3).

The numbers are given as floats, for example 1.3333333 or 1.5 and are therefore inaccurate (but always close to a quarter or a third).

The formatting method is supposed to return Unicode fractions, for example:

1.0    #=&gt; 1
1.3333 #=&gt; 1⅓
1.5    #=&gt; 1½
1.6667 #=&gt; 1⅔


My current approach is to format the number via sprintf and to apply a second formatting based on the result:

def format_fraction(number)
  fix, frac = sprintf('%0.2f', number).split('.')
  case frac
  when '00' then "#{fix}"
  when '25' then "#{fix}¼"
  when '33' then "#{fix}⅓"
  when '50' then "#{fix}½"
  when '67' then "#{fix}⅔"
  when '75' then "#{fix}¾"
  end
end


Is there a better / less string-based / more numeric way to solve this?
[Answering my own question here]

Following Marc Rohloff's suggestion, I'm using Float#rationalize with an argument of 0.01 to convert the floats to rational numbers:

1.0.rationalize(0.01)
#=&gt; (1/1)

1.3333.rationalize(0.01)
#=&gt; (4/3)

1.5.rationalize(0.01)
#=&gt; (3/2)

1.6666.rationalize(0.01)
#=&gt; (5/3)


divmod can then be used to get the fixed and fractional part:

(5/3r).divmod(1)
#=&gt; [1, (2/3)]


Applied to my method:

def format_fraction(number)
  fix, frac = number.rationalize(0.01).divmod(1)
  case frac
  when 0/1r then "#{fix}"
  when 1/4r then "#{fix}¼"
  when 1/3r then "#{fix}⅓"
  when 1/2r then "#{fix}½"
  when 2/3r then "#{fix}⅔"
  when 3/4r then "#{fix}¾"
  end
end

format_fraction(1.0)    #=&gt; "1"
format_fraction(1.3333) #=&gt; "1⅓"
format_fraction(1.5)    #=&gt; "1½"
format_fraction(1.6666) #=&gt; "1⅔"


It's not a huge change, but the when arguments now resemble the output more closely, which makes the code easier to understand IMO.

The method could be further shortened by extracting the rational => string pairs:

FRACTIONS = { 1/4r =&gt; '¼', 1/3r =&gt; '⅓', 1/2r =&gt; '½', 2/3r =&gt; '⅔', 3/4r =&gt; '¾' }

def format_fraction(number)
  fix, frac = number.rationalize(0.01).divmod(1)
  [fix, FRACTIONS[frac]].join
end