Skip to content

Use big-math

Package org.gciatto.kt.math.big is a port of big-math (by Eric Obermühlner, MIT license): the functions java.math lacks, at any precision, on every platform. big-math's BigDecimalMath static methods are extension functions on BigDecimal (x.log(mc)), or top-level functions when they have no BigDecimal argument (pi(mc), factorial(n)) and for atan2(y, x, mc), and take a MathContext for the precision of the result. Java sees them as the static methods of the BigDecimalMath class, as in big-math; JavaScript, as functions taking the BigDecimal as their first argument.

It is part of Kt-Math's single artifact: see Add Kt-Math as a dependency.

Constants

        assertDigits("3.1415926535897932384626433832795028841971693993751", pi(mc))
        assertDigits("2.7182818284590452353602874713526624977572470937000", e(mc))
        assertDigits("3.14159", pi(MathContext(6)))

Roots, powers and logarithms

        assertDigits("1.4142135623730950488016887242096980785696718753769", dec("2").sqrt(mc))
        assertDigits("1.2599210498948731647672106072782283505702514647015", dec("2").root(dec("3"), mc))
        assertDigits("0.69314718055994530941723212145817656807550013436026", dec("2").log(mc))
        assertDigits("3", dec("1000").log10(mc))
        assertDigits("1E+1", dec("1024").log2(mc))
        assertDigits("1024", dec("2").pow(dec("10"), mc))
        assertDigits(
            "1.4142135623730950488016887242096980785696718753769",
            dec("2").pow(dec("0.5"), mc),
        )

Trigonometric and hyperbolic functions

        assertDigits("0.84147098480789650665250232163029899962256306079837", dec("1").sin(mc))
        assertDigits("0.54030230586813971740093660744297660373231042061792", dec("1").cos(mc))
        assertDigits("0.78539816339744830961566084581987572104929234984378", dec("1").atan(mc))
        assertDigits("1.1752011936438014568823818505956008151557179813341", dec("1").sinh(mc))
        assertFailsWith<ArithmeticException> { dec("1.5").asin(mc) }

Factorial, gamma, Bernoulli numbers

        assertDigits("2432902008176640000", factorial(20))
        assertDigits("0.88622692545275801364908374167057259139877472806119", dec("1.5").gamma(mc))
        assertEquals("1/6", BigRational.bernoulli(2).reduce().toRationalString())
        assertEquals("-1/30", BigRational.bernoulli(4).reduce().toRationalString())
        assertFailsWith<UnsupportedOperationException> { dec("1").exp(MathContext.UNLIMITED) }

Complex numbers

BigComplex ports big-math's BigComplex and BigComplexMath: arithmetic, with operators when exact, and the functions above as members (z.log(mc), z.pow(w, mc), z.sqrt(mc), ...).

        val mc = MathContext(30)
        val i = BigComplex.I
        val z = BigComplex.valueOf(3.0, 4.0)
        assertEquals(BigComplex.valueOf(-1.0), i * i)
        assertDigits("5.0", z.abs(mc))
        assertEquals("(2.20 - 0.40 i)", z.div(BigComplex.valueOf(1.0, 2.0), mc).toString())
        assertEquals("(-7.00 + 24.00 i)", z.pow(2, mc).toString())
        assertEquals("(0 + 3.14159265358979323846264338328 i)", BigComplex.valueOf(-1.0).log(mc).toString())
        assertEquals("(0E-33 + 1.17520119364380145688238185060 i)", i.sin(mc).toString())
        // the cube roots of 8: 2 (the principal one), -1 + 1.732... i, -1 - 1.732... i
        assertEquals(BigComplex.valueOf(2.0), BigComplex.valueOf(8.0).root(3, 0, mc))
        assertEquals(
            "(-1.00000000000000000000000000000 + 1.73205080756887729352744634151 i)",
            BigComplex.valueOf(8.0).root(3, 1, mc).toString(),
        )

Ranges

big-math's BigDecimalStream is range and rangeClosed, returning Kotlin sequences, plus step on a..b and a..<b (computed with MathContext.DECIMAL128).

        val quarter = dec("0.25")
        assertEquals("0, 0.25, 0.50, 0.75, 1.00", (dec("0")..dec("1") step quarter).joinToString())
        assertEquals("0, 0.25, 0.50, 0.75", (dec("0")..<dec("1") step quarter).joinToString())
        assertEquals("1, 0.75, 0.50", (dec("1")..<dec("0.25") step -quarter).toList().joinToString())
        assertEquals("1, 1.3333", rangeClosed(dec("1"), dec("1.5"), dec("0.3333"), mc).joinToString())

big-math's BigFloat (a BigDecimal bundled with its MathContext) and DefaultBigDecimalMath (thread-local default MathContexts) are not ported: BigDecimal and an explicit MathContext do the same.

The results are compared with big-math itself in Kt-Math's JVM tests, digit by digit.