//
// Author: Klaus Niederkrueger <kniederk@math.uni-koeln.de>
//

#include "knumbertest.h"
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <QString>

QString numtypeToString(KNumber::NumType arg)
{
    switch (arg) {
    case KNumber::SpecialType:
        return QLatin1String( "Special");
    case KNumber::IntegerType:
        return QLatin1String( "Integer");
    case KNumber::FractionType:
        return QLatin1String( "Fraction");
    case KNumber::FloatType:
        return QLatin1String( "Float");
    default:
        return QLatin1String( "Unknown:") + QString::number(static_cast<int>(arg));

    }
}

void checkResult(const QString &string, const KNumber &result,
                 const QString &desired_string, KNumber::NumType desired)
{
    std::cout << "Testing result of: " << string.toAscii().constData() <<
              " should give " << desired_string.toAscii().constData() << " and gives " <<
              result.toQString(12).toAscii().constData() << "....\n";
    std::cout << "The type of the result should be " <<
              numtypeToString(desired).toAscii().constData() << " and gives " <<
              numtypeToString(result.type()).toAscii().constData() << "....  ";

    if (result.type() == desired  &&
            result.toQString(12) == desired_string) {
        std::cout << "OK\n";
        return;
    }

    std::cout << "Failed\n";
    exit(1);
}

void checkTruth(const QString &string, bool computation,
                bool desired_result)
{
    std::cout << "Testing truth of: " << string.toAscii().constData() <<
              " should be " << desired_result << " and is " <<
              computation << "....\n";

    if (computation == desired_result) {
        std::cout << "OK\n";
        return;
    }

    std::cout << "Failed\n";
    exit(1);
}


void checkType(const QString &string, KNumber::NumType test_arg,
               KNumber::NumType desired)
{
    std::cout << "Testing type of: " << string.toAscii().constData() << " should give " <<
              numtypeToString(desired).toAscii().constData() << " and gives " <<
              numtypeToString(test_arg).toAscii().constData() << "....";

    if (test_arg == desired) {
        std::cout << "OK\n";
        return;
    }

    std::cout << "Failed\n";
    exit(1);

}


void testingCompare()
{
    std::cout << "\n\nTesting Compare:\n";

    checkTruth("KNumber(5) == KNumber(2)", KNumber(5) == KNumber(2), false);
    checkTruth("KNumber(5) > KNumber(2)", KNumber(5) > KNumber(2), true);
    checkTruth("KNumber(5) < KNumber(2)", KNumber(5) < KNumber(2), false);
    checkTruth("KNumber(5) < KNumber(0)", KNumber(5) < KNumber(0), false);
    checkTruth("KNumber(-5) < KNumber(0)", KNumber(-5) < KNumber(0), true);
    checkTruth("KNumber(5) >= KNumber(2)", KNumber(5) >= KNumber(2), true);
    checkTruth("KNumber(5) <= KNumber(2)", KNumber(5) <= KNumber(2), false);
    checkTruth("KNumber(5) != KNumber(2)", KNumber(5) != KNumber(2), true);

    checkTruth("KNumber(2) == KNumber(2)", KNumber(2) == KNumber(2), true);
    checkTruth("KNumber(2) > KNumber(2)", KNumber(2) > KNumber(2), false);
    checkTruth("KNumber(2) < KNumber(2)", KNumber(2) < KNumber(2), false);
    checkTruth("KNumber(2) >= KNumber(2)", KNumber(2) >= KNumber(2), true);
    checkTruth("KNumber(2) <= KNumber(2)", KNumber(2) <= KNumber(2), true);
    checkTruth("KNumber(2) != KNumber(2)", KNumber(2) != KNumber(2), false);

    checkTruth("KNumber(5) == KNumber(\"1/2\")", KNumber(5) == KNumber(QLatin1String("1/2")), false);
    checkTruth("KNumber(5) > KNumber(\"1/2\")", KNumber(5) > KNumber(QLatin1String("1/2")), true);
    checkTruth("KNumber(5) < KNumber(\"1/2\")", KNumber(5) < KNumber(QLatin1String("1/2")), false);
    checkTruth("KNumber(5) >= KNumber(\"1/2\")", KNumber(5) >= KNumber(QLatin1String("1/2")), true);
    checkTruth("KNumber(5) <= KNumber(\"1/2\")", KNumber(5) <= KNumber(QLatin1String("1/2")), false);
    checkTruth("KNumber(5) != KNumber(\"1/2\")", KNumber(5) != KNumber(QLatin1String("1/2")), true);

    checkTruth("KNumber(\"1/2\") == KNumber(\"1/2\")", KNumber(QLatin1String("1/2")) == KNumber(QLatin1String("1/2")), true);
    checkTruth("KNumber(\"1/2\") > KNumber(\"1/2\")", KNumber(QLatin1String("1/2")) > KNumber(QLatin1String("1/2")), false);
    checkTruth("KNumber(\"1/2\") < KNumber(\"1/2\")", KNumber(QLatin1String("1/2")) < KNumber(QLatin1String("1/2")), false);
    checkTruth("KNumber(\"1/2\") >= KNumber(\"1/2\")", KNumber(QLatin1String("1/2")) >= KNumber(QLatin1String("1/2")), true);
    checkTruth("KNumber(\"1/2\") <= KNumber(\"1/2\")", KNumber(QLatin1String("1/2")) <= KNumber(QLatin1String("1/2")), true);
    checkTruth("KNumber(\"1/2\") != KNumber(\"1/2\")", KNumber(QLatin1String("1/2")) != KNumber(QLatin1String("1/2")), false);

    checkTruth("KNumber(\"3/2\") == KNumber(\"1/2\")", KNumber("3/2") == KNumber(QLatin1String("1/2")), false);
    checkTruth("KNumber(\"3/2\") > KNumber(\"1/2\")", KNumber("3/2") > KNumber(QLatin1String("1/2")), true);
    checkTruth("KNumber(\"3/2\") < KNumber(\"1/2\")", KNumber("3/2") < KNumber(QLatin1String("1/2")), false);
    checkTruth("KNumber(\"3/2\") >= KNumber(\"1/2\")", KNumber("3/2") >= KNumber(QLatin1String("1/2")), true);
    checkTruth("KNumber(\"3/2\") <= KNumber(\"1/2\")", KNumber("3/2") <= KNumber(QLatin1String("1/2")), false);
    checkTruth("KNumber(\"3/2\") != KNumber(\"1/2\")", KNumber("3/2") != KNumber(QLatin1String("1/2")), true);

}


void testingAdditions()
{
    std::cout << "\n\nTesting additions:\n";

    checkResult("KNumber(5) + KNumber(2)", KNumber(5) + KNumber(2), "7", KNumber::IntegerType);
    checkResult("KNumber(5) + KNumber(\"2/3\")", KNumber(5) + KNumber(QLatin1String("2.3")), "17/3", KNumber::FractionType);
    checkResult("KNumber(5) + KNumber(\"2.3\")", KNumber(5) + KNumber(QLatin1String("2.3")), "7.3", KNumber::FloatType);

    checkResult("KNumber(\"5/3\") + KNumber(2)", KNumber(QLatin1String("5/3")) + KNumber(2), "11/3", KNumber::FractionType);
    checkResult("KNumber(\"5/3\") + KNumber(\"2/3\")", KNumber(QLatin1String("5/3")) + KNumber(QLatin1String("2.3")), "7/3", KNumber::FractionType);
    checkResult("KNumber(\"5/3\") + KNumber(\"1/3\")", KNumber(QLatin1String("5/3")) + KNumber("1/3"), QLatin1String("2"), KNumber::IntegerType);
    checkResult("KNumber(\"5/3\") + KNumber(\"-26/3\")", KNumber(QLatin1String("5/3")) + KNumber("-26/3"), "-7", KNumber::IntegerType);
    checkResult("KNumber(\"5/2\") + KNumber(2.3)", KNumber(QLatin1String("5/2")) + KNumber(2.3), "4.8", KNumber::FloatType);

    checkResult("KNumber(5.3) + KNumber(2)", KNumber(5.3) + KNumber(2), "7.3", KNumber::FloatType);
    checkResult("KNumber(5.3) + KNumber(\"2/4\")", KNumber(5.3) + KNumber("2/4"), "5.8", KNumber::FloatType);
    checkResult("KNumber(5.3) + KNumber(2.3)", KNumber(5.3) + KNumber(2.3), "7.6", KNumber::FloatType);

}

void testingSubtractions()
{
    std::cout << "\n\nTesting subtractions:\n";

    checkResult("KNumber(5) - KNumber(2)", KNumber(5) - KNumber(2), QLatin1String("3"), KNumber::IntegerType);
    checkResult("KNumber(5) - KNumber(\"2/3\")", KNumber(5) - KNumber(QLatin1String("2.3")), "13/3", KNumber::FractionType);
    checkResult("KNumber(5) - KNumber(2.3)", KNumber(5) - KNumber(2.3), "2.7", KNumber::FloatType);

    checkResult("KNumber(\"5/3\") - KNumber(2)", KNumber(QLatin1String("5/3")) - KNumber(2), "-1/3", KNumber::FractionType);
    checkResult("KNumber(\"5/3\") - KNumber(\"1/3\")", KNumber(QLatin1String("5/3")) - KNumber("1/3"), "4/3", KNumber::FractionType);
    checkResult("KNumber(\"5/3\") - KNumber(\"2/3\")", KNumber(QLatin1String("5/3")) - KNumber(QLatin1String("2.3")), QLatin1String("1"), KNumber::IntegerType);
    checkResult("KNumber(\"-5/3\") - KNumber(\"4/3\")", KNumber(QLatin1String("-5/3")) - KNumber("4/3"), "-3", KNumber::IntegerType);
    checkResult("KNumber(\"5/4\") - KNumber(2.2)", KNumber("5/4") - KNumber(2.2), "-0.95", KNumber::FloatType);

    checkResult("KNumber(5.3) - KNumber(2)", KNumber(5.3) - KNumber(2), "3.3", KNumber::FloatType);
    checkResult("KNumber(5.3) - KNumber(\"3/4\")", KNumber(5.3) - KNumber("3/4"), "4.55", KNumber::FloatType);
    checkResult("KNumber(5.3) - KNumber(2.3)", KNumber(5.3) - KNumber(2.3), QLatin1String("3"), KNumber::FloatType);

}


void testingMultiplications()
{
    std::cout << "\n\nTesting multiplications:\n";

    checkResult("KNumber(5) * KNumber(2)", KNumber(5) * KNumber(2), "10", KNumber::IntegerType);
    checkResult("KNumber(5) * KNumber(\"2/3\")", KNumber(5) * KNumber(QLatin1String("2.3")), "10/3", KNumber::FractionType);
    checkResult("KNumber(5) * KNumber(\"2/5\")", KNumber(5) * KNumber("2/5"), QLatin1String("2"), KNumber::IntegerType);
    checkResult("KNumber(5) * KNumber(2.3)", KNumber(5) * KNumber(2.3), "11.5", KNumber::FloatType);
    checkResult("KNumber(0) * KNumber(\"2/5\")", KNumber(0) * KNumber("2/5"), QLatin1String("0"), KNumber::IntegerType);
    checkResult("KNumber(0) * KNumber(2.3)", KNumber(0) * KNumber(2.3), QLatin1String("0"), KNumber::IntegerType);

    checkResult("KNumber(\"5/3\") * KNumber(2)", KNumber(QLatin1String("5/3")) * KNumber(2), "10/3", KNumber::FractionType);
    checkResult("KNumber(\"5/3\") * KNumber(0)", KNumber(QLatin1String("5/3")) * KNumber(0), QLatin1String("0"), KNumber::IntegerType);
    checkResult("KNumber(\"5/3\") * KNumber(\"2/3\")", KNumber(QLatin1String("5/3")) * KNumber(QLatin1String("2.3")), "10/9", KNumber::FractionType);
    checkResult("KNumber(\"25/6\") * KNumber(\"12/5\")", KNumber("25/6") * KNumber("12/5"), "10", KNumber::IntegerType);
    checkResult("KNumber(\"5/2\") * KNumber(2.3)", KNumber(QLatin1String("5/2")) * KNumber(2.3), "5.75", KNumber::FloatType);

    checkResult("KNumber(5.3) * KNumber(2)", KNumber(5.3) * KNumber(2), "10.6", KNumber::FloatType);
    checkResult("KNumber(5.3) * KNumber(0)", KNumber(5.3) * KNumber(0), QLatin1String("0"), KNumber::IntegerType);
    checkResult("KNumber(5.3) * KNumber(\"1/2\")", KNumber(5.3) * KNumber(QLatin1String("1/2")), "2.65", KNumber::FloatType);
    checkResult("KNumber(5.3) * KNumber(2.3)", KNumber(5.3) * KNumber(2.3), "12.19", KNumber::FloatType);

}

void testingDivisions()
{
    std::cout << "\n\nTesting divisions:\n";

    checkResult("KNumber(5) / KNumber(2)", KNumber(5) / KNumber(2), QLatin1String("5/2"), KNumber::FractionType);
    checkResult("KNumber(122) / KNumber(2)", KNumber(122) / KNumber(2), "61", KNumber::IntegerType);
    checkResult("KNumber(12) / KNumber(0)", KNumber(12) / KNumber(0), QLatin1String("inf"), KNumber::SpecialType);
    checkResult("KNumber(-12) / KNumber(0)", KNumber(-12) / KNumber(0), QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("KNumber(5) / KNumber(\"2/3\")", KNumber(5) / KNumber(QLatin1String("2.3")), "15/2", KNumber::FractionType);
    checkResult("KNumber(6) / KNumber(\"2/3\")", KNumber(6) / KNumber(QLatin1String("2.3")), "9", KNumber::IntegerType);
    checkResult("KNumber(5) / KNumber(2.5)", KNumber(5) / KNumber(2.5), QLatin1String("2"), KNumber::FloatType);
    checkResult("KNumber(5) / KNumber(0.0)", KNumber(5) / KNumber(0.0), QLatin1String("inf"), KNumber::SpecialType);
    checkResult("KNumber(-5) / KNumber(0.0)", KNumber(-5) / KNumber(0.0), QLatin1String("-inf"), KNumber::SpecialType);

    checkResult("KNumber(\"5/3\") / KNumber(2)", KNumber(QLatin1String("5/3")) / KNumber(2), "5/6", KNumber::FractionType);
    checkResult("KNumber(\"5/3\") / KNumber(0)", KNumber(QLatin1String("5/3")) / KNumber(0), QLatin1String("inf"), KNumber::SpecialType);
    checkResult("KNumber(\"-5/3\") / KNumber(0)", KNumber(QLatin1String("-5/3")) / KNumber(0), QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("KNumber(\"5/3\") / KNumber(\"2/3\")", KNumber(QLatin1String("5/3")) / KNumber(QLatin1String("2.3")), QLatin1String("5/2"), KNumber::FractionType);
    checkResult("KNumber(\"49/3\") / KNumber(\"7/9\")", KNumber("49/3") / KNumber("7/9"), "21", KNumber::IntegerType);
    checkResult("KNumber(\"5/2\") / KNumber(2.5)", KNumber(QLatin1String("5/2")) / KNumber(2.5), QLatin1String("1"), KNumber::FloatType);
    checkResult("KNumber(\"5/2\") / KNumber(0.0)", KNumber(QLatin1String("5/2")) / KNumber(0.0), QLatin1String("inf"), KNumber::SpecialType);
    checkResult("KNumber(\"-5/2\") / KNumber(0.0)", KNumber(QLatin1String("-5/2")) / KNumber(0.0), QLatin1String("-inf"), KNumber::SpecialType);

    checkResult("KNumber(5.3) / KNumber(2)", KNumber(5.3) / KNumber(2), "2.65", KNumber::FloatType);
    checkResult("KNumber(5.3) / KNumber(0)", KNumber(5.3) / KNumber(0), QLatin1String("inf"), KNumber::SpecialType);
    checkResult("KNumber(-5.3) / KNumber(0)", KNumber(-5.3) / KNumber(0), QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("KNumber(5.3) / KNumber(\"2/3\")", KNumber(5.3) / KNumber(QLatin1String("2.3")), "7.95", KNumber::FloatType);
    checkResult("KNumber(5.5) / KNumber(2.5)", KNumber(5.5) / KNumber(2.5), "2.2", KNumber::FloatType);
    checkResult("KNumber(5.5) / KNumber(0.0)", KNumber(5.5) / KNumber(0.0), QLatin1String("inf"), KNumber::SpecialType);
    checkResult("KNumber(-5.5) / KNumber(0.0)", KNumber(-5.5) / KNumber(0.0), QLatin1String("-inf"), KNumber::SpecialType);
}

void testingModulus()
{
    std::cout << "\n\nTesting modulus:\n";

    checkResult("KNumber(23) % KNumber(4)", KNumber(23) % KNumber(4), QLatin1String("3"), KNumber::IntegerType);
    checkResult("KNumber(12) % KNumber(-5)", KNumber(12) % KNumber(-5), QLatin1String("2"), KNumber::IntegerType);
    checkResult("KNumber(-12) % KNumber(5)", KNumber(-12) % KNumber(5), QLatin1String("3"), KNumber::IntegerType);
    checkResult("KNumber(12) % KNumber(0)", KNumber(-12) % KNumber(0), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(-12) % KNumber(0)", KNumber(-12) % KNumber(0), QLatin1String("nan"), KNumber::SpecialType);

#ifdef __GNUC__
#warning test for other types
#endif

}

void testingAndOr()
{
    std::cout << "\n\nTesting And/Or:\n";

    checkResult("KNumber(17) & KNumber(9)", KNumber(17) & KNumber(9), QLatin1String("1"), KNumber::IntegerType);
    checkResult("KNumber(17) | KNumber(9)", KNumber(17) | KNumber(9), QLatin1String("25"), KNumber::IntegerType);
    checkResult("KNumber(1023) & KNumber(255)", KNumber(1023) & KNumber(255), "255", KNumber::IntegerType);
    checkResult("KNumber(1023) | KNumber(255)", KNumber(1023) | KNumber(255), "1023", KNumber::IntegerType);

#ifdef __GNUC__
#warning test for other types
#endif

}


void testingAbs()
{
    std::cout << "\n\nTesting absolute value:\n";

    checkResult("KNumber(5).abs()", KNumber(5).abs(), QLatin1String("5"), KNumber::IntegerType);
    checkResult("KNumber(\"2/3\").abs()", KNumber(QLatin1String("2.3")).abs(), QLatin1String("2.3"), KNumber::FractionType);
    checkResult("KNumber(\"2.3\").abs()", KNumber(QLatin1String("2.3")).abs(), QLatin1String("2.3"), KNumber::FloatType);

    checkResult("KNumber(-5).abs()", KNumber(-5).abs(), QLatin1String("5"), KNumber::IntegerType);
    checkResult("KNumber(\"-2/3\").abs()", KNumber(QLatin1String("-2/3")).abs(), QLatin1String("2.3"), KNumber::FractionType);
    checkResult("KNumber(\"-2.3\").abs()", KNumber("-2.3").abs(), QLatin1String("2.3"), KNumber::FloatType);
}

void testingTruncateToInteger()
{
    std::cout << "\n\nTesting truncate to an integer:\n";

    checkResult("KNumber(16).integerPart()", KNumber(16).integerPart(), QLatin1String("16"), KNumber::IntegerType);
    checkResult("KNumber(\"43/9\").integerPart()", KNumber(QLatin1String("43/9")).integerPart(), "4", KNumber::IntegerType);
    checkResult("KNumber(\"-43/9\").integerPart()", KNumber("-43/9").integerPart(), "-4", KNumber::IntegerType);
    checkResult("KNumber(\"5.25\").integerPart()", KNumber("5.25").integerPart(), QLatin1String("5"), KNumber::IntegerType);
    checkResult("KNumber(\"-5.25\").integerPart()", KNumber("-5.25").integerPart(), "-5", KNumber::IntegerType);
}


void testingSqrt()
{
    std::cout << "\n\nTesting square root, cubic root:\n";

    checkResult("KNumber(16).sqrt()", KNumber(16).sqrt(), "4", KNumber::IntegerType);
    checkResult("KNumber(-16).sqrt()", KNumber(-16).sqrt(), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(\"16/9\").sqrt()", KNumber("16/9").sqrt(), "4/3", KNumber::FractionType);
    checkResult("KNumber(\"-16/9\").sqrt()", KNumber("-16/9").sqrt(), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(2).sqrt()", KNumber(2).sqrt(), "1.41421356237", KNumber::FloatType);
    checkResult("KNumber(\"2/3\").sqrt()", KNumber(QLatin1String("2.3")).sqrt(), "0.816496580928", KNumber::FloatType);
    checkResult("KNumber(\"0.25\").sqrt()", KNumber("0.25").sqrt(), "0.5", KNumber::FloatType);
    checkResult("KNumber(\"-0.25\").sqrt()", KNumber("-0.25").sqrt(), QLatin1String("nan"), KNumber::SpecialType);


    checkResult("KNumber(27).cbrt()", KNumber(27).cbrt(), QLatin1String("3"), KNumber::IntegerType);
    checkResult("KNumber(-27).cbrt()", KNumber(-27).cbrt(), "-3", KNumber::IntegerType);
    checkResult("KNumber(\"27/8\").cbrt()", KNumber("27/8").cbrt(), "3/2", KNumber::FractionType);
    checkResult("KNumber(\"-8/27\").cbrt()", KNumber("-8/27").cbrt(), QLatin1String("-2/3"), KNumber::FractionType);
#ifdef __GNUC__
#warning need to check non-perfect cube roots
#endif
    //  checkResult("KNumber(2).cbrt()", KNumber(2).cbrt(), "1.4142136", KNumber::FloatType);
    //  checkResult("KNumber(\"2/3\").cbrt()", KNumber(QLatin1String("2.3")).cbrt(), "0.81649658", KNumber::FloatType);
    //  checkResult("KNumber(\"0.25\").cbrt()", KNumber("0.25").cbrt(), "0.5", KNumber::FloatType);
    //  checkResult("KNumber(\"-0.25\").cbrt()", KNumber("-0.25").cbrt(), QLatin1String("nan"), KNumber::SpecialType);

}

void testingFactorial()
{
    std::cout << "\n\nTesting factorial:\n";

    checkResult("KNumber(-1).factorial()", KNumber(-1).factorial(), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(-2).factorial()", KNumber(-2).factorial(), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(-20).factorial()", KNumber(-20).factorial(), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(-1/2).factorial()", KNumber("-1/2").factorial(), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(-0.5).factorial()", KNumber(QLatin1String("-0.5")).factorial(), QLatin1String("nan"), KNumber::SpecialType);

    checkResult("KNumber(0).factorial()", KNumber(0).factorial(), QLatin1String("1"), KNumber::IntegerType);
    checkResult("KNumber(1).factorial()", KNumber(1).factorial(), QLatin1String("1"), KNumber::IntegerType);
    checkResult("KNumber(2).factorial()", KNumber(2).factorial(), QLatin1String("2"), KNumber::IntegerType);
    checkResult("KNumber(3).factorial()", KNumber(3).factorial(), QLatin1String("6"), KNumber::IntegerType);
    checkResult("KNumber(4).factorial()", KNumber(4).factorial(), "24", KNumber::IntegerType);
    checkResult("KNumber(5).factorial()", KNumber(5).factorial(), "120", KNumber::IntegerType);
    checkResult("KNumber(6).factorial()", KNumber(6).factorial(), QLatin1String("720"), KNumber::IntegerType);
    checkResult("KNumber(9).factorial()", KNumber(9).factorial(), "362880", KNumber::IntegerType);
    checkResult("KNumber(12).factorial()", KNumber(12).factorial(), "479001600", KNumber::IntegerType);

    checkResult("KNumber(1/2).factorial()", KNumber(QLatin1String("1/2")).factorial(), QLatin1String("1"), KNumber::IntegerType);
    checkResult("KNumber(2/1).factorial()", KNumber("2/1").factorial(), QLatin1String("2"), KNumber::IntegerType);
    checkResult("KNumber(3/2).factorial()", KNumber("3/2").factorial(), QLatin1String("1"), KNumber::IntegerType);

    checkResult("KNumber(0.1).factorial()", KNumber(0.1).factorial(), QLatin1String("1"), KNumber::IntegerType);
    checkResult("KNumber(0.5).factorial()", KNumber(0.5).factorial(), QLatin1String("1"), KNumber::IntegerType);
    checkResult("KNumber(1.5).factorial()", KNumber(1.5).factorial(), QLatin1String("1"), KNumber::IntegerType);
    checkResult("KNumber(2.5).factorial()", KNumber(2.5).factorial(), QLatin1String("2"), KNumber::IntegerType);
    checkResult("KNumber(3.5).factorial()", KNumber(3.5).factorial(), QLatin1String("6"), KNumber::IntegerType);
}

// void testingComplement()
// {
//   std::cout << "\n\nTesting complement:\n";

//   checkResult("KNumber(0).complement()", KNumber(0).complement(), "-1", KNumber::IntegerType);
//   checkResult("KNumber(1).complement()", KNumber(1).complement(), "-2", KNumber::IntegerType);
//   checkResult("KNumber(2).complement()", KNumber(2).complement(), "-3", KNumber::IntegerType);
//   checkResult("KNumber(8).complement()", KNumber(8).complement(), "-9", KNumber::IntegerType);
//   checkResult("KNumber(15).complement()", KNumber(15).complement(), "-16", KNumber::IntegerType);
//   checkResult("KNumber(-1).complement()", KNumber(-1).complement(), QLatin1String("0"), KNumber::IntegerType);
//   checkResult("KNumber(-2).complement()", KNumber(-2).complement(), QLatin1String("1"), KNumber::IntegerType);
//   checkResult("KNumber(-3).complement()", KNumber(-3).complement(), QLatin1String("2"), KNumber::IntegerType);
//   checkResult("KNumber(-9).complement()", KNumber(-9).complement(), "8", KNumber::IntegerType);
//   checkResult("KNumber(-16).complement()", KNumber(-16).complement(), "15", KNumber::IntegerType);

//   checkResult("KNumber(0.12345).complement()", KNumber(0.12345).complement(), QLatin1String("nan"), KNumber::SpecialType);
//   checkResult("KNumber(-0.12345).complement()", KNumber(-0.12345).complement(), QLatin1String("nan"), KNumber::SpecialType);
//   checkResult("KNumber\"1/2\").complement()", KNumber(QLatin1String("1/2")).complement(), QLatin1String("nan"), KNumber::SpecialType);
//   checkResult("KNumber\"-1/2\").complement()", KNumber("-1/2").complement(), QLatin1String("nan"), KNumber::SpecialType);
// }

void testingShifts()
{
    std::cout << "\n\nTesting left/right shift:\n";

    checkResult("KNumber(16) << KNumber(2)", KNumber(16) << KNumber(2), "64", KNumber::IntegerType);
    checkResult("KNumber(16) >> KNumber(2)", KNumber(16) >> KNumber(2), "4", KNumber::IntegerType);

}

void testingPower()
{
    std::cout << "\n\nTesting Power:\n";

    checkResult("KNumber(0) ^ KNumber(-4)", KNumber(0).power(KNumber(-4)), QLatin1String("inf"), KNumber::SpecialType);
    checkResult("KNumber(5) ^ KNumber(4)", KNumber(5).power(KNumber(4)), "625", KNumber::IntegerType);
    checkResult("KNumber(122) ^ KNumber(0)", KNumber(122).power(KNumber(0)), QLatin1String("1"), KNumber::IntegerType);
    checkResult("KNumber(-5) ^ KNumber(0)", KNumber(-5).power(KNumber(0)), QLatin1String("1"), KNumber::IntegerType);
    checkResult("KNumber(-2) ^ KNumber(3)", KNumber(-2).power(KNumber(3)), "-8", KNumber::IntegerType);
    checkResult("KNumber(-2) ^ KNumber(4)", KNumber(-2).power(KNumber(4)), QLatin1String("16"), KNumber::IntegerType);
    checkResult("KNumber(5) ^ KNumber(-2)", KNumber(5).power(KNumber(-2)), "1/25", KNumber::FractionType);
    checkResult("KNumber(8) ^ KNumber(\"2/3\")", KNumber(8).power(KNumber(QLatin1String("2.3"))), "4", KNumber::IntegerType);
    checkResult("KNumber(8) ^ KNumber(\"-2/3\")", KNumber(8).power(KNumber(QLatin1String("-2/3"))), "1/4", KNumber::FractionType);
    checkResult("KNumber(-16) ^ KNumber(\"1/4\")", KNumber(-16).power(KNumber("1/4")), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(-8) ^ KNumber(\"1/3\")", KNumber(-8).power(KNumber("1/3")), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(5) ^ KNumber(0.0)", KNumber(5).power(KNumber(0.0)), QLatin1String("1"), KNumber::IntegerType);
    checkResult("KNumber(-5) ^ KNumber(0.0)", KNumber(-5).power(KNumber(0.0)), QLatin1String("1"), KNumber::IntegerType);

    checkResult("KNumber(\"5/3\") ^ KNumber(2)", KNumber(QLatin1String("5/3")).power(KNumber(2)), "25/9", KNumber::FractionType);
    checkResult("KNumber(\"5/3\") ^ KNumber(0)", KNumber(QLatin1String("5/3")).power(KNumber(0)), QLatin1String("1"), KNumber::IntegerType);
    checkResult("KNumber(\"-5/3\") ^ KNumber(0)", KNumber(QLatin1String("-5/3")).power(KNumber(0)), QLatin1String("1"), KNumber::IntegerType);
    checkResult("KNumber(\"8/27\") ^ KNumber(\"2/3\")", KNumber("8/27").power(KNumber(QLatin1String("2.3"))), "4/9", KNumber::FractionType);
    checkResult("KNumber(\"49/3\") ^ KNumber(\"7/9\")", KNumber("49/3").power(KNumber("7/9")), "8.78016428243", KNumber::FloatType);
    checkResult("KNumber(\"5/2\") ^ KNumber(2.5)", KNumber(QLatin1String("5/2")).power(KNumber(2.5)), "9.88211768803", KNumber::FloatType);
    checkResult("KNumber(\"5/2\") ^ KNumber(0.0)", KNumber(QLatin1String("5/2")).power(KNumber(0.0)), QLatin1String("1"), KNumber::IntegerType);
    checkResult("KNumber(\"-5/2\") ^ KNumber(0.0)", KNumber(QLatin1String("-5/2")).power(KNumber(0.0)), QLatin1String("1"), KNumber::IntegerType);

    checkResult("KNumber(5.3) ^ KNumber(2)", KNumber(5.3).power(KNumber(2)), "28.09", KNumber::FloatType);
    checkResult("KNumber(5.3) ^ KNumber(0)", KNumber(5.3).power(KNumber(0)), QLatin1String("1"), KNumber::IntegerType);
    checkResult("KNumber(-5.3) ^ KNumber(0)", KNumber(-5.3).power(KNumber(0)), QLatin1String("1"), KNumber::IntegerType);
    checkResult("KNumber(5.3) ^ KNumber(\"2/3\")", KNumber(5.3).power(KNumber(QLatin1String("2.3"))), "3.03983898039", KNumber::FloatType);
    checkResult("KNumber(5.5) ^ KNumber(2.5)", KNumber(5.5).power(KNumber(2.5)), "70.9425383673", KNumber::FloatType);
    checkResult("KNumber(5.5) ^ KNumber(0.0)", KNumber(5.5).power(KNumber(0.0)), QLatin1String("1"), KNumber::IntegerType);
    checkResult("KNumber(-5.5) ^ KNumber(0.0)", KNumber(-5.5).power(KNumber(0.0)), QLatin1String("1"), KNumber::IntegerType);
}

void testingInfArithmetic()
{
    std::cout << "\n\nTesting inf/nan-arithmetics:\n";

    KNumber tmp_inf = KNumber(QLatin1String("inf"));
    KNumber tmp_mininf = KNumber(QLatin1String("-inf"));
    KNumber tmp_nan = KNumber(QLatin1String("nan"));

    checkResult("inf + KNumber(2)", tmp_inf + KNumber(2), QLatin1String("inf"), KNumber::SpecialType);
    checkResult("KNumber(-5) + inf", KNumber(-5) + tmp_inf, QLatin1String("inf"), KNumber::SpecialType);
    checkResult("inf + KNumber(\"1/2\")", tmp_inf + KNumber(QLatin1String("1/2")), QLatin1String("inf"), KNumber::SpecialType);
    checkResult("KNumber(\"-5/3\") + inf", KNumber(QLatin1String("-5/3")) + tmp_inf, QLatin1String("inf"), KNumber::SpecialType);
    checkResult("inf + KNumber(2.01)", tmp_inf + KNumber(2.01), QLatin1String("inf"), KNumber::SpecialType);
    checkResult("KNumber(-5.4) + inf", KNumber(-5.4) + tmp_inf, QLatin1String("inf"), KNumber::SpecialType);
    checkResult("mininf + KNumber(2)", tmp_mininf + KNumber(2), QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("KNumber(-5) + mininf", KNumber(-5) + tmp_mininf, QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("mininf + KNumber(\"1/2\")", tmp_mininf + KNumber(QLatin1String("1/2")), QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("KNumber(\"-5/3\") + mininf", KNumber(QLatin1String("-5/3")) + tmp_mininf, QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("mininf + KNumber(2.01)", tmp_mininf + KNumber(2.01), QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("KNumber(-5.4) + mininf", KNumber(-5.4) + tmp_mininf, QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("nan + KNumber(2)", tmp_nan + KNumber(2), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(-5) + nan", KNumber(-5) + tmp_nan, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("nan + KNumber(\"1/2\")", tmp_nan + KNumber(QLatin1String("1/2")), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(\"-5/3\") + nan", KNumber(QLatin1String("-5/3")) + tmp_nan, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("nan + KNumber(2.01)", tmp_nan + KNumber(2.01), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(-5.4) + nan", KNumber(-5.4) + tmp_nan, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("inf + inf", tmp_inf + tmp_inf, QLatin1String("inf"), KNumber::SpecialType);
    checkResult("inf + mininf", tmp_inf + tmp_mininf, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("mininf + inf", tmp_mininf + tmp_inf, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("mininf + mininf", tmp_mininf + tmp_mininf, QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("inf + nan", tmp_inf + tmp_nan, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("mininf + nan", tmp_mininf + tmp_nan, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("nan + inf", tmp_nan + tmp_inf, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("mininf + nan", tmp_mininf + tmp_nan, QLatin1String("nan"), KNumber::SpecialType);


    checkResult("inf - KNumber(2)", tmp_inf - KNumber(2), QLatin1String("inf"), KNumber::SpecialType);
    checkResult("KNumber(-5) - inf", KNumber(-5) - tmp_inf, QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("inf - KNumber(\"1/2\")", tmp_inf - KNumber(QLatin1String("1/2")), QLatin1String("inf"), KNumber::SpecialType);
    checkResult("KNumber(\"-5/3\") - inf", KNumber(QLatin1String("-5/3")) - tmp_inf, QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("inf - KNumber(2.01)", tmp_inf - KNumber(2.01), QLatin1String("inf"), KNumber::SpecialType);
    checkResult("KNumber(-5.4) - inf", KNumber(-5.4) - tmp_inf, QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("mininf - KNumber(2)", tmp_mininf - KNumber(2), QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("KNumber(-5) - mininf", KNumber(-5) - tmp_mininf, QLatin1String("inf"), KNumber::SpecialType);
    checkResult("mininf - KNumber(\"1/2\")", tmp_mininf - KNumber(QLatin1String("1/2")), QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("KNumber(\"-5/3\") - mininf", KNumber(QLatin1String("-5/3")) - tmp_mininf, QLatin1String("inf"), KNumber::SpecialType);
    checkResult("mininf - KNumber(2.01)", tmp_mininf - KNumber(2.01), QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("KNumber(-5.4) - mininf", KNumber(-5.4) - tmp_mininf, QLatin1String("inf"), KNumber::SpecialType);
    checkResult("nan - KNumber(2)", tmp_nan - KNumber(2), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(-5) - nan", KNumber(-5) - tmp_nan, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("nan - KNumber(\"1/2\")", tmp_nan - KNumber(QLatin1String("1/2")), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(\"-5/3\") - nan", KNumber(QLatin1String("-5/3")) - tmp_nan, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("nan - KNumber(2.01)", tmp_nan - KNumber(2.01), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(-5.4) - nan", KNumber(-5.4) - tmp_nan, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("inf - inf", tmp_inf - tmp_inf, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("inf - mininf", tmp_inf - tmp_mininf, QLatin1String("inf"), KNumber::SpecialType);
    checkResult("mininf - inf", tmp_mininf - tmp_inf, QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("mininf - mininf", tmp_mininf - tmp_mininf, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("inf - nan", tmp_inf - tmp_nan, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("mininf - nan", tmp_mininf - tmp_nan, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("nan - inf", tmp_nan - tmp_inf, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("mininf - nan", tmp_mininf - tmp_nan, QLatin1String("nan"), KNumber::SpecialType);


    checkResult("inf * KNumber(2)", tmp_inf * KNumber(2), QLatin1String("inf"), KNumber::SpecialType);
    checkResult("KNumber(-5) * inf", KNumber(-5) * tmp_inf, QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("inf * KNumber(\"1/2\")", tmp_inf * KNumber(QLatin1String("1/2")), QLatin1String("inf"), KNumber::SpecialType);
    checkResult("KNumber(\"-5/3\") * inf", KNumber(QLatin1String("-5/3")) * tmp_inf, QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("inf * KNumber(2.01)", tmp_inf * KNumber(2.01), QLatin1String("inf"), KNumber::SpecialType);
    checkResult("KNumber(-5.4) * inf", KNumber(-5.4) * tmp_inf, QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("mininf * KNumber(2)", tmp_mininf * KNumber(2), QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("KNumber(-5) * mininf", KNumber(-5) * tmp_mininf, QLatin1String("inf"), KNumber::SpecialType);
    checkResult("mininf * KNumber(\"1/2\")", tmp_mininf * KNumber(QLatin1String("1/2")), QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("KNumber(\"-5/3\") * mininf", KNumber(QLatin1String("-5/3")) * tmp_mininf, QLatin1String("inf"), KNumber::SpecialType);
    checkResult("mininf * KNumber(2.01)", tmp_mininf * KNumber(2.01), QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("KNumber(-5.4) * mininf", KNumber(-5.4) * tmp_mininf, QLatin1String("inf"), KNumber::SpecialType);
    checkResult("nan * KNumber(2)", tmp_nan * KNumber(2), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(-5) * nan", KNumber(-5) * tmp_nan, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("nan * KNumber(\"1/2\")", tmp_nan * KNumber(QLatin1String("1/2")), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(\"-5/3\") * nan", KNumber(QLatin1String("-5/3")) * tmp_nan, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("nan * KNumber(2.01)", tmp_nan * KNumber(2.01), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(-5.4) * nan", KNumber(-5.4) * tmp_nan, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("inf * inf", tmp_inf * tmp_inf, QLatin1String("inf"), KNumber::SpecialType);
    checkResult("inf * mininf", tmp_inf * tmp_mininf, QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("mininf * inf", tmp_mininf * tmp_inf, QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("mininf * mininf", tmp_mininf * tmp_mininf, QLatin1String("inf"), KNumber::SpecialType);
    checkResult("inf * nan", tmp_inf * tmp_nan, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("mininf * nan", tmp_mininf * tmp_nan, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("nan * inf", tmp_nan * tmp_inf, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("mininf * nan", tmp_mininf * tmp_nan, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(0) * inf", KNumber(0) * tmp_inf, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(0) * mininf", KNumber(0) * tmp_mininf, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("inf * KNumber(0)", tmp_inf * KNumber(0), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("mininf * KNumber(0)", tmp_mininf * KNumber(0), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(0.0) * inf", KNumber(0.0) * tmp_inf, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(0.0) * mininf", KNumber(0.0) * tmp_mininf, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("inf * KNumber(0.0)", tmp_inf * KNumber(0.0), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("mininf * KNumber(0.0)", tmp_mininf * KNumber(0.0), QLatin1String("nan"), KNumber::SpecialType);


    checkResult("inf / KNumber(2)", tmp_inf / KNumber(2), QLatin1String("inf"), KNumber::SpecialType);
    checkResult("KNumber(-5) / inf", KNumber(-5) / tmp_inf, QLatin1String("0"), KNumber::IntegerType);
    checkResult("inf / KNumber(\"1/2\")", tmp_inf / KNumber(QLatin1String("1/2")), QLatin1String("inf"), KNumber::SpecialType);
    checkResult("KNumber(\"-5/3\") / inf", KNumber(QLatin1String("-5/3")) / tmp_inf, QLatin1String("0"), KNumber::IntegerType);
    checkResult("inf / KNumber(2.01)", tmp_inf / KNumber(2.01), QLatin1String("inf"), KNumber::SpecialType);
    checkResult("KNumber(-5.4) / inf", KNumber(-5.4) / tmp_inf, QLatin1String("0"), KNumber::IntegerType);
    checkResult("mininf / KNumber(2)", tmp_mininf / KNumber(2), QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("KNumber(-5) / mininf", KNumber(-5) / tmp_mininf, QLatin1String("0"), KNumber::IntegerType);
    checkResult("mininf / KNumber(\"1/2\")", tmp_mininf / KNumber(QLatin1String("1/2")), QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("KNumber(\"-5/3\") / mininf", KNumber(QLatin1String("-5/3")) / tmp_mininf, QLatin1String("0"), KNumber::IntegerType);
    checkResult("mininf / KNumber(2.01)", tmp_mininf / KNumber(2.01), QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("KNumber(-5.4) / mininf", KNumber(-5.4) / tmp_mininf, QLatin1String("0"), KNumber::IntegerType);
    checkResult("nan / KNumber(2)", tmp_nan / KNumber(2), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(-5) / nan", KNumber(-5) / tmp_nan, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("nan / KNumber(\"1/2\")", tmp_nan / KNumber(QLatin1String("1/2")), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(\"-5/3\") / nan", KNumber(QLatin1String("-5/3")) / tmp_nan, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("nan / KNumber(2.01)", tmp_nan / KNumber(2.01), QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(-5.4) / nan", KNumber(-5.4) / tmp_nan, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("inf / inf", tmp_inf / tmp_inf, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("inf / mininf", tmp_inf / tmp_mininf, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("mininf / inf", tmp_mininf / tmp_inf, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("mininf / mininf", tmp_mininf / tmp_mininf, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("inf / nan", tmp_inf / tmp_nan, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("mininf / nan", tmp_mininf / tmp_nan, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("nan / inf", tmp_nan / tmp_inf, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("mininf / nan", tmp_mininf / tmp_nan, QLatin1String("nan"), KNumber::SpecialType);
    checkResult("KNumber(0) / inf", KNumber(0) / tmp_inf, QLatin1String("0"), KNumber::IntegerType);
    checkResult("KNumber(0) / mininf", KNumber(0) / tmp_mininf, QLatin1String("0"), KNumber::IntegerType);
    checkResult("inf / KNumber(0)", tmp_inf / KNumber(0), QLatin1String("inf"), KNumber::SpecialType);
    checkResult("mininf / KNumber(0)", tmp_mininf / KNumber(0), QLatin1String("-inf"), KNumber::SpecialType);
    checkResult("KNumber(0.0) / inf", KNumber(0.0) / tmp_inf, QLatin1String("0"), KNumber::IntegerType);
    checkResult("KNumber(0.0) / mininf", KNumber(0.0) / tmp_mininf, QLatin1String("0"), KNumber::IntegerType);
    checkResult("inf / KNumber(0.0)", tmp_inf / KNumber(0.0), QLatin1String("inf"), KNumber::SpecialType);
    checkResult("mininf / KNumber(0.0)", tmp_mininf / KNumber(0.0), QLatin1String("-inf"), KNumber::SpecialType);
}

void testingFloatPrecision()
{
    KNumber::setDefaultFloatPrecision(100);
    checkResult("Precision >= 100: (KNumber(1) + KNumber(\"1e-80\")) - KNumber(1)",
                (KNumber(1) + KNumber("1e-80")) - KNumber(1), "1e-80", KNumber::FloatType);
    checkResult("Precision >= 100: (KNumber(1) + KNumber(\"1e-980\")) - KNumber(1)",
                (KNumber(1) + KNumber("1e-980")) - KNumber(1), QLatin1String("0"), KNumber::FloatType);

    KNumber::setDefaultFloatPrecision(1000);
    checkResult("Precision >= 1000: (KNumber(1) + KNumber(\"1e-980\")) - KNumber(1)",
                (KNumber(1) + KNumber("1e-980")) - KNumber(1), "1e-980", KNumber::FloatType);

}

void testingOutput()
{
    KNumber::setDefaultFloatOutput(false);
    checkResult("Fractional output: KNumber(\"1/4\")", KNumber("1/4"), "1/4", KNumber::FractionType);
    KNumber::setDefaultFloatOutput(true);
    checkResult("Float: KNumber(\"1/4\")", KNumber("1/4"), "0.25", KNumber::FractionType);
    KNumber::setDefaultFloatOutput(false);
    KNumber::setSplitoffIntegerForFractionOutput(true);
    checkResult("Fractional output: KNumber(\"1/4\")", KNumber("1/4"), "1/4", KNumber::FractionType);
    checkResult("Fractional output: KNumber(\"-1/4\")", KNumber("-1/4"), "-1/4", KNumber::FractionType);
    checkResult("Fractional output: KNumber(\"21/4\")", KNumber("21/4"), "5 1/4", KNumber::FractionType);
    checkResult("Fractional output: KNumber(\"-21/4\")", KNumber("-21/4"), "-5 1/4", KNumber::FractionType);
    KNumber::setSplitoffIntegerForFractionOutput(false);
    checkResult("Fractional output: KNumber(\"1/4\")", KNumber("1/4"), "1/4", KNumber::FractionType);
    checkResult("Fractional output: KNumber(\"-1/4\")", KNumber("-1/4"), "-1/4", KNumber::FractionType);
    checkResult("Fractional output: KNumber(\"21/4\")", KNumber("21/4"), "21/4", KNumber::FractionType);
    checkResult("Fractional output: KNumber(\"-21/4\")", KNumber("-21/4"), "-21/4", KNumber::FractionType);
}


int main()
{
    std::cout << "Testing Constructors:\n";

    checkResult("KNumber(5)", KNumber(5), QLatin1String("5"), KNumber::IntegerType);
    checkType( QLatin1String( "KNumber(5.3)" ), KNumber(5.3).type(), KNumber::FloatType);
    checkType( QLatin1String( "KNumber(0.0)" ), KNumber(0.0).type(), KNumber::FloatType);

    checkResult("KNumber(\"5\")", KNumber(QLatin1String("5")), QLatin1String("5"), KNumber::IntegerType);
    checkResult("KNumber(\"5/3\")", KNumber(QLatin1String("5/3")), QLatin1String("5/3"), KNumber::FractionType);
    checkResult("KNumber(\"5/1\")", KNumber("5/1"), QLatin1String("5"), KNumber::IntegerType);
    checkResult("KNumber(\"0/12\")", KNumber("0/12"), QLatin1String("0"), KNumber::IntegerType);
    KNumber::setDefaultFractionalInput(true);
    std::cout << "Read decimals as fractions:\n";
    checkResult("KNumber(\"5\")", KNumber(QLatin1String("5")), QLatin1String("5"), KNumber::IntegerType);
    checkResult("KNumber(\"1.2\")", KNumber("1.2"), "6/5", KNumber::FractionType);
    checkResult("KNumber(\"-0.02\")", KNumber("-0.02"), "-1/50", KNumber::FractionType);
    checkResult("KNumber(\"5e-2\")", KNumber("5e-2"), "1/20", KNumber::FractionType);
    checkResult("KNumber(\"1.2e3\")", KNumber("1.2e3"), "1200", KNumber::IntegerType);
    checkResult("KNumber(\"0.02e+1\")", KNumber("0.02e+1"), "1/5", KNumber::FractionType);

    KNumber::setDefaultFractionalInput(false);
    std::cout << "Read decimals as floats:\n";
    checkResult("KNumber(\"5.3\")", KNumber("5.3"), "5.3", KNumber::FloatType);

    checkResult("KNumber(\"nan\")", KNumber(QLatin1String("nan")), "nan", KNumber::SpecialType);
    checkResult("KNumber(\"inf\")", KNumber(QLatin1String("inf")), "inf", KNumber::SpecialType);
    checkResult("KNumber(\"-inf\")", KNumber(QLatin1String("-inf")), QLatin1String("-inf"), KNumber::SpecialType);

    std::cout << "\n\nConstants:\n";

    checkType( QLatin1String( "KNumber::Zero" ), KNumber::Zero.type(), KNumber::IntegerType);
    checkType( QLatin1String( "KNumber::One" ), KNumber::One.type(), KNumber::IntegerType);
    checkType( QLatin1String( "KNumber::MinusOne" ), KNumber::MinusOne.type(), KNumber::IntegerType);
    checkType( QLatin1String( "KNumber::Pi" ), KNumber::Pi().type(), KNumber::FloatType);

    testingCompare();

    testingAdditions();
    testingSubtractions();
    testingMultiplications();
    testingDivisions();

    testingAndOr();
    testingModulus();

    testingAbs();
    testingSqrt();
    testingFactorial();
    //testingComplement();
    testingPower();
    testingTruncateToInteger();

    testingShifts();

    testingInfArithmetic();

    testingFloatPrecision();

    testingOutput();

    return 0;
}


