The OpenD Programming Language

Decimal

Stack-allocated decimal type.

Constructors

this
this(const(C)[] str, int exponentShift)
this
this(T x)

Constructs Decimal from the floating point number using the Ryu algorithm.

Members

Functions

fromStringImpl
bool fromStringImpl(const(C)[] str, DecimalExponentKey key, int exponentShift)
fromStringWithThousandsSeparatorImpl
bool fromStringWithThousandsSeparatorImpl(const(C)[] str, C thousandsSeparator, C fractionSeparator, DecimalExponentKey key, int exponentShift)

Handle thousand separators for non exponential numbers.

isInfinity
bool isInfinity()
isNaN
bool isNaN()
isSpecial
bool isSpecial()
opAssign
ref opAssign(Decimal!rhsMaxSize64 rhs)
opCast
T opCast()

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.

opOpAssign
ref opOpAssign(Decimal!rhsMaxSize64 rhs)
toString
void toString(W w, NumericSpec spec)
toString
immutable(C)[] toString(NumericSpec spec)
view
DecimalView!size_t view()
DecimalView!(const size_t) view()

Variables

coefficient
BigInt!size64 coefficient;
exponent
long exponent;

Parameters

size64

count of 64bit words in coefficient

Examples

import mir.test: should;
import mir.conv: to;
Decimal!128 decimal = void;
DecimalExponentKey key;

assert(decimal.fromStringImpl("3.141592653589793378e-10", key));
decimal.opCast!double.should == 0x1.596bf8ce7631ep-32;
key.should == DecimalExponentKey.e;
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);
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");

Check @nogc toString impl

import mir.format: stringBuf;
auto str = "5.28238923728e-876543210";
auto decimal = Decimal!1(str);
auto buffer = stringBuf;
buffer << decimal;
assert(buffer.data == str);
Decimal!4 i = "-0";

assert(i.view.coefficient.coefficients.length == 0);
assert(i.coefficient.view.unsigned.coefficients.length == 0);
assert(i.coefficient.view == 0L);
assert(cast(long) i.coefficient == 0);
assert(i.coefficient.sign);
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");
1 import mir.test: should;
2 
3 import mir.conv: to;
4 Decimal!3 decimal;
5 DecimalExponentKey key;
6 
7 // Check precise percentate parsing
8 assert(decimal.fromStringImpl("71.7", key, -2));
9 key.should == DecimalExponentKey.dot;
10 // The result is exact value instead of 0.7170000000000001 = 71.7 / 100
11 (cast(double) decimal).should == 0.717;
12 
13 assert(decimal.fromStringImpl("+0.334e-5"w, key));
14 key.should == DecimalExponentKey.e;
15 (cast(double) decimal).should == 0.334e-5;
16 
17 assert(decimal.fromStringImpl("100_000_000"w, key));
18 key.should == DecimalExponentKey.none;
19 (cast(double) decimal).should == 1e8;
20 
21 assert(decimal.fromStringImpl("-334D-5"d, key));
22 key.should == DecimalExponentKey.D;
23 (cast(double) decimal).should == -334e-5;
24 
25 assert(decimal.fromStringImpl("2482734692817364218734682973648217364981273648923423", key));
26 key.should == DecimalExponentKey.none;
27 (cast(double) decimal).should == 2482734692817364218734682973648217364981273648923423.0;
28 
29 assert(decimal.fromStringImpl(".023", key));
30 key.should == DecimalExponentKey.dot;
31 (cast(double) decimal).should == .023;
32 
33 assert(decimal.fromStringImpl("0E100", key));
34 key.should == DecimalExponentKey.E;
35 (cast(double) decimal).should == 0;
36 
37 foreach (str; ["-nan", "-NaN", "-NAN"])
38 {
39     assert(decimal.fromStringImpl(str, key));
40     assert(decimal.coefficient.length > 0);
41     assert(decimal.exponent == decimal.exponent.max);
42     assert(decimal.coefficient.sign);
43     key.should == DecimalExponentKey.nan;
44     auto nan = cast(double) decimal;
45     (cast(double) decimal).should == double.nan;
46 }
47 
48 foreach (str; ["inf", "Inf", "INF"])
49 {
50     assert(decimal.fromStringImpl(str, key));
51     assert(decimal.coefficient.length == 0);
52     assert(decimal.exponent == decimal.exponent.max);
53     assert(key == DecimalExponentKey.infinity);
54     (cast(double) decimal).should == double.infinity;
55 }
56 
57 assert(decimal.fromStringImpl("-inf", key));
58 assert(decimal.coefficient.length == 0);
59 assert(decimal.exponent == decimal.exponent.max);
60 assert(key == DecimalExponentKey.infinity);
61 should(cast(double) decimal) == -double.infinity;
62 
63 assert(!decimal.fromStringImpl("3.3.4", key));
64 assert(!decimal.fromStringImpl("3.4.", key));
65 assert(decimal.fromStringImpl("4.", key));
66 assert(!decimal.fromStringImpl(".", key));
67 assert(decimal.fromStringImpl("0.", key));
68 assert(decimal.fromStringImpl("00", key));
69 assert(!decimal.fromStringImpl("0d", key));
import mir.math.constant: PI;
Decimal!2 decimal = "3.141592653589793378e-40"; // constructor
assert(cast(double) decimal == double(PI) / 1e40);
// 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);
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);

Meta