RosettaCodeData/Task/Bernoulli-numbers/Scala/bernoulli-numbers.scala
2023-07-01 13:44:08 -04:00

49 lines
1.3 KiB
Scala

/** Roll our own pared-down BigFraction class just for these Bernoulli Numbers */
case class BFraction( numerator:BigInt, denominator:BigInt ) {
require( denominator != BigInt(0), "Denominator cannot be zero" )
val gcd = numerator.gcd(denominator)
val num = numerator / gcd
val den = denominator / gcd
def unary_- = BFraction(-num, den)
def -( that:BFraction ) = that match {
case f if f.num == BigInt(0) => this
case f if f.den == this.den => BFraction(this.num - f.num, this.den)
case f => BFraction(((this.num * f.den) - (f.num * this.den)), this.den * f.den )
}
def *( that:Int ) = BFraction( num * that, den )
override def toString = num + " / " + den
}
def bernoulliB( n:Int ) : BFraction = {
val aa : Array[BFraction] = Array.ofDim(n+1)
for( m <- 0 to n ) {
aa(m) = BFraction(1,(m+1))
for( n <- m to 1 by -1 ) {
aa(n-1) = (aa(n-1) - aa(n)) * n
}
}
aa(0)
}
assert( {val b12 = bernoulliB(12); b12.num == -691 && b12.den == 2730 } )
val r = for( n <- 0 to 60; b = bernoulliB(n) if b.num != 0 ) yield (n, b)
val numeratorSize = r.map(_._2.num.toString.length).max
// Print the results
r foreach{ case (i,b) => {
val label = f"b($i)"
val num = (" " * (numeratorSize - b.num.toString.length)) + b.num
println( f"$label%-6s $num / ${b.den}" )
}}