Report a bug
If you spot a problem with this page, click here to create a GitHub issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

mir.bignum.fp

Note The module doesn't provide full arithmetic API for now.

struct Fp(uint size) if (size % ((uint).sizeof * 8) == 0 && (size >= (uint).sizeof * 8));
Software floating point number.
Parameters:
size coefficient size in bits
nothrow this(bool sign, long exponent, UInt!size normalizedCoefficient);
pure nothrow @nogc @safe this(T)(const T value, bool normalize = true)
if (isFloatingPoint!T && (T.mant_dig <= size));
Constructs Fp from hardaware floating point number.
Parameters:
T value Hardware floating point number. Special values nan and inf aren't allowed.
bool normalize flag to indicate if the normalization should be performed.
Examples:
enum h = -33.0 * 2.0 ^^ -10;
auto f = Fp!64(h);
assert(f.sign);
assert(f.exponent == -10 - (64 - 6));
assert(f.coefficient == 33UL << (64 - 6));
assert(cast(double) f == h);

// CTFE
static assert(cast(double) Fp!64(h) == h);

f = Fp!64(-0.0);
assert(f.sign);
assert(f.exponent == 0);
assert(f.coefficient == 0);

// subnormals
static assert(cast(float) Fp!64(float.min_normal / 2) == float.min_normal / 2);
static assert(cast(float) Fp!64(float.min_normal * float.epsilon) == float.min_normal * float.epsilon);
// subnormals
static assert(cast(double) Fp!64(double.min_normal / 2) == double.min_normal / 2);
static assert(cast(double) Fp!64(double.min_normal * double.epsilon) == double.min_normal * double.epsilon);
// subnormals
static if (real.mant_dig <= 64)
{
    static assert(cast(real) Fp!128(real.min_normal / 2) == real.min_normal / 2);
    static assert(cast(real) Fp!128(real.min_normal * real.epsilon) == real.min_normal * real.epsilon);
}

enum d = cast(float) Fp!64(float.min_normal / 2, false);

// subnormals
static assert(cast(float) Fp!64(float.min_normal / 2, false) == float.min_normal / 2, d.stringof);
static assert(cast(float) Fp!64(float.min_normal * float.epsilon, false) == float.min_normal * float.epsilon);
// subnormals
static assert(cast(double) Fp!64(double.min_normal / 2, false) == double.min_normal / 2);
static assert(cast(double) Fp!64(double.min_normal * double.epsilon, false) == double.min_normal * double.epsilon);
// subnormals
static if (real.mant_dig <= 64)
{
    static assert(cast(real) Fp!64(real.min_normal / 2, false) == real.min_normal / 2);
    static assert(cast(real) Fp!64(real.min_normal * real.epsilon, false) == real.min_normal * real.epsilon);
}

import mir.bignum.fixed: UInt;

assert(cast(double)Fp!128(+double.infinity) == +double.infinity);
assert(cast(double)Fp!128(-double.infinity) == -double.infinity);

import mir.math.ieee : signbit;
auto r = cast(double)Fp!128(-double.nan);
assert(r != r && r.signbit);
nothrow this(uint isize)(UInt!isize integer, bool normalizedInteger = false);

this(ulong value);
Examples:
import mir.bignum.fixed: UInt;

auto fp = Fp!128(UInt!128.fromHexString("afbbfae3cd0aff2714a1de7022b0029d"));
assert(fp.exponent == 0);
assert(fp.coefficient == UInt!128.fromHexString("afbbfae3cd0aff2714a1de7022b0029d"));

fp = Fp!128(UInt!128.fromHexString("afbbfae3cd0aff2714a1de7022b0029d"), true);
assert(fp.exponent == 0);
assert(fp.coefficient == UInt!128.fromHexString("afbbfae3cd0aff2714a1de7022b0029d"));

fp = Fp!128(UInt!128.fromHexString("ae3cd0aff2714a1de7022b0029d"));
assert(fp.exponent == -20);
assert(fp.coefficient == UInt!128.fromHexString("ae3cd0aff2714a1de7022b0029d00000"));

fp = Fp!128(UInt!128.fromHexString("e7022b0029d"));
assert(fp.exponent == -84);
assert(fp.coefficient == UInt!128.fromHexString("e7022b0029d000000000000000000000"));

fp = Fp!128(UInt!64.fromHexString("e7022b0029d"));
assert(fp.exponent == -84);
assert(fp.coefficient == UInt!128.fromHexString("e7022b0029d000000000000000000000"));

fp = Fp!128(UInt!64.fromHexString("e7022b0029dd0aff"), true);
assert(fp.exponent == -64);
assert(fp.coefficient == UInt!128.fromHexString("e7022b0029dd0aff0000000000000000"));

fp = Fp!128(UInt!64.fromHexString("e7022b0029d"));
assert(fp.exponent == -84);
assert(fp.coefficient == UInt!128.fromHexString("e7022b0029d000000000000000000000"));

fp = Fp!128(UInt!192.fromHexString("ffffffffffffffffffffffffffffffff1000000000000000"));
assert(fp.exponent == 64);
assert(fp.coefficient == UInt!128.fromHexString("ffffffffffffffffffffffffffffffff"));

fp = Fp!128(UInt!192.fromHexString("ffffffffffffffffffffffffffffffff8000000000000000"));
assert(fp.exponent == 65);
assert(fp.coefficient == UInt!128.fromHexString("80000000000000000000000000000000"));

fp = Fp!128(UInt!192.fromHexString("fffffffffffffffffffffffffffffffe8000000000000000"));
assert(fp.exponent == 64);
assert(fp.coefficient == UInt!128.fromHexString("fffffffffffffffffffffffffffffffe"));

fp = Fp!128(UInt!192.fromHexString("fffffffffffffffffffffffffffffffe8000000000000001"));
assert(fp.exponent == 64);
assert(fp.coefficient == UInt!128.fromHexString("ffffffffffffffffffffffffffffffff"));
this(long value);
this(int value);
this(uint value);
const @property bool isNaN() scope;
const @property bool isInfinity() scope;
const @property bool isSpecial() scope;
const bool opEquals(const Fp rhs) scope;
nothrow ref Fp opOpAssign(string op)(Fp rhs) scope return
if (op == "*" || op == "/");
const nothrow Fp!(max(size, rhsSize)) opBinary(string op : "*", uint rhsSize)(Fp!rhsSize rhs);
Examples:
import mir.bignum.fixed: UInt;

auto a = Fp!128(0, -13, UInt!128.fromHexString("dfbbfae3cd0aff2714a1de7022b0029d"));
auto b = Fp!128(1, 100, UInt!128.fromHexString("e3251bacb112c88b71ad3f85a970a314"));
auto fp = a.opBinary!"*"(b);
assert(fp.sign);
assert(fp.exponent == 100 - 13 + 128);
assert(fp.coefficient == UInt!128.fromHexString("c6841dd302415d785373ab6d93712988"));
const nothrow Fp!(max(size, rhsSize)) opBinary(string op : "/", uint rhsSize)(Fp!rhsSize rhs);
Uses approximate division for now

TODO use full precision division for void when Fp division is ready

const nothrow T opCast(T)()
if (is(Unqual!T == bool));
const nothrow T opCast(T, bool noSpecial = false, bool noHalf = false)()
if (is(T == float) || is(T == double) || is(T == real));
Examples:
import mir.bignum.fixed: UInt;
auto fp = Fp!128(1, 100, UInt!128.fromHexString("e3251bacb112cb8b71ad3f85a970a314"));
assert(cast(double)fp == -0xE3251BACB112C8p+172);

fp = Fp!128(1, long.max, UInt!128.init);
assert(cast(double)fp == -double.infinity);

import mir.math.ieee : signbit;
fp = Fp!128(1, long.max, UInt!128(123));
auto r = cast(double)fp;
assert(r != r && r.signbit);
Examples:
import mir.bignum.fixed: UInt;
auto fp = Fp!128(1, 100, UInt!128.fromHexString("e3251bacb112cb8b71ad3f85a970a314"));
static if (real.mant_dig == 64)
    assert(cast(real)fp == -0xe3251bacb112cb8bp+164L);
Examples:
import mir.bignum.fixed: UInt;
auto fp = Fp!64(1, 100, UInt!64(0xe3251bacb112cb8b));
version (DigitalMars)
{
    // https://issues.dlang.org/show_bug.cgi?id=20963
    assert(cast(double)fp == -0xE3251BACB112C8p+108
        || cast(double)fp == -0xE3251BACB112D0p+108);
}
else
{
    assert(cast(double)fp == -0xE3251BACB112C8p+108);
}
Examples:
import mir.bignum.fixed: UInt;
auto fp = Fp!64(1, 100, UInt!64(0xe3251bacb112cb8b));
static if (real.mant_dig == 64)
    assert(cast(real)fp == -0xe3251bacb112cb8bp+100L);
const nothrow T opCast(T : Fp!newSize, bool noSpecial = false, size_t newSize)()
if (newSize != size);
Examples:
import mir.bignum.fixed: UInt;
auto fp = cast(Fp!64) Fp!128(UInt!128.fromHexString("afbbfae3cd0aff2784a1de7022b0029d"));
assert(fp.exponent == 64);
assert(fp.coefficient == UInt!64.fromHexString("afbbfae3cd0aff28"));

assert(Fp!128(-double.infinity) * Fp!128(1) == Fp!128(-double.infinity));
pure nothrow @nogc @trusted Fp!(coefficientizeA + coefficientizeB) extendedMul(bool noSpecial = false, uint coefficientizeA, uint coefficientizeB)(Fp!coefficientizeA a, Fp!coefficientizeB b);
template fp_log2(T) if (is(T == float) || is(T == double) || is(T == real))
Examples:
import mir.math.common: log2, approxEqual;
import mir.bignum.fp: fp_log2;

double x = 123456789.0e+123;
assert(approxEqual(x.Fp!128.fp_log2!double, x.log2));
T fp_log2(uint size)(Fp!size x);
template fp_log(T) if (is(T == float) || is(T == double) || is(T == real))
Examples:
import mir.math.common: log, approxEqual;
import mir.bignum.fp: fp_log;

double x = 123456789.0e+123;
assert(approxEqual(x.Fp!128.fp_log!double, x.log));
T fp_log(uint size)(Fp!size x);