分数小数変換を改良した

分数から循環小数への変換で、単純な筆算アルゴリズムに変更。

あとテストを改良した。assert_equal(期待する値, 計算式)という形式で呼ぶのがベストかな?

#repeating-decimal.rb
require 'rational'

class Rational
  def self.from_rd(s)
    case s
    when /^(-?)([0-9]+)$/
      return s.to_i.to_r
    when /^(-?)([0-9]*)\.([0-9]*)$/
      return ($1+$2).to_i + ($1+$3).to_i.to_r / 10**$3.size
    when /^(-?)([0-9]*)\.([0-9]*)\[([0-9]*)\]$/
      return ($1+$2).to_i + ( ($1+$3).to_i.to_r + ($1+$4).to_i.to_r / (10**$4.size-1) ) / 10**$3.size
    else
      return nil
    end
  end

  def to_rd
    frac = self;
    digs = []
    mods = []
    sign = ""
    if frac < 0 then
      sign = "-"
      frac = -frac
    end
    frac -= intg = frac.to_i
    return sign + intg.to_s if frac == 0
    while frac > 0
      if ind = mods.index(frac) then
        return sign + intg.to_s + "." + digs[0...ind].collect{|i| i+?0}.pack("C*") + "[" + digs[ind...digs.size].collect{|i| i+?0}.pack("C*") + "]"
      end
      mods.push(frac)
      frac *= 10
      digs.push(frac.to_i)
      frac -= frac.to_i
    end
    return sign + intg.to_s + "." + digs.collect{|i| i+?0}.pack("C*")
  end
end
#!/usr/bin/ruby -Ku
#rdtest.rb
require "runit/testcase"
require "runit/cui/testrunner"
require "repeating-decimal"

class RDTest < RUNIT::TestCase
  def test1
    assert_equal(Rational(0,1), Rational.from_rd("0"))
  end

  def test2
    assert_equal(Rational(-0,1), Rational.from_rd("-0"))
  end

  def test3
    assert_equal(Rational(11,10), Rational.from_rd("1.1"))
  end

  def test4
    assert_equal(Rational(-11,10), Rational.from_rd("-1.1"))
  end

  def test5
    assert_equal(Rational(1,3), Rational.from_rd("0.[3]"))
  end

  def test6
    assert_equal(Rational(-1,3), Rational.from_rd("-0.[3]"))
  end

  def test7
    assert_equal(Rational(1,6), Rational.from_rd("0.1[6]"))
  end

  def test8
    assert_equal(Rational(-1,6), Rational.from_rd("-0.1[6]"))
  end

  def test9
    assert_equal("0", Rational(0,1).to_rd)
  end

  def test10
    #assert_equal("-0", Rational(-0,1).to_rd)
  end

  def test11
    assert_equal("1.1", Rational(11,10).to_rd)
  end

  def test12
    assert_equal("-1.1", Rational(-11,10).to_rd)
  end

  def test13
    assert_equal("0.[3]", Rational(1,3).to_rd)
  end

  def test14
    assert_equal("-0.[3]", Rational(-1,3).to_rd)
  end

  def test15
    assert_equal("0.1[6]", Rational(1,6).to_rd)
  end

  def test16
    assert_equal("-0.1[6]", Rational(-1,6).to_rd)
  end

  def test17
    rat = Rational(38657,14272)
    assert_equal(rat, Rational.from_rd(rat.to_rd))
  end

  def test18
    rd = "475.12937462[1836752938]"
    assert_equal(rd, Rational.from_rd(rd).to_rd)
  end
end

RUNIT::CUI::TestRunner.run(RDTest.suite)