/*
 * MIT License
 *
 * Copyright (c) 2002-2026 Mikko Tommila
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package org.apfloat;

import java.math.RoundingMode;
import java.util.Arrays;

import junit.framework.TestSuite;
import static java.math.RoundingMode.*;

/**
 * @version 1.16.0
 * @author Mikko Tommila
 */

public class ApfloatMathTest
    extends ApfloatTestCase
{
    public ApfloatMathTest(String methodName)
    {
        super(methodName);
    }

    public static void main(String[] args)
    {
        junit.textui.TestRunner.run(suite());
    }

    public static TestSuite suite()
    {
        TestSuite suite = new TestSuite();

        suite.addTest(new ApfloatMathTest("testIntegerPow"));
        suite.addTest(new ApfloatMathTest("testScale"));
        suite.addTest(new ApfloatMathTest("testInverseRoot"));
        suite.addTest(new ApfloatMathTest("testRoot"));
        suite.addTest(new ApfloatMathTest("testAbs"));
        suite.addTest(new ApfloatMathTest("testCopySign"));
        suite.addTest(new ApfloatMathTest("testFloor"));
        suite.addTest(new ApfloatMathTest("testCeil"));
        suite.addTest(new ApfloatMathTest("testTruncate"));
        suite.addTest(new ApfloatMathTest("testFrac"));
        suite.addTest(new ApfloatMathTest("testRound"));
        suite.addTest(new ApfloatMathTest("testRoundToPrecision"));
        suite.addTest(new ApfloatMathTest("testRoundToInteger"));
        suite.addTest(new ApfloatMathTest("testRoundToPlaces"));
        suite.addTest(new ApfloatMathTest("testRoundToMultiple"));
        suite.addTest(new ApfloatMathTest("testNegate"));
        suite.addTest(new ApfloatMathTest("testModf"));
        suite.addTest(new ApfloatMathTest("testFmod"));
        suite.addTest(new ApfloatMathTest("testMultiplyAdd"));
        suite.addTest(new ApfloatMathTest("testMultiplySubtract"));
        suite.addTest(new ApfloatMathTest("testAgm"));
        suite.addTest(new ApfloatMathTest("testFactorial"));
        suite.addTest(new ApfloatMathTest("testDoubleFactorial"));
        suite.addTest(new ApfloatMathTest("testPi"));
        suite.addTest(new ApfloatMathTest("testLog"));
        suite.addTest(new ApfloatMathTest("testLogBase"));
        suite.addTest(new ApfloatMathTest("testExp"));
        suite.addTest(new ApfloatMathTest("testPow"));
        suite.addTest(new ApfloatMathTest("testAcosh"));
        suite.addTest(new ApfloatMathTest("testAsinh"));
        suite.addTest(new ApfloatMathTest("testAtanh"));
        suite.addTest(new ApfloatMathTest("testCosh"));
        suite.addTest(new ApfloatMathTest("testSinh"));
        suite.addTest(new ApfloatMathTest("testTanh"));
        suite.addTest(new ApfloatMathTest("testAcos"));
        suite.addTest(new ApfloatMathTest("testAsin"));
        suite.addTest(new ApfloatMathTest("testAtan"));
        suite.addTest(new ApfloatMathTest("testAtan2"));
        suite.addTest(new ApfloatMathTest("testCos"));
        suite.addTest(new ApfloatMathTest("testSin"));
        suite.addTest(new ApfloatMathTest("testTan"));
        suite.addTest(new ApfloatMathTest("testSinc"));
        suite.addTest(new ApfloatMathTest("testW"));
        suite.addTest(new ApfloatMathTest("testToRadians"));
        suite.addTest(new ApfloatMathTest("testToDegrees"));
        suite.addTest(new ApfloatMathTest("testProduct"));
        suite.addTest(new ApfloatMathTest("testSum"));
        suite.addTest(new ApfloatMathTest("testE"));
        suite.addTest(new ApfloatMathTest("testEuler"));
        suite.addTest(new ApfloatMathTest("testCatalan"));
        suite.addTest(new ApfloatMathTest("testGlaisher"));
        suite.addTest(new ApfloatMathTest("testKhinchin"));
        suite.addTest(new ApfloatMathTest("testGamma"));
        suite.addTest(new ApfloatMathTest("testGammaIncomplete"));
        suite.addTest(new ApfloatMathTest("testGammaIncompleteGeneralized"));
        suite.addTest(new ApfloatMathTest("testLogGamma"));
        suite.addTest(new ApfloatMathTest("testDigamma"));
        suite.addTest(new ApfloatMathTest("testPolygamma"));
        suite.addTest(new ApfloatMathTest("testBarnesG"));
        suite.addTest(new ApfloatMathTest("testLogBarnesG"));
        suite.addTest(new ApfloatMathTest("testBeta"));
        suite.addTest(new ApfloatMathTest("testBetaIncomplete"));
        suite.addTest(new ApfloatMathTest("testBetaIncompleteGeneralized"));
        suite.addTest(new ApfloatMathTest("testPochhammer"));
        suite.addTest(new ApfloatMathTest("testBinomial"));
        suite.addTest(new ApfloatMathTest("testZeta"));
        suite.addTest(new ApfloatMathTest("testZetaHurwitz"));
        suite.addTest(new ApfloatMathTest("testHypergeometric0F1"));
        suite.addTest(new ApfloatMathTest("testHypergeometric1F1"));
        suite.addTest(new ApfloatMathTest("testHypergeometric2F1"));
        suite.addTest(new ApfloatMathTest("testHypergeometric0F1Regularized"));
        suite.addTest(new ApfloatMathTest("testHypergeometric1F1Regularized"));
        suite.addTest(new ApfloatMathTest("testHypergeometric2F1Regularized"));
        suite.addTest(new ApfloatMathTest("testHypergeometricU"));
        suite.addTest(new ApfloatMathTest("testErf"));
        suite.addTest(new ApfloatMathTest("testErfc"));
        suite.addTest(new ApfloatMathTest("testErfi"));
        suite.addTest(new ApfloatMathTest("testInverseErf"));
        suite.addTest(new ApfloatMathTest("testInverseErfc"));
        suite.addTest(new ApfloatMathTest("testDawsonF"));
        suite.addTest(new ApfloatMathTest("testFresnelS"));
        suite.addTest(new ApfloatMathTest("testFresnelC"));
        suite.addTest(new ApfloatMathTest("testExpIntegralE"));
        suite.addTest(new ApfloatMathTest("testExpIntegralEi"));
        suite.addTest(new ApfloatMathTest("testLogIntegral"));
        suite.addTest(new ApfloatMathTest("testSinIntegral"));
        suite.addTest(new ApfloatMathTest("testCosIntegral"));
        suite.addTest(new ApfloatMathTest("testSinhIntegral"));
        suite.addTest(new ApfloatMathTest("testCoshIntegral"));
        suite.addTest(new ApfloatMathTest("testAiryAi"));
        suite.addTest(new ApfloatMathTest("testAiryAiPrime"));
        suite.addTest(new ApfloatMathTest("testAiryBi"));
        suite.addTest(new ApfloatMathTest("testAiryBiPrime"));
        suite.addTest(new ApfloatMathTest("testBesselJ"));
        suite.addTest(new ApfloatMathTest("testBesselI"));
        suite.addTest(new ApfloatMathTest("testBesselY"));
        suite.addTest(new ApfloatMathTest("testBesselK"));
        suite.addTest(new ApfloatMathTest("testStruveH"));
        suite.addTest(new ApfloatMathTest("testStruveL"));
        suite.addTest(new ApfloatMathTest("testAngerJ"));
        suite.addTest(new ApfloatMathTest("testWeberE"));
        suite.addTest(new ApfloatMathTest("testEllipticK"));
        suite.addTest(new ApfloatMathTest("testEllipticE"));
        suite.addTest(new ApfloatMathTest("testHermiteH"));
        suite.addTest(new ApfloatMathTest("testLaguerreL"));
        suite.addTest(new ApfloatMathTest("testLaguerreLGeneralized"));
        suite.addTest(new ApfloatMathTest("testLegendreP"));
        suite.addTest(new ApfloatMathTest("testLegendrePAssociated"));
        suite.addTest(new ApfloatMathTest("testLegendreQ"));
        suite.addTest(new ApfloatMathTest("testLegendreQAssociated"));
        suite.addTest(new ApfloatMathTest("testChebyshevT"));
        suite.addTest(new ApfloatMathTest("testChebyshevU"));
        suite.addTest(new ApfloatMathTest("testGegenbauerCRenormalized"));
        suite.addTest(new ApfloatMathTest("testGegenbauerC"));
        suite.addTest(new ApfloatMathTest("testJacobiP"));
        suite.addTest(new ApfloatMathTest("testFibonacci"));
        suite.addTest(new ApfloatMathTest("testEulerE"));
        suite.addTest(new ApfloatMathTest("testBernoulliB"));
        suite.addTest(new ApfloatMathTest("testHarmonicNumber"));
        suite.addTest(new ApfloatMathTest("testHarmonicNumberGeneralized"));
        suite.addTest(new ApfloatMathTest("testPolylog"));
        suite.addTest(new ApfloatMathTest("testClausenCl"));
        suite.addTest(new ApfloatMathTest("testClausenSl"));
        suite.addTest(new ApfloatMathTest("testClausenS"));
        suite.addTest(new ApfloatMathTest("testClausenC"));
        suite.addTest(new ApfloatMathTest("testLogisticSigmoid"));
        suite.addTest(new ApfloatMathTest("testRandom"));
        suite.addTest(new ApfloatMathTest("testRandomGaussian"));
        suite.addTest(new ApfloatMathTest("testContinuedFraction"));
        suite.addTest(new ApfloatMathTest("testConvergents"));
        suite.addTest(new ApfloatMathTest("testMax"));
        suite.addTest(new ApfloatMathTest("testMin"));
        suite.addTest(new ApfloatMathTest("testNextAfter"));
        suite.addTest(new ApfloatMathTest("testNextUp"));
        suite.addTest(new ApfloatMathTest("testNextDown"));
        suite.addTest(new ApfloatMathTest("testUlp"));

        return suite;
    }

    public static void testIntegerPow()
    {
        Apfloat x = new Apfloat(2, 1000);
        assertEquals("2^30", new Apfloat(1 << 30), ApfloatMath.pow(x, 30));
        assertEquals("2^60", new Apfloat(1L << 60), ApfloatMath.pow(x, 60));
        assertEquals("2^-1", new Apfloat("0.5"), ApfloatMath.pow(x, -1));
        assertEquals("2^-3", new Apfloat("0.125"), ApfloatMath.pow(x, -3));
        assertEquals("2^0", new Apfloat(1), ApfloatMath.pow(x, 0));

        assertEquals("2^1000000000", ApfloatMath.pow(x, 1000000000).precision(10), ApfloatMath.pow(x.precision(11), 1000000000).precision(10));

        x = new Apfloat("1.00000000000000000000000000000000000000001", 50);
        assertEquals("1.00000000000000000000000000000000000000001^0x7FFFFFFFFFFFFFFF", new Apfloat("1.0000000000000000000000922337203685477580700042535"), ApfloatMath.pow(x, 0x7FFFFFFFFFFFFFFFL), new Apfloat(1e-48));
        assertEquals("1.00000000000000000000000000000000000000001^0x8000000000000000", new Apfloat("0.99999999999999999999990776627963145224192000425352"), ApfloatMath.pow(x, 0x8000000000000000L), new Apfloat(1e-48));

        assertEquals("2^1000 * 5^1000 = 10^1000", ApfloatMath.pow(new Apfloat(10), 1000), ApfloatMath.pow(new Apfloat(2), 1000).multiply(ApfloatMath.pow(new Apfloat(5), 1000)));
        assertEquals("2^10000 * 5^10000 = 10^10000", ApfloatMath.pow(new Apfloat(10), 10000), ApfloatMath.pow(new Apfloat(2), 10000).multiply(ApfloatMath.pow(new Apfloat(5), 10000)));
        assertEquals("2^100000 * 5^100000 = 10^100000", ApfloatMath.pow(new Apfloat(10), 100000), ApfloatMath.pow(new Apfloat(2), 100000).multiply(ApfloatMath.pow(new Apfloat(5), 100000)));
        assertEquals("2^1000000 * 5^1000000 = 10^1000000", ApfloatMath.pow(new Apfloat(10), 1000000), ApfloatMath.pow(new Apfloat(2), 1000000).multiply(ApfloatMath.pow(new Apfloat(5), 1000000)));

        try
        {
            ApfloatMath.pow(new Apfloat(0), 0);
            fail("0^0 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK; result would be undefined
            assertEquals("Localization key", "pow.zeroToZero", aae.getLocalizationKey());
        }
    }

    public static void testScale()
    {
        for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++)
        {
            Apfloat x = ApfloatMath.scale(new Apfloat(1, 5, radix), 5);
            assertEquals("1 precision", 5, x.precision());
            assertEquals("1 string", "100000", x.toString(true));

            x = ApfloatMath.scale(new Apfloat(-1, 5, radix), -5);
            assertEquals("-1 precision", 5, x.precision());
            assertEquals("-1 string", "-0.00001", x.toString(true));

            x = ApfloatMath.scale(new Apfloat(1, 5, radix), Long.MIN_VALUE / 2);
            x = ApfloatMath.scale(x, Long.MAX_VALUE);
            assertEquals("-2^62 precision", 5, x.precision());
            assertEquals("-2^62 string", "1e4611686018427387903", x.toString());

            x = ApfloatMath.scale(new Apfloat(1, 5, radix), Long.MIN_VALUE / -2);
            x = ApfloatMath.scale(x, Long.MIN_VALUE);
            assertEquals("2^62 precision", 5, x.precision());
            assertEquals("2^62 string", "1e-4611686018427387904", x.toString());

            x = ApfloatMath.scale(new Apfloat(1, 5, radix), Long.MIN_VALUE / 2);
            x = ApfloatMath.scale(x, Long.MIN_VALUE / 2);
            assertEquals("underflow", "0", x.toString());

            x = ApfloatMath.scale(new Apfloat(1, 5, radix), Long.MIN_VALUE / 2);
            x = ApfloatMath.scale(x, Long.MIN_VALUE);
            assertEquals("underflow 2", "0", x.toString());

            x = ApfloatMath.scale(new Apfloat(radix - 1, 5, radix), 5);
            assertEquals("9 precision", 5, x.precision());
            assertEquals("9 string", Character.forDigit(radix - 1, radix) + "00000", x.toString(true));
        }
    }

    public static void testInverseRoot()
    {
        Apfloat x = new Apfloat("1.2345678901234567890123456789"),
                invX,
                invSqrtX;
        assertEquals("1.2345678901234567890123456789^-1", new Apfloat("0.810000007290000066339000603685715"), ApfloatMath.inverseRoot(x, 1), new Apfloat(1e-30));
        assertEquals("-2^-1/3", new Apfloat(-0.79370052598409973737585281963615), ApfloatMath.inverseRoot(new Apfloat(-2.0), 3), new Apfloat(1e-15));
        assertEquals("-2^-1/5", new Apfloat(-0.87055056329612413913627001747975), ApfloatMath.inverseRoot(new Apfloat(-2.0), 5), new Apfloat(1e-15));
        assertEquals("-2^-1/7", new Apfloat(-0.9057236642639066715941728732151), ApfloatMath.inverseRoot(new Apfloat(-2.0), 7), new Apfloat(1e-15));

        x = new Apfloat("3.[encoded data, 50000 characters]");
        invX = new Apfloat("0.[encoded data, 50000 characters]");
        invSqrtX = new Apfloat("0.[encoded data, 50000 characters]");

        for (int prec = 25000; prec <= 50000; prec += 1000)
        {
            Apfloat tmpX = x.precision(prec),
                    expectedInvX = invX.precision(prec),
                    expectedInvSqrtX = invSqrtX.precision(prec),
                    actualInvX = ApfloatMath.inverseRoot(tmpX, 1),
                    actualInvSqrtX = ApfloatMath.inverseRoot(tmpX, 2);

            assertEquals("inv prec " + prec + " precision", prec, actualInvX.precision());
            assertEquals("inv prec " + prec + " value", expectedInvX, actualInvX, new Apfloat("5e-" + prec));
            assertEquals("invsqrt prec " + prec + " precision", prec, actualInvSqrtX.precision());
            assertEquals("invsqrt prec " + prec + " value", expectedInvSqrtX, actualInvSqrtX, new Apfloat("5e-" + prec));
        }

        assertEquals("inverseRoot(9.78675172784960122038e10773, 7912)", Apfloat.ONE.divide(new Apfloat(23, 21)), ApfloatMath.inverseRoot(new Apfloat("9.78675172784960122038e10773"), 7912), new Apfloat(1e-20));

        assertEquals("1", new Apfloat(1), ApfloatMath.inverseRoot(Apfloat.ONE, 5));
        assertEquals("sqrt(2)", new Apfloat(1.4142135623730950488016887242097), ApfloatMath.inverseRoot(new Apfloat(2.0), -2), new Apfloat(1e-15));
        //assertEquals("inv 0x7FFFFFFFFFFFFFFFth root of 2", new Apfloat("0.999999999999999999924848832098"), ApfloatMath.inverseRoot(new Apfloat(2, 30), 0x7FFFFFFFFFFFFFFFL), new Apfloat(2e-29));
        //assertEquals("inv 0x8000000000000000th root of 2", new Apfloat("1.0000000000000000000751511679"), ApfloatMath.inverseRoot(new Apfloat(2, 30), 0x8000000000000000L), new Apfloat(2e-29));

        try
        {
            ApfloatMath.inverseRoot(x, 0);
            fail("inverse zeroth root accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK: inverse zeroth root
            assertEquals("Localization key", "inverseRoot.zeroth", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.inverseRoot(new Apfloat(-2), 2);
            fail("inverse sqrt of -2 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK: result would be imaginary
            assertEquals("Localization key", "root.evenOfNegative", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.inverseRoot(new Apfloat(0), 2);
            fail("inverse sqrt of 0 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK: result would be infinite
            assertEquals("Localization key", "inverseRoot.ofZero", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.inverseRoot(new Apfloat(3), 2, 0);
            fail("precision 0 accepted");
        }
        catch (IllegalArgumentException iae)
        {
            // OK: invalid input
        }

        try
        {
            ApfloatMath.inverseRoot(new Apfloat(3), 2);
            fail("infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK: can't have infinite memory
            assertEquals("Localization key", "inverseRoot.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testRoot()
    {
        assertEquals("0", new Apfloat(0), ApfloatMath.root(Apfloat.ZERO, 3));
        assertEquals("1", new Apfloat(1), ApfloatMath.root(Apfloat.ONE, 5));
        assertEquals("1st root", new Apfloat(2), ApfloatMath.root(new Apfloat(2), 1));
        assertEquals("root(2, 2)", new Apfloat(1.4142135623730950488016887242097), ApfloatMath.root(new Apfloat(2.0), 2), new Apfloat(1e-15));
        assertEquals("root(2, -2)", new Apfloat(0.70710678118654752440084436210485), ApfloatMath.root(new Apfloat(2.0), -2), new Apfloat(5e-16));
        //assertEquals("0x7FFFFFFFFFFFFFFFth root of 2", new Apfloat("1.0000000000000000000751511679015"), ApfloatMath.root(new Apfloat(2, 30), 0x7FFFFFFFFFFFFFFFL), new Apfloat(2e-29));
        //assertEquals("0x8000000000000000th root of 2", new Apfloat("0.99999999999999999992484883209847"), ApfloatMath.root(new Apfloat(2, 30), 0x8000000000000000L), new Apfloat(2e-29));
        assertEquals("sqrt(2)", new Apfloat(1.4142135623730950488016887242097), ApfloatMath.sqrt(new Apfloat(2.0)), new Apfloat(1e-15));
        assertEquals("cbrt(2)", new Apfloat(1.2599210498948731647672106072782), ApfloatMath.cbrt(new Apfloat(2.0)), new Apfloat(1e-15));

        assertEquals("root(2^1048576,1048576)", new Apfloat(2), ApfloatMath.root(ApfloatMath.pow(new Apfloat(2, 30), 1048576), 1048576), new Apfloat(1e-29));
        assertEquals("root(2^100000000000,100000000000)", new Apfloat(2), ApfloatMath.root(ApfloatMath.pow(new Apfloat(2, 30), 100000000000L), 100000000000L), new Apfloat(1e-29));
        //assertEquals("root(2^100000000000000000,100000000000000000)", new Apfloat(2), ApfloatMath.root(ApfloatMath.pow(new Apfloat(2, 30), 100000000000000000L), 100000000000000000L), new Apfloat(1e-29));

        assertEquals("0 radix 12", 12, ApfloatMath.root(new Apint(0, 12), 3).radix());

        try
        {
            ApfloatMath.root(new Apfloat(2), 0);
            fail("zeroth root accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK: zeroth root
            assertEquals("Localization key", "root.zeroth", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.root(new Apfloat(-2), 2);
            fail("sqrt of -2 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK: result would be imaginary
            assertEquals("Localization key", "root.evenOfNegative", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.root(new Apfloat(0), 0);
            fail("0th root of 0 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK: result would be undefined
            assertEquals("Localization key", "root.zeroth", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.root(new Apfloat(3), 2);
            fail("infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK: can't have infinite memory
            assertEquals("Localization key", "inverseRoot.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testAbs()
    {
        Apfloat x = new Apfloat(2);
        assertEquals("2", new Apfloat(2), ApfloatMath.abs(x));

        x = new Apfloat(-2);
        assertEquals("-2", new Apfloat(2), ApfloatMath.abs(x));

        x = new Apfloat(0);
        assertEquals("0", new Apfloat(0), ApfloatMath.abs(x));
    }

    public static void testCopySign()
    {
        assertEquals("2, 1", new Apfloat(2), ApfloatMath.copySign(new Apfloat(2), new Apfloat(1)));
        assertEquals("2, -1", new Apfloat(-2), ApfloatMath.copySign(new Apfloat(2), new Apfloat(-1)));
        assertEquals("-2, 1", new Apfloat(2), ApfloatMath.copySign(new Apfloat(-2), new Apfloat(1)));
        assertEquals("-2, -1", new Apfloat(-2), ApfloatMath.copySign(new Apfloat(-2), new Apfloat(-1)));

        assertEquals("0, 0", new Apfloat(0), ApfloatMath.copySign(new Apfloat(0), new Apfloat(0)));
        assertEquals("0, 1", new Apfloat(0), ApfloatMath.copySign(new Apfloat(0), new Apfloat(1)));
        assertEquals("0, -1", new Apfloat(0), ApfloatMath.copySign(new Apfloat(0), new Apfloat(-1)));
        assertEquals("1, 0", new Apfloat(0), ApfloatMath.copySign(new Apfloat(1), new Apfloat(0)));
        assertEquals("-1, 0", new Apfloat(0), ApfloatMath.copySign(new Apfloat(-1), new Apfloat(0)));
    }

    public static void testFloor()
    {
        Apfloat x = new Apfloat("1.1");
        assertEquals("1.1", new Apfloat(1), ApfloatMath.floor(x));
    }

    public static void testCeil()
    {
        Apfloat x = new Apfloat("1.1");
        assertEquals("1.1", new Apfloat(2), ApfloatMath.ceil(x));
    }

    public static void testTruncate()
    {
        Apfloat x = new Apfloat("-1.1");
        assertEquals("-1.1", new Apfloat(-1), ApfloatMath.truncate(x));
    }

    public static void testFrac()
    {
        Apfloat x = new Apfloat("-1.1");
        assertEquals("-1.1", new Apfloat("-0.1"), ApfloatMath.frac(x));
    }

    @SuppressWarnings("deprecation")
    public static void testRound()
    {
        Apfloat[] inputs = { new Apfloat("5.5"),
                             new Apfloat("2.5"),
                             new Apfloat("1.6"),
                             new Apfloat("1.1"),
                             new Apfloat("1.0"),
                             new Apfloat("-1.0"),
                             new Apfloat("-1.1"),
                             new Apfloat("-1.6"),
                             new Apfloat("-2.5"),
                             new Apfloat("-5.5") };
        RoundingMode[] roundingModes = { UP,            DOWN,          CEILING,       FLOOR,         HALF_UP,       HALF_DOWN,     HALF_EVEN,     UNNECESSARY   };
        Apfloat[][] expected =       { { new Apint(6),  new Apint(5),  new Apint(6),  new Apint(5),  new Apint(6),  new Apint(5),  new Apint(6),  null          },
                                       { new Apint(3),  new Apint(2),  new Apint(3),  new Apint(2),  new Apint(3),  new Apint(2),  new Apint(2),  null          },
                                       { new Apint(2),  new Apint(1),  new Apint(2),  new Apint(1),  new Apint(2),  new Apint(2),  new Apint(2),  null          },
                                       { new Apint(2),  new Apint(1),  new Apint(2),  new Apint(1),  new Apint(1),  new Apint(1),  new Apint(1),  null          },
                                       { new Apint(1),  new Apint(1),  new Apint(1),  new Apint(1),  new Apint(1),  new Apint(1),  new Apint(1),  new Apint(1)  },
                                       { new Apint(-1), new Apint(-1), new Apint(-1), new Apint(-1), new Apint(-1), new Apint(-1), new Apint(-1), new Apint(-1) },
                                       { new Apint(-2), new Apint(-1), new Apint(-1), new Apint(-2), new Apint(-1), new Apint(-1), new Apint(-1), null          },
                                       { new Apint(-2), new Apint(-1), new Apint(-1), new Apint(-2), new Apint(-2), new Apint(-2), new Apint(-2), null          },
                                       { new Apint(-3), new Apint(-2), new Apint(-2), new Apint(-3), new Apint(-3), new Apint(-2), new Apint(-2), null          },
                                       { new Apint(-6), new Apint(-5), new Apint(-5), new Apint(-6), new Apint(-6), new Apint(-5), new Apint(-6), null          } };

        for (int i = 0; i < inputs.length; i++)
        {
            Apfloat input = inputs[i];
            for (int j = 0; j < roundingModes.length; j++)
            {
                RoundingMode roundingMode = roundingModes[j];
                Object result;
                try
                {
                    result = ApfloatMath.round(input, 1, roundingMode);
                }
                catch (ApfloatArithmeticException aae)
                {
                    assertEquals("Localization key", "roundingNecessary", aae.getLocalizationKey());
                    result = null;
                }
                assertEquals(expected[i][j], result);
            }
        }

        assertEquals(new Apfloat("555.5600"), ApfloatMath.round(new Apfloat("555.5555"), 5, RoundingMode.HALF_EVEN));
        assertEquals(new Apfloat("555.5560"), ApfloatMath.round(new Apfloat("555.5555"), 6, RoundingMode.HALF_EVEN));
        assertEquals(new Apfloat("555.5555"), ApfloatMath.round(new Apfloat("555.5555"), 7, RoundingMode.HALF_EVEN));
        assertEquals(new Apfloat("555.5555"), ApfloatMath.round(new Apfloat("555.5555"), Apfloat.INFINITE, RoundingMode.HALF_EVEN));
        assertEquals(new Apfloat("0.0005555600"), ApfloatMath.round(new Apfloat("0.0005555555"), 5, RoundingMode.HALF_EVEN));

        assertEquals(new Apfloat("1.1010", Apfloat.DEFAULT, 2), ApfloatMath.round(new Apfloat("1.10101", Apfloat.DEFAULT, 2), 5, RoundingMode.HALF_EVEN));
        assertEquals(new Apfloat("1.1100", Apfloat.DEFAULT, 2), ApfloatMath.round(new Apfloat("1.10111", Apfloat.DEFAULT, 2), 5, RoundingMode.HALF_EVEN));
        assertEquals(new Apfloat("1.1111", Apfloat.DEFAULT, 3), ApfloatMath.round(new Apfloat("1.11111", Apfloat.DEFAULT, 3), 5, RoundingMode.HALF_EVEN));
        assertEquals(new Apfloat("1.1112", Apfloat.DEFAULT, 3), ApfloatMath.round(new Apfloat("1.11112", Apfloat.DEFAULT, 3), 5, RoundingMode.HALF_EVEN));
        assertEquals(new Apfloat("1.1112", Apfloat.DEFAULT, 3), ApfloatMath.round(new Apfloat("1.11121", Apfloat.DEFAULT, 3), 5, RoundingMode.HALF_EVEN));
        assertEquals(new Apfloat("1.1120", Apfloat.DEFAULT, 3), ApfloatMath.round(new Apfloat("1.11122", Apfloat.DEFAULT, 3), 5, RoundingMode.HALF_EVEN));
        assertEquals(new Apfloat("1.1111", Apfloat.DEFAULT, 3), ApfloatMath.round(new Apfloat("1.1111111111111111111111111111", Apfloat.DEFAULT, 3), 5, RoundingMode.HALF_EVEN));
        assertEquals(new Apfloat("1.1112", Apfloat.DEFAULT, 3), ApfloatMath.round(new Apfloat("1.1111111111111111111111111112", Apfloat.DEFAULT, 3), 5, RoundingMode.HALF_EVEN));

        assertEquals(new Apfloat("2", Apfloat.DEFAULT, 28), ApfloatMath.round(new Apfloat("1.r", Apfloat.DEFAULT, 28), 1, RoundingMode.HALF_EVEN));
        assertEquals(new Apfloat("2", Apfloat.DEFAULT, 36), ApfloatMath.round(new Apfloat("1.z", Apfloat.DEFAULT, 36), 1, RoundingMode.HALF_EVEN));

        assertEquals(new Apfloat("1.1e9223372036853775808"), ApfloatMath.round(new Apfloat("1.1e9223372036853775808"), 100000000000L, RoundingMode.HALF_EVEN));
        assertEquals(new Apfloat("1.1e-9223372036853775808"), ApfloatMath.round(new Apfloat("1.1e-9223372036853775808"), 100000000000L, RoundingMode.HALF_EVEN));

        assertEquals(new Apfloat(0), ApfloatMath.round(new Apfloat(0), 1, RoundingMode.UNNECESSARY));
        assertEquals(new Apfloat(0), ApfloatMath.round(new Apfloat(0), Apfloat.INFINITE, RoundingMode.UNNECESSARY));

        Apfloat a = ApfloatMath.round(new Apfloat(1), Apfloat.INFINITE, RoundingMode.UNNECESSARY);
        assertEquals("1, infinite precision", Apfloat.INFINITE, a.precision());
        assertEquals("1, infinite value", new Apfloat(1), a);
        a = ApfloatMath.round(new Apfloat(1), 1, RoundingMode.UNNECESSARY);
        assertEquals("1, 1 precision", 1, a.precision());
        assertEquals("1, 1 value", new Apfloat(1), a);

        a = ApfloatMath.round(new Apfloat(12345, 4), 4, RoundingMode.UNNECESSARY);
        assertEquals("12345, 4 precision ", 4, a.precision());
        assertEquals("12345, 4 value", new Apfloat(12340), a.precision(5));
        a = ApfloatMath.round(new Apfloat(12345).precision(4), 4, RoundingMode.UNNECESSARY);
        assertEquals("12345, inifite/4 precision", 4, a.precision());
        assertEquals("12345, inifite/4 value", new Apfloat(12340), a.precision(5));
        a = ApfloatMath.round(new Apfloat(12345, 4), 5, RoundingMode.UNNECESSARY);
        assertEquals("12345, 5 precision", 5, a.precision());
        assertEquals("12345, 5 value", new Apfloat(12340), a);
        a = ApfloatMath.round(new Apfloat(12345).precision(4), 5, RoundingMode.UNNECESSARY);
        assertEquals("12345, inifite/5 precision", 5, a.precision());
        assertEquals("12345, inifite/5 value", new Apfloat(12340), a);

        try
        {
            ApfloatMath.round(new Apfloat(1000), 0, RoundingMode.HALF_EVEN);
            fail("precision 0 accepted");
        }
        catch (IllegalArgumentException iae)
        {
            // OK; invalid precision
        }

        try
        {
            ApfloatMath.round(new Apfloat(1000), -1, RoundingMode.HALF_EVEN);
            fail("precision -1 accepted");
        }
        catch (IllegalArgumentException iae)
        {
            // OK; invalid precision
        }

        try
        {
            ApfloatMath.round(new Apfloat(1000), Long.MIN_VALUE, RoundingMode.HALF_EVEN);
            fail("precision Long.MIN_VALUE accepted");
        }
        catch (IllegalArgumentException iae)
        {
            // OK; invalid precision
        }
    }

    public static void testRoundToPrecision()
    {
        Apfloat a = ApfloatMath.roundToPrecision(new Apfloat(4), 2, RoundingMode.UNNECESSARY);
        assertEquals("4, 2, infinite precision", 2, a.precision());
        assertEquals("4, 2, infinite value", new Apfloat(4), a);

        a = ApfloatMath.roundToPrecision(new Apfloat("1.1e-1000000", Apfloat.INFINITE), Apfloat.INFINITE - 1, RoundingMode.UNNECESSARY);
        assertEquals("1.1e-1000000, infinite-1 precision", Apfloat.INFINITE - 1, a.precision());
        assertEquals("1.1e-1000000, infinite-1 value", new Apfloat("1.1e-1000000"), a);
    }

    public static void testRoundToInteger()
    {
        Apint a = ApfloatMath.roundToInteger(new Apfloat(40), RoundingMode.UNNECESSARY);
        assertEquals("40", new Apfloat(40), a);

        a = ApfloatMath.roundToInteger(new Apfloat("4.1"), RoundingMode.UP);
        assertEquals("4.1 UP", new Apfloat(5), a);

        a = ApfloatMath.roundToInteger(new Apfloat("4.9"), RoundingMode.DOWN);
        assertEquals("4.9 DOWN", new Apfloat(4), a);

        a = ApfloatMath.roundToInteger(new Apfloat("-4.9"), RoundingMode.CEILING);
        assertEquals("-4.9 CEILING", new Apfloat(-4), a);

        a = ApfloatMath.roundToInteger(new Apfloat("-4.1"), RoundingMode.FLOOR);
        assertEquals("-4.1 FLOOR", new Apfloat(-5), a);

        a = ApfloatMath.roundToInteger(new Apfloat("5.4"), RoundingMode.HALF_UP);
        assertEquals("5.4 HALF_UP", new Apfloat(5), a);
        a = ApfloatMath.roundToInteger(new Apfloat("5.5"), RoundingMode.HALF_UP);
        assertEquals("5.5 HALF_UP", new Apfloat(6), a);
        a = ApfloatMath.roundToInteger(new Apfloat("5.6"), RoundingMode.HALF_UP);
        assertEquals("5.6 HALF_UP", new Apfloat(6), a);

        a = ApfloatMath.roundToInteger(new Apfloat("5.4"), RoundingMode.HALF_DOWN);
        assertEquals("5.4 HALF_DOWN", new Apfloat(5), a);
        a = ApfloatMath.roundToInteger(new Apfloat("5.5"), RoundingMode.HALF_DOWN);
        assertEquals("5.5 HALF_DOWN", new Apfloat(5), a);
        a = ApfloatMath.roundToInteger(new Apfloat("5.6"), RoundingMode.HALF_DOWN);
        assertEquals("5.6 HALF_DOWN", new Apfloat(6), a);

        a = ApfloatMath.roundToInteger(new Apfloat("-5.4"), RoundingMode.HALF_EVEN);
        assertEquals("-5.4 HALF_EVEN", new Apfloat(-5), a);
        a = ApfloatMath.roundToInteger(new Apfloat("-5.5"), RoundingMode.HALF_EVEN);
        assertEquals("-5.5 HALF_EVEN", new Apfloat(-6), a);
        a = ApfloatMath.roundToInteger(new Apfloat("-5.6"), RoundingMode.HALF_EVEN);
        assertEquals("-5.6 HALF_EVEN", new Apfloat(-6), a);

        a = ApfloatMath.roundToInteger(new Apfloat("1e-1000000000000000"), RoundingMode.UP);
        assertEquals("1e-1000000000000000 UP", new Apfloat(1), a);

        try
        {
            ApfloatMath.roundToInteger(new Apfloat("1.1"), RoundingMode.UNNECESSARY);
            fail("rounding accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK; rounding necessary
            assertEquals("Localization key", "roundingNecessary", aae.getLocalizationKey());
        }
    }

    public static void testRoundToPlaces()
    {
        Apfloat a = ApfloatMath.roundToPlaces(new Apfloat("1.2345", Apfloat.INFINITE), 4, RoundingMode.UNNECESSARY);
        assertEquals("1.2345, 4, infinite precision", Apfloat.INFINITE, a.precision());
        assertEquals("1.2345, 4, infinite value", new Apfloat("1.2345"), a);

        a = ApfloatMath.roundToPlaces(new Apfloat(0), Long.MIN_VALUE, RoundingMode.UNNECESSARY);
        assertEquals("0, MIN_VALUE precision", Apfloat.INFINITE, a.precision());
        assertEquals("0, MIN_VALUE value", new Apfloat(0), a);

        a = ApfloatMath.roundToPlaces(new Apfloat("1.2345"), 2, RoundingMode.DOWN);
        assertEquals("1.2345, 2, DOWN precision", Apfloat.INFINITE, a.precision());
        assertEquals("1.2345, 2, DOWN value", new Apfloat("1.23"), a);

        a = ApfloatMath.roundToPlaces(new Apfloat("1.2345"), 2, RoundingMode.UP);
        assertEquals("1.2345, 2, UP precision", Apfloat.INFINITE, a.precision());
        assertEquals("1.2345, 2, UP value", new Apfloat("1.24"), a);

        a = ApfloatMath.roundToPlaces(new Apfloat("123.45"), -2, RoundingMode.CEILING);
        assertEquals("123.45, -2, CEILING precision", Apfloat.INFINITE, a.precision());
        assertEquals("123.45, -2, CEILING value", new Apfloat("200"), a);

        a = ApfloatMath.roundToPlaces(new Apfloat("-123.45"), -4, RoundingMode.FLOOR);
        assertEquals("-123.45, -4, FLOOR precision", Apfloat.INFINITE, a.precision());
        assertEquals("-123.45, -4, FLOOR value", new Apfloat("-10000"), a);

        a = ApfloatMath.roundToPlaces(new Apfloat("-123.45"), 1, RoundingMode.HALF_UP);
        assertEquals("-123.45, 1, HALF_UP precision", Apfloat.INFINITE, a.precision());
        assertEquals("-123.45, 1, HALF_UP value", new Apfloat("-123.5"), a);

        a = ApfloatMath.roundToPlaces(new Apfloat("-123.45"), 1, RoundingMode.HALF_DOWN);
        assertEquals("-123.45, 1, HALF_DOWN precision", Apfloat.INFINITE, a.precision());
        assertEquals("-123.45, 1, HALF_DOWN value", new Apfloat("-123.4"), a);

        a = ApfloatMath.roundToPlaces(new Apfloat("123.45"), 1, RoundingMode.HALF_EVEN);
        assertEquals("123.45, 1, HALF_EVEN precision", Apfloat.INFINITE, a.precision());
        assertEquals("123.45, 1, HALF_EVEN value", new Apfloat("123.4"), a);

        a = ApfloatMath.roundToPlaces(new Apfloat("123.45e1000000"), Long.MIN_VALUE, RoundingMode.DOWN);
        assertEquals("123.45e1000000, MIN_VALUE, UP precision", Apfloat.INFINITE, a.precision());
        assertEquals("123.45e1000000, MIN_VALUE, UP value", new Apfloat(0), a);

        try
        {
            ApfloatMath.roundToPlaces(new Apfloat("1.1"), Long.MIN_VALUE, RoundingMode.DOWN);
            fail("Should underflow or overflow");
        }
        catch (OverflowException oe)
        {
            // OK; underflow / overflow
            assertEquals("Localization key", "underflow.overflow", oe.getLocalizationKey());
        }

        try
        {
            ApfloatMath.roundToPlaces(new Apfloat("1.1"), Long.MIN_VALUE, RoundingMode.UP);
            fail("Should underflow or overflow");
        }
        catch (OverflowException oe)
        {
            // OK; underflow / overflow
            assertEquals("Localization key", "underflow.overflow", oe.getLocalizationKey());
        }

        try
        {
            ApfloatMath.roundToPlaces(new Apfloat("1.2345"), 2, RoundingMode.UNNECESSARY);
            fail("rounding accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK; rounding necessary
            assertEquals("Localization key", "roundingNecessary", aae.getLocalizationKey());
        }
    }

    public static void testRoundToMultiple()
    {
        Apfloat a = ApfloatMath.roundToMultiple(new Apfloat(4), new Apfloat(2), RoundingMode.UNNECESSARY);
        assertEquals("4, 2, infinite precision", Apfloat.INFINITE, a.precision());
        assertEquals("4, 2, infinite value", new Apfloat(4), a);

        a = ApfloatMath.roundToMultiple(new Apfloat("1.3"), new Apfloat("0.3"), RoundingMode.UP);
        assertEquals("1.3, 0.3, UP precision", 1, a.precision());
        assertEquals("1.3, 0.3, UP value", new Apfloat("1.5", 1), a);   // Highly questionable if this is meaningful at all

        a = ApfloatMath.roundToMultiple(new Apfloat("1.3"), new Apfloat("0.30"), RoundingMode.UP);
        assertEquals("1.3, 0.30, UP precision", 2, a.precision());
        assertEquals("1.3, 0.30, UP value", new Apfloat("1.5"), a);

        a = ApfloatMath.roundToMultiple(new Apfloat("2.3"), new Apfloat("1.1"), RoundingMode.DOWN);
        assertEquals("2.3, 1.1, DOWN precision", 2, a.precision());
        assertEquals("2.3, 1.1, DOWN value", new Apfloat("2.2"), a);

        a = ApfloatMath.roundToMultiple(new Apfloat("2.2"), new Apfloat("1.1"), RoundingMode.UNNECESSARY);
        assertEquals("2.2, 1.1, UNNECESSARY precision", 2, a.precision());
        assertEquals("2.2, 1.1, UNNECESSARY value", new Apfloat("2.2"), a);

        a = ApfloatMath.roundToMultiple(new Apfloat("3.3"), new Apfloat("2.2"), RoundingMode.HALF_DOWN);
        assertEquals("3.3, 2.2, HALF_DOWN precision", 2, a.precision());
        assertEquals("3.3, 2.2, HALF_DOWN value", new Apfloat("2.2"), a);

        a = ApfloatMath.roundToMultiple(new Apfloat("3.3"), new Apfloat("2.2"), RoundingMode.HALF_UP);
        assertEquals("3.3, 2.2, HALF_UP precision", 2, a.precision());
        assertEquals("3.3, 2.2, HALF_UP value", new Apfloat("4.4"), a);

        a = ApfloatMath.roundToMultiple(new Apfloat("5.5"), new Apfloat("2.2"), RoundingMode.HALF_EVEN);
        assertEquals("5.5, 2.2, HALF_EVEN precision", 2, a.precision());
        assertEquals("5.5, 2.2, HALF_EVEN value", new Apfloat("4.4"), a);

        a = ApfloatMath.roundToMultiple(new Apfloat("-2.9"), new Apfloat("1.1"), RoundingMode.CEILING);
        assertEquals("-2.9, 1.1, CEILING precision", 2, a.precision());
        assertEquals("-2.9, 1.1, CEILING value", new Apfloat("-2.2"), a);

        a = ApfloatMath.roundToMultiple(new Apfloat("-2.3"), new Apfloat("1.1"), RoundingMode.FLOOR);
        assertEquals("-2.3, 1.1, FLOOR precision", 2, a.precision());
        assertEquals("-2.3, 1.1, FLOOR value", new Apfloat("-3.3"), a);

        a = ApfloatMath.roundToMultiple(new Apfloat("123456.7"), new Apfloat("0.3"), RoundingMode.UP);
        assertEquals("123456.7, 0.3, UP precision", 1, a.precision());
        assertEquals("123456.7, 0.3, UP value", new Apfloat("123456.9", 1), a); // Highly questionable if this is meaningful at all

        a = ApfloatMath.roundToMultiple(new Apfloat("0.3"), new Apfloat("123456.7"), RoundingMode.UP);
        assertEquals("0.3, 123456.7, UP precision", 7, a.precision());
        assertEquals("0.3, 123456.7, UP value", new Apfloat("123456.7"), a);

        a = ApfloatMath.roundToMultiple(new Apfloat("0"), new Apfloat("123456.7"), RoundingMode.UP);
        assertEquals("0, 123456.7, UP precision", Apfloat.INFINITE, a.precision());
        assertEquals("0, 123456.7, UP value", new Apfloat(0), a);

        try
        {
            ApfloatMath.roundToMultiple(new Apfloat("1.2345"), new Apfloat(0), RoundingMode.UP);
            fail("Non-zero as multiple of zero");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK; impossible
            assertEquals("Localization key", "round.ofZero", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.roundToMultiple(new Apfloat("2.3e8999999999999999999"), new Apfloat("1.1e-8999999999999999999"), RoundingMode.UP);
            fail("Too big scale difference");
        }
        catch (OverflowException oe)
        {
            // OK; too big scale difference
            assertEquals("Localization key", "overflow", oe.getLocalizationKey());
        }
    }

    @SuppressWarnings("deprecation")
    public static void testNegate()
    {
        Apfloat x = new Apfloat(2);
        assertEquals("2", new Apfloat(-2), ApfloatMath.negate(x));

        x = new Apfloat(-2);
        assertEquals("-2", new Apfloat(2), ApfloatMath.negate(x));

        x = new Apfloat(0);
        assertEquals("0", new Apfloat(0), ApfloatMath.negate(x));
    }

    public static void testModf()
    {
        Apfloat[] f = ApfloatMath.modf(new Apfloat(2));
        assertEquals("2 i", new Apfloat(2), f[0]);
        assertEquals("2 f", new Apfloat(0), f[1]);

        f = ApfloatMath.modf(new Apfloat("1.5"));
        assertEquals("1.5 i", new Apfloat(1), f[0]);
        assertEquals("1.5 f", new Apfloat("0.5"), f[1]);
        assertEquals("1.5 f precision", 1, f[1].precision());

        f = ApfloatMath.modf(new Apfloat("-1.5", 3));
        assertEquals("-1.5 i", new Apfloat(-2), f[0]);
        assertEquals("-1.5 f", new Apfloat("0.5"), f[1]);
        assertEquals("-1.5 f precision", 2, f[1].precision());
    }

    public static void testFmod()
    {
        assertEquals("0, 1", new Apfloat(0), ApfloatMath.fmod(new Apfloat(0), Apfloat.ONE));
        assertEquals("1, 0", new Apfloat(0), ApfloatMath.fmod(new Apfloat(1), Apfloat.ZERO));

        assertEquals("2, 3", new Apfloat(2), ApfloatMath.fmod(new Apfloat(2), new Apfloat(3)));
        assertEquals("2, -3", new Apfloat(2), ApfloatMath.fmod(new Apfloat(2), new Apfloat(-3)));
        assertEquals("-2, 3", new Apfloat(-2), ApfloatMath.fmod(new Apfloat(-2), new Apfloat(3)));
        assertEquals("-2, -3", new Apfloat(-2), ApfloatMath.fmod(new Apfloat(-2), new Apfloat(-3)));

        assertEquals("200, 3 no precision", new Apfloat(0), ApfloatMath.fmod(new Apfloat(200, 1), new Apfloat(3)));
        assertEquals("20, 3 no precision", new Apfloat(0), ApfloatMath.fmod(new Apfloat(20, 1), new Apfloat(3)));
        assertEquals("20, 3 no precision radix", 12, ApfloatMath.fmod(new Apfloat(20, 1, 12), new Apfloat(3, Apfloat.DEFAULT, 12)).radix());

        assertEquals("20, 2", new Apfloat(0), ApfloatMath.fmod(new Apfloat(20, 2), new Apfloat(2)));

        Apfloat a = ApfloatMath.fmod(new Apfloat(20, 2), new Apfloat(3));
        assertEquals("20, 3 precision 1, precision", 1, a.precision());
        assertEquals("20, 3 precision 1, value", new Apfloat(2), a);

        a = ApfloatMath.fmod(new Apfloat("11257801564015978614078912465097"), new Apfloat("12590784789234078934789457778"));
        assertEquals("11257801564015978614078912465097, 12590784789234078934789457778, precision", 28, a.precision());
        assertEquals("11257801564015978614078912465097, 12590784789234078934789457778, value", new Apfloat("1639962440712046377137211565"), a);

        a = ApfloatMath.fmod(new Apfloat("11257801564015978614078912465097"), new Apfloat(13));
        assertEquals("11257801564015978614078912465097, 13, precision", 1, a.precision());
        assertEquals("11257801564015978614078912465097, 13, value", new Apfloat(4), a);

        a = ApfloatMath.fmod(new Apfloat("11257801564015978614078912465097"), new Apfloat(19));
        assertEquals("11257801564015978614078912465097, 19, precision", 2, a.precision());
        assertEquals("11257801564015978614078912465097, 19, value", new Apfloat(18), a);

        a = ApfloatMath.fmod(new Apfloat("123"), new Apfloat("13"));
        assertEquals("123, 13, precision", 1, a.precision());
        assertEquals("123, 13, value", new Apfloat(6), a);

        a = ApfloatMath.fmod(new Apfloat("123"), new Apfloat("14"));
        assertEquals("123, 14, precision", 2, a.precision());
        assertEquals("123, 14, value", new Apfloat(11), a);

        a = ApfloatMath.fmod(new Apfloat("123"), new Apfloat("61"));
        assertEquals("123, 61, precision", 1, a.precision());
        assertEquals("123, 61, value", new Apfloat(1), a);

        a = ApfloatMath.fmod(new Apfloat("123"), new Apfloat("99"));
        assertEquals("123, 99, precision", 2, a.precision());
        assertEquals("123, 99, value", new Apfloat(24), a);

        for (int i = 5; i <= 150; i++)
        {
            StringBuilder buffer = new StringBuilder();

            for (int j = 0; j < i; j++)
            {
                buffer.append((char) ('1' - (j & 1)));
            }

            String value = buffer.toString();

            Apfloat x = new Apfloat(value, Apfloat.DEFAULT, 9),
                    y = new Apfloat(value, Apfloat.DEFAULT, 9),
                    one = new Apfloat(1, Apfloat.DEFAULT, 9);

            assertEquals(x + ", " + y, new Apfloat(0), ApfloatMath.fmod(x, y));
            assertEquals("-" + x + ", " + y, new Apfloat(0), ApfloatMath.fmod(x.negate(), y));
            assertEquals(x + "+1, " + y, new Apfloat(1, Apfloat.DEFAULT, 9), ApfloatMath.fmod(x.add(one), y));
            assertEquals("-1-" + x + ", " + y, new Apfloat(-1, Apfloat.DEFAULT, 9), ApfloatMath.fmod(one.add(x).negate(), y));
        }

        assertEquals("very long, very long", new Apfloat("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057150"), ApfloatMath.fmod(new Apfloat("610195307303654352666518121441737650909904045487886269771428999892641560353287146586044778246190438153093623532301738649952435264069156612677948549906937800453397951028502213195775639617773794408985442106591307693813584425141736150542412855661591984057451813085814343390198354303417947862296970200397097469208547"), new Apfloat("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151")));
        assertEquals("very long, -very long", new Apfloat("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057150"), ApfloatMath.fmod(new Apfloat("610195307303654352666518121441737650909904045487886269771428999892641560353287146586044778246190438153093623532301738649952435264069156612677948549906937800453397951028502213195775639617773794408985442106591307693813584425141736150542412855661591984057451813085814343390198354303417947862296970200397097469208547"), new Apfloat("-6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151")));
        assertEquals("-very long, very long", new Apfloat("-6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057150"), ApfloatMath.fmod(new Apfloat("-610195307303654352666518121441737650909904045487886269771428999892641560353287146586044778246190438153093623532301738649952435264069156612677948549906937800453397951028502213195775639617773794408985442106591307693813584425141736150542412855661591984057451813085814343390198354303417947862296970200397097469208547"), new Apfloat("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151")));
        assertEquals("-very long, -very long", new Apfloat("-6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057150"), ApfloatMath.fmod(new Apfloat("-610195307303654352666518121441737650909904045487886269771428999892641560353287146586044778246190438153093623532301738649952435264069156612677948549906937800453397951028502213195775639617773794408985442106591307693813584425141736150542412855661591984057451813085814343390198354303417947862296970200397097469208547"), new Apfloat("-6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151")));

        a = ApfloatMath.fmod(new Apfloat("2.3e9000000000000000000"), new Apfloat("1.1e-9000000000000000000"));
        assertEquals("1.1e9000000000000000000, 1.1e-9000000000000000000, precision", Apfloat.INFINITE, a.precision());
        assertEquals("1.1e9000000000000000000, 1.1e-9000000000000000000, value", new Apfloat(0), a);
    }

    public static void testMultiplyAdd()
    {
        Apfloat a = ApfloatMath.multiplyAdd(new Apfloat("2"), new Apfloat("3"), new Apfloat("4"), new Apfloat("5"));
        assertEquals("2 * 3 + 4 * 5 precision", 1, a.precision());
        assertEquals("2 * 3 + 4 * 5 value", new Apfloat(26), a.precision(2));

        a = ApfloatMath.multiplyAdd(new Apfloat("2", 2), new Apfloat("3", 2), new Apfloat("4", 2), new Apfloat("5", 2));
        assertEquals("2 * 3 + 4 * 5, prec 2, precision", 2, a.precision());
        assertEquals("2 * 3 + 4 * 5, prec 2, value", new Apfloat(26), a);

        a = ApfloatMath.multiplyAdd(new Apfloat(20, 1, 12), new Apfloat(30, 1, 12), new Apfloat("4", 1, 12), new Apfloat("5", 1, 12));
        assertEquals("20 * 30 + 4 * 5, prec 1, precision", 1, a.precision());
        assertEquals("20 * 30 + 4 * 5, prec 1, value", new Apfloat(600, 1, 12), a);

        a = ApfloatMath.multiplyAdd(new Apfloat(200, 2), new Apfloat(300, 2), new Apfloat(4), new Apfloat(5));
        assertEquals("200 * 300 + 4 * 5, prec 2, precision", 2, a.precision());
        assertEquals("200 * 300 + 4 * 5, prec 2, value", new Apfloat(60000), a.precision(Apfloat.INFINITE));

        a = ApfloatMath.multiplyAdd(new Apfloat("4", 1, 12), new Apfloat("5", 1, 12), new Apfloat(20, 1, 12), new Apfloat(30, 1, 12));
        assertEquals("4 * 5 + 20 * 30, prec 1, precision", 1, a.precision());
        assertEquals("4 * 5 + 20 * 30, prec 1, value", new Apfloat(600, 1, 12), a);

        a = ApfloatMath.multiplyAdd(new Apfloat(4), new Apfloat(5), new Apfloat(200, 2), new Apfloat(300, 2));
        assertEquals("4 * 5 + 200 * 300, prec 2, precision", 2, a.precision());
        assertEquals("4 * 5 + 200 * 300, prec 2, value", new Apfloat(60000), a.precision(Apfloat.INFINITE));

        // xxxxx000 * xxxxx + xxx00000 * xxx0 =
        // xxxxxx0000000 + xxxx00000000 =
        // xxxxx00000000 + xxxx00000000 =
        // xxxx000000000 / xxxx00000000
        a = ApfloatMath.multiplyAdd(new Apfloat(12345678, 8), new Apfloat(12345, 5), new Apfloat(12345678, 5), new Apfloat(1234, 3));
        assertEquals("5-4-4 precision", 4, a.precision());
        assertEquals("5-4-4 value", new Apfloat(167641961562L), a, new Apfloat(100000000));
    }

    public static void testMultiplySubtract()
    {
        Apfloat a = ApfloatMath.multiplySubtract(new Apfloat(2), new Apfloat(3), new Apfloat(4), new Apfloat(5));
        assertEquals("2 * 3 - 4 * 5 precision", Apfloat.INFINITE, a.precision());
        assertEquals("2 * 3 - 4 * 5 value", new Apfloat(-14), a.precision(2));
    }

    public static void testAgm()
    {
        Apfloat a = ApfloatMath.agm(new Apfloat(1, 100), new Apfloat(2, 100));
        assertEquals("1, 2 precision", 100, a.precision());
        assertEquals("1, 2 value", new Apfloat("1.4567910310469068691864323832650819749738639432213055907941723832679264545802509002574737128184484443281894"), a, new Apfloat("5e-99"));

        a = ApfloatMath.agm(new Apfloat(1, 1), new Apfloat(2, 1));
        assertEquals("1, 2, prec 1, precision", 1, a.precision());
        assertEquals("1, 2, prec 1, value", new Apfloat(1), a, new Apfloat(1));

        a = ApfloatMath.agm(new Apfloat(1, 10), new Apfloat(2, 20));
        assertEquals("1, 2, prec 10-20, precision", 10, a.precision());
        assertEquals("1, 2, prec 10-20, value", new Apfloat("1.456791031"), a, new Apfloat("5e-9"));

        a = ApfloatMath.agm(new Apfloat(-1, 20), new Apfloat(-2, 10));
        assertEquals("-1, -2, prec 10-20, precision", 10, a.precision());
        assertEquals("-1, -2, prec 10-20, value", new Apfloat("-1.456791031"), a, new Apfloat("5e-9"));

        a = ApfloatMath.agm(new Apfloat("1.000000000e10"), new Apfloat("1.000000000e-10"));
        assertEquals("1e10, 1e-10, precision 10", 10, a.precision());
        assertEquals("1e10, 1e-10, value, precision 10", new Apfloat("331126196.7"), a, new Apfloat("0.5"));

        a = ApfloatMath.agm(new Apfloat("1.0000000000000000000e10"), new Apfloat("1.000000000e-10"));
        assertEquals("1e10, 1e-10, precision 10-20", 10, a.precision());
        assertEquals("1e10, 1e-10, value, precision 10-20", new Apfloat("331126196.7"), a, new Apfloat("0.5"));

        a = ApfloatMath.agm(new Apfloat(1, 10), new Apfloat(1, 20));
        assertEquals("1, 1, prec 10-20, precision", 10, a.precision());
        assertEquals("1, 1, prec 10-20, value", new Apfloat(1), a);

        a = ApfloatMath.agm(new Apfloat(1, 20), new Apfloat(1, 10));
        assertEquals("1, 1, prec 20-10, precision", 10, a.precision());
        assertEquals("1, 1, prec 20-10, value", new Apfloat(1), a);

        a = ApfloatMath.agm(new Apfloat(0), new Apfloat(1));
        assertEquals("0, 1", new Apfloat(0), a);

        a = ApfloatMath.agm(Apfloat.ONE, Apfloat.ZERO);
        assertEquals("1, 0", new Apfloat(0), a);

        a = ApfloatMath.agm(new Apfloat(-1), new Apfloat(1));
        assertEquals("-1, 1", new Apfloat(0), a);

        a = ApfloatMath.agm(new Apint(1, 12), new Apint(0, 12));
        assertEquals("1, 0 radix", 12, a.radix());
        a = ApfloatMath.agm(new Apint(1, 12), new Apint(-1, 12));
        assertEquals("1, -1 radix", 12, a.radix());

        a = new Apfloat("1.456791031046906869186432383265081974973863943221305590794172383267926454580250900257473712818448444328189401816036799935576243074340124511691213249952279376897021197672689372826666678270743290207238456460096313336749441664951640082693223908626337673838241025488726264513659066040887588510046672813094743978935512911720175447186956416035641113070606125170400972745374521370401420144157682323238964502909132239229201863020459196677536211529560998432049400961861338863911084030381488628159073170114235547302303533626208986835613080075985703121250813571733533606272496417145565136129415437696905495272776402217189832840401938243495416339663411171247074920049399475823655320274233156954218768925951056191034134712504572955839404827707329984173302332020201906541083764475690954512308594220997449412380273230046465841574004772512701790771147617828666064344158947341035545499540170260305012929701470776236465507485850428931202947542598396287345703761265310456809232764193204759624931172723676784849010063883831645335627155765372880260543270126668904548807658246837332956745606320439206000827315925297924120517572792956898069837182018081118012502131089972469511003170367875430017874462279301921060156857761490839367431915105478717272782446538831715921363968336746689231345994523668360452657260101103397053499527132362563007397454373813873045156390854348724120700844774879469375150443446048584280930172395926036732129188875719856402864926298810995160417385214470404976503137921156910217010840121652176385776278443131535045190731074843750437867090838446698767945050890489992429995490314062282068159093045161404523458248697227150619981888378435664415174711160595006902423143459075966810454416997061373268370421830924936517791683419258027937814913005585514983905421612991836639607353242591728408919130405601743611335886762255281130983568838120661186537684120574342592819568100284858774281240119689820354838043041113162808407169939503577633814675423251711145297625856010709698328986771681300270753462124431438249079287242299178307352064301908595916689642113630953871478324579363224590054821977720752752434856153962211487647114809252498114236281605836155826301649837304049554058938232508056924063922852025132566569884400145216494747221972532532860069992021237959974546155685028445119102475386567214984215767810803373267199219113161724471869212162578104306058776030926578404910389652192404389117677295835067825022753770320621321736011850304863716204309012040569800028743530750682957857187725797496332806514717356341562788595136219969639265644529365016344351116338283641806458971781098774751480098405354570139783225722233163294120124683588116225556912157809787231837370485212940457115577099959109605532398430813959714213851721154337178339537086640233608391562229893503493649411031401362724533210284028590050377655433375682840029673698157498020943869571637004045326975420227362140674697142027390581797343320575190963092149403833594112151706423118043310372943975783109168287709984495991399458167906285118753395839483377129729549566614285242117269351913253207745257819406658932664711556189413");

        for (int prec = 500; prec <= 3000; prec += 100)
        {
            Apfloat agm = ApfloatMath.agm(new Apfloat(1, prec), new Apfloat(2, prec));

            assertEquals("agm prec " + prec + " precision", prec, agm.precision());
            assertEquals("agm prec " + prec + " value", a.precision(prec), agm, new Apfloat("5e-" + prec));
        }

        for (int prec = 901; prec < 1000; prec++)
        {
            Apfloat agm = ApfloatMath.agm(new Apfloat(1, prec), new Apfloat(2, prec));

            assertEquals("agm prec " + prec + " precision", prec, agm.precision());
            assertEquals("agm prec " + prec + " value", a.precision(prec), agm, new Apfloat("5e-" + prec));
        }

        try
        {
            ApfloatMath.agm(new Apfloat(1.0), new Apfloat(-2.0));
            fail("AGM with complex result accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK; non-real result
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.agm(new Apfloat(1), new Apfloat(2));
            fail("AGM to infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; can't calculate this to infinite precision
            assertEquals("Localization key", "agm.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testFactorial()
    {
        Apfloat result = ApfloatMath.factorial(100, 10);
        assertEquals("value", new Apfloat(9.332621544e157), result, new Apfloat("5e148"));
        assertEquals("precision", 10, result.precision());

        result = ApfloatMath.factorial(10, Apfloat.INFINITE, 16);
        assertEquals("value 16", new Apfloat(0x375F00, Apfloat.DEFAULT, 16), result);
        assertEquals("precision 16", Apfloat.INFINITE, result.precision());

        try
        {
            ApfloatMath.factorial(7, 10, 1);
            fail("Radix 1 accepted");
        }
        catch (NumberFormatException nfe)
        {
            // OK; invalid radix
        }
    }

    public static void testDoubleFactorial()
    {
        Apfloat result = ApfloatMath.doubleFactorial(99, 10);
        assertEquals("value", new Apfloat(2.725392140e78), result, new Apfloat("5e69"));
        assertEquals("precision", 10, result.precision());

        result = ApfloatMath.doubleFactorial(11, Apfloat.INFINITE, 16);
        assertEquals("value 16", new Apfloat(0x289B, Apfloat.DEFAULT, 16), result);
        assertEquals("precision 16", Apfloat.INFINITE, result.precision());

        try
        {
            ApfloatMath.doubleFactorial(7, 10, 1);
            fail("Radix 1 accepted");
        }
        catch (NumberFormatException nfe)
        {
            // OK; invalid radix
        }
    }

    public static void testPi()
    {
        Apfloat pi10 = new Apfloat("3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912983367336244065664308602139494639522473719070217986094370277053921717629317675238467481846766940513200056812714526356082778577134275778960917363717872146844090122495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859502445945534690830264252230825334468503526193118817101000313783875288658753320838142061717766914730359825349042875546873115956286388235378759375195778185778053217122680661300192787661119590921642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151");

        assertEquals("prec 100", pi10.precision(100), ApfloatMath.pi(100), new Apfloat(5e-98));
        assertEquals("prec 1000", pi10, ApfloatMath.pi(1000), new Apfloat("5e-998"));
        assertEquals("prec 500 precision", 500, ApfloatMath.pi(500).precision());
        assertEquals("prec 500 value", pi10.precision(500), ApfloatMath.pi(500));
        assertEquals("prec 50 precision", 50, ApfloatMath.pi(50).precision());
        assertEquals("prec 50 value", pi10.precision(50), ApfloatMath.pi(50));

        assertEquals("base 16", new Apfloat("3.243F6A8885A308D313198A2E03707344A4093822299F31D00", Apfloat.DEFAULT, 16), ApfloatMath.pi(50, 16), new Apfloat(5e-100, 1, 16));

        for (int prec = 1000; prec <= 1100; prec++)
        {
            Apfloat pi = ApfloatMath.pi(prec);

            assertEquals("pi prec " + prec + " precision", prec, pi.precision());
            assertEquals("pi prec " + prec + " value", pi10.precision(prec), pi, new Apfloat("5e-" + (prec - 2)));
        }

        try
        {
            ApfloatMath.pi(0);
            fail("Precision 0 accepted");
        }
        catch (IllegalArgumentException e)
        {
            // OK; invalid precision
        }

        try
        {
            ApfloatMath.pi(Apfloat.INFINITE);
            fail("Infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; invalid precision
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }

        try
        {
            ApfloatMath.pi(50, 1);
            fail("Radix 1 accepted");
        }
        catch (NumberFormatException nfe)
        {
            // OK; invalid radix
        }
    }

    public static void testLog()
    {
        Apfloat a = ApfloatMath.log(new Apfloat(2, 100));
        assertEquals("2, 100 precision", 100, a.precision());
        assertEquals("2, 100 value", new Apfloat("0.693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687"), a, new Apfloat("5e-99"));

        a = ApfloatMath.log(new Apfloat(3, 150, 16));
        assertEquals("3, 150 precision", 150, a.precision());
        assertEquals("3, 150 value", new Apfloat("1.193ea7aad030a976a4198d55053b7cb5be1442d9b7e08df03d97eeea5149358caa9782d20cc698505071f733039a8ed5625c15071ea7bca1cf37d8f11024c66486d094e21e74d0a547df6", Apfloat.DEFAULT, 16), a, ApfloatMath.scale(new Apfloat(5, 1, 16), -148));

        a = ApfloatMath.log(new Apfloat(1, 1, 12));
        assertEquals("1", new Apfloat(0), a);
        assertEquals("1 radix", 12, a.radix());

        a = ApfloatMath.log(new Apfloat("2.71828182845904523536028747135266249775724709369995957496696762772407663035354759457138217852516642"));
        assertEquals("e, 99, precision", 99, a.precision());
        assertEquals("e, 99, value", new Apfloat(1), a, new Apfloat("5e-97"));

        a = ApfloatMath.log(new Apfloat("2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427"));
        assertEquals("e, 100, precision", 100, a.precision());
        assertEquals("e, 100, value", new Apfloat(1), a, new Apfloat("5e-98"));

        a = ApfloatMath.log(new Apfloat("7.38905609893065022723042746057500781318031557055184732408712782252257379607905776338431248507912179"));
        assertEquals("e^2, 99, precision", 99, a.precision());
        assertEquals("e^2, 99, value", new Apfloat(2), a, new Apfloat("5e-98"));

        a = ApfloatMath.log(new Apfloat("7.389056098930650227230427460575007813180315570551847324087127822522573796079057763384312485079121794"));
        assertEquals("e^2, 100, precision", 100, a.precision());
        assertEquals("e^2, 100, value", new Apfloat(2), a, new Apfloat("5e-98"));

        a = ApfloatMath.log(new Apfloat("1.1"));
        assertEquals("1.1, precision", 1, a.precision());

        a = ApfloatMath.log(new Apfloat("1.01"));
        assertEquals("1.01, precision", 1, a.precision());

        a = ApfloatMath.log(new Apfloat("1.1", 3));
        assertEquals("1.1, 3, precision", 2, a.precision());

        a = ApfloatMath.log(new Apfloat("2.567534329783818000500533029709932117494558299117260796421579784603311989535237879614227625064708170e2171472", 100));
        assertEquals("e^5000000, 100 precision", 106, a.precision());
        assertEquals("e^5000000, 100 value", new Apfloat(5000000), a, new Apfloat("5e-99"));

        a = ApfloatMath.log(new Apfloat("3.894787261069254290252471079176073765185215930321023940272302235080330044710873765250549604329029361e-2171473", 100));
        assertEquals("-e^5000000, 100 precision", 100, a.precision());
        assertEquals("-e^5000000, 100 value", new Apfloat(-5000000), a, new Apfloat("5e-92"));

        Apfloat x = new Apfloat("0.693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687542001481020570685733685520235758130557032670751635075961930727570828371435190307038623891673471123350115364497955239120475172681574932065155524734139525882950453007095326366642654104239157814952043740430385500801944170641671518644712839968171784546957026271631064546150257207402481637773389638550695260668341137273873722928956493547025762652098859693201965058554764703306793654432547632744951250406069438147104689946506220167720424524529612687946546193165174681392672504103802546259656869144192871608293803172714367782654877566485085674077648451464439940461422603193096735402574446070308096085047486638523138181676751438667476647890881437141985494231519973548803751658612753529166100071053558249879414729509293113897155998205654392871700072180857610252368892132449713893203784393530887748259701715591070882368362758984258918535302436342143670611892367891923723146723217205340164925687274778234453534");
        a = new Apfloat("-0.3665129205816643270124391582326694694542634478371052630536777136705616153193527385494558228566989083583025230453648347655663425171940646634814655030562792138730255618922699717672286041800832613019942189532855463393890461583132806371040809369384417114396747846899170526422674184027391035004631190422189323680484095772276875435803559664871149188455813202333163965976808249936452933584668462357426343756525369861095695215917735720106501342222449994153507078142297833029637774311970293974350362633156244687655088608994135490709908943039494582566844946811522717063194325489044697564936223469819270466722804100902961886880218201749101992361055490535324877585339998097074377916278218193441996319021050429330124241505927926809754056140292099176158224802342090188412736812269321284034933052507728909167575791393588626671908786468115956639594429979580206395481395923027937867469315592027193309322415124007731716247058993690703827533513739231800701041955722130456332586628947326070184882339110039410732806653401");

        for (int prec = 500; prec <= 800; prec += 100)
        {
            Apfloat log = ApfloatMath.log(x.precision(prec));

            assertEquals("log(log2) prec " + prec + " precision", prec, log.precision());
            assertEquals("log(log2) prec " + prec + " value", a.precision(prec), log, new Apfloat("5e-" + prec));
        }

        for (int prec = 900; prec <= 1000; prec++)
        {
            Apfloat log = ApfloatMath.log(x.precision(prec));

            // NOTE: EXTRA ALLOWED ERROR NEEDED FOR CASE prec=1000
            assertEquals("log(log2) prec " + prec + " precision", prec, log.precision());
            assertEquals("log(log2) prec " + prec + " value", a.precision(prec), log, new Apfloat("11e-" + prec));
        }

        a = new Apfloat("0.6931471805599453094172321214581765680755001343602552541206800094933936219696947156058633269964186875420014810205706857336855202357581305570326707516350759619307275708283714351903070386238916734711233501153644979552391204751726815749320651555247341395258829504530070953263666426541042391578149520437404303855008019441706416715186447128399681717845469570262716310645461502572074024816377733896385506952606683411372738737229289564935470257626520988596932019650585547647033067936544325476327449512504060694381471046899465062201677204245245296126879465461931651746813926725041038025462596568691441928716082938031727143677826548775664850856740776484514644399404614226031930967354025744460703080960850474866385231381816767514386674766478908814371419854942315199735488037516586127535291661000710535582498794147295092931138971559982056543928717000721808576102523688921324497138932037843935308877482597017155910708823683627589842589185353024363421436706118923678919237231467232172053401649256872747782344535347648114941864238677677440606956265737960086707625719918473402265146283790488306203306114463007371949");

        for (int prec = 1000; prec <= 1100; prec++)
        {
            Apfloat log = ApfloatMath.log(new Apfloat(2, prec));

            assertEquals("log(2) prec " + prec + " precision", prec, log.precision());
            assertEquals("log(2) prec " + prec + " value", a.precision(prec), log, new Apfloat("5e-" + prec));
        }

        try
        {
            ApfloatMath.log(new Apfloat(0));
            fail("log of zero accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK; result would be -infinite
            assertEquals("Localization key", "log.ofZero", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.log(new Apfloat(-1));
            fail("log of -1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK; result would be complex
            assertEquals("Localization key", "log.ofNegative", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.log(new Apfloat(2));
            fail("log to infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; can't calculate this to infinite precision
            assertEquals("Localization key", "log.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testLogBase()
    {
        Apfloat a = ApfloatMath.log(new Apfloat(4, 100), new Apfloat(2, 100));
        assertEquals("4 base 2, precision 100", 100, a.precision());
        assertEquals("4 base 2, value", new Apfloat(2), a, new Apfloat("5e-99"));

        a = ApfloatMath.log(new Apfloat(8, 400), new Apfloat(2, 200));
        assertEquals("4 base 2, precision 200", 200, a.precision());
        assertEquals("4 base 2, value", new Apfloat(3), a, new Apfloat("5e-199"));

        a = ApfloatMath.log(new Apfloat(16, 300), new Apfloat(2, 600));
        assertEquals("4 base 2, precision 300", 300, a.precision());
        assertEquals("4 base 2, value", new Apfloat(4), a, new Apfloat("5e-299"));

        a = ApfloatMath.log(new Apfloat(16, 400), new Apfloat(2));
        assertEquals("4 base 2, precision 400", 400, a.precision());
        assertEquals("4 base 2, value", new Apfloat(4), a, new Apfloat("5e-399"));

        a = ApfloatMath.log(new Apfloat(16), new Apfloat(2, 500));
        assertEquals("4 base 2, precision 500", 500, a.precision());
        assertEquals("4 base 2, value", new Apfloat(4), a, new Apfloat("5e-499"));

        a = ApfloatMath.log(new Apfloat(2, 5), new Apfloat("1.01", 7));
        assertEquals("2 base 1.01, precision", 5, a.precision());
        assertEquals("2 base 1.01, value", new Apfloat("69.661"), a, new Apfloat("5e-3"));

        a = ApfloatMath.log(new Apfloat("1.01", 7), new Apfloat(2, 5));
        assertEquals("1.01 base 2, precision", 5, a.precision());
        assertEquals("1.01 base 2, value", new Apfloat("0.014355"), a, new Apfloat("5e-6"));
    }

    public static void testExp()
    {
        Apfloat a = ApfloatMath.exp(new Apfloat(2, 100));
        assertEquals("2, 100 precision", 100, a.precision());
        assertEquals("2, 100 value", new Apfloat("7.389056098930650227230427460575007813180315570551847324087127822522573796079057763384312485079121794"), a, new Apfloat("5e-98"));

        a = ApfloatMath.exp(new Apfloat(3, 150, 16));
        assertEquals("3, 150 precision", 150, a.precision());
        assertEquals("3, 150 value", new Apfloat("14.15E5BF6FB105F2D4BDFC53744C3A390585839728AA90A12389790C837E6FF2A68ABFE2D58DAFA5273C74EB175B9D0BD5584DFC81BE96F62CE66F428A2A50FFCBDF4083E8EE811BE42F", Apfloat.DEFAULT, 16), a, ApfloatMath.scale(new Apfloat(5, 1, 16), -147));

        a = ApfloatMath.exp(new Apfloat(0, 1, 17));
        assertEquals("1 radix", 17, a.radix());
        assertEquals("1 prec", Apfloat.INFINITE, a.precision());
        assertEquals("1 value", new Apfloat(1), a);

        a = ApfloatMath.exp(new Apfloat("0.1"));
        assertEquals("0.1, precision", 2, a.precision());

        a = ApfloatMath.exp(new Apfloat("0.01"));
        assertEquals("0.01, precision", 3, a.precision());

        a = ApfloatMath.exp(new Apfloat("0.1", 2));
        assertEquals("0.1, 2, precision", 3, a.precision());

        a = ApfloatMath.exp(new Apfloat("1e-10", 32));
        assertEquals("1e-10", new Apfloat("1.0000000001000000000050000000002"), a, new Apfloat("5e-31"));

        //a = ApfloatMath.exp(new Apfloat("1e" + Long.MIN_VALUE / 3 * 2));
        //assertEquals("1e-2/3MIN", new Apfloat(1), a);

        a = ApfloatMath.exp(new Apfloat(5000000, 21));
        assertEquals("5000000, 15 precision", 15, a.precision());
        assertEquals("5000000, 15 value", new Apfloat("2.56753432978382e2171472"), a, new Apfloat("5e2171458"));

        a = ApfloatMath.exp(new Apfloat(5000000, 106));
        assertEquals("5000000, 100 precision", 100, a.precision());
        assertEquals("5000000, 100 value", new Apfloat("2.567534329783818000500533029709932117494558299117260796421579784603311989535237879614227625064708170e2171472"), a, new Apfloat("5e2171373"));

        a = ApfloatMath.exp(new Apfloat(-5000000, 106));
        assertEquals("-5000000, 100 precision", 100, a.precision());
        assertEquals("-5000000, 100 value", new Apfloat("3.894787261069254290252471079176073765185215930321023940272302235080330044710873765250549604329029361e-2171473"), a, new Apfloat("5e-2171572"));

        a = ApfloatMath.exp(new Apfloat("-1e25", 50));
        assertEquals("-1e25, 50 value", new Apfloat(0), a);

        a = ApfloatMath.exp(new Apfloat("-1e25"));
        assertEquals("-1e25, 1 value", new Apfloat(0), a);

        a = ApfloatMath.exp(new Apfloat("-1e25", Apfloat.INFINITE));
        assertEquals("-1e25, infinite value", new Apfloat(0), a);

        a = ApfloatMath.exp(new Apfloat("-21237598959199934509.830775042768"));
        assertEquals("-21237598959199934509.830775042768 value", new Apfloat(0), a);

        // How to compute this with some other tool:
        // exp(-2.123759895919992e19) = exp(-21237598959199920000) = exp(-2737330 * 2304964 * 3366000)
        // = (exp(-2737330) ^ 2304964) ^ 3366000
        // = ((4.8512289541615048587 * 10 ^ -1188808) ^ 2304964) ^ 3366000
        // = (4.8512289541615048587 ^ 2304964 * 10 ^ (-1188808 * 2304964)) ^ 3366000
        // = (4.3958838520520181922 * 10 ^ 1580863 * 10 ^ (-1188808 * 2304964)) ^ 3366000
        // = (4.3958838520520181922 * 10 ^ (1580863 + (-1188808 * 2304964)) ^ 3366000
        // = 4.3958838520520181922 ^ 3366000 * 10 ^ ((1580863 + (-1188808 * 2304964)) * 3366000)
        // = 3.4628920318050121308 * 10 ^ 2164493 * 10 ^ ((1580863 + (-1188808 * 2304964)) * 3366000)
        // = 3.4628920318050121308 * 10 ^ (2164493 + (1580863 + (-1188808 * 2304964)) * 3366000)
        // = 3.4628920318050121308 * 10 ^ -9223372036854769507
        a = ApfloatMath.exp(new Apfloat("-2.1237598959199920000000000000000000e19"));
        assertEquals("-2.123759895919992e19 precision", 16, a.precision());
        assertEquals("-2.123759895919992e19 value", new Apfloat("3.462892031805012e-9223372036854769507"), a, new Apfloat("5e-9223372036854769491"));

        a = ApfloatMath.exp(new Apfloat("-100000000000000000000", 30, 17));
        assertEquals("underflow radix", 17, a.radix());
        assertEquals("underflow prec", Apfloat.INFINITE, a.precision());
        assertEquals("underflow value", new Apfloat(0), a);

        a = new Apfloat("2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932003059921817413596629043572900334295260595630738132328627943490763233829880753195251019011573834187930702154089149934884167509244761460668082264800168477411853742345442437107539077744992069551702761838606261331384583000752044933826560297606737113200709328709127443747047230696977209310141692836819025515108657463772111252389784425056953696770785449969967946864454905987931636889230098793127736178215424999229576351482208269895193668033182528869398496465105820939239829488793320362509443117301238197068416140397019837679320683282376464804295311802328782509819455815301756717361332069811250996181881593041690351598888519345807273866738589422879228499892086805825749279610484198444363463244968487560233624827041978623209002160990235304369941849146314093431738143640546253152096183690888707016768396424378140592714563549061303107208510383750510115747704171898610687396965521267154688957035035");

        for (int prec = 500; prec <= 800; prec += 100)
        {
            Apfloat exp = ApfloatMath.exp(new Apfloat(1, prec));

            assertEquals("exp prec " + prec + " precision", prec, exp.precision());
            assertEquals("exp prec " + prec + " value", a.precision(prec), exp, new Apfloat("5e-" + (prec - 1)));
        }

        for (int prec = 900; prec <= 1000; prec++)
        {
            Apfloat exp = ApfloatMath.exp(new Apfloat(1, prec));

            assertEquals("exp prec " + prec + " precision", prec, exp.precision());
            assertEquals("exp prec " + prec + " value", a.precision(prec), exp, new Apfloat("5e-" + (prec - 1)));
        }

        try
        {
            ApfloatMath.exp(new Apfloat("50000000000000000000", 500000000));
            fail("Overflow should have occurred");
        }
        catch (OverflowException oe)
        {
            // OK; result would overflow
            assertEquals("Localization key", "overflow", oe.getLocalizationKey());
        }

        try
        {
            ApfloatMath.exp(new Apfloat(2));
            fail("exp to infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; can't calculate this to infinite precision
            assertEquals("Localization key", "exp.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testPow()
    {
        Apfloat a = ApfloatMath.pow(new Apfloat(2, 100), new Apfloat("0.5", 100));
        assertEquals("2, 100 precision", 100, a.precision(), 1);
        assertEquals("2, 100 value", new Apfloat("1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573"), a, new Apfloat("5e-98"));

        a = new Apfloat("1.193EA7AAD030A976A4198D55053B7CB5BE1442D9B7E08DF03D97EEEA5149358CAA9782D20CC698505071F733039A8ED5625C15071EA7BCA1CF37D8F11024C66486D094E21E74D0A547DF6", 150, 16);
        a = ApfloatMath.pow(a, a);
        assertEquals("3, 150 precision", 150, a.precision(), 1);
        assertEquals("3, 150 value", new Apfloat("1.1BDD7EF9BE61C2CAB36ED12BED65238AFAC02791331A39420E85923B550F899BC353D7408E2B07B374E294888A03E98DCBF9B55433D064C6D28E005F42ED02FAD35AC14C5E4A2E1F30AD8", Apfloat.DEFAULT, 16), a, ApfloatMath.scale(new Apfloat(5, 1, 16), -148));

        a = ApfloatMath.pow(new Apfloat(2), new Apfloat(0));
        assertEquals("2^0", new Apfloat(1), a);

        a = ApfloatMath.pow(new Apfloat(2), new Apfloat(1));
        assertEquals("2^1", new Apfloat(2), a);

        a = ApfloatMath.pow(new Apfloat(0), new Apfloat(2));
        assertEquals("0^2", new Apfloat(0), a);

        a = ApfloatMath.pow(new Apfloat(0), new Apfloat("0.1"));
        assertEquals("0^0.1", new Apfloat(0), a);

        a = ApfloatMath.pow(new Apfloat(1), new Apfloat(2));
        assertEquals("1^2", new Apfloat(1), a);

        a = ApfloatMath.pow(new Apfloat("-3.21000"), new Apfloat("-2.00000"));
        assertEquals("-3.21^-2.00 precision", 6, a.precision());
        assertEquals("-3.21^-2.00 value", new Apfloat("0.0970487"), a, new Apfloat("5e-7"));

        a = ApfloatMath.pow(new Apfloat("-1.000000000000000000000000000010000000000"), new Apfloat("1.000000000000000000000000000000000000000e20"));
        assertEquals("-1.00000000000000000000000000001^1e20 precision", 20, a.precision());
        assertEquals("-1.00000000000000000000000000001^1e20 value", new Apfloat("1.0000000010000000000"), a, new Apfloat("5e-19"));

        try
        {
            ApfloatMath.pow(new Apfloat("1.2"), new Apfloat("57"));
        }
        catch (LossOfPrecisionException lope)
        {
            // OK
            assertEquals("Localization key", "lossOfPrecision", lope.getLocalizationKey());
        }

        a = ApfloatMath.pow(new Apfloat("1.02"), new Apfloat("57"));
        assertEquals("1.02^57, precision", 1, a.precision());

        a = ApfloatMath.pow(new Apfloat("1.2"), new Apfloat("1.0"));
        assertEquals("1.2^1.0, precision", 2, a.precision());

        a = ApfloatMath.pow(new Apfloat("1.2"), new Apfloat("1"));
        assertEquals("1.2^1, precision", 1, a.precision());

        a = ApfloatMath.pow(new Apfloat("1.02"), new Apfloat("1.00"));
        assertEquals("1.02^1.00, precision", 3, a.precision());

        a = ApfloatMath.pow(new Apfloat("1.02"), new Apfloat("1"));
        assertEquals("1.02^1, precision", 1, a.precision());

        a = ApfloatMath.pow(new Apfloat("1.2"), new Apfloat("0.01"));
        assertEquals("1.2^0.01, precision", 4, a.precision());

        a = ApfloatMath.pow(new Apfloat("1.02"), new Apfloat("0.01"));
        assertEquals("1.02^0.01, precision", 5, a.precision());

        a = ApfloatMath.pow(new Apfloat("12312312342343245234234.4554123", 100), new Apfloat("432.243245234", 100));
        assertEquals("12312312342343245234234.4554123^432.243245234, precision", 96, a.precision());
        assertEquals("12312312342343245234234.4554123^432.243245234, value", new Apfloat("2.51239266531220414856835532497217396556903456254971203012293241477748612273092084132746823767646e9548"), a, new Apfloat("5e9453"));

        Apfloat x = new Apfloat("0.693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687542001481020570685733685520235758130557032670751635075961930727570828371435190307038623891673471123350115364497955239120475172681574932065155524734139525882950453007095326366642654104239157814952043740430385500801944170641671518644712839968171784546957026271631064546150257207402481637773389638550695260668341137273873722928956493547025762652098859693201965058554764703306793654432547632744951250406069438147104689946506220167720424524529612687946546193165174681392672504103802546259656869144192871608293803172714367782654877566485085674077648451464439940461422603193096735402574446070308096085047486638523138181676751438667476647890881437141985494231519973548803751658612753529166100071053558249879414729509293113897155998205654392871700072180857610252368892132449713893203784393530887748259701715591070882368362758984258918535302436342143670611892367891923723146723217205340164925687274778234453534"),
                y = new Apfloat("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420198");
        a = new Apfloat("0.316182943197044690614169268497792885452164361693051710732667324268823185192218337501840769380849175934963329367241486177119992719972036535656516370698214957622438377784029981033223873271141421939813138295037738564766790036552697116686100077566696580000839312315156298008831180831582540185037993133224966864508908869785121857911552089207739673945009998248291357701939332415732827372723670347306280056437522519983428006474751126018076658937443328965140553449786853150070311258642464494464377283951772289329403314138401969945114622833848835745934222479165579350121531744358768058822541639234759395945505389376644705555314322615751906758924387381898831546019383916458560077972932084527603542042873539826316621369800590919207282064653521206479549258209266902697520830020862834814623634525867254396928645227883965555367571830849867301421792625669502862980792359748616959118702882311710152741878652879534809041570410154075983958637237380877034358236840420087080482174290845507248144579739353309032206160873");

        for (int prec = 500; prec <= 800; prec += 100)
        {
            Apfloat pow = ApfloatMath.pow(x.precision(prec), y.precision(prec));

            assertEquals("pow prec " + prec + " precision", prec, pow.precision());
            assertEquals("pow prec " + prec + " value", a.precision(prec), pow, new Apfloat("5e-" + prec));
        }

        for (int prec = 900; prec <= 1000; prec++)
        {
            Apfloat pow = ApfloatMath.pow(x.precision(prec), y.precision(prec));

            // NOTE: EXTRA ALLOWED ERROR NEEDED FOR CASE prec=1000
            assertEquals("pow prec " + prec + " precision", prec, pow.precision());
            assertEquals("pow prec " + prec + " value", a.precision(prec), pow, new Apfloat("10e-" + prec));
        }

        try
        {
            ApfloatMath.pow(new Apfloat(0), new Apfloat(0));
            fail("0^0 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK; result would be undefined
            assertEquals("Localization key", "pow.zeroToZero", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.pow(new Apfloat(0), new Apfloat("-1.0"));
            fail("0^-1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK; result would be undefined
            assertEquals("Localization key", "pow.zeroToNegative", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.pow(new Apfloat(0), new Apfloat("-1.5"));
            fail("0^-1.5 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK; result would be undefined
            assertEquals("Localization key", "pow.zeroToNegative", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.pow(new Apfloat(0), new Apfloat("-2.0"));
            fail("0^-2 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK; result would be undefined
            assertEquals("Localization key", "pow.zeroToNegative", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.pow(new Apfloat(100, 100), new Apfloat(5000000000000000000L, 100));
            fail("Overflow should have occurred");
        }
        catch (OverflowException oe)
        {
            // OK; result would overflow
            assertEquals("Localization key", "overflow", oe.getLocalizationKey());
        }

        try
        {
            ApfloatMath.pow(new Apfloat(-2), new Apfloat("1.3"));
            fail("pow of negative number accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK; result would be complex
            assertEquals("Localization key", "pow.negativeToNonInteger", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.pow(new Apfloat(3), new Apfloat(-1));
            fail("pow to infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; can't calculate this to infinite precision
            assertEquals("Localization key", "pow.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testAcosh()
    {
        Apfloat a = ApfloatMath.acosh(new Apfloat(2, 100));
        assertEquals("2, 100 precision", 100, a.precision(), 1);
        assertEquals("2, 100 value", new Apfloat("1.316957896924816708625046347307968444026981971467516479768472256920460185416443976074219013450101783"), a, new Apfloat("5e-98"));

        a = ApfloatMath.acosh(new Apfloat("1e5000000", 94));
        assertEquals("1e5000000, 100 precision", 100, a.precision(), 1);
        assertEquals("1e5000000, 100 value", new Apfloat("11512926.158117408980035266690653942496182075518643999240421893625517872541780384370874701631311318488"), a, new Apfloat("5e-91"));

        a = ApfloatMath.acosh(new Apfloat(1, 100));
        assertEquals("1, 100 value", new Apfloat(0), a);

        try
        {
            ApfloatMath.acosh(new Apfloat("0"));
            fail("acosh(0) accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK; result would be complex
            assertEquals("Localization key", "root.evenOfNegative", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.acosh(new Apfloat("0.9"));
            fail("acosh(0.9) accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK; result would be complex
            assertEquals("Localization key", "root.evenOfNegative", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.acosh(new Apfloat("-0.5"));
            fail("acosh(-0.5) accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK; result would be complex
            assertEquals("Localization key", "root.evenOfNegative", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.acosh(new Apfloat(2));
            fail("Infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; can't calculate this to infinite precision
            assertEquals("Localization key", "inverseRoot.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testAsinh()
    {
        Apfloat a = ApfloatMath.asinh(new Apfloat(2, 100));
        assertEquals("2, 100 precision", 100, a.precision(), 1);
        assertEquals("2, 100 value", new Apfloat("1.443635475178810342493276740273105269405553003156981558983054506520491602824665323236028287368170425"), a, new Apfloat("5e-98"));

        a = ApfloatMath.asinh(new Apfloat(-2, 100));
        assertEquals("-2, 100 precision", 100, a.precision(), 1);
        assertEquals("-2, 100 value", new Apfloat("-1.443635475178810342493276740273105269405553003156981558983054506520491602824665323236028287368170425"), a, new Apfloat("5e-98"));

        a = ApfloatMath.asinh(new Apfloat("1e5000000", 94));
        assertEquals("1e5000000, 100 precision", 100, a.precision(), 1);
        assertEquals("1e5000000, 100 value", new Apfloat("11512926.158117408980035266690653942496182075518643999240421893625517872541780384370874701631311318488"), a, new Apfloat("5e-91"));

        a = ApfloatMath.asinh(new Apfloat(0));
        assertEquals("0, 100 value", new Apfloat(0), a);

        try
        {
            ApfloatMath.asinh(new Apfloat(2));
            fail("Infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; can't calculate this to infinite precision
            assertEquals("Localization key", "inverseRoot.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testAtanh()
    {
        Apfloat a = ApfloatMath.atanh(new Apfloat("0.5", 100));
        assertEquals("0.5, 100 precision", 100, a.precision(), 1);
        assertEquals("0.5, 100 value", new Apfloat("0.5493061443340548456976226184612628523237452789113747258673471668187471466093044834368078774068660444"), a, new Apfloat("5e-99"));

        a = ApfloatMath.atanh(new Apfloat("-0.5", 100));
        assertEquals("-0.5, 100 precision", 100, a.precision(), 1);
        assertEquals("-0.5, 100 value", new Apfloat("-0.5493061443340548456976226184612628523237452789113747258673471668187471466093044834368078774068660444"), a, new Apfloat("5e-99"));

        a = ApfloatMath.atanh(new Apfloat(0));
        assertEquals("0, 100 value", new Apfloat(0), a);

        try
        {
            ApfloatMath.atanh(new Apfloat("1"));
            fail("atanh(1) accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK; result would be infinite
            assertEquals("Localization key", "divide.byZero", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.atanh(new Apfloat("-1"));
            fail("atanh(-1) accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK; result would be infinite
            assertEquals("Localization key", "log.ofZero", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.atanh(new Apfloat("0.5", Apfloat.INFINITE));
            fail("Infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; can't calculate this to infinite precision
            assertEquals("Localization key", "log.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testCosh()
    {
        Apfloat a = ApfloatMath.cosh(new Apfloat(2, 100));
        assertEquals("2, 100 precision", 100, a.precision(), 1);
        assertEquals("2, 100 value", new Apfloat("3.7621956910836314595622134777737461082939735582307116027776433475883235850902727266607053037848894217"), a, new Apfloat("5e-98"));

        a = ApfloatMath.cosh(new Apfloat(-2, 100));
        assertEquals("-2, 100 precision", 100, a.precision(), 1);
        assertEquals("-2, 100 value", new Apfloat("3.7621956910836314595622134777737461082939735582307116027776433475883235850902727266607053037848894217"), a, new Apfloat("5e-98"));

        a = ApfloatMath.cosh(new Apfloat(5000000, 106));
        assertEquals("5000000, 100 precision", 100, a.precision(), 1);
        assertEquals("5000000, 100 value", new Apfloat("1.283767164891909000250266514854966058747279149558630398210789892301655994767618939807113812532354085e2171472"), a, new Apfloat("5e2171372"));

        a = ApfloatMath.cosh(new Apfloat(0));
        assertEquals("0, 100 value", new Apfloat(1), a);

        try
        {
            ApfloatMath.cosh(new Apfloat(1));
            fail("Infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; can't calculate this to infinite precision
            assertEquals("Localization key", "exp.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testSinh()
    {
        Apfloat a = ApfloatMath.sinh(new Apfloat(2, 100));
        assertEquals("2, 100 precision", 100, a.precision(), 1);
        assertEquals("2, 100 value", new Apfloat("3.626860407847018767668213982801261704886342012321135721309484474934250210988785036723607181294232373"), a, new Apfloat("5e-98"));

        a = ApfloatMath.sinh(new Apfloat(-2, 100));
        assertEquals("-2, 100 precision", 100, a.precision(), 1);
        assertEquals("-2, 100 value", new Apfloat("-3.626860407847018767668213982801261704886342012321135721309484474934250210988785036723607181294232373"), a, new Apfloat("5e-98"));

        a = ApfloatMath.sinh(new Apfloat(5000000, 106));
        assertEquals("5000000, 100 precision", 100, a.precision(), 1);
        assertEquals("5000000, 100 value", new Apfloat("1.283767164891909000250266514854966058747279149558630398210789892301655994767618939807113812532354085e2171472"), a, new Apfloat("5e2171372"));

        a = ApfloatMath.sinh(new Apfloat(0));
        assertEquals("0, 100 value", new Apfloat(0), a);

        try
        {
            ApfloatMath.sinh(new Apfloat(1));
            fail("Infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; can't calculate this to infinite precision
            assertEquals("Localization key", "exp.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testTanh()
    {
        Apfloat a = ApfloatMath.tanh(new Apfloat(2, 100));
        assertEquals("2, 100 precision", 100, a.precision(), 1);
        assertEquals("2, 100 value", new Apfloat("0.96402758007581688394641372410092315025502997624093477604826321741310794631761020255947485004520768915"), a, new Apfloat("5e-99"));

        a = ApfloatMath.tanh(new Apfloat(-2, 100));
        assertEquals("-2, 100 precision", 100, a.precision(), 1);
        assertEquals("-2, 100 value", new Apfloat("-0.96402758007581688394641372410092315025502997624093477604826321741310794631761020255947485004520768915"), a, new Apfloat("5e-99"));

        a = ApfloatMath.tanh(new Apfloat(5000000, 100));
        assertEquals("5000000, 100 precision", 4343037, a.precision(), 1);
        assertEquals("5000000, 100 value", new Apfloat(1).subtract(new Apfloat("3.03387356179746871517892756452203249280217116298171287391802587502345779082540217305405121824e-4342945")), a, new Apfloat("5e-4343037"));

        a = ApfloatMath.tanh(new Apfloat(0));
        assertEquals("0, 100 value", new Apfloat(0), a);

        try
        {
            ApfloatMath.tanh(new Apfloat(1));
            fail("Infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; can't calculate this to infinite precision
            assertEquals("Localization key", "exp.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testAcos()
    {
        Apfloat a = ApfloatMath.acos(new Apfloat("0.5", 100));
        assertEquals("0.5, 100 precision", 100, a.precision(), 1);
        assertEquals("0.5, 100 value", new Apfloat("1.04719755119659774615421446109316762806572313312503527365831486410260546876206966620934494178070569"), a, new Apfloat("5e-98"));

        a = ApfloatMath.acos(new Apfloat("-0.5", 100));
        assertEquals("-0.5, 100 precision", 100, a.precision(), 1);
        assertEquals("-0.5, 100 value", new Apfloat("2.09439510239319549230842892218633525613144626625007054731662972820521093752413933241868988356141138"), a, new Apfloat("5e-98"));

        a = ApfloatMath.acos(new Apfloat("1e-100"));
        assertEquals("0, 100 precision", 100, a.precision(), 1);
        assertEquals("0, 100 value", new Apfloat("1.57079632679489661923132169163975144209858469968755291048747229615390820314310449931401741267105853"), a, new Apfloat("5e-98"));

        a = ApfloatMath.acos(new Apfloat(1, 100));
        assertEquals("1, 100 value", new Apfloat(0), a);

        try
        {
            ApfloatMath.acos(new Apfloat(0));
            fail("acos(0) accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; result would have infinite precision
            assertEquals("Localization key", "log.infinitePrecision", iee.getLocalizationKey());
        }

        try
        {
            ApfloatMath.acos(new Apfloat("1.1"));
            fail("acos(1.1) accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK; result would be complex
            assertEquals("Localization key", "root.evenOfNegative", aae.getLocalizationKey());
        }
    }

    public static void testAsin()
    {
        Apfloat a = ApfloatMath.asin(new Apfloat("0.5", 100));
        assertEquals("0.5, 100 precision", 100, a.precision(), 1);
        assertEquals("0.5, 100 value", new Apfloat("0.5235987755982988730771072305465838140328615665625176368291574320513027343810348331046724708903528447"), a, new Apfloat("5e-99"));

        a = ApfloatMath.asin(new Apfloat("-0.5", 100));
        assertEquals("-0.5, 100 precision", 100, a.precision(), 1);
        assertEquals("-0.5, 100 value", new Apfloat("-0.5235987755982988730771072305465838140328615665625176368291574320513027343810348331046724708903528447"), a, new Apfloat("5e-99"));

        a = ApfloatMath.asin(new Apfloat("0.00001", 100));
        assertEquals("0.00001, 100 precision", 100, a.precision(), 1);
        assertEquals("0.00001, 100 value", new Apfloat("0.00001000000000016666666667416666666711309523812562003968477689844894697641769350752329383472276925426623"), a, new Apfloat("5e-103"));

        a = ApfloatMath.asin(new Apfloat(1, 100));
        assertEquals("1, 100 precision", 100, a.precision(), 1);
        assertEquals("1, 100 value", new Apfloat("1.57079632679489661923132169163975144209858469968755291048747229615390820314310449931401741267105853"), a, new Apfloat("5e-98"));

        a = ApfloatMath.asin(new Apfloat(0));
        assertEquals("0, 100 value", new Apfloat(0), a);

        try
        {
            ApfloatMath.asin(new Apfloat("1.1"));
            fail("asin(1.1) accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK; result would be complex
            assertEquals("Localization key", "root.evenOfNegative", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.asin(new Apfloat(1));
            fail("Infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; result would have infinite precision
            assertEquals("Localization key", "log.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testAtan()
    {
        Apfloat a = ApfloatMath.atan(new Apfloat("0.5", 100));
        assertEquals("0.5, 100 precision", 100, a.precision(), 1);
        assertEquals("0.5, 100 value", new Apfloat("0.4636476090008061162142562314612144020285370542861202638109330887201978641657417053006002839848878926"), a, new Apfloat("5e-99"));

        a = ApfloatMath.atan(new Apfloat("-0.5", 100));
        assertEquals("-0.5, 100 precision", 100, a.precision(), 1);
        assertEquals("-0.5, 100 value", new Apfloat("-0.4636476090008061162142562314612144020285370542861202638109330887201978641657417053006002839848878926"), a, new Apfloat("5e-99"));

        a = ApfloatMath.atan(new Apfloat(0));
        assertEquals("0, 100 value", new Apfloat(0), a);

        try
        {
            ApfloatMath.atan(new Apfloat(1));
            fail("Infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; result would have infinite precision
            assertEquals("Localization key", "log.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testAtan2()
    {
        Apfloat a = ApfloatMath.atan2(new Apfloat(0), new Apfloat(2, 20));
        assertEquals("0,2 value", new Apfloat(0), a);

        a = ApfloatMath.atan2(new Apfloat(2, 20), new Apfloat(2, 20));
        assertEquals("2,2 precision", 20, a.precision(), 1);
        assertEquals("2,2 value", new Apfloat("0.78539816339744830962"), a, new Apfloat("5e-20"));

        a = ApfloatMath.atan2(new Apfloat(2, 20), new Apfloat(0));
        assertEquals("2,0 precision", 20, a.precision());
        assertEquals("2,0 value", new Apfloat("1.5707963267948966192"), a, new Apfloat("5e-19"));

        a = ApfloatMath.atan2(new Apfloat(2, 20), new Apfloat(-2, 20));
        assertEquals("2,-2 precision", 20, a.precision(), 1);
        assertEquals("2,-2 value", new Apfloat("2.3561944901923449288"), a, new Apfloat("5e-19"));

        a = ApfloatMath.atan2(new Apfloat(0), new Apfloat(-2, 20));
        assertEquals("0,-2 precision", 20, a.precision());
        assertEquals("0,-2 value", new Apfloat("3.1415926535897932385"), a, new Apfloat("5e-19"));

        a = ApfloatMath.atan2(new Apfloat(-2, 20), new Apfloat(2, 20));
        assertEquals("-2,2 precision", 20, a.precision(), 1);
        assertEquals("-2,2 value", new Apfloat("-0.78539816339744830962"), a, new Apfloat("5e-20"));

        a = ApfloatMath.atan2(new Apfloat(-2, 20), new Apfloat(0));
        assertEquals("-2,0 precision", 20, a.precision(), 1);
        assertEquals("-2,0 value", new Apfloat("-1.5707963267948966192"), a, new Apfloat("5e-19"));

        a = ApfloatMath.atan2(new Apfloat(-2, 20), new Apfloat(-2, 20));
        assertEquals("-2,-2 precision", 20, a.precision(), 1);
        assertEquals("-2,-2 value", new Apfloat("-2.3561944901923449288"), a, new Apfloat("5e-19"));

        a = ApfloatMath.atan2(new Apfloat(2, 20), new Apfloat(3, 20));
        assertEquals("2,3 precision", 20, a.precision(), 1);
        assertEquals("2,3 value", new Apfloat("0.58800260354756755125"), a, new Apfloat("5e-20"));

        a = ApfloatMath.atan2(new Apfloat("6.618533197939224e-13"), new Apfloat("0.9999999966650702"));
        assertEquals("6.618533197939224e-13,0.9999999966650702 precision", 16, a.precision(), 1);
        assertEquals("6.618533197939224e-13,0.9999999966650702 value", new Apfloat("6.61853322001157e-13"), a, new Apfloat("5e-27"));

        a = ApfloatMath.atan2(new Apfloat("-6.618533197939224e-13"), new Apfloat("0.9999999966650702"));
        assertEquals("-6.618533197939224e-13,0.9999999966650702 precision", 16, a.precision(), 1);
        assertEquals("-6.618533197939224e-13,0.9999999966650702 value", new Apfloat("-6.61853322001157e-13"), a, new Apfloat("5e-27"));

        a = ApfloatMath.atan2(new Apfloat(0, 1, 12), new Apfloat(2, 20, 12));
        assertEquals("0,2 radix", 12, a.radix());

        try
        {
            ApfloatMath.atan2(new Apfloat(0), new Apfloat(0));
            fail("atan2(0,0) accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK; result would be undefined
            assertEquals("Localization key", "atan2.ofOrigin", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.atan2(new Apfloat(2), new Apfloat(3));
            fail("atan2 to infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; result would have infinite precision
            assertEquals("Localization key", "atan2.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testCos()
    {
        Apfloat a = ApfloatMath.cos(new Apfloat(1, 100));
        assertEquals("1, 100 precision", 100, a.precision(), 1);
        assertEquals("1, 100 value", new Apfloat("0.5403023058681397174009366074429766037323104206179222276700972553811003947744717645179518560871830893"), a, new Apfloat("5e-99"));

        a = ApfloatMath.cos(new Apfloat(-1, 100));
        assertEquals("-1, 100 precision", 100, a.precision(), 1);
        assertEquals("-1, 100 value", new Apfloat("0.5403023058681397174009366074429766037323104206179222276700972553811003947744717645179518560871830893"), a, new Apfloat("5e-99"));

        a = ApfloatMath.cos(new Apfloat("3141592653589793239.462643383"));
        assertEquals("1e18pi + 1 precision", 10, a.precision(), 1);
        assertEquals("1e18pi + 1 value", new Apfloat("0.5403023058"), a, new Apfloat("5e-10"));

        a = ApfloatMath.cos(new Apfloat("1e-10", 32));
        assertEquals("1e-10 prec 32 value", new Apfloat("0.99999999999999999999500000000000"), a, new Apfloat("5e-32"));

        a = ApfloatMath.cos(new Apfloat("1e-10", 3));
        assertEquals("1e-10 prec 3 value", new Apfloat("0.99999999999999999999500"), a, new Apfloat("5e-23"));

        a = ApfloatMath.cos(new Apfloat(0));
        assertEquals("0, 100 value", new Apfloat(1), a);

        try
        {
            ApfloatMath.cos(new Apfloat(1000, 3));
            fail("cos(1000 prec 3) accepted");
        }
        catch (LossOfPrecisionException lope)
        {
            // OK; loss of precision
            assertEquals("Localization key", "imag.lossOfPrecision", lope.getLocalizationKey());
        }

        try
        {
            ApfloatMath.cos(new Apfloat(1));
            fail("Infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; result would have infinite precision
            assertEquals("Localization key", "exp.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testSin()
    {
        Apfloat a = ApfloatMath.sin(new Apfloat(1, 100));
        assertEquals("1, 100 precision", 100, a.precision(), 1);
        assertEquals("1, 100 value", new Apfloat("0.8414709848078965066525023216302989996225630607983710656727517099919104043912396689486397435430526959"), a, new Apfloat("5e-99"));

        a = ApfloatMath.sin(new Apfloat(-1, 100));
        assertEquals("-1, 100 precision", 100, a.precision(), 1);
        assertEquals("-1, 100 value", new Apfloat("-0.8414709848078965066525023216302989996225630607983710656727517099919104043912396689486397435430526959"), a, new Apfloat("5e-99"));

        a = ApfloatMath.sin(new Apfloat("3141592653589793239.462643383"));
        assertEquals("1e18pi + 1 precision", 10, a.precision(), 1);
        assertEquals("1e18pi + 1 value", new Apfloat("0.8414709848"), a, new Apfloat("5e-10"));

        a = ApfloatMath.sin(new Apfloat("1e-10", 32));
        assertEquals("1e-10 prec 32 value", new Apfloat("0.99999999999999999999833333333333e-10"), a, new Apfloat("5e-42"));

        a = ApfloatMath.sin(new Apfloat("1e-10", 3));
        assertEquals("1e-10 prec 3 value", new Apfloat("0.99999999999999999999833e-10"), a, new Apfloat("5e-33"));

        a = ApfloatMath.sin(new Apfloat(0));
        assertEquals("0, 100 value", new Apfloat(0), a);

        try
        {
            ApfloatMath.sin(new Apfloat(1000, 3));
            fail("sin(1000 prec 3) accepted");
        }
        catch (LossOfPrecisionException lope)
        {
            // OK; loss of precision
            assertEquals("Localization key", "imag.lossOfPrecision", lope.getLocalizationKey());
        }

        try
        {
            ApfloatMath.sin(new Apfloat(1));
            fail("Infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; result would have infinite precision
            assertEquals("Localization key", "exp.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testTan()
    {
        Apfloat a = ApfloatMath.tan(new Apfloat(1, 100));
        assertEquals("1, 100 precision", 100, a.precision(), 1);
        assertEquals("1, 100 value", new Apfloat("1.55740772465490223050697480745836017308725077238152003838394660569886139715172728955509996520224298"), a, new Apfloat("5e-98"));

        a = ApfloatMath.tan(new Apfloat(-1, 100));
        assertEquals("-1, 100 precision", 100, a.precision(), 1);
        assertEquals("-1, 100 value", new Apfloat("-1.55740772465490223050697480745836017308725077238152003838394660569886139715172728955509996520224298"), a, new Apfloat("5e-98"));

        a = ApfloatMath.tan(new Apfloat(0));
        assertEquals("0, 100 value", new Apfloat(0), a);

        try
        {
            ApfloatMath.tan(new Apfloat(1000, 3));
            fail("tan(1000 prec 3) accepted");
        }
        catch (LossOfPrecisionException lope)
        {
            // OK; loss of precision
            assertEquals("Localization key", "imag.lossOfPrecision", lope.getLocalizationKey());
        }

        try
        {
            ApfloatMath.tan(new Apfloat(1));
            fail("Infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; result would have infinite precision
            assertEquals("Localization key", "exp.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testSinc()
    {
        Apfloat a = ApfloatMath.sinc(new Apfloat(4, 20));
        assertEquals("4 precision", 20, a.precision());
        assertEquals("4 value", new Apfloat("-0.18920062382698206284"), a, new Apfloat("5e-20"));

        a = ApfloatMath.sinc(new Apfloat("0"));
        assertEquals("0 precision", Apfloat.INFINITE, a.precision());
        assertEquals("0 value", new Apint(1), a);

        a = ApfloatMath.sinc(new Apint(0, 2));
        assertEquals("0 radix 2 precision", Apfloat.INFINITE, a.precision());
        assertEquals("0 radix 2 radix", 2, a.radix());
        assertEquals("0 radix 2 value", new Apint(1, 2), a);

        try
        {
            ApfloatMath.sinc(new Apfloat(1));
            fail("Infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; result would have infinite precision
            assertEquals("Localization key", "exp.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testW()
    {
        Apfloat a = new Apfloat(3, 55, 7);
        Apfloat w = ApfloatMath.w(a);
        assertEquals("value", new Apfloat("1.023055505635040031000066002051603260046346014422202623", 55, 7), w, new Apfloat("5e-54", 1, 7));
        assertEquals("radix", 7, w.radix());
        assertEquals("precision", 55, w.precision());

        try
        {
            ApfloatMath.w(new Apfloat(1));
            fail("Infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; result would have infinite precision
            assertEquals("Localization key", "w.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testToRadians()
    {
        Apfloat a = ApfloatMath.toRadians(new Apfloat(180, 100));
        assertEquals("180 precision", 100, a.precision());
        assertEquals("180 value", new Apfloat("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068"), a, new Apfloat("5e-99"));

        a = ApfloatMath.toRadians(new Apfloat(90, 50, 16));
        assertEquals("90 precision", 50, a.precision());
        assertEquals("90 value", new Apfloat("1.921fb54442d18469898cc51701b839a252049c1114cf98e80", 50, 16), a, new Apfloat(8, 1, 16).scale(-49));

        a = ApfloatMath.toRadians(new Apfloat(0));
        assertEquals("0 precision", Apfloat.INFINITE, a.precision());
        assertEquals("0 value", new Apfloat(0), a);

        try
        {
            ApfloatMath.toRadians(new Apfloat(1));
            fail("Infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; result would have infinite precision
            assertEquals("Localization key", "divide.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testToDegrees()
    {
        Apfloat a = ApfloatMath.toDegrees(ApfloatMath.pi(100, 10));
        assertEquals("180 precision", 100, a.precision());
        assertEquals("180 value", new Apfloat(180), a, new Apfloat("5e-97"));

        a = ApfloatMath.toDegrees(ApfloatMath.pi(50, 16).divide(new Apfloat(2, 50, 16)));
        assertEquals("90 precision", 50, a.precision());
        assertEquals("90 value", new Apfloat(90, 50, 16), a, new Apfloat(8, 1, 16).scale(-48));

        a = ApfloatMath.toDegrees(new Apfloat(0));
        assertEquals("0 precision", Apfloat.INFINITE, a.precision());
        assertEquals("0 value", new Apfloat(0), a);

        try
        {
            ApfloatMath.toDegrees(new Apfloat(1));
            fail("Infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; result would have infinite precision
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testProduct()
    {
        Apfloat a = ApfloatMath.product(new Apfloat(2, 5), new Apfloat(3, 2));
        assertEquals("5-2 precision", 2, a.precision());
        assertEquals("5-2 value", new Apfloat(6), a);

        a = ApfloatMath.product(new Apfloat(2), new Apfloat(3, 5), new Apfloat(4, 8));
        assertEquals("MAX-5-8 precision", 5, a.precision());
        assertEquals("MAX-5-8 value", new Apfloat(24), a);

        a = ApfloatMath.product(Apfloat.ZERO, new Apfloat(12345));
        assertEquals("0 precision", Apfloat.INFINITE, a.precision());
        assertEquals("0 value", new Apfloat(0), a);

        a = ApfloatMath.product(new Apfloat(0, 1, 12));
        assertEquals("0 radix", 12, a.radix());

        a = ApfloatMath.product(new Apfloat("1"),
                                new Apfloat("2.50000000000000000000000000000000000000000000000000000000000000000000001"),
                                new Apfloat("2.0000000000000000000000000000000000001"),
                                new Apfloat(2));
        assertEquals("Many precision", 1, a.precision());
        assertEquals("Many value", new Apfloat(10), a);

        Apfloat[] x = new Apfloat[] { new Apfloat(1000000000000L), new Apfloat(1) };
        ApfloatMath.product(x);
        assertEquals("Array product 1 [0]", new Apfloat(1000000000000L), x[0]);
        assertEquals("Array product 1 [1]", new Apfloat(1), x[1]);

        x = new Apfloat[] { new Apfloat(1), new Apfloat(1000000000000L) };
        ApfloatMath.product(x);
        assertEquals("Array product 2 [0]", new Apfloat(1), x[0]);
        assertEquals("Array product 2 [1]", new Apfloat(1000000000000L), x[1]);

        assertEquals("Empty product", new Apfloat("1"), ApfloatMath.product());

        Apfloat[] numbers = new Apfloat[100000];
        for (int i = 0; i < numbers.length; i++)
        {
            numbers[i] = new Apfloat(i + 1);
        }
        Apfloat factorial = ApintMath.factorial(numbers.length);
        assertEquals("Factorial", factorial, ApfloatMath.product(numbers));

        numbers[0] = factorial;
        assertEquals("Factorial squared", factorial.multiply(factorial), ApfloatMath.product(numbers));
    }

    public static void testSum()
    {
        Apfloat a = ApfloatMath.sum(new Apfloat(12345000, 5), new Apfloat(12345, 5));
        assertEquals("5-2 precision", 5, a.precision());
        assertEquals("5-2 value", new Apfloat(12357000), a);

        a = ApfloatMath.sum(new Apfloat(12345678, 10), new Apfloat(12345, 5));
        assertEquals("8-5 precision", 8, a.precision());
        assertEquals("8-5 value", new Apfloat(12358023), a);

        a = ApfloatMath.sum(new Apfloat(0), new Apfloat(12345, 5));
        assertEquals("0-0 precision", 5, a.precision());
        assertEquals("0-0 value", new Apfloat(12345), a);

        a = ApfloatMath.sum(new Apfloat(12345678, 6), new Apfloat(12, 2));
        assertEquals("6-0 precision", 6, a.precision());
        assertEquals("6-0 value", new Apfloat(12345600), a);

        a = ApfloatMath.sum(new Apfloat(12345678, 5), new Apfloat(12, 2));
        assertEquals("5-0 precision", 5, a.precision());
        assertEquals("5-0 value", new Apfloat(12345000), a);

        a = ApfloatMath.sum(new Apfloat(10), new Apfloat(100, 2));
        assertEquals("10, 100 2 precision", 2, a.precision());
        assertEquals("10, 100 2 value", new Apfloat(110), a);

        a = ApfloatMath.sum(new Apfloat(10), new Apfloat(100, 3));
        assertEquals("10, 100 3 precision", 3, a.precision());
        assertEquals("10, 100 3 value", new Apfloat(110), a);

        a = ApfloatMath.sum(new Apfloat(100, 2), new Apfloat(10));
        assertEquals("100, 10 2 precision", 2, a.precision());
        assertEquals("100, 10 2 value", new Apfloat(110), a);

        a = ApfloatMath.sum(new Apfloat(10), new Apfloat(1, 2));
        assertEquals("10, 1 2 precision", 3, a.precision());
        assertEquals("10, 1 2 value", new Apfloat(11), a);

        a = ApfloatMath.sum(new Apfloat(10), new Apfloat(1, 3));
        assertEquals("10, 1 3 precision", 4, a.precision());
        assertEquals("10, 1 3 value", new Apfloat(11), a);

        a = ApfloatMath.sum(new Apfloat(1, 2), new Apfloat(10));
        assertEquals("1, 10 2 precision", 3, a.precision());
        assertEquals("1, 10 2 value", new Apfloat(11), a);

        a = ApfloatMath.sum(new Apfloat(10), new Apfloat(10));
        assertEquals("10, 10 MAX precision", Apfloat.INFINITE, a.precision());
        assertEquals("10, 10 MAX value", new Apfloat(20), a);

        a = ApfloatMath.sum(new Apfloat(10), new Apfloat(100));
        assertEquals("10, 100 MAX precision", Apfloat.INFINITE, a.precision());
        assertEquals("10, 100 MAX value", new Apfloat(110), a);

        a = ApfloatMath.sum(new Apfloat(50, 2), new Apfloat(50, 2));
        assertEquals("50, 50 2 precision", 3, a.precision());
        assertEquals("50, 50 2 value", new Apfloat(100), a);

        a = ApfloatMath.sum(new Apfloat("2"));
        assertEquals("2 precision", 1, a.precision());
        assertEquals("2 value", new Apfloat(2), a);

        a = ApfloatMath.sum(new Apfloat("1"),
                            new Apfloat("3333333.33"),
                            new Apfloat("2.2"),
                            new Apfloat("444444444400000000000000000000000000"),
                            new Apfloat("6666.6"),
                            new Apfloat("555"),
                            new Apfloat(7));
        assertEquals("Many precision", 36, a.precision());
        assertEquals("Many value", new Apfloat("444444444400000000000000000003340564"), a);

        Apfloat[] x = new Apfloat[] { new Apfloat(1000000000000L), new Apfloat(1) };
        ApfloatMath.sum(x);
        assertEquals("Array sum 1 [0]", new Apfloat(1000000000000L), x[0]);
        assertEquals("Array sum 1 [1]", new Apfloat(1), x[1]);

        x = new Apfloat[] { new Apfloat(1), new Apfloat(1000000000000L) };
        ApfloatMath.sum(x);
        assertEquals("Array sum 2 [0]", new Apfloat(1), x[0]);
        assertEquals("Array sum 2 [1]", new Apfloat(1000000000000L), x[1]);

        assertEquals("Empty sum", new Apcomplex("0"), ApfloatMath.sum());

        Apfloat[] numbers = new Apfloat[100000];
        for (int i = 0; i < numbers.length; i++)
        {
            numbers[i] = new Apfloat(i + 1);
        }
        assertEquals("Big sum", new Apfloat(5000050000L), ApfloatMath.sum(numbers));

        numbers[0] = numbers[0].add(new Apfloat("1e10000000", Apfloat.INFINITE));
        assertEquals("Big number big sum", new Apfloat(5000050000L).add(new Apfloat("1e10000000", Apfloat.INFINITE)), ApfloatMath.sum(numbers));
    }

    public static void testE()
    {
        Apfloat a = ApfloatMath.e(10);
        assertEquals("10 radix", 10, a.radix());
        assertEquals("10 precision", 10, a.precision());
        assertEquals("10 value", new Apfloat("2.718281828"), a, new Apfloat("5e-9"));
        a = ApfloatMath.e(50);
        assertEquals("50 radix", 10, a.radix());
        assertEquals("50 precision", 50, a.precision());
        assertEquals("50 value", new Apfloat("2.7182818284590452353602874713526624977572470937000"), a, new Apfloat("5e-49"));
        a = ApfloatMath.e(20, 16);
        assertEquals("20 radix", 16, a.radix());
        assertEquals("20 precision", 20, a.precision());
        assertEquals("20 value", new Apfloat("2.b7e151628aed2a6abf7", 20, 16), a, new Apfloat("0.0000000000000000008", 1, 16));

        try
        {
            ApfloatMath.e(0);
            fail("Precision 0 accepted");
        }
        catch (IllegalArgumentException e)
        {
            // OK; invalid precision
        }

        try
        {
            ApfloatMath.e(Apfloat.INFINITE);
            fail("Infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; invalid precision
            assertEquals("Localization key", "e.infinitePrecision", iee.getLocalizationKey());
        }

        try
        {
            ApfloatMath.e(50, 1);
            fail("Radix 1 accepted");
        }
        catch (NumberFormatException nfe)
        {
            // OK; invalid radix
        }
    }

    public static void testEuler()
    {
        Apfloat a = ApfloatMath.euler(10);
        assertEquals("10 radix", 10, a.radix());
        assertEquals("10 precision", 10, a.precision());
        assertEquals("10 value", new Apfloat("0.5772156649"), a, new Apfloat("5e-10"));
        a = ApfloatMath.euler(50);
        assertEquals("50 radix", 10, a.radix());
        assertEquals("50 precision", 50, a.precision());
        assertEquals("50 value", new Apfloat("0.57721566490153286060651209008240243104215933593992"), a, new Apfloat("5e-50"));
        a = ApfloatMath.euler(20, 16);
        assertEquals("20 radix", 16, a.radix());
        assertEquals("20 precision", 20, a.precision());
        assertEquals("20 value", new Apfloat("0.93c467e37db0c7a4d1be", 20, 16), a, new Apfloat("0.00000000000000000008", 1, 16));

        a = ApfloatMath.eulerSmall(2000, 10);
        assertEquals("long and short match", EulerHelper.euler(2000, 10), a);

        a = ApfloatMath.euler(2500, 10);
        assertEquals("short and long match", ApfloatMath.eulerSmall(2500, 10), a);

        for (int radix = 2; radix <= 36; radix++)
        {
            a = ApfloatMath.eulerSmall(20, radix);
            assertEquals("long and short match radix " + radix + " precision 20", EulerHelper.euler(20, radix), a);
            a = ApfloatMath.eulerSmall(200, radix);
            assertEquals("long and short match radix " + radix + " precision 200", EulerHelper.euler(200, radix), a);
        }

        try
        {
            ApfloatMath.euler(0);
            fail("Precision 0 accepted");
        }
        catch (IllegalArgumentException iae)
        {
            // OK; invalid precision
        }

        try
        {
            ApfloatMath.euler(-1);
            fail("Precision -1 accepted");
        }
        catch (IllegalArgumentException iae)
        {
            // OK; invalid precision
        }

        try
        {
            ApfloatMath.euler(Apfloat.INFINITE);
            fail("Infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; invalid precision
            assertEquals("Localization key", "euler.infinitePrecision", iee.getLocalizationKey());
        }

        try
        {
            ApfloatMath.euler(50, 1);
            fail("Radix 1 accepted");
        }
        catch (NumberFormatException nfe)
        {
            // OK; invalid radix
        }
    }

    public static void testCatalan()
    {
        Apfloat a = ApfloatMath.catalan(10);
        assertEquals("10 radix", 10, a.radix());
        assertEquals("10 precision", 10, a.precision());
        assertEquals("10 value", new Apfloat("0.9159655942"), a, new Apfloat("5e-10"));
        a = ApfloatMath.catalan(50);
        assertEquals("50 radix", 10, a.radix());
        assertEquals("50 precision", 50, a.precision());
        assertEquals("50 value", new Apfloat("0.91596559417721901505460351493238411077414937428167"), a, new Apfloat("5e-50"));
        a = ApfloatMath.catalan(20, 16);
        assertEquals("20 radix", 16, a.radix());
        assertEquals("20 precision", 20, a.precision());
        assertEquals("20 value", new Apfloat("0.ea7cb89f409ae8452158", 20, 16), a, new Apfloat("0.00000000000000000008", 1, 16));

        try
        {
            ApfloatMath.catalan(0);
            fail("Precision 0 accepted");
        }
        catch (IllegalArgumentException iae)
        {
            // OK; invalid precision
        }

        try
        {
            ApfloatMath.catalan(-1);
            fail("Precision -1 accepted");
        }
        catch (IllegalArgumentException iae)
        {
            // OK; invalid precision
        }

        try
        {
            ApfloatMath.catalan(Apfloat.INFINITE);
            fail("Infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; invalid precision
            assertEquals("Localization key", "catalan.infinitePrecision", iee.getLocalizationKey());
        }

        try
        {
            ApfloatMath.catalan(50, 1);
            fail("Radix 1 accepted");
        }
        catch (NumberFormatException nfe)
        {
            // OK; invalid radix
        }
    }

    public static void testGlaisher()
    {
        Apfloat a = ApfloatMath.glaisher(10);
        assertEquals("10 radix", 10, a.radix());
        assertEquals("10 precision", 10, a.precision());
        assertEquals("10 value", new Apfloat("1.282427129"), a, new Apfloat("5e-9"));
        a = ApfloatMath.glaisher(50);
        assertEquals("50 radix", 10, a.radix());
        assertEquals("50 precision", 50, a.precision());
        assertEquals("50 value", new Apfloat("1.2824271291006226368753425688697917277676889273250"), a, new Apfloat("5e-49"));
        a = ApfloatMath.glaisher(20, 16);
        assertEquals("20 radix", 16, a.radix());
        assertEquals("20 precision", 20, a.precision());
        assertEquals("20 value", new Apfloat("1.484d24f2fd8731313ed", 20, 16), a, new Apfloat("0.0000000000000000008", 1, 16));

        try
        {
            ApfloatMath.glaisher(0);
            fail("Precision 0 accepted");
        }
        catch (IllegalArgumentException iae)
        {
            // OK; invalid precision
        }

        try
        {
            ApfloatMath.glaisher(-1);
            fail("Precision -1 accepted");
        }
        catch (IllegalArgumentException iae)
        {
            // OK; invalid precision
        }

        try
        {
            ApfloatMath.glaisher(Apfloat.INFINITE);
            fail("Infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; invalid precision
            assertEquals("Localization key", "glaisher.infinitePrecision", iee.getLocalizationKey());
        }

        try
        {
            ApfloatMath.glaisher(50, 1);
            fail("Radix 1 accepted");
        }
        catch (NumberFormatException nfe)
        {
            // OK; invalid radix
        }
    }

    public static void testKhinchin()
    {
        Apfloat a = ApfloatMath.khinchin(10);
        assertEquals("10 radix", 10, a.radix());
        assertEquals("10 precision", 10, a.precision());
        assertEquals("10 value", new Apfloat("2.685452001"), a, new Apfloat("5e-9"));
        a = ApfloatMath.khinchin(50);
        assertEquals("50 radix", 10, a.radix());
        assertEquals("50 precision", 50, a.precision());
        assertEquals("50 value", new Apfloat("2.6854520010653064453097148354817956938203822939945"), a, new Apfloat("5e-49"));
        a = ApfloatMath.khinchin(20, 16);
        assertEquals("20 radix", 16, a.radix());
        assertEquals("20 precision", 20, a.precision());
        assertEquals("20 value", new Apfloat("2.af79c8478da1aef2fdf", 20, 16), a, new Apfloat("0.0000000000000000008", 1, 16));

        try
        {
            ApfloatMath.khinchin(0);
            fail("Precision 0 accepted");
        }
        catch (IllegalArgumentException iae)
        {
            // OK; invalid precision
        }

        try
        {
            ApfloatMath.khinchin(-1);
            fail("Precision -1 accepted");
        }
        catch (IllegalArgumentException iae)
        {
            // OK; invalid precision
        }

        try
        {
            ApfloatMath.khinchin(Apfloat.INFINITE);
            fail("Infinite precision accepted");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK; invalid precision
            assertEquals("Localization key", "khinchin.infinitePrecision", iee.getLocalizationKey());
        }

        try
        {
            ApfloatMath.khinchin(50, 1);
            fail("Radix 1 accepted");
        }
        catch (NumberFormatException nfe)
        {
            // OK; invalid radix
        }
    }

    public static void testGamma()
    {
        Apfloat a = ApfloatMath.gamma(new Apfloat("0.50000000"));
        assertEquals("0.5 precision", 8, a.precision());
        assertEquals("0.5 value", new Apfloat("1.7724539"), a, new Apfloat("5e-7"));
        a = ApfloatMath.gamma(new Apfloat("-0.50000000"));
        assertEquals("-0.5 precision", 8, a.precision());
        assertEquals("-0.5 value", new Apfloat("-3.5449077"), a, new Apfloat("5e-7"));
        a = ApfloatMath.gamma(new Apfloat(1, 8, 5));
        assertEquals("1 precision", 8, a.precision());
        assertEquals("1 radix", 5, a.radix());
        assertEquals("1 value", new Apfloat("1"), a);
        a = ApfloatMath.gamma(new Apfloat(2, 100, 15));
        assertEquals("2 precision", 100, a.precision());
        assertEquals("2 radix", 15, a.radix());
        assertEquals("2 value", new Apfloat("1"), a);
        a = ApfloatMath.gamma(new Apfloat("3.0000"));
        assertEquals("3 precision", 5, a.precision());
        assertEquals("3 value", new Apfloat("2"), a);
        a = ApfloatMath.gamma(new Apfloat(4));
        assertEquals("4 precision", Apfloat.INFINITE, a.precision());
        assertEquals("4 value", new Apfloat(6), a);
        a = ApfloatMath.gamma(new Apfloat("1.6", 50, 12));
        assertEquals("1.5 precision", 50, a.precision());
        assertEquals("1.5 radix", 12, a.radix());
        assertEquals("1.5 value", new Apfloat("0.a77497505445a57663a7a6a27293557aa7636b52055b106267", 50, 12), a, new Apfloat("6e-50", 1, 12));
        a = ApfloatMath.gamma(new Apfloat("100.1", 200));
        assertEquals("100.1 precision", 198, a.precision());
        assertEquals("100.1 radix", 10, a.radix());
        assertEquals("100.1 value", new Apfloat("1.47845449465151367987473964370058459815616330531263071222863411464877072133812707322505189203455965790627278052589675722784367103797434916544534856714784021130076746063941341581673323445817944799010e156"), a, new Apfloat("5e-41"));
        a = ApfloatMath.gamma(new Apfloat("1000000000000.1", 200));
        assertEquals("1000000000000.1 precision", 187, a.precision());
        assertEquals("1000000000000.1 radix", 10, a.radix());
        assertEquals("1000000000000.1 value", new Apfloat("2.224653017598333183967851025493808141494831993379408189875623062445371016679508334427856798243992091090588534116479723793172610167211719300756575577203942719906409747242019348186775610123e11565705518092"), a, new Apfloat("5e11565705517906"));
        a = ApfloatMath.gamma(new Apfloat("1000000000000.1", 40));
        assertEquals("1000000000000.1 precision", 27, a.precision());
        assertEquals("1000000000000.1 radix", 10, a.radix());
        assertEquals("1000000000000.1 value", new Apfloat("2.22465301759833318396785103e11565705518092"), a, new Apfloat("5e11565705518066"));
        a = ApfloatMath.gamma(new Apfloat("1.110100011010100101001010001000000000000000110011001100110011001100110011001100110011001100110011001100110011001100110011001100110011e39", 133, 2));
        assertEquals("1000000000000.1 radix 2 precision", 88, a.precision());
        assertEquals("1000000000000.1 radix 2 radix", 2, a.radix());
        assertEquals("1000000000000.1 radix 2 value", new Apfloat("1.101100110001111000000001111011100111100110011010110000111001101101000111111101101001101e38420442097744", Apfloat.DEFAULT, 2), a, new Apfloat("1e38420442097657", 1, 2));
        a = ApfloatMath.gamma(new Apfloat("cre66i9s.3lllllllllllllllm", 25, 36));
        assertEquals("1000000000000.1 radix 36 precision", 17, a.precision());
        assertEquals("1000000000000.1 radix 36 radix", 36, a.radix());
        assertEquals("1000000000000.1 radix 36 value", ApfloatMath.scale(new Apfloat("3.nbkxpiq7zeevaryz", Apfloat.DEFAULT, 36), 7431527940352L), a, ApfloatMath.scale(new Apfloat("h", 1, 36), 7431527940336L));
        a = ApfloatMath.gamma(new Apfloat("100000000000000000.1", 100));
        assertEquals("100000000000000000.1 precision", 82, a.precision());
        assertEquals("100000000000000000.1 radix", 10, a.radix());
        assertEquals("100000000000000000.1 value", new Apfloat("6.823026252477337409854801263715027688793307758143854258250527972341074891269582940e1656570551809674810"), a, new Apfloat("5e1656570551809674729"));
        try
        {
            ApfloatMath.gamma(new Apfloat("0"));
            fail("Gamma of zero");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "gamma.ofZero", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.gamma(new Apfloat("-1"));
            fail("Gamma of -1");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "gamma.ofNegativeInteger", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.gamma(new Apfloat("1e100", 100));
            fail("Gamma overflow");
        }
        catch (OverflowException oe)
        {
            // OK
            assertEquals("Localization key", "overflow", oe.getLocalizationKey());
        }
        try
        {
            ApfloatMath.gamma(new Apfloat("4.5", Apfloat.INFINITE));
            fail("Gamma infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "gamma.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testGammaIncomplete()
    {
        Apfloat a = ApfloatMath.gamma(new Apfloat("2.0000000"), new Apfloat("1.0000000"));
        assertEquals("2,1 precision", 8, a.precision());
        assertEquals("2,1 value", new Apfloat("0.73575888"), a, new Apfloat("5e-8"));
        a = ApfloatMath.gamma(new Apfloat("4.0000000"), new Apfloat("6.0000000"));
        assertEquals("4,6 precision", 8, a.precision());
        assertEquals("4,6 value", new Apfloat("0.90722330"), a, new Apfloat("5e-8"));
        a = ApfloatMath.gamma(new Apfloat("4.50000"), new Apfloat("6.50000"));
        assertEquals("4.5,6.5 precision", 6, a.precision());
        assertEquals("4.5,6.5 value", new Apfloat("1.89139"), a, new Apfloat("5e-5"));
        a = ApfloatMath.gamma(new Apfloat("-0.500000"), new Apfloat("0.500000"));
        assertEquals("-0.5,0.5 precision", 6, a.precision());
        assertEquals("-0.5,0.5 value", new Apfloat("0.590691"), a, new Apfloat("5e-6"));

        a = ApfloatMath.gamma(new Apfloat(1, 10), new Apfloat(-1, 10));
        assertEquals("1,-1 precision", 10, a.precision());
        assertEquals("1,-1 value", new Apfloat("2.718281828"), a, new Apfloat("5e-9"));
        a = ApfloatMath.gamma(new Apfloat(100, 10), new Apfloat(1, 10));
        assertEquals("100,1 precision", 10, a.precision());
        assertEquals("100,1 value", new Apfloat("9.332621544e155"), a, new Apfloat("5e-146"));
        a = ApfloatMath.gamma(new Apfloat("-100.5", 12), new Apfloat(1, 12));
        assertEquals("-100.5,1 precision", 11, a.precision());
        assertEquals("-100.5,1 value", new Apfloat("0.00362407278773"), a, new Apfloat("5e-13"));

        a = ApfloatMath.gamma(new Apfloat(-1, 10), new Apfloat(1, 10));
        assertEquals("-1,1 precision", 10, a.precision());
        assertEquals("-1,1 value", new Apfloat("0.1484955068"), a, new Apfloat("5e-10"));
        a = ApfloatMath.gamma(new Apfloat(-1, 10), new Apfloat(10, 10));
        assertEquals("-1,10 precision", 9, a.precision());
        assertEquals("-1,10 value", new Apfloat("3.830240466e-7"), a, new Apfloat("5e-16"));
        a = ApfloatMath.gamma(new Apfloat(-10, 10), new Apfloat(1, 10));
        assertEquals("-10,1 precision", 10, a.precision());
        assertEquals("-10,1 value", new Apfloat("0.03314854471"), a, new Apfloat("5e-11"));
        a = ApfloatMath.gamma(new Apfloat(-10, 10), new Apfloat(10, 10));
        assertEquals("-10,10 precision", 9, a.precision());
        assertEquals("-10,10 value", new Apfloat("2.214690319e-16"), a, new Apfloat("5e-24"));

        a = ApfloatMath.gamma(new Apfloat(4, 10), new Apfloat("0.1", 10));
        assertEquals("4,0.1 precision", 10, a.precision());
        assertEquals("4,0.1 value", new Apfloat("5.999976919"), a, new Apfloat("5e-9"));
        a = ApfloatMath.gamma(new Apfloat(4, 10), new Apfloat("-0.1", 10));
        assertEquals("4,-0.1 precision", 10, a.precision());
        assertEquals("4,-0.1 value", new Apfloat("5.999972914"), a, new Apfloat("5e-9"));

        a = ApfloatMath.gamma(new Apfloat("-1.000e-50"), new Apfloat("100.0"));
        assertEquals("-1e-50,100 precision", 2, a.precision());
        assertEquals("-1e-50,100 value", new Apfloat("3.7e-46"), a, new Apfloat("5e-47"));

        a = ApfloatMath.gamma(new Apfloat("4.5000000"), Apfloat.ZERO);
        assertEquals("4.5,0 precision", 8, a.precision());
        assertEquals("4.5,0 value", new Apfloat("11.631728"), a, new Apfloat("5e-6"));

        a = ApfloatMath.gamma(new Apfloat("1234567890.0000000000"), new Apfloat("0.12345678900000000"));
        assertEquals("1234567890,0.123456789 precision", 10, a.precision());
        assertEquals("1234567890,0.123456789", new Apfloat("9.091929131e10687926435"), a, new Apfloat("5e10687926426"));

        a = ApfloatMath.gamma(new Apfloat("0.12345678900000000"), new Apfloat("1234567890.000000000"));
        assertEquals("0.123456789,1234567890 precision", 10, a.precision());
        assertEquals("0.123456789,1234567890", new Apfloat("7.395260483e-536166031"), a, new Apfloat("5e-536166022"));

        a = ApfloatMath.gamma(new Apfloat("4.0000000", Apfloat.DEFAULT, 11), new Apfloat("0.60000000", Apfloat.DEFAULT, 11));
        assertEquals("4,0.6 precision radix 11", 8, a.precision());
        assertEquals("4,0.6 value radix 11", new Apfloat("5.a929793", Apfloat.DEFAULT, 11), a, new Apfloat("5e-7", Apfloat.DEFAULT, 11));

        a = ApfloatMath.gamma(new Apfloat("4.0000000", Apfloat.DEFAULT, 11), new Apfloat("-0.60000000", Apfloat.DEFAULT, 11));
        assertEquals("4,-0.6 precision radix 11", 8, a.precision());
        assertEquals("4,-0.6 value radix 11", new Apfloat("5.a6928aa", Apfloat.DEFAULT, 11), a, new Apfloat("5e-7", Apfloat.DEFAULT, 11));

        a = ApfloatMath.gamma(new Apfloat("4.0000000", Apfloat.DEFAULT, 11), new Apfloat("6.0000000", Apfloat.DEFAULT, 11));
        assertEquals("4,6 precision radix 11", 8, a.precision());
        assertEquals("4,6 value radix 11", new Apfloat("0.9a857246", Apfloat.DEFAULT, 11), a, new Apfloat("5e-8", Apfloat.DEFAULT, 11));

        a = ApfloatMath.gamma(new Apfloat("-4.0000000", Apfloat.DEFAULT, 11), new Apfloat("6.0000000", Apfloat.DEFAULT, 11));
        assertEquals("-4,6 precision radix 11", 8, a.precision());
        assertEquals("-4,6 value radix 11", new Apfloat("3.57a6772e-7", Apfloat.DEFAULT, 11), a, new Apfloat("5e-14", Apfloat.DEFAULT, 11));

        try
        {
            ApfloatMath.gamma(Apfloat.ZERO, Apfloat.ZERO);
            fail("Gamma of zero");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "gammaIncomplete.upperOfNonpositive", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.gamma(new Apfloat("-0.500000"), new Apfloat("-0.500000"));
            fail("Non-real result");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.gamma(new Apfloat(-1, 10), new Apfloat(-2, 10));
            fail("Non-real result");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK non-real result
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.gamma(new Apfloat(0, 10), new Apfloat(-1, 10));
            fail("Non-real result");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK non-real result
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.gamma(new Apfloat("1e100", 100), new Apfloat("1.000e102"));
            fail("Overflow");
        }
        catch (OverflowException oe)
        {
            // OK
            assertEquals("Localization key", "overflow", oe.getLocalizationKey());
        }
        try
        {
            ApfloatMath.gamma(new Apfloat(4), new Apfloat(5));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "gammaIncomplete.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testGammaIncompleteGeneralized()
    {
        Apfloat a = ApfloatMath.gamma(new Apfloat("2.0000000"), Apfloat.ZERO, new Apfloat("1.0000000"));
        assertEquals("2,0,1 precision", 7, a.precision());
        assertEquals("2,0,1 value", new Apfloat("0.26424112"), a, new Apfloat("5e-8"));
        a = ApfloatMath.gamma(new Apfloat("1.0000000"), Apfloat.ZERO, new Apfloat("2.0000000"));
        assertEquals("1,0,2 precision", 7, a.precision());
        assertEquals("1,0,2 value", new Apfloat("0.86466472"), a, new Apfloat("5e-8"));
        a = ApfloatMath.gamma(new Apfloat("4.0000000"), Apfloat.ZERO, new Apfloat("1.0000000"));
        assertEquals("4,0,1 precision", 7, a.precision());
        assertEquals("4,0,1 value", new Apfloat("0.11392894"), a, new Apfloat("5e-8"));
        a = ApfloatMath.gamma(new Apfloat("4.0000000"), Apfloat.ZERO, new Apfloat("6.0000000"));
        assertEquals("4,0,6 precision", 8, a.precision());
        assertEquals("4,0,6 value", new Apfloat("5.0927767"), a, new Apfloat("5e-7"));
        a = ApfloatMath.gamma(new Apfloat("1.0000000"), Apfloat.ZERO, new Apfloat("100.0000000"));
        assertEquals("1,0,100 precision", 8, a.precision());
        assertEquals("1,0,100 value", new Apfloat(1), a, new Apfloat("5e-7"));
        a = ApfloatMath.gamma(new Apfloat(1, 10), Apfloat.ZERO, new Apfloat(-1, 10));
        assertEquals("1,0,-1 precision", 10, a.precision());
        assertEquals("1,0,-1 value", new Apfloat("-1.718281828"), a, new Apfloat("5e-9"));
        a = ApfloatMath.gamma(new Apfloat(2, 10), Apfloat.ZERO, new Apfloat("-0.2", 10));
        assertEquals("2,0,-0.2 precision", 10, a.precision());
        assertEquals("2,0,-0.2 value", new Apfloat("0.02287779347"), a, new Apfloat("5e-11"));
        a = ApfloatMath.gamma(new Apfloat(1000, 10), Apfloat.ZERO, new Apfloat(1, 10));
        assertEquals("1000,0,1 precision", 10, a.precision());
        assertEquals("1000,0,1 value", new Apfloat("0.0003682473202"), a, new Apfloat("5e-13"));

        a = ApfloatMath.gamma(new Apfloat(4.0), new Apfloat(0.01), new Apfloat(10000.0));
        assertEquals("4,0.01,10000 precision", 16, a.precision());
        assertEquals("4,0.01,10000 value", new Apfloat("5.999999997519917"), a, new Apfloat("5e-15"));
        a = ApfloatMath.gamma(new Apfloat(4.0), new Apfloat(10000.0), new Apfloat(0.01));
        assertEquals("4,10000,0.01 precision", 16, a.precision());
        assertEquals("4,10000,0.01 value", new Apfloat("-5.999999997519917"), a, new Apfloat("5e-15"));

        a = ApfloatMath.gamma(new Apfloat(4.0), new Apfloat(0.01), new Apfloat(0.02));
        assertEquals("4,0.01,0.02 precision", 15, a.precision());
        assertEquals("4,0.01,0.02 value", new Apfloat("3.68852198942455e-8"), a, new Apfloat("5e-22"));
        a = ApfloatMath.gamma(new Apfloat(4.0), new Apfloat(10000.0), new Apfloat(20000.0));
        assertEquals("4,10000.0,20000.0 precision", 12, a.precision());
        assertEquals("4,10000.0,20000.0 value", new Apfloat("1.13582457861018e-4331"), a, new Apfloat("5e-4342"));

        a = ApfloatMath.gamma(new Apfloat("4.0000000"), new Apfloat("1.0000000"), Apfloat.ZERO);
        assertEquals("4,1,0 precision", 7, a.precision());
        assertEquals("4,1,0 value", new Apfloat("-0.11392894"), a, new Apfloat("5e-8"));

        a = ApfloatMath.gamma(new Apfloat(-4), new Apfloat(10000.0), new Apfloat(0.01));
        assertEquals("-4,10000,0.01 precision", 16, a.precision());
        assertEquals("-4,10000,0.01 value", new Apfloat("-24669150.2547202578891267"), a, new Apfloat("5e-8"));

        a = ApfloatMath.gamma(Apfloat.ZERO, new Apfloat(1.0), new Apfloat(2.0));
        assertEquals("0,1,2 precision", 16, a.precision());
        assertEquals("0,1,2 value", new Apfloat("0.1704834236874592"), a, new Apfloat("5e-16"));

        a = ApfloatMath.gamma(new Apint(1, 12), new Apint(1, 12), new Apint(1, 12));
        assertEquals("1,1,1 value", new Apfloat(0), a);
        assertEquals("1,1,1 radix", 12, a.radix());

        try
        {
            ApfloatMath.gamma(Apfloat.ZERO, Apfloat.ZERO, Apfloat.ZERO);
            fail("Gamma of zero");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "gamma.ofZero", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.gamma(new Apfloat(-1, 10), Apfloat.ZERO, new Apfloat(1, 10));
            fail("Lower gamma of non-positive integer");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK a is non-positive integer
            assertEquals("Localization key", "gammaIncomplete.lowerOfNonpositiveInteger", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.gamma(Apfloat.ZERO, new Apfloat(-1, 10), Apfloat.ZERO);
            fail("Lower gamma of non-positive integer");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK a is non-positive integer
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.gamma(Apfloat.ZERO, Apfloat.ZERO, new Apfloat(-1, 10));
            fail("Lower gamma of non-positive integer");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK a is non-positive integer
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.gamma(new Apfloat("1e100", 100), new Apfloat("1.000e102"), new Apfloat("1.000e103"));
            fail("Overflow");
        }
        catch (OverflowException oe)
        {
            // OK
            assertEquals("Localization key", "overflow", oe.getLocalizationKey());
        }
        try
        {
            ApfloatMath.gamma(new Apfloat(4), Apfloat.ZERO, new Apfloat(5));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "gammaIncomplete.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testLogGamma()
    {
        Apfloat a = ApfloatMath.logGamma(new Apfloat(6, 30, 10));
        assertEquals("6 precision", 29, a.precision());
        assertEquals("6 value", new Apfloat("4.7874917427820459942477009345232"), a, new Apfloat("5e-28"));

        a = ApfloatMath.logGamma(new Apfloat("4.20000"));
        assertEquals("4.2 precision", 6, a.precision());
        assertEquals("4.2 value", new Apfloat("2.04856"), a, new Apfloat("5e-5"));

        a = ApfloatMath.logGamma(new Apfloat("1.50000"));
        assertEquals("1.5 precision", 5, a.precision());
        assertEquals("1.5 value", new Apfloat("-0.120782"), a, new Apfloat("5e-5"));

        try
        {
            ApfloatMath.logGamma(new Apfloat("-0.1"));
            fail("Log gamma of non-positive value");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK a is negative
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.logGamma(Apfloat.ZERO);
            fail("Lower gamma of zero");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK a is zero
            assertEquals("Localization key", "logGamma.ofZero", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.logGamma(new Apfloat("-1"));
            fail("Log gamma of negative integer");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK a is negative
            assertEquals("Localization key", "logGamma.ofNegativeInteger", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.logGamma(new Apfloat(2));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "logGamma.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testDigamma()
    {
        Apfloat a = ApfloatMath.digamma(new Apfloat(6, 30, 10));
        assertEquals("6 precision", 30, a.precision(), 1);
        assertEquals("6 value", new Apfloat("1.70611766843180047272682124325"), a, new Apfloat("5e-29"));

        a = ApfloatMath.digamma(new Apfloat("-6.5", 30, 10));
        assertEquals("-6.5 precision", 30, a.precision(), 1);
        assertEquals("-6.5 value", new Apfloat("1.94675748424608678806929117727"), a, new Apfloat("5e-29"));

        a = ApfloatMath.digamma(new Apfloat("1e100", 30, 10));
        assertEquals("1e100 precision", 33, a.precision(), 1);
        assertEquals("1e100 value", new Apfloat("230.258509299404568401799145468436"), a, new Apfloat("5e-29"));

        a = ApfloatMath.digamma(new Apfloat("-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.1"));
        assertEquals("-1e100-1 precision", 4, a.precision());
        assertEquals("-1e100-1 value", new Apfloat("239.927337"), a, new Apfloat("5e-1"));

        a = ApfloatMath.digamma(new Apfloat("1e1000000", 30, 10));
        assertEquals("1e1000000 precision", 36, a.precision(), 1);
        assertEquals("1e1000000 value", new Apfloat("2302585.09299404568401799145468436421"), a, new Apfloat("5e-26"));

        a = ApfloatMath.digamma(new Apfloat(1, 1));
        assertEquals("1 precision", 1, a.precision());
        assertEquals("1 value", new Apfloat("-0.6"), a, new Apfloat("5e-1"));

        try
        {
            ApfloatMath.digamma(new Apfloat(0));
            fail("Digamma of zero");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "digamma.ofNonpositiveInteger", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.digamma(new Apfloat(-6));
            fail("Digamma of -6");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "digamma.ofNonpositiveInteger", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.digamma(new Apfloat(3));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "digamma.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testPolygamma()
    {
        Apfloat a = ApfloatMath.polygamma(3, new Apfloat(6, 30, 10));
        assertEquals("3, 6 precision", 30, a.precision(), 1);
        assertEquals("3, 6 value", new Apfloat("0.0118278281927550750219481051729"), a, new Apfloat("5e-31"));

        a = ApfloatMath.polygamma(-8, new Apfloat(6, 30, 10));
        assertEquals("-8, 6 precision", 30, a.precision(), 1);
        assertEquals("-8, 6 value", new Apfloat("48.0864862195097345668245"), a, new Apfloat("5e-28"));

        a = ApfloatMath.polygamma(1, new Apfloat("-138b.8", 5, 16));
        assertEquals("1, -5003.5 precision", 5, a.precision());
        assertEquals("1, -5003.5 value", new Apfloat("9.de91", 5, 16), a, new Apfloat("0.0008", 1, 16));

        a = ApfloatMath.polygamma(7, new Apfloat("-138b.8", 6, 16));
        assertEquals("7, -5003.5 precision", 6, a.precision());
        assertEquals("7, -5003.5 value", new Apfloat("276190", 6, 16), a, new Apfloat("8", 1, 16));

        try
        {
            ApfloatMath.polygamma(-1, new Apfloat("-0.100"));
            fail("-1, -0.1");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.polygamma(-1, new Apfloat("-1.00"));
            fail("-1, -1");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "polygamma.ofNonpositiveInteger", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.polygamma(-2, new Apfloat("-0.100"));
            fail("-2, -0.1");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.polygamma(-2, new Apfloat("-1.00"));
            fail("-2, -1");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.polygamma(3, new Apfloat(3));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "zeta.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testBarnesG()
    {
        Apfloat a = ApfloatMath.barnesG(new Apfloat(9, 30));
        assertEquals("9 precision", 30, a.precision());
        assertEquals("9 value", new Apfloat("125411328000"), a);

        a = ApfloatMath.barnesG(new Apfloat("9.5", 30));
        assertEquals("9.5 precision", 29, a.precision());
        assertEquals("9.5 value", new Apfloat("19269607235982.5876692155647834"), a, new Apfloat("5e-15"));

        a = ApfloatMath.barnesG(new Apfloat("-9.1", 30));
        assertEquals("-9.1 precision", 28, a.precision());
        assertEquals("-9.1 value", new Apfloat("-582559810489.90457112077660061"), a, new Apfloat("5e-16"));
    }

    public static void testLogBarnesG()
    {
        Apfloat a = ApfloatMath.logBarnesG(new Apfloat(18, 40));
        assertEquals("18 precision", 39, a.precision());
        assertEquals("18 value", new Apfloat("207.86974661921518309851782277903674747"), a, new Apfloat("5e-37"));

        a = ApfloatMath.logBarnesG(new Apfloat("92.7", 40));
        assertEquals("92.7 precision", 40, a.precision());
        assertEquals("92.7 value", new Apfloat("12774.93602320205147995190254619656451333"), a, new Apfloat("5e-35"));

        try
        {
            ApfloatMath.logBarnesG(new Apfloat("0"));
            fail("0");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "logG.ofNonpositiveInteger", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.logBarnesG(new Apfloat("-0.1"));
            fail("-0.1");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.logBarnesG(new Apfloat("-1"));
            fail("-1");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "logG.ofNonpositiveInteger", aae.getLocalizationKey());
        }
    }

    public static void testBeta()
    {
        Apfloat a = ApfloatMath.beta(new Apfloat(5, 6), new Apfloat(6, 6));
        assertEquals("5, 6 precision", 6, a.precision(), 1);
        assertEquals("5, 6 value", new Apfloat("0.000793651"), a, new Apfloat("5e-9"));

        try
        {
            ApfloatMath.beta(new Apfloat("2.5", Apfloat.INFINITE), new Apfloat(3));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "gamma.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testBetaIncomplete()
    {
        Apfloat a = ApfloatMath.beta(new Apfloat(4, 6), new Apfloat(5, 6), new Apfloat(6, 6));
        assertEquals("4, 5, 6 precision", 6, a.precision(), 1);
        assertEquals("4, 5, 6 value", new Apfloat("-20944.9"), a, new Apfloat("5e-1"));

        a = ApfloatMath.beta(new Apfloat(0), new Apfloat("1.00000"), new Apfloat("6.00000"));
        assertEquals("0, 1, 6 precision", Apfloat.INFINITE, a.precision(), 1);
        assertEquals("0, 1, 6 value", new Apfloat(0), a);

        a = ApfloatMath.beta(new Apfloat("-0.100000"), new Apfloat("1.00000"), new Apfloat("6.00000"));
        assertEquals("-0.1, 1, 6 precision", 6, a.precision(), 1);
        assertEquals("-0.1, 1, 6 value", new Apfloat("-0.128594"), a, new Apfloat("5e-6"));

        a = ApfloatMath.beta(new Apfloat("1", 40, 2), new Apfloat("10", 40, 2), new Apfloat("0.1111111111111111111111111111111111111111", Apfloat.DEFAULT, 2));
        assertEquals("1, 10, 0.1111111111111111111111111111111111111111 radix 2 value", new Apfloat("0.1000000000000000000000000000000000000000", 40, 2), a, new Apfloat("1e-40", 1, 2));
        assertEquals("1, 10, 0.1111111111111111111111111111111111111111 radix 2 precision", 40, a.precision());

        try
        {
            ApfloatMath.beta(new Apfloat("0.1"), new Apfloat(0), new Apfloat("1"));
            fail("Beta of 0.1, 0, 1");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "betaIncomplete.withNonpositiveInteger", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.beta(new Apfloat("4"), new Apfloat(0), new Apfloat("6"));
            fail("Beta of 4, 0, 6");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "betaIncomplete.withNonpositiveInteger", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.beta(new Apfloat("0"), new Apfloat("-0.1"), new Apfloat("6"));
            fail("Beta of 0, -0.1, 6");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.beta(new Apfloat("0"), new Apfloat("-1"), new Apfloat("6"));
            fail("Beta of 0, -1, 6");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "betaIncomplete.withNonpositiveInteger", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.beta(new Apfloat("-0.1"), new Apfloat("0.1"), new Apfloat("6"));
            fail("Beta of -0.1, 0.1, 6");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.beta(new Apfloat("1.50000"), new Apfloat("-1.50000"), new Apfloat("2.50000"));
            fail("Beta of 1.5, -1.5, 2.5");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.beta(new Apfloat(2), new Apfloat(3), new Apfloat(4));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pow.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testBetaIncompleteGeneralized()
    {
        Apfloat a = ApfloatMath.beta(new Apfloat(3, 6), new Apfloat(4, 6), new Apfloat(5, 6), new Apfloat(6, 6));
        assertEquals("3, 4, 5, 6 precision", 6, a.precision(), 1);
        assertEquals("3, 4, 5, 6 value", new Apfloat("-20339.1"), a, new Apfloat("5e-1"));

        a = ApfloatMath.beta(new Apfloat(0), new Apfloat("1.00000"), new Apfloat("2.00000"), new Apfloat("6.00000"));
        assertEquals("0, 1, 2, 6 precision", 6, a.precision(), 1);
        assertEquals("0, 1, 2, 6 value", new Apfloat("0.0238095"), a, new Apfloat("5e-7"));

        a = ApfloatMath.beta(new Apfloat("1.00000"), new Apfloat(0), new Apfloat("2.00000"), new Apfloat("6.00000"));
        assertEquals("1, 0, 2, 6 precision", 6, a.precision(), 1);
        assertEquals("1, 0, 2, 6 value", new Apfloat("-0.0238095"), a, new Apfloat("5e-7"));

        a = ApfloatMath.beta(new Apfloat("-0.100000"), new Apfloat("1.00000"), new Apfloat("2.00000"), new Apfloat("6.00000"));
        assertEquals("-0.1, 1, 2, 6 precision", 6, a.precision(), 1);
        assertEquals("-0.1, 1, 2, 6 value", new Apfloat("0.0168720"), a, new Apfloat("5e-7"));

        a = ApfloatMath.beta(new Apfloat("1.00000"), new Apfloat("-0.100000"), new Apfloat("2.00000"), new Apfloat("6.00000"));
        assertEquals("1, -0.1, 2, 6 precision", 6, a.precision(), 1);
        assertEquals("1, -0.1, 2, 6 value", new Apfloat("-0.0168720"), a, new Apfloat("5e-7"));

        a = ApfloatMath.beta(new Apfloat("0.1", 40, 2), new Apfloat("1", 40, 2), new Apfloat("10", 40, 2), new Apfloat("0.1111111111111111111111111111111111111111", Apfloat.DEFAULT, 2));
        assertEquals("0.1, 1, 10, 0.1111111111111111111111111111111111111111, 2 radix 2 value", new Apfloat("0.01100000000000000000000000000000000000001", 39, 2), a, new Apfloat("1e-40", 1, 2));
        assertEquals("0.1, 1, 10,, 0.1111111111111111111111111111111111111111, 2 radix 2 precision", 39, a.precision());

        try
        {
            ApfloatMath.beta(new Apfloat("0.1"), new Apfloat("0.2"), new Apfloat(0), new Apfloat("1"));
            fail("Beta of 0.1, 0.2, 0, 1");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "betaIncompleteGeneralized.withNonpositiveInteger", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.beta(new Apfloat("3"), new Apfloat("4"), new Apfloat(0), new Apfloat("6"));
            fail("Beta of 3, 4, 0, 6");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "betaIncompleteGeneralized.withNonpositiveInteger", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.beta(new Apfloat("0"), new Apfloat("1"), new Apfloat("-0.1"), new Apfloat("6"));
            fail("Beta of 0, 1, -0.1, 6");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.beta(new Apfloat("1"), new Apfloat("0"), new Apfloat("-0.1"), new Apfloat("6"));
            fail("Beta of 1, 0, -0.1, 6");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.beta(new Apfloat("0"), new Apfloat("1"), new Apfloat("-1"), new Apfloat("6"));
            fail("Beta of 0, 1, -1, 6");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "betaIncompleteGeneralized.withNonpositiveInteger", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.beta(new Apfloat("1"), new Apfloat("0"), new Apfloat("-1"), new Apfloat("6"));
            fail("Beta of 1, 0, -1, 6");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "betaIncompleteGeneralized.withNonpositiveInteger", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.beta(new Apfloat("-0.1"), new Apfloat("1"), new Apfloat("0.1"), new Apfloat("6"));
            fail("Beta of -0.1, 1, 0.1, 6");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.beta(new Apfloat("1"), new Apfloat("-0.1"), new Apfloat("0.1"), new Apfloat("6"));
            fail("Beta of 1, -0.1, 0.1, 6");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.beta(new Apfloat("1.50000"), new Apfloat("0.500000"), new Apfloat("-1.50000"), new Apfloat("2.50000"));
            fail("Beta of 1.5, 0.5, -1.5, 2.5");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.beta(new Apfloat("0.500000"), new Apfloat("1.50000"), new Apfloat("-1.50000"), new Apfloat("2.50000"));
            fail("Beta of 0.5, 1.5, -1.5, 2.5");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.beta(new Apfloat(2), new Apfloat(3), new Apfloat(4), new Apfloat(5));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pow.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testPochhammer()
    {
        Apfloat a = ApfloatMath.pochhammer(new Apfloat("3.10000"), new Apfloat("2.40000"));
        assertEquals("3.1, 2.4 precision", 6, a.precision(), 1);
        assertEquals("3.1, 2.4 value", new Apfloat("23.8179"), a, new Apfloat("5e-4"));

        a = ApfloatMath.pochhammer(new Apfloat("-3.00000"), new Apfloat("2.40000"));
        assertEquals("-3, 2.4 precision", Apfloat.INFINITE, a.precision(), 1);
        assertEquals("-3, 2.4 value", new Apfloat(0), a);

        a = ApfloatMath.pochhammer(new Apfloat("-3.00000"), new Apfloat("-2.00000"));
        assertEquals("-3, -2 precision", 6, a.precision(), 1);
        assertEquals("-3, -2 value", new Apfloat("0.0500000"), a, new Apfloat("5e-7"));

        try
        {
            ApfloatMath.pochhammer(new Apfloat("-3.50000"), new Apfloat("-2.50000"));
            fail("Infinite allowed");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "gamma.ofNegativeInteger", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.pochhammer(new Apfloat(-2), new Apfloat(-3));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "divide.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testBinomial()
    {
        Apfloat a = ApfloatMath.binomial(new Apfloat("9.000000000"), new Apfloat("4.000000000"));
        assertEquals("9,4 precision", 10, a.precision());
        assertEquals("9,4 value", new Apfloat("126.0000000"), a, new Apfloat("5e-7"));

        a = ApfloatMath.binomial(new Apfloat("9.300000"), new Apfloat("4.200000"));
        assertEquals("9.3,4.2 precision", 6, a.precision());
        assertEquals("9.3,4.2 value", new Apfloat("154.376"), a, new Apfloat("5e-3"));

        a = ApfloatMath.binomial(new Apfloat("-9.30000"), new Apfloat("-4.20000"));
        assertEquals("-9.3,-4.2 precision", 6, a.precision(), 1);
        assertEquals("-9.3,-4.2 value", new Apfloat("0.000200991"), a, new Apfloat("5e-9"));

        a = ApfloatMath.binomial(new Apfloat(0), new Apfloat(0));
        assertEquals("0,0 precision", Apfloat.INFINITE, a.precision());
        assertEquals("0,0 value", new Apfloat(1), a);

        a = ApfloatMath.binomial(new Apfloat(1), new Apfloat(0));
        assertEquals("1,0 precision", Apfloat.INFINITE, a.precision());
        assertEquals("1,0 value", new Apfloat(1), a);

        a = ApfloatMath.binomial(new Apfloat("3.20000"), new Apfloat("4.00000"));
        assertEquals("3.2,4 precision", 6, a.precision());
        assertEquals("3.2,4 value", new Apfloat("0.0704000"), a, new Apfloat("5e-7"));

        a = ApfloatMath.binomial(new Apfloat("7.20000"), new Apfloat("4.20000"));
        assertEquals("7.2,4.2 precision", 6, a.precision());
        assertEquals("7.2,4.2 value", new Apfloat("38.6880"), a, new Apfloat("5e-4"));

        a = ApfloatMath.binomial(new Apfloat("3.20000"), new Apfloat("4.20000"));
        assertEquals("3.2,4.2 precision", Apfloat.INFINITE, a.precision());
        assertEquals("3.2,4.2 value", new Apfloat(0), a);

        a = ApfloatMath.binomial(new Apfloat("3.20000"), new Apfloat("-4.00000"));
        assertEquals("3.2,-4 precision", Apfloat.INFINITE, a.precision());
        assertEquals("3.2,-4 value", new Apfloat(0), a);

        try
        {
            ApfloatMath.binomial(new Apfloat("-3.0"), new Apfloat("4.2"));
            fail("Binomial of -3,4.2");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK; result is infinite
            assertEquals("Localization key", "gamma.ofNegativeInteger", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.binomial(new Apfloat(2), new Apfloat("2.5", Apfloat.INFINITE));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "gamma.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testZeta()
    {
        Apfloat a = ApfloatMath.zeta(new Apfloat("3.00000"));
        assertEquals("3 precision", 6, a.precision());
        assertEquals("3 value", new Apfloat("1.20206"), a, new Apfloat("5e-5"));

        a = ApfloatMath.zeta(new Apfloat("-101.000"));
        assertEquals("-101 precision", 4, a.precision());
        assertEquals("-101 value", new Apfloat("-7.261e78"), a, new Apfloat("5e75"));

        a = ApfloatMath.zeta(new Apfloat("-1001.000"));
        assertEquals("-1001 precision", 4, a.precision());
        assertEquals("-1001 value", new Apfloat("-1.349e1771"), a, new Apfloat("5e1768"));

        a = ApfloatMath.zeta(new Apfloat("-3.00000"));
        assertEquals("-3 precision", 6, a.precision());
        assertEquals("-3 value", new Apfloat("0.00833333"), a, new Apfloat("5e-8"));

        a = ApfloatMath.zeta(new Apfloat("-5.00000"));
        assertEquals("-5 precision", 6, a.precision());
        assertEquals("-5 value", new Apfloat("-0.00396825"), a, new Apfloat("5e-8"));

        a = ApfloatMath.zeta(new Apfloat("0.500000"));
        assertEquals("0.5 precision", 6, a.precision());
        assertEquals("0.5 value", new Apfloat("-1.46035"), a, new Apfloat("5e-5"));

        a = ApfloatMath.zeta(new Apfloat("0"));
        assertEquals("0 precision", Apfloat.INFINITE, a.precision());
        assertEquals("0 value", new Apfloat("-0.5"), a);

        a = ApfloatMath.zeta(new Apint(0, 11));
        assertEquals("0 precision", Apfloat.INFINITE, a.precision());
        assertEquals("0 value", new Aprational(new Apint(-1, 11), new Apint(2, 11)), a);

        a = ApfloatMath.zeta(new Apfloat(1000, 80));
        assertEquals("1000 precision 80", 80, a.precision());
        assertEquals("1000 value 80", new Apfloat(1), a, new Apfloat("5e-79"));
        assertTrue("1000 result 80 >= 1", a.compareTo(new Apfloat(1)) >= 0);

        a = ApfloatMath.zeta(new Apfloat(1000, 85));
        assertEquals("1000 precision 85", 85, a.precision());
        assertEquals("1000 value 85", new Apfloat(1), a, new Apfloat("5e-84"));
        assertTrue("1000 result 85 >= 1", a.compareTo(new Apfloat(1)) >= 0);

        a = ApfloatMath.zeta(new Apfloat(1000, 90));
        assertEquals("1000 precision 90", 90, a.precision());
        assertEquals("1000 value 90", new Apfloat(1), a, new Apfloat("5e-89"));
        assertTrue("1000 result 90 >= 1", a.compareTo(new Apfloat(1)) >= 0);

        a = ApfloatMath.zeta(new Apfloat(1000, 95));
        assertEquals("1000 precision 95", 95, a.precision());
        assertEquals("1000 value 95", new Apfloat(1), a, new Apfloat("5e-94"));
        assertTrue("1000 result 95 >= 1", a.compareTo(new Apfloat(1)) >= 0);

        a = ApfloatMath.zeta(new Apfloat(1000, 100));
        assertEquals("1000 precision 100", 100, a.precision());
        assertEquals("1000 value 100", new Apfloat(1), a, new Apfloat("5e-99"));
        assertTrue("1000 result 100 >= 1", a.compareTo(new Apfloat(1)) >= 0);

        try
        {
            ApfloatMath.zeta(new Apint(1, 11));
            fail("Zeta of one");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "zeta.ofOne", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.zeta(new Apfloat(2));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "zeta.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testZetaHurwitz()
    {
        Apfloat a = ApfloatMath.zeta(new Apfloat("3.00000"), new Apfloat("4.00000"));
        assertEquals("3,4 precision", 6, a.precision());
        assertEquals("3,4 value", new Apfloat("0.0400199"), a, new Apfloat("5e-7"));

        a = ApfloatMath.zeta(new Apfloat("3.00000"), new Apfloat("-4.20000"));
        assertEquals("3,4.2 precision", 6, a.precision());
        assertEquals("3,4.2 value", new Apfloat("-123.502"), a, new Apfloat("5e-3"));

        a = ApfloatMath.zeta(new Apfloat("-3.00000"), new Apfloat("-4.20000"));
        assertEquals("-3,4.2 precision", 6, a.precision());
        assertEquals("-3,4.2 value", new Apfloat("-119.2381"), a, new Apfloat("5e-3"));

        a = ApfloatMath.zeta(new Apfloat("3.00000"), new Apfloat("4.20000"));
        assertEquals("3,4.2 precision", 6, a.precision());
        assertEquals("3,4.2 value", new Apfloat("0.0358824"), a, new Apfloat("5e-7"));

        a = ApfloatMath.zeta(new Apfloat("3.20000"), new Apfloat("4.00000"));
        assertEquals("-3,4.2 precision", 6, a.precision());
        assertEquals("-3,4.2 value", new Apfloat("0.0282234"), a, new Apfloat("5e-7"));

        a = ApfloatMath.zeta(new Apfloat("3.20000"), new Apfloat("4.20000"));
        assertEquals("-3,4.2 precision", 6, a.precision());
        assertEquals("-3,4.2 value", new Apfloat("0.0250343"), a, new Apfloat("5e-7"));

        a = ApfloatMath.zeta(new Apfloat("-3.00000"), new Apfloat("-3.00000"));
        assertEquals("-3,-3 precision", 6, a.precision());
        assertEquals("-3,-3 value", new Apfloat("-35.9917"), a, new Apfloat("5e-4"));

        a = ApfloatMath.zeta(new Apfloat("-3.00000"), new Apfloat("-1.00000"));
        assertEquals("-3,-1 precision", 6, a.precision());
        assertEquals("-3,-1 value", new Apfloat("-0.991667"), a, new Apfloat("5e-6"));

        a = ApfloatMath.zeta(new Apfloat("-3.00000"), new Apfloat("0"));
        assertEquals("-3,0 precision", 6, a.precision());
        assertEquals("-3,0 value", new Apfloat("0.00833333"), a, new Apfloat("5e-8"));

        a = ApfloatMath.zeta(new Apfloat("-33.0000"), new Apfloat("0"));
        assertEquals("-33,0 precision", 6, a.precision());
        assertEquals("-33,0 value", new Apfloat("-1.26357e10"), a, new Apfloat("5e5"));

        a = ApfloatMath.zeta(new Apfloat("-333.000"), new Apfloat("0"));
        assertEquals("-333,0 precision", 6, a.precision());
        assertEquals("-333,0 value", new Apfloat("-5.2873977e430"), a, new Apfloat("5e425"));

        a = ApfloatMath.zeta(new Apfloat("-3.00000"), new Apfloat("1.00000"));
        assertEquals("-3,1 precision", 6, a.precision());
        assertEquals("-3,1 value", new Apfloat("0.00833333"), a, new Apfloat("5e-8"));

        a = ApfloatMath.zeta(new Apfloat("0"), new Apfloat("0"));
        assertEquals("0,0 precision", Apfloat.INFINITE, a.precision());
        assertEquals("0,0 value", new Apfloat("0.5"), a);

        try
        {
            ApfloatMath.zeta(new Apint(1, 11), new Apint(2, 11));
            fail("Zeta of s one");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "zeta.ofFirstOne", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.zeta(new Apfloat("-3.2"), new Apfloat("-4.2"));
            fail("Zeta of s noninteger and a nonpositive");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.zeta(new Apfloat("-3.2"), new Apfloat("-4.0"));
            fail("Zeta of s noninteger and a nonpositive");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.zeta(new Apfloat("-3.2"), new Apfloat("-4.2"));
            fail("Zeta of s noninteger and a nonpositive");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.zeta(new Apfloat("3.0"), new Apfloat("-3.0"));
            fail("3, -3 division by zero");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "zeta.ofSecondNonpositiveInteger", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.zeta(new Apfloat(2), new Apfloat(3));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "zeta.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testHypergeometric0F1()
    {
        Apfloat a = ApfloatMath.hypergeometric0F1(new Apfloat("2.00000"), new Apfloat("3.00000"));
        assertEquals("2, 3 precision", 6, a.precision());
        assertEquals("2, 3 value", new Apfloat("3.46865"), a, new Apfloat("5e-5"));

        a = ApfloatMath.hypergeometric0F1(new Apfloat(2, 60, 2), new Apfloat(3, 60, 2));
        assertEquals("2, 3 radix 2 precision", 60, a.precision());
        assertEquals("2, 3 radix 2 radix", 2, a.radix());
        assertEquals("2, 3 radix 2 value", new Apfloat("11.0111011111111001011010111110000111011011111111101110000100", 60, 2), a, new Apfloat("1e-58", 1, 2));

        try
        {
            ApfloatMath.hypergeometric0F1(new Apfloat(3), new Apfloat(4));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "hypergeometric.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testHypergeometric1F1()
    {
        Apfloat a = ApfloatMath.hypergeometric1F1(new Apfloat("2.00000"), new Apfloat("3.00000"), new Apfloat("4.00000"));
        assertEquals("2, 3, 4 precision", 6, a.precision());
        assertEquals("2, 3, 4 value", new Apfloat("20.5993"), a, new Apfloat("5e-4"));

        a = ApfloatMath.hypergeometric1F1(new Apfloat(2, 60, 2), new Apfloat(3, 60, 2), new Apfloat(4, 60, 2));
        assertEquals("2, 3, 4 radix 2 precision", 59, a.precision());
        assertEquals("2, 3, 4 radix 2 radix", 2, a.radix());
        assertEquals("2, 3, 4 radix 2 value", new Apfloat("10100.1001100101101100001000101001110101101011110000100100110", 60, 2), a, new Apfloat("1e-54", 1, 2));

        try
        {
            ApfloatMath.hypergeometric1F1(new Apfloat(3), new Apfloat(4), new Apfloat(5));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "hypergeometric.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testHypergeometric2F1()
    {
        Apfloat a = ApfloatMath.hypergeometric2F1(new Apfloat("1.00000"), new Apfloat("2.20000"), new Apfloat("3.30000"), new Apfloat("0.100000"));
        assertEquals("1, 2.2, 3.3, 0.1 precision", 6, a.precision());
        assertEquals("1, 2.2, 3.3, 0.1 value", new Apfloat("1.0720565"), a, new Apfloat("5e-6"));

        // x = 1
        a = ApfloatMath.hypergeometric2F1(new Apfloat("1.00000"), new Apfloat("2.20000"), new Apfloat("3.30000"), new Apfloat("1.000000"));
        assertEquals("1, 2.2, 3.3, 1 precision", 6, a.precision());
        assertEquals("1, 2.2, 3.3, 1 value", new Apfloat("23.0000"), a, new Apfloat("5e-4"));

        // Polynomial cases
        a = ApfloatMath.hypergeometric2F1(new Apfloat("-1.00000"), new Apfloat("2.20000"), new Apfloat("3.30000"), new Apfloat("5.000000"));
        assertEquals("-1, 2.2, 3.3, 5 precision", 6, a.precision());
        assertEquals("-1, 2.2, 3.3, 5 value", new Apfloat("-2.33333"), a, new Apfloat("5e-5"));

        a = ApfloatMath.hypergeometric2F1(new Apfloat("-3.00000"), new Apfloat("-1.00000"), new Apfloat("-2.00000"), new Apfloat("1.00000"));
        assertEquals("-3, -1, -2, 1 precision", 6, a.precision());
        assertEquals("-3, -1, -2, 1 value", new Apfloat("-0.500000"), a, new Apfloat("5e-6"));

        a = ApfloatMath.hypergeometric2F1(new Apfloat("-3.00000"), new Apfloat("-2.00000"), new Apfloat("-3.00000"), new Apfloat("1.00000"));
        assertEquals("-3, -2, -3, 1 precision", Apfloat.INFINITE, a.precision());
        assertEquals("-3, -2, -3, 1 value", new Apfloat("0"), a);

        a = ApfloatMath.hypergeometric2F1(new Apfloat(1, 40, 2), new Apfloat(2, 40, 2), new Apfloat(3, 40, 2), new Apfloat("0.1111111111111111111111111111111111111111", Apfloat.DEFAULT, 2));
        assertEquals("1, 2, 3, 0.1111111111111111111111111111111111111111 radix 2 value", new Apfloat("110101.0111001110100111011111010111000111", 40, 2), a, new Apfloat("1e-31", 1, 2));
        assertEquals("1, 2, 3, 0.1111111111111111111111111111111111111111 radix 2 precision", 40, a.precision());

        try
        {
            ApfloatMath.hypergeometric2F1(new Apfloat("1.00000"), new Apfloat("2.20000"), new Apfloat("3.30000"), new Apfloat("1.000001"));
            fail("2F1 of x > 1");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.hypergeometric2F1(new Apfloat(1), new Apfloat(2), new Apfloat(4), new Apfloat(2));
            fail("2F1 of x > 1 with infinite precision");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.hypergeometric2F1(new Apfloat("-2.00000"), new Apfloat("2.20000"), new Apfloat("-1.00000"), new Apfloat("0.000001"));
            fail("Infinite accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK result would be infinite
            assertEquals("Localization key", "divide.byZero", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.hypergeometric2F1(new Apfloat(2), new Apfloat(3), new Apfloat(6), new Apfloat(1));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "hypergeometric.infinitePrecision", iee.getLocalizationKey());
        }

        try
        {
            ApfloatMath.hypergeometric2F1(new Apfloat(-3), new Apfloat(-2), new Apfloat(-1), new Apfloat(1));
            fail("Division by zero accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "divide.byZero", aae.getLocalizationKey());
        }
    }

    public static void testHypergeometric0F1Regularized()
    {
        Apfloat a = ApfloatMath.hypergeometric0F1Regularized(new Apfloat("3.00000"), new Apfloat("4.00000"));
        assertEquals("3, 4 precision", 6, a.precision());
        assertEquals("3, 4 value", new Apfloat("1.60555"), a, new Apfloat("5e-5"));

        a = ApfloatMath.hypergeometric0F1Regularized(new Apfloat("-3.00000"), new Apfloat("-4.00000"));
        assertEquals("-3, -4 precision", 5, a.precision());
        assertEquals("-3, -4 value", new Apfloat("4.49807"), a, new Apfloat("5e-4"));

        a = ApfloatMath.hypergeometric0F1Regularized(new Apfloat(0), new Apfloat("-1009.00000"));
        assertEquals("0, -1009 precision", 6, a.precision());
        assertEquals("0, -1009 value", new Apfloat("0.259919"), a, new Apfloat("5e-6"));

        a = ApfloatMath.hypergeometric0F1Regularized(new Apfloat(-3, 60, 2), new Apfloat(4, 60, 2));
        assertEquals("-3, 4 radix 2 precision", 59, a.precision());
        assertEquals("-3, 4 radix 2 radix", 2, a.radix());
        assertEquals("-3, 4 radix 2 value", new Apfloat("10110.1010100100010000101101110110011111011100110111001110011", 60, 2), a, new Apfloat("1e-54", 1, 2));

        try
        {
            ApfloatMath.hypergeometric0F1Regularized(new Apfloat(-3), new Apfloat(4));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pow.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testHypergeometric1F1Regularized()
    {
        Apfloat a = ApfloatMath.hypergeometric1F1Regularized(new Apfloat("2.00000"), new Apfloat("3.00000"), new Apfloat("4.00000"));
        assertEquals("2, 3, 4 precision", 6, a.precision());
        assertEquals("2, 3, 4 value", new Apfloat("10.2996"), a, new Apfloat("5e-4"));

        a = ApfloatMath.hypergeometric1F1Regularized(new Apfloat("2.00000"), new Apfloat("-3.00000"), new Apfloat("4.00000"));
        assertEquals("2, -3, 4 precision", 6, a.precision());
        assertEquals("2, -3, 4 value", new Apfloat("125794"), a, new Apfloat("5e0"));

        a = ApfloatMath.hypergeometric1F1Regularized(new Apfloat(2, 60, 2), new Apfloat(-3, 60, 2), new Apfloat(4, 60, 2));
        assertEquals("2, -3, 4 radix 2 precision", 59, a.precision());
        assertEquals("2, -3, 4 radix 2 radix", 2, a.radix());
        assertEquals("2, -3, 4 radix 2 value", new Apfloat("11110101101100010.0010001100111110110000100001101000110111010", 60, 2), a, new Apfloat("1e-42", 1, 2));

        try
        {
            ApfloatMath.hypergeometric1F1Regularized(new Apfloat(3), new Apfloat(-4), new Apfloat(5));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pow.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testHypergeometric2F1Regularized()
    {
        Apfloat a = ApfloatMath.hypergeometric2F1Regularized(new Apfloat("1.00000"), new Apfloat("2.20000"), new Apfloat("3.30000"), new Apfloat("0.100000"));
        assertEquals("1, 2.2, 3.3, 0.1 precision", 6, a.precision());
        assertEquals("1, 2.2, 3.3, 0.1 value", new Apfloat("0.399509"), a, new Apfloat("5e-6"));

        // x = 1
        a = ApfloatMath.hypergeometric2F1Regularized(new Apfloat("1.00000"), new Apfloat("2.20000"), new Apfloat("3.30000"), new Apfloat("1.000000"));
        assertEquals("1, 2.2, 3.3, 1 precision", 6, a.precision());
        assertEquals("1, 2.2, 3.3, 1 value", new Apfloat("8.57110"), a, new Apfloat("5e-5"));

        // Polynomial cases
        a = ApfloatMath.hypergeometric2F1Regularized(new Apfloat("-1.00000"), new Apfloat("2.20000"), new Apfloat("3.30000"), new Apfloat("5.000000"));
        assertEquals("-1, 2.2, 3.3, 5 precision", 6, a.precision());
        assertEquals("-1, 2.2, 3.3, 5 value", new Apfloat("-0.869532"), a, new Apfloat("5e-6"));

        a = ApfloatMath.hypergeometric2F1Regularized(new Apfloat("-3.00000"), new Apfloat("-1.00000"), new Apfloat("-2.00000"), new Apfloat("1.00000"));
        assertEquals("-3, -1, -2, 1 precision", Apfloat.INFINITE, a.precision());
        assertEquals("-3, -1, -2, 1 value", new Apfloat("0"), a);

        a = ApfloatMath.hypergeometric2F1Regularized(new Apfloat("-3.00000"), new Apfloat("-2.00000"), new Apfloat("-3.00000"), new Apfloat("1.00000"));
        assertEquals("-3, -2, -3, 1 precision", Apfloat.INFINITE, a.precision());
        assertEquals("-3, -2, -3, 1 value", new Apfloat("0"), a);

        // Needs regularization
        a = ApfloatMath.hypergeometric2F1Regularized(new Apfloat("-2.00000"), new Apfloat("2.20000"), new Apfloat("-1.00000"), new Apfloat("0.100000"));
        assertEquals("-2, 2.2, -1, 0.1 precision", 6, a.precision());
        assertEquals("-2, 2.2, -1, 0.1 value", new Apfloat("0.0704000"), a, new Apfloat("5e-7"));

        a = ApfloatMath.hypergeometric2F1Regularized(new Apfloat(1, 40, 2), new Apfloat(2, 40, 2), new Apfloat(3, 40, 2), new Apfloat("0.1111111111111111111111111111111111111111", Apfloat.DEFAULT, 2));
        assertEquals("1, 2, 3, 0.1111111111111111111111111111111111111111 radix 2 value", new Apfloat("11010.10111001110100111011111010111000111", 40, 2), a, new Apfloat("1e-32", 1, 2));
        assertEquals("1, 2, 3, 0.1111111111111111111111111111111111111111 radix 2 precision", 40, a.precision());

        try
        {
            ApfloatMath.hypergeometric2F1Regularized(new Apfloat("1.00000"), new Apfloat("2.20000"), new Apfloat("3.30000"), new Apfloat("1.000001"));
            fail("2F1 of x > 1");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.hypergeometric2F1Regularized(new Apfloat(1), new Apfloat(2), new Apfloat(4), new Apfloat(2));
            fail("2F1 of x > 1 with infinite precision");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.hypergeometric2F1Regularized(new Apfloat(2), new Apfloat(3), new Apfloat(6), new Apfloat(1));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "hypergeometric.infinitePrecision", iee.getLocalizationKey());
        }

        try
        {
            ApfloatMath.hypergeometric2F1Regularized(new Apfloat(-3), new Apfloat(-2), new Apfloat(-1), new Apfloat(1));    // Needs regularization
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "hypergeometric.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testHypergeometricU()
    {
        Apfloat a = ApfloatMath.hypergeometricU(new Apfloat("2.00000"), new Apfloat("3.10000"), new Apfloat("4.00000"));
        assertEquals("2, 3.1, 4 precision", 6, a.precision());
        assertEquals("2, 3.1, 4 value", new Apfloat("0.0649421"), a, new Apfloat("5e-7"));

        a = ApfloatMath.hypergeometricU(new Apfloat("-2.10000"), new Apfloat("3.30000"), new Apfloat("2.00000"));
        assertEquals("-2.1, 3.3, 2 precision", 6, a.precision());
        assertEquals("-2.1, 3.3, 2 value", new Apfloat("2.13433"), a, new Apfloat("5e-5"));

        a = ApfloatMath.hypergeometricU(new Apfloat("2.10000"), new Apfloat("3.00000"), new Apfloat("2.00000"));
        assertEquals("2.1, 3, 2 precision", 6, a.precision());
        assertEquals("2.1, 3, 2 value", new Apfloat("0.218408"), a, new Apfloat("5e-6"));

        // Polynomial cases
        a = ApfloatMath.hypergeometricU(new Apfloat(0), new Apfloat("3.10000"), new Apfloat("-2.00000"));
        assertEquals("0, 3.1, -2 precision", 6, a.precision());
        assertEquals("0, 3.1, -2 value", new Apfloat("1.00000"), a, new Apfloat("5e-5"));

        a = ApfloatMath.hypergeometricU(new Apfloat("-2.00000"), new Apfloat("3.10000"), new Apfloat("-2.00000"));
        assertEquals("-2, 3.1, -2 precision", 6, a.precision());
        assertEquals("-2, 3.1, -2 value", new Apfloat("33.1100"), a, new Apfloat("5e-4"));

        a = ApfloatMath.hypergeometricU(new Apfloat("2.00000"), new Apfloat("3.00000"), new Apfloat("-2.00000"));
        assertEquals("2, 3, -2 precision", 6, a.precision());
        assertEquals("2, 3, -2 value", new Apfloat("0.250000"), a, new Apfloat("5e-6"));

        a = ApfloatMath.hypergeometricU(new Apfloat("-1.0"), new Apfloat("-1.5"), new Apfloat("0"));
        assertEquals("-1, -1.5, 0 precision", 2, a.precision());
        assertEquals("-1, -1.5, 0 value", new Apcomplex("1.5"), a, new Apfloat("5e-1"));

        a = ApfloatMath.hypergeometricU(new Apfloat("1.0"), new Apfloat("-1.5"), new Apfloat("0"));
        assertEquals("1, -1.5, 0 precision", 2, a.precision());
        assertEquals("1, -1.5, 0 value", new Apcomplex("0.40"), a, new Apfloat("5e-2"));

        a = ApfloatMath.hypergeometricU(new Apfloat("1.0"), new Apfloat("0.50"), new Apfloat("0"));
        assertEquals("1, 0.5, 0 precision", 2, a.precision());
        assertEquals("1, 0.5, 0 value", new Apcomplex("2.0"), a, new Apfloat("5e-1"));

        // Limit cases
        a = ApfloatMath.hypergeometricU(new Apfloat("1.50000"), new Apfloat("-2.00000"), new Apfloat("0.100000"));
        assertEquals("1.5, -2, 0.1 precision", 6, a.precision());
        assertEquals("1.5, -2, 0.1 value", new Apfloat("0.160301"), a, new Apfloat("5e-6"));

        a = ApfloatMath.hypergeometricU(new Apfloat("1.50000"), new Apfloat("2.00000"), new Apfloat("0.100000"));
        assertEquals("1.5, 2, 0.1 precision", 6, a.precision());
        assertEquals("1.5, 2, 0.1 value", new Apfloat("9.96165"), a, new Apfloat("5e-5"));

        try
        {
            ApfloatMath.hypergeometricU(new Apfloat("1.1"), new Apfloat("2.1"), new Apfloat("-0.10"));
            fail("x < 0 and not polynomial");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.hypergeometricU(new Apfloat("1.0"), new Apfloat("2.1"), new Apfloat("-0.10"));
            fail("x < 0 and not polynomial");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.hypergeometricU(new Apfloat("3.0"), new Apfloat("2.0"), new Apfloat("-1.0"));
            fail("x < 0 and not polynomial");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.hypergeometricU(new Apfloat("-0.50"), new Apfloat("1.0"), new Apfloat("0"));
            fail("x == 0 and not polynomial");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK result would be infinite
            assertEquals("Localization key", "pow.zeroToNegative", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.hypergeometricU(new Apfloat(3), new Apfloat(4), new Apfloat(5));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pow.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testErf()
    {
        Apfloat a = ApfloatMath.erf(new Apfloat("2.00000"));
        assertEquals("2 precision", 8, a.precision());
        assertEquals("2 value", new Apfloat("0.99532226"), a, new Apfloat("5e-8"));

        try
        {
            ApfloatMath.erf(new Apfloat(3));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testErfc()
    {
        Apfloat a = ApfloatMath.erfc(new Apfloat("2.00000"));
        assertEquals("2 precision", 6, a.precision());
        assertEquals("2 value", new Apfloat("0.00467773"), a, new Apfloat("5e-8"));

        try
        {
            ApfloatMath.erfc(new Apfloat(3));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testErfi()
    {
        Apfloat a = ApfloatMath.erfi(new Apfloat("2.00000"));
        assertEquals("2 precision", 6, a.precision());
        assertEquals("2 value", new Apfloat("18.5648"), a, new Apfloat("5e-4"));

        try
        {
            ApfloatMath.erfi(new Apfloat(3));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testInverseErf()
    {
        Apfloat a = ApfloatMath.inverseErf(new Apfloat("0.500000"));
        assertEquals("0.5 precision", 6, a.precision());
        assertEquals("0.5 value", new Apfloat("0.476936"), a, new Apfloat("5e-6"));

        a = ApfloatMath.inverseErf(new Apfloat("-0.0100000"));
        assertEquals("-0.01 precision", 6, a.precision());
        assertEquals("-0.01 value", new Apfloat("-0.00886250"), a, new Apfloat("5e-8"));

        a = ApfloatMath.inverseErf(new Apfloat("0.8", 100));
        assertEquals("0.8 precision", 100, a.precision());
        assertEquals("0.8 value", new Apfloat("0.9061938024368232200711627030956628666508668747462206614653792171330100552167389208141318241092656917"), a, new Apfloat("5e-100"));

        a = ApfloatMath.inverseErf(new Apfloat("0.99999999999999999999999999999999999999999999999999"));
        assertEquals("0.99999999999999999999999999999999999999999999999999 precision", 1, a.precision());
        assertEquals("0.99999999999999999999999999999999999999999999999999 value", new Apfloat("10"), a, new Apfloat("5e1"));

        a = ApfloatMath.inverseErf(new Apfloat("0.99999999999999999999999999999999999999999999999999", 99));
        assertEquals("0.99999999999999999999999999999999999999999999999999 precision", 50, a.precision());
        assertEquals("0.99999999999999999999999999999999999999999999999999 value", new Apfloat("10.592090169527365189021663925329799115594206455417"), a, new Apfloat("5e-48"));

        a = ApfloatMath.inverseErf(new Apfloat("0.7", 100, 9));
        assertEquals("0.7 precision", 100, a.precision());
        assertEquals("0.7 radix", 9, a.radix());
        assertEquals("0.7 value", new Apfloat("0.76818487807617820173552655636302134801487816266142015806376400456247340635433763871153387630807580274340", 100, 9), a, new Apfloat("5e-100", 1, 9));

        a = ApfloatMath.inverseErf(new Apfloat("0"));
        assertEquals("0 precision", Apfloat.INFINITE, a.precision());
        assertEquals("0 value", new Apfloat("0"), a);

        try
        {
            ApfloatMath.inverseErf(new Apfloat("1"));
            fail("1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.inverseErf(new Apfloat("-1"));
            fail("-1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.inverseErf(new Apfloat("1.1"));
            fail("1.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.inverseErf(new Apfloat("-1.1"));
            fail("-1.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.inverseErf(new Aprational("1/2"));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testInverseErfc()
    {
        Apfloat a = ApfloatMath.inverseErfc(new Apfloat("0.500000"));
        assertEquals("0.5 precision", 6, a.precision());
        assertEquals("0.5 value", new Apfloat("0.476936"), a, new Apfloat("5e-6"));

        a = ApfloatMath.inverseErfc(new Apfloat("1.0100000"));
        assertEquals("1.01 precision", 6, a.precision());
        assertEquals("1.01 value", new Apfloat("-0.00886250"), a, new Apfloat("5e-8"));

        a = ApfloatMath.inverseErfc(new Apfloat("0.8", 100));
        assertEquals("0.8 precision", 100, a.precision());
        assertEquals("0.8 value", new Apfloat("0.1791434546212916764927490166264718703039092770195297157934243908496107231958296585375860598181676620"), a, new Apfloat("5e-100"));

        a = ApfloatMath.inverseErfc(new Apfloat("1.99999999999999999999999999999999999999999999999999"));
        assertEquals("1.99999999999999999999999999999999999999999999999999 precision", 1, a.precision());
        assertEquals("1.99999999999999999999999999999999999999999999999999 value", new Apfloat("-10.592090169527365189021663925329799115594206455417"), a, new Apfloat("5e1"));

        a = ApfloatMath.inverseErfc(new Apfloat("1.99999999999999999999999999999999999999999999999999", 100));
        assertEquals("1.99999999999999999999999999999999999999999999999999 precision", 50, a.precision());
        assertEquals("1.99999999999999999999999999999999999999999999999999 value", new Apfloat("-10.592090169527365189021663925329799115594206455417"), a, new Apfloat("5e-48"));

        a = ApfloatMath.inverseErfc(new Apfloat("1e-50"));
        assertEquals("1e-50 precision", 1, a.precision());
        assertEquals("1e-50 value", new Apfloat("10"), a, new Apfloat("5e1"));

        a = ApfloatMath.inverseErfc(new Apfloat("0.7", 100, 9));
        assertEquals("0.7 precision", 100, a.precision());
        assertEquals("0.7 radix", 9, a.radix());
        assertEquals("0.7 value", new Apfloat("0.171425663605753727353512758150323485886618501752544182326432531337856381220182625185238532254168736114352", 100, 9), a, new Apfloat("5e-100", 1, 9));

        a = ApfloatMath.inverseErfc(new Apfloat("1"));
        assertEquals("1 precision", Apfloat.INFINITE, a.precision());
        assertEquals("1 value", new Apfloat("0"), a);

        try
        {
            ApfloatMath.inverseErfc(new Apfloat("0"));
            fail("0 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.inverseErfc(new Apfloat("2"));
            fail("2 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.inverseErfc(new Apfloat("-0.1"));
            fail("-0.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.inverseErfc(new Apfloat("2.1"));
            fail("2.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.inverseErfc(new Aprational("1/2"));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testDawsonF()
    {
        Apfloat a = ApfloatMath.dawsonF(new Apfloat("2.00000"));
        assertEquals("2 precision", 6, a.precision());
        assertEquals("2 value", new Apfloat("0.301340"), a, new Apfloat("5e-6"));

        a = ApfloatMath.dawsonF(new Apfloat("200000.00000000000000"));
        assertEquals("200000 precision", 11, a.precision());
        assertEquals("200000 value", new Apfloat("2.5000000000e-6"), a, new Apfloat("5e-16"));

        try
        {
            ApfloatMath.dawsonF(new Apfloat(3));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "hypergeometric.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testFresnelS()
    {
        Apfloat a = ApfloatMath.fresnelS(new Apfloat("2.00000"));
        assertEquals("2 precision", 6, a.precision());
        assertEquals("2 value", new Apfloat("0.343416"), a, new Apfloat("5e-6"));

        a = ApfloatMath.fresnelS(new Apfloat("200000.00000000000000"));
        assertEquals("200000 precision", 15, a.precision());
        assertEquals("200000 value", new Apfloat("0.4999984084505691190421"), a, new Apfloat("5e-15"));

        try
        {
            ApfloatMath.fresnelS(new Apfloat(3));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testFresnelC()
    {
        Apfloat a = ApfloatMath.fresnelC(new Apfloat("2.00000"));
        assertEquals("2 precision", 6, a.precision());
        assertEquals("2 value", new Apfloat("0.488253"), a, new Apfloat("5e-6"));

        a = ApfloatMath.fresnelC(new Apfloat("200000.00000000000000"));
        assertEquals("200000 precision", 15, a.precision());
        assertEquals("200000 value", new Apfloat("0.500000000000000"), a, new Apfloat("5e-15"));

        try
        {
            ApfloatMath.fresnelC(new Apfloat(3));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testExpIntegralE()
    {
        Apfloat a = ApfloatMath.expIntegralE(new Apfloat("2.00000"), new Apfloat("3.00000"));
        assertEquals("2, 3 precision", 6, a.precision());
        assertEquals("2, 3 value", new Apfloat("0.0106419"), a, new Apfloat("5e-7"));

        a = ApfloatMath.expIntegralE(new Apfloat("-0.100000"), new Apfloat("0.100000"));
        assertEquals("-0.1, 0.1 precision", 6, a.precision());
        assertEquals("-0.1, 0.1 value", new Apfloat("11.1138"), a, new Apfloat("5e-4"));

        a = ApfloatMath.expIntegralE(new Apfloat("0"), new Apfloat("-0.100000"));
        assertEquals("0, -0.1 precision", 6, a.precision());
        assertEquals("0, -0.1 value", new Apfloat("-11.0517"), a, new Apfloat("5e-4"));

        try
        {
            ApfloatMath.expIntegralE(new Apfloat("0"), new Apfloat("0"));
            fail("0, 0");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "pow.zeroToNegative", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.expIntegralE(new Apfloat("0.100000"), new Apfloat("-0.100000"));
            fail("x negative");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.expIntegralE(new Apfloat(3), new Apfloat(4));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pow.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testExpIntegralEi()
    {
        Apfloat a = ApfloatMath.expIntegralEi(new Apfloat("3.00000"));
        assertEquals("3 precision", 6, a.precision());
        assertEquals("3 value", new Apfloat("9.93383"), a, new Apfloat("5e-5"));

        a = ApfloatMath.expIntegralEi(new Apfloat("-3.00000"));
        assertEquals("-3 precision", 6, a.precision());
        assertEquals("-3 value", new Apfloat("-0.0130484"), a, new Apfloat("5e-7"));

        try
        {
            ApfloatMath.expIntegralEi(new Apfloat("0"));
            fail("Ei of zero");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "gammaIncomplete.upperOfNonpositive", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.expIntegralEi(new Apfloat(3));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testLogIntegral()
    {
        Apfloat a = ApfloatMath.logIntegral(new Apfloat("3.000000"));
        assertEquals("3 precision", 6, a.precision());
        assertEquals("3 value", new Apfloat("2.16359"), a, new Apfloat("5e-5"));

        a = ApfloatMath.logIntegral(new Apfloat("0.0500000"));
        assertEquals("0.05 precision", 6, a.precision());
        assertEquals("0.05 value", new Apfloat("-0.0131194"), a, new Apfloat("5e-7"));

        a = ApfloatMath.logIntegral(new Apfloat("1.1", 17));
        assertEquals("1.1 precision", 16, a.precision());
        assertEquals("1.1 value", new Apfloat("-1.675772830319200"), a, new Apfloat("5e-15"));

        a = ApfloatMath.logIntegral(new Apfloat("0.5", 50));
        assertEquals("0.5 precision", 50, a.precision());
        assertEquals("0.5 value", new Apfloat("-0.37867104306108797672720718463656098055123404097821"), a, new Apfloat("5e-50"));

        a = ApfloatMath.logIntegral(new Apfloat("0"));
        assertEquals("0 precision", Apfloat.INFINITE, a.precision());
        assertEquals("0 value", new Apfloat("0"), a, new Apfloat("5e-7"));

        try
        {
            ApfloatMath.logIntegral(new Apfloat("1"));
            fail("li of 1");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "gammaIncomplete.upperOfNonpositive", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.logIntegral(new Apfloat("-0.1"));
            fail("li of negative number");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.logIntegral(new Apfloat(3));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "log.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testSinIntegral()
    {
        Apfloat a = ApfloatMath.sinIntegral(new Apfloat("-3.00000"));
        assertEquals("-3 precision", 6, a.precision());
        assertEquals("-3 value", new Apfloat("-1.84865"), a, new Apfloat("5e-5"));

        try
        {
            ApfloatMath.sinIntegral(new Apfloat(3));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testCosIntegral()
    {
        Apfloat a = ApfloatMath.cosIntegral(new Apfloat("3.00000"));
        assertEquals("3 precision", 6, a.precision());
        assertEquals("3 value", new Apfloat("0.119630"), a, new Apfloat("5e-6"));

        try
        {
            ApfloatMath.cosIntegral(new Apfloat("0"));
            fail("Ci of zero");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "log.ofZero", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.cosIntegral(new Apfloat("-0.1"));
            fail("Ci of negative number");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.cosIntegral(new Apfloat(3));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "gammaIncomplete.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testSinhIntegral()
    {
        Apfloat a = ApfloatMath.sinhIntegral(new Apfloat("-3.00000"));
        assertEquals("-3 precision", 6, a.precision());
        assertEquals("-3 value", new Apfloat("-4.97344"), a, new Apfloat("5e-5"));

        try
        {
            ApfloatMath.sinhIntegral(new Apfloat(3));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testCoshIntegral()
    {
        Apfloat a = ApfloatMath.coshIntegral(new Apfloat("3.00000"));
        assertEquals("3 precision", 6, a.precision());
        assertEquals("3 value", new Apfloat("4.96039"), a, new Apfloat("5e-5"));

        try
        {
            ApfloatMath.coshIntegral(new Apfloat("0"));
            fail("Chi of zero");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "log.ofZero", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.coshIntegral(new Apfloat("-0.1"));
            fail("Chi of negative number");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.coshIntegral(new Apfloat(3));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "gammaIncomplete.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testAiryAi()
    {
        Apfloat a = ApfloatMath.airyAi(new Apfloat("-3.00000"));
        assertEquals("-3 precision", 6, a.precision());
        assertEquals("-3 value", new Apfloat("-0.378814"), a, new Apfloat("5e-6"));

        try
        {
            ApfloatMath.airyAi(new Apfloat(3));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "divide.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testAiryAiPrime()
    {
        Apfloat a = ApfloatMath.airyAiPrime(new Apfloat("-3.00000"));
        assertEquals("-3 precision", 6, a.precision());
        assertEquals("-3 value", new Apfloat("0.314584"), a, new Apfloat("5e-6"));

        try
        {
            ApfloatMath.airyAiPrime(new Apfloat(3));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "divide.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testAiryBi()
    {
        Apfloat a = ApfloatMath.airyBi(new Apfloat("-3.00000"));
        assertEquals("-3 precision", 6, a.precision());
        assertEquals("-3 value", new Apfloat("-0.198290"), a, new Apfloat("5e-6"));

        try
        {
            ApfloatMath.airyBi(new Apfloat(3));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "divide.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testAiryBiPrime()
    {
        Apfloat a = ApfloatMath.airyBiPrime(new Apfloat("-3.00000"));
        assertEquals("-3 precision", 6, a.precision());
        assertEquals("-3 value", new Apfloat("-0.675611"), a, new Apfloat("5e-6"));

        try
        {
            ApfloatMath.airyBiPrime(new Apfloat(3));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "divide.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testBesselJ()
    {
        Apfloat a = ApfloatMath.besselJ(new Apfloat("-3.00000"), new Apfloat("5.00000"));
        assertEquals("-3, 5 precision", 6, a.precision());
        assertEquals("-3, 5 value", new Apfloat("-0.364831"), a, new Apfloat("9e-6"));

        a = ApfloatMath.besselJ(new Apfloat("-1.00000"), new Apfloat("-1.10000"));
        assertEquals("-1, -1.1 precision", 6, a.precision());
        assertEquals("-1, -1.1 value", new Apfloat("0.470902"), a, new Apfloat("9e-6"));

        try
        {
            ApfloatMath.besselJ(new Apfloat("-0.1"), new Apfloat("0"));
            fail("-0.1, 0 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result is infinite
            assertEquals("Localization key", "pow.zeroToNegative", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.besselJ(new Apfloat("0.1"), new Apfloat("-0.1"));
            fail("0.1, -0.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.besselJ(new Apfloat(3), new Apfloat(4));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pow.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testBesselI()
    {
        Apfloat a = ApfloatMath.besselI(new Apfloat("-3.00000"), new Apfloat("5.00000"));
        assertEquals("-3, 5 precision", 6, a.precision());
        assertEquals("-3, 5 value", new Apfloat("10.3312"), a, new Apfloat("5e-4"));

        a = ApfloatMath.besselI(new Apfloat("-1.00000"), new Apfloat("-1.10000"));
        assertEquals("-1, -1.1 precision", 6, a.precision());
        assertEquals("-1, -1.1 value", new Apfloat("-0.637489"), a, new Apfloat("9e-6"));

        try
        {
            ApfloatMath.besselI(new Apfloat("-0.1"), new Apfloat("0"));
            fail("-0.1, 0 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result is infinite
            assertEquals("Localization key", "pow.zeroToNegative", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.besselI(new Apfloat("0.1"), new Apfloat("-0.1"));
            fail("0.1, -0.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.besselI(new Apfloat(3), new Apfloat(4));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pow.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testBesselY()
    {
        Apfloat a = ApfloatMath.besselY(new Apfloat("-3.00000"), new Apfloat("5.00000"));
        assertEquals("-3, 5 precision", 6, a.precision());
        assertEquals("-3, 5 value", new Apfloat("-0.146267"), a, new Apfloat("5e-6"));

        try
        {
            ApfloatMath.besselY(new Apfloat("1"), new Apfloat("0"));
            fail("1, 0 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result is infinite
            assertEquals("Localization key", "besselY.ofZero", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.besselY(new Apfloat("1"), new Apfloat("-0.1"));
            fail("1, -0.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.besselY(new Apfloat(3), new Apfloat(4));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testBesselK()
    {
        Apfloat a = ApfloatMath.besselK(new Apfloat("-3.00000"), new Apfloat("5.00000"));
        assertEquals("-3, 5 precision", 6, a.precision());
        assertEquals("-3, 5 value", new Apfloat("0.00829177"), a, new Apfloat("5e-8"));

        try
        {
            ApfloatMath.besselK(new Apfloat("1"), new Apfloat("0"));
            fail("1, 0 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result is infinite
            assertEquals("Localization key", "besselK.ofZero", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.besselK(new Apfloat("1"), new Apfloat("-0.1"));
            fail("1, -0.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.besselK(new Apfloat(-3), new Apfloat(4));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "gamma.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testStruveH()
    {
        Apfloat a = ApfloatMath.struveH(new Apfloat("3.00000"), new Apfloat("5.00000"));
        assertEquals("3, 5 precision", 6, a.precision());
        assertEquals("3, 5 value", new Apfloat("1.5087206466"), a, new Apfloat("5e-5"));

        a = ApfloatMath.struveH(new Apfloat("1.0000000000"), new Apfloat("-0.10000000000"));
        assertEquals("1, -0.1 precision", 11, a.precision());
        assertEquals("1, -0.1 value", new Apfloat("0.0021206516014"), a, new Apfloat("5e-13"));

        a = ApfloatMath.struveH(new Apfloat(3, 10, 9), new Apfloat(5, 10, 9));
        assertEquals("3, 5 radix 9 precision", 10, a.precision());
        assertEquals("3, 5 radix 9 value", new Apfloat("1.4517640066", 9, 9), a, new Apfloat("5e-9", 1, 9));

        try
        {
            ApfloatMath.struveH(new Apfloat("-1.00000"), new Apfloat(0));
            fail("Zero to power by zero");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "pow.zeroToZero", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.struveH(new Apfloat("1.1"), new Apfloat("-0.1"));
            fail("1.1, -0.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.struveH(new Apfloat(3), new Apfloat(5));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pow.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testStruveL()
    {
        Apfloat a = ApfloatMath.struveL(new Apfloat("3.00000"), new Apfloat("5.00000"));
        assertEquals("3, 5 precision", 6, a.precision());
        assertEquals("3, 5 value", new Apfloat("9.424304538"), a, new Apfloat("5e-5"));

        a = ApfloatMath.struveL(new Apfloat("1.0000000000"), new Apfloat("-0.10000000000"));
        assertEquals("1, -0.1 precision", 11, a.precision());
        assertEquals("1, -0.1 value", new Apfloat("0.0021234810228"), a, new Apfloat("5e-13"));

        a = ApfloatMath.struveL(new Apfloat(3, 10, 9), new Apfloat(5, 10, 9));
        assertEquals("3, 5 radix 9 precision", 10, a.precision());
        assertEquals("3, 5 radix 9 value", new Apfloat("10.3732767406", 9, 9), a, new Apfloat("5e-8", 1, 9));

        try
        {
            ApfloatMath.struveL(new Apfloat("-1.00000"), new Apfloat(0));
            fail("Zero to power by zero");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK
            assertEquals("Localization key", "pow.zeroToZero", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.struveL(new Apfloat("1.1"), new Apfloat("-0.1"));
            fail("1.1, -0.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.struveL(new Apfloat(3), new Apfloat(5));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pow.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testAngerJ()
    {
        Apfloat a = ApfloatMath.angerJ(new Apfloat("3.00000"), new Apfloat("5.00000"));
        assertEquals("3, 5 precision", 6, a.precision());
        assertEquals("3, 5 value", new Apfloat("0.3648312306"), a, new Apfloat("5e-6"));

        a = ApfloatMath.angerJ(new Apfloat("-2.10000"), new Apfloat("-2.30000"));
        assertEquals("-2.1, -2.3 precision", 4, a.precision());
        assertEquals("-2.1, -2.3 value", new Apfloat("0.410304"), a, new Apfloat("5e-6"));

        a = ApfloatMath.angerJ(new Apfloat(3, 10, 9), new Apfloat(5, 10, 9));
        assertEquals("3, 5 radix 9 precision", 10, a.precision());
        assertEquals("3, 5 radix 9 value", new Apfloat("0.32485824168", 9, 9), a, new Apfloat("5e-10", 1, 9));

        try
        {
            ApfloatMath.angerJ(new Apfloat(3), new Apfloat(5));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testWeberE()
    {
        Apfloat a = ApfloatMath.weberE(new Apfloat("3.00000"), new Apfloat("5.00000"));
        assertEquals("3, 5 precision", 5, a.precision());
        assertEquals("3, 5 value", new Apfloat("-0.2354811018"), a, new Apfloat("5e-6"));

        a = ApfloatMath.weberE(new Apfloat("-2.10000"), new Apfloat("-2.30000"));
        assertEquals("-2.1, -2.3 precision", 5, a.precision());
        assertEquals("-2.1, -2.3 value", new Apfloat("-0.112557"), a, new Apfloat("5e-6"));

        a = ApfloatMath.weberE(new Apfloat(3, 10, 9), new Apfloat(5, 10, 9));
        assertEquals("3, 5 radix 9 precision", 9, a.precision());
        assertEquals("3, 5 radix 9 value", new Apfloat("-0.2105882726", 9, 9), a, new Apfloat("5e-10", 1, 9));

        try
        {
            ApfloatMath.weberE(new Apfloat(3), new Apfloat(5));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testEllipticK()
    {
        Apfloat a = ApfloatMath.ellipticK(new Apfloat("-3.00000"));
        assertEquals("-3 precision", 6, a.precision());
        assertEquals("-3 value", new Apfloat("1.07826"), a, new Apfloat("5e-5"));

        a = ApfloatMath.ellipticK(new Apfloat("0.1111111111111111111111111111111111111111", Apfloat.DEFAULT, 2));
        assertEquals("0.1111111111111111111111111111111111111111 radix 2 value", new Apfloat("1111.001111111100111000001111010011000000", 40, 2), a, new Apfloat("1e-36", 1, 2));
        assertEquals("0.1111111111111111111111111111111111111111 radix 2 precision", 40, a.precision());

        try
        {
            ApfloatMath.ellipticK(new Apfloat("1.10000", 6, 2));
            fail("1.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.ellipticK(new Apfloat("1.00000"));
            fail("1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result is infinite
            assertEquals("Localization key", "divide.byZero", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.ellipticK(new Apfloat("0"));
            fail("Infinite expansion of pi/2");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }
        try
        {
            ApfloatMath.ellipticK(new Apfloat(-4));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testEllipticE()
    {
        Apfloat a = ApfloatMath.ellipticE(new Apfloat("-3.00000"));
        assertEquals("-3 precision", 6, a.precision());
        assertEquals("-3 value", new Apfloat("2.42211"), a, new Apfloat("5e-5"));

        a = ApfloatMath.ellipticE(new Apfloat("1.00000"));
        assertEquals("1 precision", 6, a.precision());
        assertEquals("1 value", new Apfloat("1.00000"), a, new Apfloat("5e-5"));

        a = ApfloatMath.ellipticE(new Apfloat("0.1111111111111111111111111111111111111111", Apfloat.DEFAULT, 2));
        assertEquals("0.1111111111111111111111111111111111111111 radix 2 value", new Apfloat("1.000000000000000000000000000000000000011", 40, 2), a, new Apfloat("1e-39", 1, 2));
        assertEquals("0.1111111111111111111111111111111111111111 radix 2 precision", 40, a.precision());

        try
        {
            ApfloatMath.ellipticE(new Apfloat("1.10000", 6, 2));
            fail("1.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.ellipticE(new Apfloat("0"));
            fail("Infinite expansion of pi/2");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }
        try
        {
            ApfloatMath.ellipticE(new Apfloat(-4));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testHermiteH()
    {
        Apfloat a = ApfloatMath.hermiteH(new Apfloat("2.00000"), new Apfloat("3.00000"));
        assertEquals("2, 3 precision", 6, a.precision());
        assertEquals("2, 3 value", new Apfloat("34.0000"), a, new Apfloat("5e-4"));

        try
        {
            ApfloatMath.hermiteH(new Apfloat(3), new Apfloat(4));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "gamma.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testLaguerreL()
    {
        Apfloat a = ApfloatMath.laguerreL(new Apfloat("2.00000"), new Apfloat("3.00000"));
        assertEquals("2, 3 precision", 6, a.precision());
        assertEquals("2, 3 value", new Apfloat("-0.500000"), a, new Apfloat("5e-6"));

        try
        {
            ApfloatMath.laguerreL(new Apfloat(3), new Apfloat(4));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "hypergeometric.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testLaguerreLGeneralized()
    {
        Apfloat a = ApfloatMath.laguerreL(new Apfloat("2.00000"), new Apfloat("3.00000"), new Apfloat("4.00000"));
        assertEquals("2, 3, 4 precision", 6, a.precision());
        assertEquals("2, 3, 4 value", new Apfloat("-2.00000"), a, new Apfloat("5e-5"));

        try
        {
            ApfloatMath.laguerreL(new Apfloat(3), new Apfloat(4), new Apfloat(5));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "hypergeometric.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testLegendreP()
    {
        Apfloat a = ApfloatMath.legendreP(new Apfloat("2.00000"), new Apfloat("3.00000"));
        assertEquals("2, 3 precision", 6, a.precision());
        assertEquals("2, 3 value", new Apfloat("13.0000"), a, new Apfloat("5e-4"));

        a = ApfloatMath.legendreP(new Apfloat("2.00000"), new Apfloat("-1.10000"));
        assertEquals("2, -1.1 precision", 6, a.precision());
        assertEquals("2, -1.1 value", new Apfloat("1.31500"), a, new Apfloat("5e-5"));

        a = ApfloatMath.legendreP(new Apfloat("5.000000"), new Apfloat("-1.000000"));
        assertEquals("5, -1 precision", 6, a.precision());
        assertEquals("5, -1 value", new Apfloat("-1.00000"), a, new Apfloat("5e-5"));

        a = ApfloatMath.legendreP(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2));
        assertEquals("0.1, 0.11 radix 2 precision", 18, a.precision());
        assertEquals("0.1, 0.11 radix 2 radix", 2, a.radix());
        assertEquals("0.1, 0.11 radix 2 value", new Apfloat("0.111001101111110011", 18, 2), a, new Apfloat("1e-18", 1, 2));

        try
        {
            ApfloatMath.legendreP(new Apfloat("2.10000"), new Apfloat("-1.00000"));
            fail("2.1, -1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be infinite
            assertEquals("Localization key", "hypergeometric.nonconvergence", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.legendreP(new Apfloat("2.10000"), new Apfloat("-1.10000"));
            fail("2.1, -1.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.legendreP(new Apfloat(3), new Apfloat(4));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "hypergeometric.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testLegendrePAssociated()
    {
        Apfloat a = ApfloatMath.legendreP(new Apfloat("2.10000"), new Apfloat("3.20000"), new Apfloat("0.500000"));
        assertEquals("2.1, 3.2, 0.5 precision", 6, a.precision());
        assertEquals("2.1, 3.2, 0.5 value", new Apfloat("-5.81509"), a, new Apfloat("5e-5"));

        a = ApfloatMath.legendreP(new Apfloat("2.00000"), new Apfloat("3.00000"), new Apfloat("1.10000"));
        assertEquals("2, 3, 1.1 precision", Apfloat.INFINITE, a.precision());
        assertEquals("2, 3, 1.1 value", new Apfloat("0"), a);

        a = ApfloatMath.legendreP(new Apfloat("2.00000"), new Apfloat("3.00000"), new Apfloat("-1.10000"));
        assertEquals("2, 3, -1.1 precision", Apfloat.INFINITE, a.precision());
        assertEquals("2, 3, -1.1 value", new Apfloat("0"), a);

        a = ApfloatMath.legendreP(new Apfloat("0"), new Apfloat("1.00000"), new Apfloat("1.100000"));
        assertEquals("0, 3, -1.1 precision", Apfloat.INFINITE, a.precision());
        assertEquals("0, 3, -1.1 value", new Apfloat("0"), a);

        a = ApfloatMath.legendreP(new Apfloat("-5.00000"), new Apfloat("5.00000"), new Apfloat("1.100000"));
        assertEquals("-5, 5, -1.1 precision", Apfloat.INFINITE, a.precision());
        assertEquals("-5, 5, -1.1 value", new Apfloat("0"), a);

        a = ApfloatMath.legendreP(new Apfloat("2.10000"), new Apfloat("2.00000"), new Apfloat("1.10000"));
        assertEquals("2.1, 2, 1.1 precision", 6, a.precision());
        assertEquals("2.1, 2, 1.1 value", new Apfloat("-0.777038"), a, new Apfloat("5e-6"));

        a = ApfloatMath.legendreP(new Apfloat("-5.000000"), new Apfloat("4.000000"), new Apfloat("-1.100000"));
        assertEquals("-5, 4, -1.1 precision", 6, a.precision());
        assertEquals("-5, 4, -1.1 value", new Apfloat("4.63050"), a, new Apfloat("5e-5"));

        a = ApfloatMath.legendreP(new Apfloat("-3.00000"), new Apfloat("-4.00000"), new Apfloat("-1.10000"));
        assertEquals("-3, -4, -1.1 precision", 6, a.precision());
        assertEquals("-3, -4, -1.1 value", new Apfloat("3.32587"), a, new Apfloat("5e-5"));

        a = ApfloatMath.legendreP(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2), new Apfloat("0.111", 18, 2));
        assertEquals("0.1, 0.11, 0.111 radix 2 precision", 18, a.precision());
        assertEquals("0.1, 0.11, 0.111 radix 2 radix", 2, a.radix());
        assertEquals("0.1, 0.11, 0.111 radix 2 value", new Apfloat("0.1001110100101111011", 18, 2), a, new Apfloat("1e-18", 1, 2));

        try
        {
            ApfloatMath.legendreP(new Apfloat("1.10000"), new Apfloat("1.00000"), new Apfloat("1.100000"));
            fail("1.1, 1, 1.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.legendreP(new Apfloat("1.00000"), new Apfloat("1.10000"), new Apfloat("1.100000"));
            fail("1, 1.1, 1.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.legendreP(new Apfloat("2.10000"), new Apfloat("4.00000"), new Apfloat("-1.10000"));
            fail("2.1, 4, -1.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.legendreP(new Apfloat("-4.00000"), new Apfloat("-3.00000"), new Apfloat("-1.10000"));
            fail("-4, -3, -1.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.legendreP(new Apfloat("1.00000"), new Apfloat("1.00000"), new Apfloat("1.100000"));
            fail("1, 1, 1.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.legendreP(new Apfloat("-6.00000"), new Apfloat("5.00000"), new Apfloat("1.100000"));
            fail("-6, 5, 1.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.legendreP(new Apfloat(3), new Apfloat(4), new Apfloat(5));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pow.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testLegendreQ()
    {
        Apfloat a = ApfloatMath.legendreQ(new Apfloat("2.00000"), new Apfloat("0.300000"));
        assertEquals("2, 0.3 precision", 6, a.precision());
        assertEquals("2, 0.3 value", new Apfloat("-0.562975"), a, new Apfloat("5e-6"));

        a = ApfloatMath.legendreQ(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2));
        assertEquals("0.1, 0.11 radix 2 precision", 18, a.precision());
        assertEquals("0.1, 0.11 radix 2 radix", 2, a.radix());
        assertEquals("0.1, 0.11 radix 2 value", new Apfloat("0.00111001011011111100", 18, 2), a, new Apfloat("1e-20", 1, 2));

        try
        {
            ApfloatMath.legendreQ(new Apfloat("2.10000"), new Apfloat("1.10000"));
            fail("2.1, 1.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.legendreQ(new Apfloat("2.00000"), new Apfloat("1.00000"));
            fail("2, 1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be infinite
            assertEquals("Localization key", "hypergeometric.nonconvergence", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.legendreQ(new Apfloat("2.10000"), new Apfloat("-1.00000"));
            fail("2.1, -1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be infinite
            assertEquals("Localization key", "hypergeometric.nonconvergence", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.legendreQ(new Apfloat("2.10000"), new Apfloat("-1.10000"));
            fail("2.1, -1.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.legendreQ(new Apfloat(0), new Apfloat(1));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testLegendreQAssociated()
    {
        Apfloat a = ApfloatMath.legendreQ(new Apfloat("2.00000"), new Apfloat("3.00000"), new Apfloat("0.300000"));
        assertEquals("2, 3, 0.3 precision", 6, a.precision());
        assertEquals("2, 3, 0.3 value", new Apfloat("-9.21569"), a, new Apfloat("5e-5"));

        a = ApfloatMath.legendreQ(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2), new Apfloat("0.111", 18, 2));
        assertEquals("0.1, 0.11, 0.111 radix 2 precision", 18, a.precision());
        assertEquals("0.1, 0.11, 0.111 radix 2 radix", 2, a.radix());
        assertEquals("0.1, 0.11, 0.111 radix 2 value", new Apfloat("-1.110000000111111111", 18, 2), a, new Apfloat("1e-17", 1, 2));

        try
        {
            ApfloatMath.legendreQ(new Apfloat("2.10000"), new Apfloat("3.00000"), new Apfloat("1.10000"));
            fail("2.1, 3, 1.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.legendreQ(new Apfloat("2.00000"), new Apfloat("3.00000"), new Apfloat("1.00000"));
            fail("2, 3, 1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be infinite
            assertEquals("Localization key", "pow.zeroToNegative", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.legendreQ(new Apfloat("2.10000"), new Apfloat("3.00000"), new Apfloat("-1.00000"));
            fail("2.1, 3, -1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be infinite
            assertEquals("Localization key", "pow.zeroToNegative", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.legendreQ(new Apfloat("2.10000"), new Apfloat("3.00000"), new Apfloat("-1.10000"));
            fail("2.1, 3, -1.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.legendreQ(new Apfloat(0), new Apfloat(2), new Apfloat(1));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testChebyshevT()
    {
        Apfloat a = ApfloatMath.chebyshevT(new Apfloat("2.00000"), new Apfloat("3.00000"));
        assertEquals("2, 3 precision", 6, a.precision());
        assertEquals("2, 3 value", new Apfloat("17.0000"), a, new Apfloat("5e-4"));

        a = ApfloatMath.chebyshevT(new Apfloat("2.30000"), new Apfloat("-1.00000"));
        assertEquals("2.3, -1 precision", 6, a.precision());
        assertEquals("2.3, -1 value", new Apfloat("0.587785"), a, new Apfloat("5e-6"));

        a = ApfloatMath.chebyshevT(new Apfloat("2.00000"), new Apfloat("-1.10000"));
        assertEquals("2, -1.1 precision", 6, a.precision());
        assertEquals("2, -1.1 value", new Apfloat("1.42000"), a, new Apfloat("5e-5"));

        a = ApfloatMath.chebyshevT(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2));
        assertEquals("0.1, 0.11 radix 2 precision", 18, a.precision());
        assertEquals("0.1, 0.11 radix 2 radix", 2, a.radix());
        assertEquals("0.1, 0.11 radix 2 value", new Apfloat("0.111011110111011101", 18, 2), a, new Apfloat("1e-18", 1, 2));

        try
        {
            ApfloatMath.chebyshevT(new Apfloat("2.30000"), new Apfloat("-1.00001"));
            fail("2.3, -1.00001 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.chebyshevT(new Apfloat(3), new Apfloat(4));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "inverseRoot.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testChebyshevU()
    {
        Apfloat a = ApfloatMath.chebyshevU(new Apfloat("2.00000"), new Apfloat("3.00000"));
        assertEquals("2, 3 precision", 6, a.precision());
        assertEquals("2, 3 value", new Apfloat("35.0000"), a, new Apfloat("5e-4"));

        a = ApfloatMath.chebyshevU(new Apfloat("2.00000"), new Apfloat("-1.00000"));
        assertEquals("2, -1 precision", 6, a.precision());
        assertEquals("2, -1 value", new Apfloat("3.00000"), a, new Apfloat("5e-5"));

        a = ApfloatMath.chebyshevU(new Apfloat("2.000000"), new Apfloat("-1.100000"));
        assertEquals("2, -1.1 precision", 6, a.precision());
        assertEquals("2, -1.1 value", new Apfloat("3.84000"), a, new Apfloat("5e-5"));

        a = ApfloatMath.chebyshevU(new Apfloat("0.1", 20, 2), new Apfloat("0.11", 20, 2));
        assertEquals("0.1, 0.11 radix 2 precision", 18, a.precision());
        assertEquals("0.1, 0.11 radix 2 radix", 2, a.radix());
        assertEquals("0.1, 0.11 radix 2 value", new Apfloat("1.01010110000110000", 18, 2), a, new Apfloat("1e-17", 1, 2));

        try
        {
            ApfloatMath.chebyshevU(new Apfloat("2.10000"), new Apfloat("-1.00000"));
            fail("2.1, -1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be infinite
            assertEquals("Localization key", "inverseRoot.ofZero", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.chebyshevU(new Apfloat("2.10000"), new Apfloat("-1.00001"));
            fail("2.1, -1.00001 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.chebyshevU(new Apfloat(3), new Apfloat(4));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "inverseRoot.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testGegenbauerCRenormalized()
    {
        Apfloat a = ApfloatMath.gegenbauerC(new Apfloat("2.00000"), new Apfloat("3.00000"));
        assertEquals("2, 3 precision", 6, a.precision());
        assertEquals("2, 3 value", new Apfloat("17.0000"), a, new Apfloat("5e-4"));

        a = ApfloatMath.gegenbauerC(new Apfloat("2.10000"), new Apfloat("-1.00000"));
        assertEquals("2.1, -1 precision", 6, a.precision());
        assertEquals("2.1, -1 value", new Apfloat("0.905768"), a, new Apfloat("5e-6"));

        a = ApfloatMath.gegenbauerC(new Apfloat("-2.00000"), new Apfloat("-1.10000"));
        assertEquals("-2, -1.1 precision", 6, a.precision());
        assertEquals("-2, -1.1 value", new Apfloat("-1.42000"), a, new Apfloat("5e-5"));

        a = ApfloatMath.gegenbauerC(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2));
        assertEquals("0.1, 0.11 radix 2 precision", 18, a.precision());
        assertEquals("0.1, 0.11 radix 2 radix", 2, a.radix());
        assertEquals("0.1, 0.11 radix 2 value", new Apfloat("11.1011110111011101", 18, 2), a, new Apfloat("1e-16", 1, 2));

        try
        {
            ApfloatMath.gegenbauerC(new Apfloat("0"), new Apfloat("1.00000"));
            fail("0, 1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be infinite
            assertEquals("Localization key", "divide.byZero", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.gegenbauerC(new Apfloat("2.10000"), new Apfloat("-1.00001"));
            fail("2.1, -1.00001 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.gegenbauerC(new Apfloat(3), new Apfloat(4));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "divide.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testGegenbauerC()
    {
        Apfloat a = ApfloatMath.gegenbauerC(new Apfloat("2.00000"), new Apfloat("3.00000"), new Apfloat("4.00000"));
        assertEquals("2, 3, 4 precision", 6, a.precision());
        assertEquals("2, 3, 4 value", new Apfloat("381.000"), a, new Apfloat("5e-3"));

        a = ApfloatMath.gegenbauerC(new Apfloat("-2.10000"), new Apfloat("-0.500000"), new Apfloat("2.10000"));
        assertEquals("-2.1, -0.5, 2.1 precision", 6, a.precision());
        assertEquals("-2.1, -0.5, 2.1 value", new Apfloat("-3.90011"), a, new Apfloat("5e-5"));

        a = ApfloatMath.gegenbauerC(new Apfloat("-2.000000"), new Apfloat("-3.10000"), new Apfloat("-1.100000"));
        assertEquals("-2, -3.1, -1.1 precision", Apfloat.INFINITE, a.precision());
        assertEquals("-2, -3.1, -1.1 value", new Apfloat("0"), a);

        a = ApfloatMath.gegenbauerC(new Apfloat("3.00000"), new Apfloat("0.500000"), new Apfloat("-1.00000"));
        assertEquals("3, 0.5, 2.1 precision", 6, a.precision());
        assertEquals("3, 0.5, 2.1 value", new Apfloat("-1.00000"), a, new Apfloat("5e-5"));

        a = ApfloatMath.gegenbauerC(new Apfloat("-3.00000"), new Apfloat("0.500000"), new Apfloat("-1.00000"));
        assertEquals("-3, 0.5, 2.1 precision", 6, a.precision());
        assertEquals("-3, 0.5, 2.1 value", new Apfloat("1.00000"), a, new Apfloat("5e-5"));

        a = ApfloatMath.gegenbauerC(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2), new Apfloat("0.111", 18, 2));
        assertEquals("0.1, 0.11, 0.111 radix 2 precision", 18, a.precision());
        assertEquals("0.1, 0.11, 0.111 radix 2 radix", 2, a.radix());
        assertEquals("0.1, 0.11, 0.111 radix 2 value", new Apfloat("1.00110101010011001", 18, 2), a, new Apfloat("1e-17", 1, 2));

        try
        {
            ApfloatMath.gegenbauerC(new Apfloat("2.10000"), new Apfloat("3.10000"), new Apfloat("-1.00000"));
            fail("2.1, 3.1, -1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be infinite
            assertEquals("Localization key", "hypergeometric.nonconvergence", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.gegenbauerC(new Apfloat("-2.10000"), new Apfloat("0.500000"), new Apfloat("-1.00000"));
            fail("-2.1, 0.5, -1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be infinite
            assertEquals("Localization key", "hypergeometric.nonconvergence", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.gegenbauerC(new Apfloat("2.10000"), new Apfloat("1"), new Apfloat("-1.00001"));
            fail("2.1, 1, -1.00001 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.gegenbauerC(new Apfloat(3), new Apfloat(4), new Apfloat(5));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "divide.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testJacobiP()
    {
        Apfloat a = ApfloatMath.jacobiP(new Apfloat("3.0000"), new Apfloat("4.0000"), new Apfloat("5.0000"), new Apfloat("6.0000"));
        assertEquals("3, 4, 5, 6 precision", 6, a.precision());
        assertEquals("3, 4, 5, 6 value", new Apfloat("11808.1"), a, new Apfloat("5e-1"));

        a = ApfloatMath.jacobiP(new Apfloat("2.10000"), new Apfloat("-1.00000"), new Apfloat("-1.00000"), new Apfloat("-1.00000"));
        assertEquals("2.1, -1, -1, -1 precision", 6, a.precision());
        assertEquals("2.1, -1, -1, -1 value", new Apfloat("0.0468396"), a, new Apfloat("5e-7"));

        a = ApfloatMath.jacobiP(new Apfloat("1.0000000"), new Apfloat("-2.0000000"), new Apfloat("-1.0000000"), new Apfloat("-1.1000000"));
        assertEquals("1, -2, -1, -1.1 precision", 6, a.precision());
        assertEquals("1, -2, -1, -1.1 value", new Apfloat("0.0500000"), a, new Apfloat("5e-7"));

        a = ApfloatMath.jacobiP(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2), new Apfloat("0.111", 18, 2), new Apfloat("0.1111", 18, 2));
        assertEquals("0.1, 0.11, 0.111, 0.1111 radix 2 precision", 18, a.precision());
        assertEquals("0.1, 0.11, 0.111, 0.1111 radix 2 radix", 2, a.radix());
        assertEquals("0.1, 0.11, 0.111, 0.1111 radix 2 value", new Apfloat("1.0101101000001101011", 18, 2), a, new Apfloat("1e-17", 1, 2));

        try
        {
            ApfloatMath.jacobiP(new Apfloat("2.10000"), new Apfloat("-1.00000"), new Apfloat("0.100000"), new Apfloat("-1.00000"));
            fail("2.1, -1, 0.1, -1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be infinite
            assertEquals("Localization key", "hypergeometric.nonconvergence", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.jacobiP(new Apfloat("2.10000"), new Apfloat("-1.00000"), new Apfloat("-1.00000"), new Apfloat("-1.10000"));
            fail("2.1, -1, -1, -1.1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.jacobiP(new Apfloat("-0.50000"), new Apfloat("-0.50000"), new Apfloat("1.00000"), new Apfloat("1.00000"));
            fail("-0.5, -0.5, 1, 1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "gamma.ofZero", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.jacobiP(new Apfloat(3), new Apfloat(4), new Apfloat(5), new Apfloat(6));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "divide.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testFibonacci()
    {
        Apfloat a = ApfloatMath.fibonacci(new Apfloat("3.00000"), new Apfloat("4.00000"));
        assertEquals("3, 4 precision", 6, a.precision());
        assertEquals("3, 4 value", new Apfloat("17.0000"), a, new Apfloat("5e-4"));

        a = ApfloatMath.fibonacci(new Apfloat("5.60000"), new Apfloat("7.80000"));
        assertEquals("5.6, 7.8 precision", 6, a.precision());
        assertEquals("5.6, 7.8 value", new Apfloat("13453.4"), a, new Apfloat("5e-1"));

        try
        {
            ApfloatMath.fibonacci(new Apfloat(3), new Apfloat(4));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testEulerE()
    {
        Apfloat a = ApfloatMath.eulerE(3, new Apfloat("4.00000"));
        assertEquals("3, 4 precision", 6, a.precision());
        assertEquals("3, 4 value", new Apfloat("40.2500"), a, new Apfloat("5e-4"));

        a = ApfloatMath.eulerE(56, new Apfloat("7.80000"));
        assertEquals("56, 7.8 precision", 6, a.precision());
        assertEquals("56, 7.8 value", new Apfloat("6.61538e45"), a, new Apfloat("5e40"));

        try
        {
            ApfloatMath.eulerE(3, new Apfloat(4));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "divide.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testBernoulliB()
    {
        Apfloat a = ApfloatMath.bernoulliB(3, new Apfloat("4.00000"));
        assertEquals("3, 4 precision", 6, a.precision());
        assertEquals("3, 4 value", new Apfloat("42.0000"), a, new Apfloat("5e-4"));

        a = ApfloatMath.bernoulliB(56, new Apfloat("7.80000"));
        assertEquals("56, 7.8 precision", 6, a.precision());
        assertEquals("56, 7.8 value", new Apfloat("3.43754e47"), a, new Apfloat("5e42"));

        try
        {
            ApfloatMath.bernoulliB(3, new Apfloat(4));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "divide.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testHarmonicNumber()
    {
        Apfloat a = ApfloatMath.harmonicNumber(new Apfloat("3.45000"));
        assertEquals("3.45 precision", 6, a.precision());
        assertEquals("3.45 value", new Apfloat("1.95357"), a, new Apfloat("5e-5"));

        try
        {
            ApfloatMath.harmonicNumber(new Apfloat("-1.0000"));
            fail("-1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be infinite
            assertEquals("Localization key", "digamma.ofNonpositiveInteger", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.harmonicNumber(new Apfloat(4));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "euler.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testHarmonicNumberGeneralized()
    {
        Apfloat a = ApfloatMath.harmonicNumber(new Apfloat("3.40000"), new Apfloat("5.60000"));
        assertEquals("3.4, 5.6 precision", 6, a.precision());
        assertEquals("3.4, 5.6 value", new Apfloat("1.02299"), a, new Apfloat("5e-5"));

        a = ApfloatMath.harmonicNumber(new Apfloat("-1.00000"), new Apfloat("0"));
        assertEquals("-1, 0 precision", 6, a.precision());
        assertEquals("-1, 0 value", new Apfloat("-1.00000"), a, new Apfloat("5e-5"));

        a = ApfloatMath.harmonicNumber(new Apfloat("-1.00000"), new Apfloat("-1.00000"));
        assertEquals("-1, -1 precision", Apfloat.INFINITE, a.precision());
        assertEquals("-1, -1 value", new Apfloat("0"), a);

        a = ApfloatMath.harmonicNumber(new Apfloat("-1.100000"), new Apfloat("-1.000000"));
        assertEquals("-1.1, -1 precision", 6, a.precision());
        assertEquals("-1.1, -1 value", new Apfloat("0.0550000"), a, new Apfloat("5e-5"));

        a = ApfloatMath.harmonicNumber(new Apfloat("-4.00000"), new Apfloat("-3.00000"));
        assertEquals("-4, -3 precision", 6, a.precision());
        assertEquals("-4, -3 value", new Apfloat("36.0000"), a, new Apfloat("5e-4"));

        a = ApfloatMath.harmonicNumber(new Apfloat("0.1", 21, 2), new Apfloat("0.11", 21, 2));
        assertEquals("0.5, 0.75 precision", 18, a.precision());
        assertEquals("0.5, 0.75 radix", 2, a.radix());
        assertEquals("0.5, 0.75 value", new Apfloat("0.10010110001101010101", 18, 2), a, new Apfloat("1e-18", 1, 2));

        try
        {
            ApfloatMath.harmonicNumber(new Apfloat("-1.0000"), new Apfloat("1.0000"));
            fail("-1, 1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be infinite
            assertEquals("Localization key", "digamma.ofNonpositiveInteger", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.harmonicNumber(new Apfloat("-1.10000"), new Apfloat("1.10000"));
            fail("-1.1, 1,1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.harmonicNumber(new Apfloat(3), new Apfloat(4));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "zeta.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testPolylog()
    {
        Apfloat a = ApfloatMath.polylog(new Apfloat("3.40000"), new Apfloat("-5.60000"));
        assertEquals("3.4, -5.6 precision", 6, a.precision());
        assertEquals("3.4, -5.6 value", new Apfloat("-4.15566"), a, new Apfloat("5e-5"));

        a = ApfloatMath.polylog(new Apfloat("2.00000"), new Apfloat("-3.40000"));
        assertEquals("2, -3.4 precision", 6, a.precision());
        assertEquals("2, -3.4 value", new Apfloat("-2.11882"), a, new Apfloat("5e-5"));

        a = ApfloatMath.polylog(new Apfloat("-2.00000"), new Apfloat("-3.40000"));
        assertEquals("-2, -3.4 precision", 6, a.precision());
        assertEquals("-2, -3.4 value", new Apfloat("0.0957926"), a, new Apfloat("5e-7"));

        a = ApfloatMath.polylog(new Apfloat("-2.00000"), new Apfloat("3.40000"));
        assertEquals("-2, 3.4 precision", 6, a.precision());
        assertEquals("-2, 3.4 value", new Apfloat("-1.08218"), a, new Apfloat("5e-5"));

        try
        {
            ApfloatMath.polylog(new Apfloat("3.40000"), new Apfloat("5.60000"));
            fail("3.4, 5.6 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.polylog(new Apfloat("-3.40000"), new Apfloat("5.60000"));
            fail("-3.4, 5.6 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be complex
            assertEquals("Localization key", "complex", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.polylog(new Apfloat("1.00000"), new Apfloat("1.00000"));
            fail("1, 1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be infinite
            assertEquals("Localization key", "polylog.infinite", aae.getLocalizationKey());
        }
        try
        {
            ApfloatMath.polylog(new Apfloat("0.900000"), new Apfloat("1.00000"));
            fail("0.9, 1 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be infinite
            assertEquals("Localization key", "polylog.infinite", aae.getLocalizationKey());
        }

        try
        {
            ApfloatMath.polylog(new Apfloat(-2), new Apfloat(4));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "pi.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testClausenCl()
    {
        Apfloat a = ApfloatMath.clausenCl(2, new Apfloat("-5.6000"));
        assertEquals("2, -5.6 precision", 6, a.precision());
        assertEquals("2, -5.6 value", new Apfloat("0.947911"), a, new Apfloat("5e-6"));

        a = ApfloatMath.clausenCl(3, new Apfloat("2.3000"));
        assertEquals("3, 2.3 precision", 6, a.precision());
        assertEquals("3, 2.3 value", new Apfloat("-0.661361"), a, new Apfloat("5e-6"));

        try
        {
            ApfloatMath.clausenCl(1, new Apfloat(0));
            fail("1, 0 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be infinite
            assertEquals("Localization key", "cl.ofZero", aae.getLocalizationKey());
        }
    }

    public static void testClausenSl()
    {
        Apfloat a = ApfloatMath.clausenSl(2, new Apfloat("5.6000"));
        assertEquals("2, 5.6 precision", 6, a.precision());
        assertEquals("2, 5.6 value", new Apfloat("0.688475"), a, new Apfloat("5e-6"));

        a = ApfloatMath.clausenSl(5, new Apfloat("-3.40000"));
        assertEquals("5, -3.4 precision", 6, a.precision());
        assertEquals("5, -3.4 value", new Apfloat("0.242360"), a, new Apfloat("5e-6"));

        try
        {
            ApfloatMath.clausenSl(1, new Apfloat(0));
            fail("1, 0 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be infinite
            assertEquals("Localization key", "cl.ofZero", aae.getLocalizationKey());
        }
    }

    public static void testClausenS()
    {
        Apfloat a = ApfloatMath.clausenS(new Apfloat("3.4000"), new Apfloat("5.6000"));
        assertEquals("3.4, 5.6 precision", 6, a.precision());
        assertEquals("3.4, 5.6 value", new Apfloat("-0.744352"), a, new Apfloat("5e-6"));

        a = ApfloatMath.clausenS(new Apfloat("-6.70000"), new Apfloat("-3.40000"));
        assertEquals("-6.7, -3.4 precision", 6, a.precision());
        assertEquals("-6.7, -3.4 value", new Apfloat("-0.260177"), a, new Apfloat("5e-6"));

        try
        {
            ApfloatMath.clausenS(new Apfloat("1"), new Apfloat(0));
            fail("1, 0 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be infinite
            assertEquals("Localization key", "cl.ofZero", aae.getLocalizationKey());
        }
    }

    public static void testClausenC()
    {
        Apfloat a = ApfloatMath.clausenC(new Apfloat("4.50000"), new Apfloat("7.80000"));
        assertEquals("4.5, 7.8 precision", 6, a.precision());
        assertEquals("4.5, 7.8 value", new Apfloat("0.01068628"), a, new Apfloat("5e-7"));

        a = ApfloatMath.clausenC(new Apfloat("7.6000"), new Apfloat("-5.4000"));
        assertEquals("7.6, -5.4 precision", 6, a.precision());
        assertEquals("7.6, -5.4 value", new Apfloat("0.633458"), a, new Apfloat("5e-6"));

        a = ApfloatMath.clausenC(new Apfloat("4.00000"), new Apfloat("0"));
        assertEquals("4, 0 precision", 6, a.precision());
        assertEquals("4, 0 value", new Apfloat("1.08232"), a, new Apfloat("5e-5"));

        try
        {
            ApfloatMath.clausenC(new Apfloat("1"), new Apfloat(0));
            fail("1, 0 accepted");
        }
        catch (ApfloatArithmeticException aae)
        {
            // OK, result would be infinite
            assertEquals("Localization key", "cl.ofZero", aae.getLocalizationKey());
        }
    }

    public static void testLogisticSigmoid()
    {
        Apfloat a = ApfloatMath.logisticSigmoid(new Apfloat(4, 19));
        assertEquals("4 precision", 19, a.precision());
        assertEquals("4 value", new Apfloat("0.9820137900379084420"), a, new Apfloat("5e-19"));

        a = ApfloatMath.logisticSigmoid(new Apfloat(3000, 19));
        assertEquals("3000 precision", 19, a.precision());
        assertEquals("3000 value", new Apfloat("1.000000000000000000"), a, new Apfloat("5e-18"));

        a = ApfloatMath.logisticSigmoid(new Apfloat(-3000, 19));
        assertEquals("-3000 precision", 16, a.precision());
        assertEquals("-3000 value", new Apfloat("1.3078390189212504e-1303"), a, new Apfloat("5e-1319"));

        a = ApfloatMath.logisticSigmoid(new Apfloat("1.000000000000000000e-1000000000000000000"));
        assertEquals("1e-1000000000000000000 precision", 19, a.precision());
        assertEquals("1e-1000000000000000000 value", new Apfloat("0.5000000000000000000"), a, new Apfloat("5e-19"));

        a = ApfloatMath.logisticSigmoid(new Apfloat("0"));
        assertEquals("0 precision", Apfloat.INFINITE, a.precision());
        assertEquals("0 value", new Aprational("1/2"), a);

        a = ApfloatMath.logisticSigmoid(new Apint(0, 9));
        assertEquals("0 radix 9 precision", Apfloat.INFINITE, a.precision());
        assertEquals("0 radix 9 radix", 9, a.radix());
        assertEquals("0 radix 9 value", new Aprational("1/2", 9), a);

        a = ApfloatMath.logisticSigmoid(new Apfloat("0.1", 18, 2));
        assertEquals("0.5 precision", 18, a.precision());
        assertEquals("0.5 radix", 2, a.radix());
        assertEquals("0.5 value", new Apfloat("0.10011111010110011", 18, 2), a, new Apfloat("1e-18", 1, 2));

        try
        {
            ApfloatMath.logisticSigmoid(new Apfloat(3));
            fail("Infinite expansion");
        }
        catch (InfiniteExpansionException iee)
        {
            // OK
            assertEquals("Localization key", "exp.infinitePrecision", iee.getLocalizationKey());
        }
    }

    public static void testRandom()
    {
        long maxScale = 0;
        long minScale = Long.MAX_VALUE;
        for (int i = 0; i < 1000; i++)
        {
            Apfloat a = ApfloatMath.random(1000);
            maxScale = Math.max(maxScale, a.scale());
            minScale = Math.min(minScale, a.scale());
        }
        assertEquals("random max scale", 0, maxScale);
        assertTrue("random min scale", minScale < 0);

        for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++)
        {
            for (int i = 0; i < 100; i++)
            {
                Apfloat a = ApfloatMath.random(1, radix);
                assertEquals("value < 1", -1, a.compareTo(new Apfloat(1, Apfloat.INFINITE, radix)));
                assertTrue("value >= 0", a.signum() >= 0);
            }
        }
    }

    public static void testRandomGaussian()
    {
        Apfloat sum = Apfloat.ZERO,
                squareSum = Apfloat.ZERO;
        final int N = 1000;
        for (int i = 0; i < N; i++)
        {
            Apfloat a = ApfloatMath.randomGaussian(N);
            sum = sum.add(a);
            squareSum = squareSum.add(a.multiply(a));
        }
        Apfloat n = new Apfloat(N),
                mean = sum.divide(n),
                standardDeviation = ApfloatMath.sqrt(squareSum.divide(n).subtract(mean));
        assertEquals("random mean", Apfloat.ZERO, mean, new Apfloat(0.15));
        assertEquals("random standard deviation", Apfloat.ONE, standardDeviation, new Apfloat(0.2));

        for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++)
        {
            for (int i = 0; i < 100; i++)
            {
                Apfloat a = ApfloatMath.randomGaussian(1, radix);
                assertEquals("abs value <= 5", Apfloat.ZERO, a, new Apfloat(5, Apfloat.INFINITE, radix));
            }
        }

        Apfloat a = ApfloatMath.randomGaussian(100);
        assertEquals("precision 1", 100, a.precision(), 7);
        a = ApfloatMath.randomGaussian(10);
        assertEquals("precision 2", 10, a.precision(), 7);
        a = ApfloatMath.randomGaussian(100);
        assertEquals("precision 3", 100, a.precision(), 7);
        a = ApfloatMath.randomGaussian(200);
        assertEquals("precision 4", 200, a.precision(), 7);
    }

    public static void testContinuedFraction()
    {
        Apfloat a = new Apfloat("3.14159");
        assertEquals("3.14159, 3", Arrays.asList(new Apint(3), new Apint(7), new Apint(15)), Arrays.asList(ApfloatMath.continuedFraction(a, 3)));
        assertEquals("3.14159, 30", Arrays.asList(new Apint(3), new Apint(7), new Apint(15), new Apint(1)), Arrays.asList(ApfloatMath.continuedFraction(a, 30)));
        assertEquals("3.14159, 1", Arrays.asList(new Apint(3)), Arrays.asList(ApfloatMath.continuedFraction(a, 1)));

        a = new Apfloat("-3.14159");
        assertEquals("-3.14159, 3", Arrays.asList(new Apint(-3), new Apint(-7), new Apint(-15)), Arrays.asList(ApfloatMath.continuedFraction(a, 3)));
        assertEquals("-3.14159, 30", Arrays.asList(new Apint(-3), new Apint(-7), new Apint(-15), new Apint(-1)), Arrays.asList(ApfloatMath.continuedFraction(a, 30)));

        try
        {
            ApfloatMath.continuedFraction(new Apfloat(2), 0);
            fail("Zero n allowed");
        }
        catch (IllegalArgumentException iae)
        {
            // OK
        }
        try
        {
            ApfloatMath.continuedFraction(new Apfloat(2), Integer.MIN_VALUE);
            fail("Negative n allowed");
        }
        catch (IllegalArgumentException iae)
        {
            // OK
        }
    }

    public static void testConvergents()
    {
        Apfloat a = new Apfloat("3.14159");
        assertEquals("3.14159, 3", Arrays.asList(new Aprational(3), new Aprational("22/7"), new Aprational("333/106")), Arrays.asList(ApfloatMath.convergents(a, 3)));
        assertEquals("3.14159, 30", Arrays.asList(new Aprational(3), new Aprational("22/7"), new Aprational("333/106"), new Aprational("355/113")), Arrays.asList(ApfloatMath.convergents(a, 30)));
        assertEquals("3.14159, 1", Arrays.asList(new Aprational(3)), Arrays.asList(ApfloatMath.convergents(a, 1)));

        a = new Apfloat("-3.14159");
        assertEquals("-3.14159, 3", Arrays.asList(new Aprational(-3), new Aprational("-22/7"), new Aprational("-333/106")), Arrays.asList(ApfloatMath.convergents(a, 3)));
        assertEquals("-3.14159, 30", Arrays.asList(new Aprational(-3), new Aprational("-22/7"), new Aprational("-333/106"), new Aprational("-355/113")), Arrays.asList(ApfloatMath.convergents(a, 30)));

        try
        {
            ApfloatMath.convergents(new Apfloat(2), 0);
            fail("Zero n allowed");
        }
        catch (IllegalArgumentException iae)
        {
            // OK
        }
        try
        {
            ApfloatMath.convergents(new Apfloat(2), Integer.MIN_VALUE);
            fail("Negative n allowed");
        }
        catch (IllegalArgumentException iae)
        {
            // OK
        }
    }

    public static void testMax()
    {
        assertEquals("max of 1 and 1", new Apfloat(1), ApfloatMath.max(new Apfloat(1), new Apfloat(1)));
        assertEquals("max of 1 and 2", new Apfloat(2), ApfloatMath.max(new Apfloat(1), new Apfloat(2)));
        assertEquals("max of 2 and 1", new Apfloat(2), ApfloatMath.max(new Apfloat(2), new Apfloat(1)));
    }

    public static void testMin()
    {
        assertEquals("min of 1 and 1", new Apfloat(1), ApfloatMath.min(new Apfloat(1), new Apfloat(1)));
        assertEquals("min of 1 and 2", new Apfloat(1), ApfloatMath.min(new Apfloat(1), new Apfloat(2)));
        assertEquals("min of 2 and 1", new Apfloat(1), ApfloatMath.min(new Apfloat(2), new Apfloat(1)));
    }

    public static void testNextAfter()
    {
        assertEquals("next after 0 and 0", new Apfloat(0), ApfloatMath.nextAfter(new Apfloat(0), new Apfloat(0)));
        assertEquals("next after 0 and 1", new Apfloat(0), ApfloatMath.nextAfter(new Apfloat(0), new Apfloat(1)));
        assertEquals("next after 0 and -1", new Apfloat(0), ApfloatMath.nextAfter(new Apfloat(0), new Apfloat(-1)));
        Apfloat a = ApfloatMath.nextAfter(new Apfloat("1"), new Apfloat(2));
        assertEquals("next after 1. and 2", new Apfloat(2), a);
        assertEquals("next after 1. and 2 precision", 1, a.precision());
        a = ApfloatMath.nextAfter(new Apfloat("1"), new Apfloat(0));
        assertEquals("next after 1. and 0", new Apfloat(0), a);
        a = ApfloatMath.nextAfter(new Apfloat("-1"), new Apfloat(-2));
        assertEquals("next after -1. and -2", new Apfloat(-2), a);
        assertEquals("next after -1. and -2 precision", 1, a.precision());
        a = ApfloatMath.nextAfter(new Apfloat("-1"), new Apfloat(-1));
        assertEquals("next after -1. and -1", new Apfloat(-1), a);
        assertEquals("next after -1. and -1 precision", 1, a.precision());
        a = ApfloatMath.nextAfter(new Apfloat(1), new Apfloat(2));
        assertEquals("next after 1 and 2", new Apfloat(1), a);
        assertEquals("next after 1 and 2 precision", Apfloat.INFINITE, a.precision());
    }

    public static void testNextUp()
    {
        assertEquals("next up 0", new Apfloat(0), ApfloatMath.nextUp(new Apfloat(0)));
        Apfloat a = ApfloatMath.nextUp(new Apfloat(1));
        assertEquals("next up 1", new Apfloat(1), a);
        assertEquals("next up 1 precision", Apfloat.INFINITE, a.precision());
        a = ApfloatMath.nextUp(new Apfloat("1."));
        assertEquals("next up 1.", new Apfloat(2), a);
        assertEquals("next up 1. precision", 1, a.precision());
        a = ApfloatMath.nextUp(new Apfloat("1.0"));
        assertEquals("next up 1.0", new Apfloat("1.1"), a);
        assertEquals("next up 1.0 precision", 2, a.precision());
        a = ApfloatMath.nextUp(new Apfloat("0.9"));
        assertEquals("next up 0.9", new Apfloat("1.0"), a);
        assertEquals("next up 0.9 precision", 2, a.precision());
        a = ApfloatMath.nextUp(new Apfloat("0.1"));
        assertEquals("next up 0.1", new Apfloat("0.2"), a);
        assertEquals("next up 0.1 precision", 1, a.precision());
        a = ApfloatMath.nextUp(new Apfloat("10"));
        assertEquals("next up 10.", new Apfloat("11"), a);
        assertEquals("next up 10. precision", 2, a.precision());
        a = ApfloatMath.nextUp(new Apfloat("1e1"));
        assertEquals("next up 1e1", new Apfloat("2e1"), a);
        assertEquals("next up 1e1 precision", 1, a.precision());
        a = ApfloatMath.nextUp(new Apfloat("-1e1"));
        assertEquals("next up -1e1", new Apfloat(0), a);
        assertEquals("next up -1e1 precision", Apfloat.INFINITE, a.precision());
        a = ApfloatMath.nextUp(new Apfloat("1.a", 2, 11));
        assertEquals("next up 1.a", new Apfloat("2.0", 2, 11), a);
        assertEquals("next up 1.a precision", 2, a.precision());
        assertEquals("next up 1.a radix", 11, a.radix());
        a = ApfloatMath.nextUp(new Apfloat("1e-9000000000000000000"));
        assertEquals("next up 1e-9000000000000000000", new Apfloat("2e-9000000000000000000"), a);
        assertEquals("next up 1e-9000000000000000000 precision", 1, a.precision());
        a = ApfloatMath.nextUp(new Apfloat("1e-9000000000000000000", 9000000000000000000L));
        assertEquals("next up 1e-9000000000000000000.000...", new Apfloat("1e-9000000000000000000"), a);
        assertEquals("next up 1e-9000000000000000000.000... precision", 9000000000000000000L, a.precision());
        a = ApfloatMath.nextUp(new Apfloat("1e-4611686018427387904", 4611686018427387904L));
        assertEquals("next up 1e-4611686018427387904.000...", new Apfloat("1e-4611686018427387904"), a);
        assertEquals("next up 1e-4611686018427387904.000... precision", 4611686018427387904L, a.precision());
        a = ApfloatMath.nextUp(new Apfloat("1e-4611686018427387905", 4611686018427387904L));
        assertEquals("next up 1e-4611686018427387905.000...", new Apfloat("1e-4611686018427387905"), a);
        assertEquals("next up 1e-4611686018427387905.000... precision", 4611686018427387904L, a.precision());
        a = ApfloatMath.nextUp(new Apfloat("1e-4611686018427387906", 4611686018427387904L));
        assertEquals("next up 1e-4611686018427387906.000...", new Apfloat("1e-4611686018427387906"), a);
        assertEquals("next up 1e-4611686018427387906.000... precision", 4611686018427387904L, a.precision());
    }

    public static void testNextDown()
    {
        assertEquals("next down 0", new Apfloat(0), ApfloatMath.nextDown(new Apfloat(0)));
        Apfloat a = ApfloatMath.nextDown(new Apfloat(1));
        assertEquals("next down 1", new Apfloat(1), a);
        assertEquals("next down 1 precision", Apfloat.INFINITE, a.precision());
        a = ApfloatMath.nextDown(new Apfloat("1"));
        assertEquals("next down 1.", new Apfloat(0), a);
        assertEquals("next down 1. precision", Apfloat.INFINITE, a.precision());
        a = ApfloatMath.nextDown(new Apfloat("1.0"));
        assertEquals("next down 1.0", new Apfloat("0.9"), a);
        assertEquals("next down 1.0 precision", 1, a.precision());
        a = ApfloatMath.nextDown(new Apfloat("1.1"));
        assertEquals("next down 1.1", new Apfloat("1.0"), a);
        assertEquals("next down 1.1 precision", 2, a.precision());
        a = ApfloatMath.nextDown(new Apfloat("0.1"));
        assertEquals("next down 0.1", new Apfloat(0), a);
        assertEquals("next down 0.1 precision", Apfloat.INFINITE, a.precision());
        a = ApfloatMath.nextDown(new Apfloat("0.2"));
        assertEquals("next down 0.2", new Apfloat("0.1"), a);
        assertEquals("next down 0.2 precision", 1, a.precision());
        a = ApfloatMath.nextDown(new Apfloat("10"));
        assertEquals("next down 10.", new Apfloat("9"), a);
        assertEquals("next down 10. precision", 1, a.precision());
        a = ApfloatMath.nextDown(new Apfloat("1e1"));
        assertEquals("next down 1e1", new Apfloat(0), a);
        assertEquals("next down 1e1 precision", Apfloat.INFINITE, a.precision());
        a = ApfloatMath.nextDown(new Apfloat("-1e1"));
        assertEquals("next down -1e1", new Apfloat("-2e1"), a);
        assertEquals("next down -1e1 precision", 1, a.precision());
        a = ApfloatMath.nextDown(new Apfloat("1.a", 2, 11));
        assertEquals("next down 1.a", new Apfloat("1.9", 2, 11), a);
        assertEquals("next down 1.a precision", 2, a.precision());
        assertEquals("next down 1.a radix", 11, a.radix());
        a = ApfloatMath.nextDown(new Apfloat("1e-9000000000000000000"));
        assertEquals("next down 1e-9000000000000000000", new Apfloat(0), a);
        assertEquals("next down 1e-9000000000000000000 precision", Apfloat.INFINITE, a.precision());
        a = ApfloatMath.nextDown(new Apfloat("1e-9000000000000000000", 9000000000000000000L));
        assertEquals("next down 1e-9000000000000000000.000", new Apfloat("1e-9000000000000000000"), a);
        assertEquals("next down 1e-9000000000000000000.000 precision", 9000000000000000000L, a.precision());
    }

    public static void testUlp()
    {
        assertEquals("ulp 0", new Apfloat(0), ApfloatMath.ulp(new Apfloat(0)));
        assertEquals("ulp 0 radix", 12, ApfloatMath.ulp(new Apfloat(0, 1, 12)).radix());
        Apfloat a = ApfloatMath.ulp(new Apfloat(1));
        assertEquals("ulp 1", new Apfloat(0), a);
        assertEquals("ulp 1 precision", Apfloat.INFINITE, a.precision());
        a = ApfloatMath.ulp(new Apfloat("1"));
        assertEquals("ulp 1.", new Apfloat("1"), a);
        assertEquals("ulp 1. precision", 1, a.precision());
        a = ApfloatMath.ulp(new Apfloat("1.0"));
        assertEquals("ulp 1.0", new Apfloat("0.1"), a);
        assertEquals("ulp 1.0 precision", 1, a.precision());
        a = ApfloatMath.ulp(new Apfloat("1.1"));
        assertEquals("ulp 1.1", new Apfloat("0.1"), a);
        assertEquals("ulp 1.1 precision", 1, a.precision());
        a = ApfloatMath.ulp(new Apfloat("0.1"));
        assertEquals("ulp 0.1", new Apfloat("0.1"), a);
        assertEquals("ulp 0.1 precision", 1, a.precision());
        a = ApfloatMath.ulp(new Apfloat("0.2"));
        assertEquals("ulp 0.2", new Apfloat("0.1"), a);
        assertEquals("ulp 0.2 precision", 1, a.precision());
        a = ApfloatMath.ulp(new Apfloat("10"));
        assertEquals("ulp 10.", new Apfloat("1"), a);
        assertEquals("ulp 10. precision", 1, a.precision());
        a = ApfloatMath.ulp(new Apfloat("1e1"));
        assertEquals("ulp 1e1", new Apfloat("1e1"), a);
        assertEquals("ulp 1e1 precision", 1, a.precision());
        a = ApfloatMath.ulp(new Apfloat("-1e1"));
        assertEquals("ulp -1e1", new Apfloat("1e1"), a);
        assertEquals("ulp -1e1 precision", 1, a.precision());
        a = ApfloatMath.ulp(new Apfloat("1.a", 2, 11));
        assertEquals("ulp 1.a", new Apfloat("0.1", 1, 11), a);
        assertEquals("ulp 1.a precision", 1, a.precision());
        assertEquals("ulp 1.a radix", 11, a.radix());
        a = ApfloatMath.ulp(new Apfloat("1e-9000000000000000000"));
        assertEquals("ulp 1e-9000000000000000000", new Apfloat("1e-9000000000000000000"), a);
        assertEquals("ulp 1e-9000000000000000000 precision", 1, a.precision());
        a = ApfloatMath.ulp(new Apfloat("1e-9000000000000000000", 9000000000000000000L));
        assertEquals("ulp 1e-9000000000000000000.000", new Apfloat(0), a);
        assertEquals("ulp 1e-9000000000000000000.000 precision", Apfloat.INFINITE, a.precision());
    }
}
