pure @safe unittest
{
    import std.bigint;

        ubyte[] magnitude = [1, 2, 3, 4, 5, 6];
        auto b1 = BigInt(false, magnitude);
        assert(cast(long) b1 == 0x01_02_03_04_05_06L);
        auto b2 = BigInt(true, magnitude);
        assert(cast(long) b2 == -0x01_02_03_04_05_06L);
    
}

@safe unittest
{
    import std.bigint;

        ulong data = 1_000_000_000_000;
        auto bigData = BigInt(data);
        assert(bigData == BigInt("1_000_000_000_000"));
    
}

@safe unittest
{
    import std.bigint;

        const(BigInt) b1 = BigInt("1_234_567_890");
        BigInt b2 = BigInt(b1);
        assert(b2 == BigInt("1_234_567_890"));
    
}

@safe unittest
{
    import std.bigint;

        auto b = BigInt("123");
        b = 456;
        assert(b == BigInt("456"));
    
}

@safe unittest
{
    import std.bigint;

        auto b1 = BigInt("123");
        auto b2 = BigInt("456");
        b2 = b1;
        assert(b2 == BigInt("123"));
    
}

@safe unittest
{
    import std.bigint;

        auto b = BigInt("1_000_000_000");

        b += 12345;
        assert(b == BigInt("1_000_012_345"));

        b /= 5;
        assert(b == BigInt("200_002_469"));
    
}

@safe unittest
{
    import std.bigint;

        auto x = BigInt("123");
        auto y = BigInt("321");
        x += y;
        assert(x == BigInt("444"));
    
}

@safe unittest
{
    import std.bigint;

        auto x = BigInt("123");
        auto y = BigInt("456");
        BigInt z = x * y;
        assert(z == BigInt("56088"));
    
}

@safe unittest
{
    import std.bigint;

        auto x = BigInt("123");
        x *= 300;
        assert(x == BigInt("36900"));
    
}

@safe unittest
{
    import std.bigint;

        auto  x  = BigInt("1_000_000_500");
        long  l  = 1_000_000L;
        ulong ul = 2_000_000UL;
        int   i  = 500_000;
        short s  = 30_000;

        assert(is(typeof(x % l)  == long)   && x % l  == 500L);
        assert(is(typeof(x % ul) == BigInt) && x % ul == BigInt(500));
        assert(is(typeof(x % i)  == int)    && x % i  == 500);
        assert(is(typeof(x % s)  == int)    && x % s  == 10500);
    
}

@safe unittest
{
    import std.bigint;

        auto x = BigInt("100");
        BigInt y = 123 + x;
        assert(y == BigInt("223"));

        BigInt z = 123 - x;
        assert(z == BigInt("23"));

        // Dividing a built-in integer type by BigInt always results in
        // something that fits in a built-in type, so the built-in type is
        // returned, not BigInt.
        assert(is(typeof(1000 / x) == int));
        assert(1000 / x == 10);
    
}

@safe unittest
{
    import std.bigint;

        auto x = BigInt("1234");
        assert(-x == BigInt("-1234"));

        ++x;
        assert(x == BigInt("1235"));
    
}

@safe unittest
{
    import std.bigint;

        // Note that when comparing a BigInt to a float or double the
        // full precision of the BigInt is always considered, unlike
        // when comparing an int to a float or a long to a double.
        assert(BigInt(123456789) != cast(float) 123456789);
    
}

@safe unittest
{
    import std.bigint;

        // Non-zero values are regarded as true
        auto x = BigInt("1");
        auto y = BigInt("10");
        assert(x);
        assert(y);

        // Zero value is regarded as false
        auto z = BigInt("0");
        assert(!z);
    
}

@safe unittest
{
    import std.bigint;

        import std.conv : to, ConvOverflowException;
        import std.exception : assertThrown;

        assert(BigInt("0").to!int == 0);

        assert(BigInt("0").to!ubyte == 0);
        assert(BigInt("255").to!ubyte == 255);
        assertThrown!ConvOverflowException(BigInt("256").to!ubyte);
        assertThrown!ConvOverflowException(BigInt("-1").to!ubyte);
    
}

@system unittest
{
    import std.bigint;

        assert(cast(float)  BigInt("35540592535949172786332045140593475584")
                == 35540592535949172786332045140593475584.0f);
        assert(cast(double) BigInt("35540601499647381470685035515422441472")
                == 35540601499647381470685035515422441472.0);
        assert(cast(real)   BigInt("35540601499647381470685035515422441472")
                == 35540601499647381470685035515422441472.0L);

        assert(cast(float)  BigInt("-0x1345_6780_0000_0000_0000_0000_0000") == -0x1.3456_78p+108f       );
        assert(cast(double) BigInt("-0x1345_678a_bcde_f000_0000_0000_0000") == -0x1.3456_78ab_cdefp+108 );
        assert(cast(real)   BigInt("-0x1345_678a_bcde_f000_0000_0000_0000") == -0x1.3456_78ab_cdefp+108L);
    
}

@system unittest
{
    import std.bigint;

        // BigInts whose values cannot be exactly represented as float/double/real
        // are rounded when cast to float/double/real. When cast to float or
        // double or 64-bit real the rounding is strictly defined. When cast
        // to extended-precision real the rounding rules vary by environment.

        // BigInts that fall somewhere between two non-infinite floats/doubles
        // are rounded to the closer value when cast to float/double.
        assert(cast(float) BigInt(0x1aaa_aae7) == 0x1.aaa_aaep+28f);
        assert(cast(float) BigInt(0x1aaa_aaff) == 0x1.aaa_ab0p+28f);
        assert(cast(float) BigInt(-0x1aaa_aae7) == -0x1.aaaaaep+28f);
        assert(cast(float) BigInt(-0x1aaa_aaff) == -0x1.aaaab0p+28f);

        assert(cast(double) BigInt(0x1aaa_aaaa_aaaa_aa77) == 0x1.aaa_aaaa_aaaa_aa00p+60);
        assert(cast(double) BigInt(0x1aaa_aaaa_aaaa_aaff) == 0x1.aaa_aaaa_aaaa_ab00p+60);
        assert(cast(double) BigInt(-0x1aaa_aaaa_aaaa_aa77) == -0x1.aaa_aaaa_aaaa_aa00p+60);
        assert(cast(double) BigInt(-0x1aaa_aaaa_aaaa_aaff) == -0x1.aaa_aaaa_aaaa_ab00p+60);

        // BigInts that fall exactly between two non-infinite floats/doubles
        // are rounded away from zero when cast to float/double. (Note that
        // in most environments this is NOT the same rounding rule rule used
        // when casting int/long to float/double.)
        assert(cast(float) BigInt(0x1aaa_aaf0) == 0x1.aaa_ab0p+28f);
        assert(cast(float) BigInt(-0x1aaa_aaf0) == -0x1.aaaab0p+28f);

        assert(cast(double) BigInt(0x1aaa_aaaa_aaaa_aa80) == 0x1.aaa_aaaa_aaaa_ab00p+60);
        assert(cast(double) BigInt(-0x1aaa_aaaa_aaaa_aa80) == -0x1.aaa_aaaa_aaaa_ab00p+60);

        // BigInts that are bounded on one side by the largest positive or
        // most negative finite float/double and on the other side by infinity
        // or -infinity are rounded as if in place of infinity was the value
        // `2^^(T.max_exp)` when cast to float/double.
        assert(cast(float) BigInt("999_999_999_999_999_999_999_999_999_999_999_999_999") == float.infinity);
        assert(cast(float) BigInt("-999_999_999_999_999_999_999_999_999_999_999_999_999") == -float.infinity);

        assert(cast(double) BigInt("999_999_999_999_999_999_999_999_999_999_999_999_999") < double.infinity);
        assert(cast(real) BigInt("999_999_999_999_999_999_999_999_999_999_999_999_999") < real.infinity);
    
}

@safe unittest
{
    import std.bigint;

        const(BigInt) x = BigInt("123");
        BigInt y = cast() x;    // cast away const
        assert(y == x);
    
}

@safe unittest
{
    import std.bigint;

        auto x = BigInt("100");
        auto y = BigInt("10");
        int z = 50;
        const int w = 200;

        assert(y < x);
        assert(x > z);
        assert(z > y);
        assert(x < w);
    
}

@safe unittest
{
    import std.bigint;

        auto x = BigInt("0x1abc_de80_0000_0000_0000_0000_0000_0000");
        BigInt y = x - 1;
        BigInt z = x + 1;

        double d = 0x1.abcde8p124;
        assert(y < d);
        assert(z > d);
        assert(x >= d && x <= d);

        // Note that when comparing a BigInt to a float or double the
        // full precision of the BigInt is always considered, unlike
        // when comparing an int to a float or a long to a double.
        assert(BigInt(123456789) < cast(float) 123456789);
    
}

@safe unittest
{
    import std.bigint;

        auto b = BigInt("12345");
        long l = b.toLong();
        assert(l == 12345);
    
}

@safe unittest
{
    import std.bigint;

        auto big = BigInt("5_000_000");
        auto i = big.toInt();
        assert(i == 5_000_000);

        // Numbers that are too big to fit into an int will be clamped to int.max.
        auto tooBig = BigInt("5_000_000_000");
        i = tooBig.toInt();
        assert(i == int.max);
    
}

@safe unittest
{
    import std.bigint;

        import std.format : format;

        auto x = BigInt("1_000_000");
        x *= 12345;

        assert(format("%d", x) == "12345000000");
        assert(format("%x", x) == "2_dfd1c040");
        assert(format("%X", x) == "2_DFD1C040");
        assert(format("%o", x) == "133764340100");
    
}

@safe pure unittest
{
    import std.bigint;

        string[BigInt] aa;
        aa[BigInt(123)] = "abc";
        aa[BigInt(456)] = "def";

        assert(aa[BigInt(123)] == "abc");
        assert(aa[BigInt(456)] == "def");
    
}

@safe pure unittest
{
    import std.bigint;

        auto a = BigInt("1000");
        assert(a.ulongLength() == 1);
        assert(a.getDigit(0) == 1000);

        assert(a.uintLength() == 1);
        assert(a.getDigit!uint(0) == 1000);

        auto b = BigInt("2_000_000_000_000_000_000_000_000_000");
        assert(b.ulongLength() == 2);
        assert(b.getDigit(0) == 4584946418820579328);
        assert(b.getDigit(1) == 108420217);

        assert(b.uintLength() == 3);
        assert(b.getDigit!uint(0) == 3489660928);
        assert(b.getDigit!uint(1) == 1067516025);
        assert(b.getDigit!uint(2) == 108420217);
    
}

@safe unittest
{
    import std.bigint;

    BigInt a = "9588669891916142";
    BigInt b = "7452469135154800";
    auto c = a * b;
    assert(c == BigInt("71459266416693160362545788781600"));
    auto d = b * a;
    assert(d == BigInt("71459266416693160362545788781600"));
    assert(d == c);
    d = c * BigInt("794628672112");
    assert(d == BigInt("56783581982794522489042432639320434378739200"));
    auto e = c + d;
    assert(e == BigInt("56783581982865981755459125799682980167520800"));
    auto f = d + c;
    assert(f == e);
    auto g = f - c;
    assert(g == d);
    g = f - d;
    assert(g == c);
    e = 12345678;
    g = c + e;
    auto h = g / b;
    auto i = g % b;
    assert(h == a);
    assert(i == e);
    BigInt j = "-0x9A56_57f4_7B83_AB78";
    BigInt k = j;
    j ^^= 11;
    assert(k ^^ 11 == j);
}

@safe pure unittest
{
    import std.bigint;

    auto x = BigInt("123");
    x *= 1000;
    x += 456;

    auto xstr = x.toDecimalString();
    assert(xstr == "123456");
}

@safe unittest
{
    import std.bigint;

    auto x = BigInt("123");
    x *= 1000;
    x += 456;

    auto xstr = x.toHex();
    assert(xstr == "1E240");
}

nothrow pure @safe unittest
{
    import std.bigint;

    assert((-1).absUnsign == 1);
    assert(1.absUnsign == 1);
}

@safe pure nothrow unittest
{
    import std.bigint;

    auto a = BigInt(123);
    auto b = BigInt(25);
    BigInt q, r;

    divMod(a, b, q, r);

    assert(q == 4);
    assert(r == 23);
    assert(q * b + r == a);
}

@safe unittest
{
    import std.bigint;

    BigInt base = BigInt("123456789012345678901234567890");
    BigInt exponent = BigInt("1234567890123456789012345678901234567");
    BigInt modulus = BigInt("1234567");

    BigInt result = powmod(base, exponent, modulus);
    assert(result == 359079);
}