2009年11月4日水曜日

[Scala] Rational+

某所の宿題メモ(No.8 まで)。


class Rational(n: Int, d: Int) {
require(d != 0)
private val g = gcd(n.abs, d.abs)
private def gcd(a: Int, b: Int): Int =
if (b == 0) a else gcd(b, a % b)

// 4. denom > 0 となるように
val numer: Int = if(d > 0) n / g else -n / g
val denom: Int = if(d > 0) d / g else -d / g

def this(n: Int) = this(n, 1)

override def toString = numer + " / " + denom

def + (that: Rational): Rational =
new Rational(
numer * that.denom + that.numer * denom,
denom * that.denom
)

// 2. 単項演算子 -
def unary_- = new Rational(-numer, denom)
// 2. unary_- を使って - をリライト
def - (that: Rational): Rational = this + (- that)

def * (that: Rational): Rational =
new Rational(numer * that.numer, denom * that.denom)

// 3. inv (逆数)
def inv = {
require(numer != 0)
new Rational(denom, numer)
}
// 3. inv を使って / をリライト
def / (that: Rational):Rational = this * that.inv

// 6. < の定義
def < (that: Rational) =
this.numer * that.denom < that.numer * this.denom

// 7. toDoubleメソッドの定義
def toDouble = numer.toDouble / denom.toDouble
}

object Rational {
// 1. implicit def
implicit def intToRational(x:Int) = new Rational(x)

// 8. 循環小数 -> Rational 変換関数
// どこに置くか迷ったけど、一応ここに。
// もっと効率よく書けそうだけど...
val periodReg = """(\d+)\.(\d*)\{(\d+)\}""".r
def period2Rational(period: String):Rational =
period match {
case periodReg(a,b,c) => {
val intPart = a.toInt
val nonRepeatPart =
if(b == "") new Rational(0)
else new Rational(b.toInt, Math.pow(10.0, b.length).toInt)
val repeatPart =
new Rational(c.toInt, (Math.pow(10.0, c.length)-1).toInt) / Math.pow(10.0, b.length).toInt
intPart + nonRepeatPart + repeatPart
}
case _ => error("Invalid argument: " + period)
}
}


No.8 は こちらサイト を参考にしました。無限等比級数と考えるんですね。昔習ったような気もする。

scala> Rational.period2Rational("0.{3}")
res3: Rational = 1 / 3
scala> 1.0 / 3.0
res4: Double = 0.3333333333333333

scala> Rational.period2Rational("0.2{142857}")
res5: Rational = 3 / 14
scala> 3.0 / 14.0
res6: Double = 0.21428571428571427

scala> Rational.period2Rational("0.153{42}")
res9: Rational = 5063 / 33000
scala> 5063.0 / 33000.0
res10: Double = 0.15342424242424244



No.9 はまた今度(たぶん)。

0 件のコメント:

コメントを投稿