// Exact rationals. Nothing here rounds unless you ask it to.
//
// moon run src/examples/04-fractions
///|
fn main raise {
// Arithmetic stays exact, so a third plus a sixth is a half and not
// 0.49999999999999994.
let third = @moonnum.parse_fraction("1/3")
let sixth = @moonnum.parse_fraction("1/6")
println("1/3 + 1/6 = \{(third + sixth)}")
println("1/3 * 3 = \{(third * @moonnum.parse_fraction("3"))}")
println("1/3 + 0.5 = \{(third + @moonnum.parse_fraction("0.5"))}")
// A decimal literal is read as a power of ten, not through a float, so 0.1
// is exactly one tenth here.
println("")
let tenth = @moonnum.parse_fraction("0.1")
println("0.1 as a fraction: \{tenth}")
println("0.1 + 0.2 = \{(tenth + @moonnum.parse_fraction("0.2"))}")
println("as a double, 0.1 is: \{@moonnum.repr_float(0.1)}")
println("and its exact value: \{@moonnum.as_ratio(0.1)}")
// Converting a float keeps every bit; converting a fraction can overflow.
println("")
println("of_float(1.5) = \{@moonnum.Fraction::of_float(1.5)}")
println("to_double(1/3) = \{@moonnum.repr_float(third.to_double())}")
// Rounding is half to even, and it returns a fraction.
println("")
println("round(7/2) = \{@moonnum.parse_fraction("7/2").round_big()}")
println("round(5/2) = \{@moonnum.parse_fraction("5/2").round_big()}")
println("round(1/3, 3) = \{third.round(ndigits=3)}")
println("floor(-7/2) = \{@moonnum.parse_fraction("-7/2").floor_big()}")
println("ceil(-7/2) = \{@moonnum.parse_fraction("-7/2").ceil_big()}")
// A power keeps the value a ratio: the exponent goes to the numerator and
// the denominator separately, so nothing is rounded on the way.
println("")
let two_thirds = @moonnum.parse_fraction("2/3")
println("(2/3) ** 3 = \{two_thirds.pow(3N)}")
println("(2/3) ** -1 = \{two_thirds.pow(-1N)}")
println("(7/2) ** 10 = \{@moonnum.parse_fraction("7/2").pow(10N)}")
let zero_power : String = @moonnum.parse_fraction("0").pow(-1N).to_string() catch {
@moonnum.ZeroDivision => "division by zero"
_ => "refused"
}
println("0 ** -1 = \{zero_power}")
// The best rational approximation with a small denominator: the way to turn
// 3.141592653589793 into 355/113.
println("")
let pi = @moonnum.as_ratio(3.141592653589793)
println("pi as a fraction: \{pi}")
println("with denominator <= 10: \{pi.limit_denominator(max=10N)}")
println("with denominator <= 1000: \{pi.limit_denominator(max=1000N)}")
// At ten digits the fraction and the double agree; at twenty they do not.
println("")
println(
"22/7 at 20 digits: \{@moonnum.format(@moonnum.parse("22/7"), ".20f")}",
)
println("22.0/7.0 at 20: \{@moonnum.format_float(22.0 / 7.0, ".20f")}")
// Formatting either prints the ratio or rounds it like a float.
println("")
println("default: \{third.format("")}")
println(".6f: \{third.format(".6f")}")
println(">12.4f: |\{third.format(">12.4f")}|")
println(".3%: \{third.format(".3%")}")
println("#: \{@moonnum.parse_fraction("5/2").format("#")}")
}