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.decimal

Stack-allocated decimal type.

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

struct Decimal(size_t maxSize64) if (maxSize64 && (maxSize64 <= (ushort).max));
Stack-allocated decimal type.
Parameters:
maxSize64 count of 64bit words in coefficient
Examples:
import mir.conv: to;
Decimal!3 decimal;
DecimalExponentKey key;

import mir.math.constant: PI;
assert(decimal.fromStringImpl("3.141592653589793378e-10", key));
assert(cast(double) decimal == double(PI) / 1e10);
assert(key == DecimalExponentKey.e);
Examples:
import mir.conv: to;
Decimal!3 decimal;
DecimalExponentKey key;

assert(decimal.fromStringImpl("0", key));
assert(key == DecimalExponentKey.none);
assert(decimal.exponent == 0);
assert(decimal.coefficient.length == 0);
assert(!decimal.coefficient.sign);
assert(cast(double) decimal.coefficient == 0);

assert(decimal.fromStringImpl("-0.0", key));
assert(key == DecimalExponentKey.dot);
assert(decimal.exponent == -1);
assert(decimal.coefficient.length == 0);
assert(decimal.coefficient.sign);
assert(cast(double) decimal.coefficient == 0);

assert(decimal.fromStringImpl("0e0", key));
assert(key == DecimalExponentKey.e);
assert(decimal.exponent == 0);
assert(decimal.coefficient.length == 0);
assert(!decimal.coefficient.sign);
assert(cast(double) decimal.coefficient == 0);
sizediff_t exponent;
BigInt!maxSize64 coefficient;
DecimalView!size_t view();

const DecimalView!(const(size_t)) view();
pure @nogc @safe this(C)(scope const(C)[] str, int exponentShift = 0)
if (isSomeChar!C);
Examples:
import mir.math.constant: PI;
Decimal!2 decimal = "3.141592653589793378e-40"; // constructor
assert(cast(double) decimal == double(PI) / 1e40);
this(T)(const T x)
if (isFloatingPoint!T && (maxSize64 >= 1 + (T.mant_dig >= 64)));
Constructs Decimal from the floating point number using the Ryu algorithm.
The number is the shortest decimal representation that being converted back would result the same floating-point number.
Examples:
// float and double can be used to construct Decimal of any length
auto decimal64 = Decimal!1(-1.235e-7);
assert(decimal64.exponent == -10);
assert(decimal64.coefficient == -1235);

// real number may need Decimal at least length of 2
auto decimal128 = Decimal!2(-1.235e-7L);
assert(decimal128.exponent == -10);
assert(decimal128.coefficient == -1235);

decimal128 = Decimal!2(1234e3f);
assert(decimal128.exponent == 3);
assert(decimal128.coefficient == 1234);
ref auto opAssign(size_t rhsMaxSize64)(auto ref scope const Decimal!rhsMaxSize64 rhs) return
if (rhsMaxSize64 < maxSize64);
@trusted bool fromStringWithThousandsSeparatorImpl(C, bool allowSpecialValues = true, bool allowStartingPlus = true, bool allowLeadingZeros = true)(scope const(C)[] str, const C thousandsSeparator, const C fractionSeparator, out DecimalExponentKey key, int exponentShift = 0)
if (isSomeChar!C);
Handle thousand separators for non exponential numbers.
Returns:
false in case of overflow or incorrect string.
Examples:
Decimal!3 decimal;
DecimalExponentKey key;

assert(decimal.fromStringWithThousandsSeparatorImpl("12,345.678", ',', '.', key));
assert(cast(double) decimal == 12345.678);
assert(key == DecimalExponentKey.dot);

assert(decimal.fromStringWithThousandsSeparatorImpl("12,345,678", ',', '.', key, -3));
assert(cast(double) decimal == 12345.678);
assert(key == DecimalExponentKey.none);

assert(decimal.fromStringWithThousandsSeparatorImpl("021 345,678", ' ', ',', key));
assert(cast(double) decimal == 21345.678);
assert(key == DecimalExponentKey.dot);
pure nothrow @nogc scope @trusted bool fromStringImpl(C, bool allowSpecialValues = true, bool allowDotOnBounds = true, bool allowDExponent = true, bool allowStartingPlus = true, bool allowUnderscores = true, bool allowLeadingZeros = true, bool allowExponent = true, bool checkEmpty = true)(scope const(C)[] str, out DecimalExponentKey key, int exponentShift = 0)
if (isSomeChar!C);
Returns:
false in case of overflow or incorrect string.
Examples:
import mir.conv: to;
Decimal!3 decimal;
DecimalExponentKey key;

// Check precise percentate parsing
assert(decimal.fromStringImpl("71.7", key, -2));
assert(key == DecimalExponentKey.dot);
// The result is exact value instead of 0.7170000000000001 = 71.7 / 100
assert(cast(double) decimal == 0.717);

assert(decimal.fromStringImpl("+0.334e-5"w, key));
assert(key == DecimalExponentKey.e);
assert(cast(double) decimal == 0.334e-5);

assert(decimal.fromStringImpl("100_000_000"w, key));
assert(key == DecimalExponentKey.none);
assert(cast(double) decimal == 1e8);

assert(decimal.fromStringImpl("-334D-5"d, key));
assert(key == DecimalExponentKey.D);
assert(cast(double) decimal == -334e-5);

assert(decimal.fromStringImpl("2482734692817364218734682973648217364981273648923423", key));
assert(key == DecimalExponentKey.none);
assert(cast(double) decimal == 2482734692817364218734682973648217364981273648923423.0);

assert(decimal.fromStringImpl(".023", key));
assert(key == DecimalExponentKey.dot);
assert(cast(double) decimal == .023);

assert(decimal.fromStringImpl("0E100", key));
assert(key == DecimalExponentKey.E);
assert(cast(double) decimal == 0);

foreach (str; ["-nan", "-NaN", "-NAN"])
{
    assert(decimal.fromStringImpl(str, key));
    assert(decimal.coefficient.length > 0);
    assert(decimal.exponent == decimal.exponent.max);
    assert(decimal.coefficient.sign);
    assert(key == DecimalExponentKey.nan);
    assert(cast(double) decimal != cast(double) decimal);
}

foreach (str; ["inf", "Inf", "INF"])
{
    assert(decimal.fromStringImpl(str, key));
    assert(decimal.coefficient.length == 0);
    assert(decimal.exponent == decimal.exponent.max);
    assert(key == DecimalExponentKey.infinity);
    assert(cast(double) decimal == double.infinity);
}

assert(decimal.fromStringImpl("-inf", key));
assert(decimal.coefficient.length == 0);
assert(decimal.exponent == decimal.exponent.max);
assert(key == DecimalExponentKey.infinity);
assert(cast(double) decimal == -double.infinity);

assert(!decimal.fromStringImpl("3.3.4", key));
assert(!decimal.fromStringImpl("3.4.", key));
assert(decimal.fromStringImpl("4.", key));
assert(!decimal.fromStringImpl(".", key));
assert(decimal.fromStringImpl("0.", key));
assert(decimal.fromStringImpl("00", key));
assert(!decimal.fromStringImpl("0d", key));
const pure nothrow @safe immutable(C)[] toString(C = char)(NumericSpec spec = NumericSpec.init)
if (isSomeChar!C && isMutable!C);
Examples:
auto str = "-3.4010447314490204552169750449563978034784726557588085989975288830070948234680e-13245";
auto decimal = Decimal!4(str);
assert(decimal.toString == str, decimal.toString);

decimal = Decimal!4.init;
assert(decimal.toString == "0.0");
const void toString(C = char, W)(ref scope W w, NumericSpec spec = NumericSpec.init)
if (isSomeChar!C && isMutable!C);
Examples:
Check @nogc toString impl
import mir.format: stringBuf;
auto str = "5.28238923728e-876543210";
auto decimal = Decimal!1(str);
stringBuf buffer;
buffer << decimal;
assert(buffer.data == str, buffer.data);
const T opCast(T, bool wordNormalized = false, bool nonZero = false)()
if (isFloatingPoint!T && isMutable!T);
Mir parsing supports up-to quadruple precision. The conversion error is 0 ULP for normal numbers. Subnormal numbers with an exponent greater than or equal to -512 have upper error bound equal to 1 ULP.
const @property bool isNaN();
const @property bool isInfinity();
pure ref @safe auto opOpAssign(string op, size_t rhsMaxSize64)(ref const Decimal!rhsMaxSize64 rhs) return
if (op == "+" || op == "-");
Examples:
import std.stdio;
auto a = Decimal!1("777.7");
auto b = Decimal!1("777");
import mir.format;
assert(stringBuf() << cast(double)a - cast(double)b << getData == "0.7000000000000455");
a -= b;
assert(stringBuf() << a << getData == "0.7");

a = Decimal!1("-777.7");
b = Decimal!1("777");
a += b;
assert(stringBuf() << a << getData == "-0.7");

a = Decimal!1("777.7");
b = Decimal!1("-777");
a += b;
assert(stringBuf() << a << getData == "0.7");

a = Decimal!1("777");
b = Decimal!1("777.7");
a -= b;
assert(stringBuf() << a << getData == "-0.7");