decimal.decimal

IEEE 754-2008 implementation of decimal floating point data types. Decimal values are represented in memory using an integral coefficient and a 10-based exponent. Implementation is based on binary integer decimal encoding, supported by Intel.

Decimal data types use the same semantics as the built-in floating point data type (NaNs, infinities, etc.), the main difference being that they use internally a 10 exponent instead of a 2 exponent.

The current implementation supports three decimal data types, as specified by IEEE 754-2008 standard. The supported types are: decimal32, decimal64 and decimal128, but they can be easily extended to other bit widths if a underlying unsigned integral type is provided.

Decimal data types are best used in financial applications because arithmetic operation results are exact.

$(DIVC quickindex, $(BOOKTABLE ,

CategoryMembersClassicscopysign fabs fdim fmod fma getNaNPayload modf NaN nextAfter nextDown nextToward nextUp remainder sgnComparisonapproxEqual cmp fmax fmaxAbs fmin fminAbs isEqual isGreater isGreaterOrEqual isGreaterOrUnordered isIdentical isLess isLessOrEqual isLessOrUnordered isNotEqual isUnordered sameQuantum totalOrder totalOrderAbsConversionfromDPD fromMsCurrency fromMsDecimal to toDPD toExact toMsCurrency toMsDecimalData typesDecimal decimal32 decimal64 decimal128 DecimalClass DecimalControl ExceptionFlags Precision RoundingModeExceptionsDecimalException DivisionByZeroException InexactException InvalidOperationException OverflowException UnderflowExceptionExponentiations & logarithmscbrt compound exp exp10 exp10m1 exp2 exp2m1 expm1 frexp ilogb ldexp log log10 log10p1 log2 log2p1 logp1 nextPow10 pow quantexp root rsqrt scalbn sqrt truncPow10IntrospectiondecimalClass isCanonical isFinite isInfinity isNaN isNormal isPowerOf10 isSignaling isSubnormal isZero signbitReductiondot poly scaledProd scaledProdSum scaledProdDiff sum sumAbs sumSquareRoundingceil floor lrint lround nearbyint quantize rint rndtonl round truncTrigonometryacos acosh asin asinh atan atan2 atan2pi atanh atanpi cos cosh cospi hypot sin sinh sinpi tan tanh

Public Imports

std.traits
public import std.traits : isIntegral, isFloatingPoint, isSomeChar, isSomeString;
std.format
public import std.format : FormatSpec, FormatException;
std.range.primitives
public import std.range.primitives : isInputRange, ElementType;
core.sys.windows.wtypes
public import core.sys.windows.wtypes : DECIMAL;

Members

Aliases

Precision
alias Precision = uint

Precision used to round _decimal operation results. Every result will be adjusted to fit the specified precision. Use DecimalControl to query or set the context precision

decimal128
alias decimal128 = Decimal!128

Shorthand notations for Decimal types

decimal32
alias decimal32 = Decimal!32
decimal64
alias decimal64 = Decimal!64

Shorthand notations for Decimal types

nextToward
alias nextToward = nextAfter

Returns the next value after or before x, toward y.

Classes

DecimalException
class DecimalException

Root object for all _decimal exceptions

DivisionByZeroException
class DivisionByZeroException

Thrown if the denominator of a _decimal division operation is zero.

InexactException
class InexactException

Thrown if the result of a _decimal operation was rounded to fit in the destination format.

InvalidOperationException
class InvalidOperationException

Thrown if any operand of a _decimal operation is not a number or si not finite

OverflowException
class OverflowException

Thrown if the result of a _decimal operation exceeds the largest finite number of the destination format.

UnderflowException
class UnderflowException

Thrown if the result of a _decimal operation is smaller the smallest finite number of the destination format.

Enums

DecimalClass
enum DecimalClass

IEEE-754-2008 floating point categories

ExceptionFlags
enum ExceptionFlags

These flags indicate that an error has occurred. They indicate that a 0, NaN or an infinity value has been generated, that a result is inexact, or that a signalling NaN has been encountered. If the corresponding traps are set using DecimalControl, an exception will be thrown after setting these error flags.

RoundingMode
enum RoundingMode

Rounding modes. To better understand how rounding is performed, consult the table below.

precisionDefault
anonymousenum precisionDefault

Precision used to round _decimal operation results. Every result will be adjusted to fit the specified precision. Use DecimalControl to query or set the context precision

Functions

NaN
decimal128 NaN(T payloadHi, T payloadLo)

Creates a quiet NaN value using the specified payload Notes: Payloads are masked to fit the current representation, having a limited bit width of to mant_dig - 2;

NaN
D NaN(T payload)

Creates a quiet NaN value using the specified payload Notes: Payloads are masked to fit the current representation, having a limited bit width of to mant_dig - 2;

acos
D acos(D x)

Calculates the arc cosine of x, returning a value ranging from 0 to π. Exceptions:

InvalidOperationExceptionx is signaling NaN or |x| > 1.0
InexactExceptionthe result is inexact
acosh
D acosh(D x)

Calculates the inverse hyperbolic cosine of x Exceptions:

InvalidOperationExceptionx is signaling NaN or x < 1.0
InexactExceptionthe result is inexact
approxEqual
bool approxEqual(D1 x, D2 y, D3 maxRelDiff, D4 maxAbsDiff)
bool approxEqual(D1 x, D2 y, D3 maxRelDiff)
bool approxEqual(D1 x, D2 y)

Computes whether two values are approximately equal, admitting a maximum relative difference, or a maximum absolute difference.

asin
D asin(D x)

Calculates the arc sine of x, returning a value ranging from -π/2 to +π/2. Exceptions:

InvalidOperationExceptionx is signaling NaN or |x| > 1.0
InexactExceptionthe result is inexact
asinh
D asinh(D x)

Calculates the inverse hyperbolic sine of x Exceptions:

InvalidOperationExceptionx is signaling NaN
UnderflowExceptionthe result is too small to be represented
InexactExceptionthe result is inexact
atan
D atan(D x)

Calculates the arc tangent of x, returning a value ranging from -π/2 to π/2. Exceptions:

InvalidOperationExceptionx is signaling NaN
InexactExceptionthe result is inexact
UnderflowExceptionthe result is too small to be represented
atan2
auto atan2(D1 y, D2 x)

Calculates the arc tangent of y / x, returning a value ranging from -π to π. Exceptions:

InvalidOperationExceptionx or y is signaling NaN
InexactExceptionthe result is inexact
UnderflowExceptionthe result is too small to be represented
atan2pi
auto atan2pi(D1 y, D2 x)

Calculates the arc tangent of y / x divided by π, returning a value ranging from -1 to 1. Exceptions:

InvalidOperationExceptionx or y is signaling NaN
InexactExceptionthe result is inexact
UnderflowExceptionthe result is too small to be represented
atanh
D atanh(D x)

Calculates the inverse hyperbolic tangent of x Exceptions:

InvalidOperationExceptionx is signaling NaN or |x| > 1.0
DivisionByZeroException|x| = 1.0
UnderflowExceptionthe result is too small to be represented
InexactExceptionthe result is inexact
atanpi
D atanpi(D x)

Calculates the arc tangent of x divided by π, returning a value ranging from -1/2 to 1/2. Exceptions:

InvalidOperationExceptionx is signaling NaN
InexactExceptionthe result is inexact
UnderflowExceptionthe result is too small to be represented
cbrt
D cbrt(D x)

Computes the cubic root of x

ceil
D ceil(D x)

Returns the value of x rounded upward to the next integer (toward positive infinity). This operation is silent, doesn't throw any exception.

cmp
int cmp(D1 x, D2 y)

Defines a total order on all _decimal values.

compound
auto compound(D x, int n)

Computes (1 + x)n where n is an integer

copysign
D1 copysign(D1 to, D2 from)

Copies the sign of a _decimal value to another. This operation is silent, no error flags are set and no exceptions are thrown.

cos
D cos(D x)

Returns cosine of x.

cosh
D cosh(D x)

Calculates the hyperbolic cosine of x.

cospi
D cospi(D x)

Returns cosine of xπ.

decimalClass
DecimalClass decimalClass(D x)

Returns the decimal class where x falls into. This operation is silent, no exception flags are set and no exceptions are thrown.

dot
D dot(const(D)[] x, const(D)[] y)

Sums xi * yi using a higher precision, rounding only once at the end.

exp
D exp(D x)

Calculates ex

exp10
D exp10(D x)

Calculates 10x

exp10m1
D exp10m1(D x)

Calculates 10x - 1

exp2
D exp2(D x)

Calculates 2x

exp2m1
D exp2m1(D x)

Calculates 2x - 1

expm1
D expm1(D x)

Calculates ex - 1

fabs
D fabs(D x)

Calculates |x|. This operation is silent, no error flags are set and no exceptions are thrown.

fdim
auto fdim(D1 x, D2 y)

Returns the positive difference between x and y. If x ≤ y, retuns 0.0

floor
D floor(D x)

Returns the value of x rounded downward to the previous integer (toward negative infinity). This operation is silent, doesn't throw any exception.

fma
auto fma(D1 x, D2 y, D3 z)

Returns (x * y) + z, rounding only once according to the current precision and rounding mode

fmax
auto fmax(D1 x, D2 y)

Returns the larger _decimal value between x and y

fmaxAbs
auto fmaxAbs(D1 x, D2 y)

Returns the larger _decimal value between absolutes of x and y

fmin
auto fmin(D1 x, D2 y)

Returns the smaller _decimal value between x and y

fminAbs
auto fminAbs(D1 x, D2 y)

Returns the smaller _decimal value between absolutes of x and y

fmod
auto fmod(D1 x, D2 y)

Calculates the remainder of the division x / y

frexp
D frexp(D x, int y)

Separates _decimal _value into coefficient and exponent. This operation is silent, doesn't throw any exception.

fromDPD
decimal128 fromDPD(decimal128 x)
decimal64 fromDPD(decimal64 x)
decimal32 fromDPD(decimal32 x)

Converts the specified value from internal encoding from/to densely packed decimal encoding Notes: Decimal values are represented internaly using binary integer _decimal encoding, supported by Intel (BID). This function converts the specified value to/from densely packed _decimal encoding, supported by IBM (DPD). Please note that a DPD encoded _decimal cannot be passed to a function from this module, there is no way to determine if a _decimal value is BID-encoded or DPD-encoded, all functions will assume a BID-encoding.

fromMsCurrency
D fromMsCurrency(ulong x)

Converts the specified value to/from Microsoft currency data type;

fromMsDecimal
D fromMsDecimal(DECIMAL x)

Converts the specified value to/from Microsoft _decimal data type;

getNaNPayload
uint getNaNPayload(decimal32 x)
ulong getNaNPayload(decimal64 x)
ulong getNaNPayload(decimal128 x, ulong payloadHi)

Extracts the current payload from a NaN value Note: These functions do not check if x is truly a NaN value before extracting the payload. Using them on finite values will extract a part of the coefficient

hypot
auto hypot(D1 x, D2 y)

Calculates the length of the hypotenuse of a right-angled triangle with sides of length x and y. The hypotenuse is the value of the square root of the sums of the squares of x and y.

ilogb
int ilogb(D x)

Returns the 10-exponent of x as a signed integral value..

isCanonical
bool isCanonical(D x)

Determines if x is canonical. This operation is silent, no error flags are set and no exceptions are thrown.

isEqual
bool isEqual(D1 x, D2 y)

Compares two _decimal operands for equality

isFinite
bool isFinite(D x)

Determines if x is a finite value. This operation is silent, no error flags are set and no exceptions are thrown.

isGreater
bool isGreater(D1 x, D2 y)
isGreaterOrEqual
bool isGreaterOrEqual(D1 x, D2 y)
isGreaterOrUnordered
bool isGreaterOrUnordered(D1 x, D2 y)

Compares two _decimal operands. This operation is silent, no exception flags are set and no exceptions are thrown.

isIdentical
bool isIdentical(D x, D y)

Checks if two _decimal values are identical

isInfinity
bool isInfinity(D x)

Determines if x represents infinity. This operation is silent, no error flags are set and no exceptions are thrown.

isLess
bool isLess(D1 x, D2 y)
isLessOrEqual
bool isLessOrEqual(D1 x, D2 y)
isLessOrUnordered
bool isLessOrUnordered(D1 x, D2 y)

Compares two _decimal operands. This operation is silent, no exception flags are set and no exceptions are thrown.

isNaN
bool isNaN(D x)

Determines if x represents a NaN. This operation is silent, no error flags are set and no exceptions are thrown.

isNormal
bool isNormal(D x)

Determines if x is normalized. This operation is silent, no error flags are set and no exceptions are thrown.

isNotEqual
bool isNotEqual(D1 x, D2 y)

Compares two _decimal operands for equality

isPowerOf10
bool isPowerOf10(D x)

Checks whether a _decimal value is a power of ten. This operation is silent, no exception flags are set and no exceptions are thrown.

isSignaling
bool isSignaling(D x)

Determines if x represents a signaling NaN. This operation is silent, no error flags are set and no exceptions are thrown.

isSubnormal
bool isSubnormal(D x)

Determines if x is subnormal (denormalized). This operation is silent, no error flags are set and no exceptions are thrown.

isUnordered
bool isUnordered(D1 x, D2 y)

Compares two _decimal operands. This operation is silent, no exception flags are set and no exceptions are thrown.

isZero
bool isZero(D x)

Determines if x represents the value zero. This operation is silent, no error flags are set and no exceptions are thrown.

ldexp
D ldexp(D x, int n)

Efficiently calculates 2 * 10n. $(BOOKTABLE,

InvalidOperationExceptionx is signaling NaN

$(TR

UnderflowExceptionresult is subnormal or too small to be represented

$(TR

OverflowExceptionresult is too big to be representedInexactExceptionresult is inexact
log
D log(D x)

Calculates the natural logarithm of logex.

log10
D log10(D x)

Calculates log10x.

log10p1
D log10p1(D x)

Calculates log10(x + 1).

log2
D log2(D x)

Calculates log2x.

log2p1
D log2p1(D x)

Calculates log2(x + 1).

logp1
D logp1(D x)

Calculates loge(x + 1).

lrint
long lrint(D x, RoundingMode mode)
long lrint(D x)

Returns the value of x rounded using the specified rounding _mode. If no rounding _mode is specified the default context rounding _mode is used instead.

lround
long lround(D x)

Returns the value of x rounded away from zero.

modf
D modf(D x, D y)

Splits x in integral and fractional part.

nearbyint
D nearbyint(D x, RoundingMode mode)
D nearbyint(D x)

Returns the value of x rounded using the specified rounding _mode. If no rounding _mode is specified the default context rounding _mode is used instead.

nextAfter
D1 nextAfter(D1 x, D2 y)

Returns the next value after or before x, toward y.

nextDown
D nextDown(D x)

Returns the previous _decimal value before x.

nextPow10
D nextPow10(D x)

Gives the next power of 10 after x.

nextUp
D nextUp(D x)

Returns the next representable _decimal value after x.

poly
auto poly(D1 x, const(D2)[] a)

Calculates a0 + a1x + a2x2 + .. + anxn

pow
D pow(D x, T n)

Compute the value of xn, where n is integral

pow
auto pow(D1 x, D2 x)

Compute the value of xy

quantexp
int quantexp(D x)

Returns the exponent encoded into the specified _decimal value;

quantize
D1 quantize(D1 x, D2 y)

Express a value using another value exponent

remainder
auto remainder(D1 x, D2 y)

Calculates the remainder of the division x / y

rint
D rint(D x, RoundingMode mode)
D rint(D x)

Returns the value of x rounded using the specified rounding _mode. If no rounding _mode is specified the default context rounding _mode is used instead. This function is similar to nearbyint, but if the rounded value is not exact it will throw InexactException

rndtonl
D rndtonl(D x, RoundingMode mode)
D rndtonl(D x)

Returns the value of x rounded using the specified rounding _mode. If no rounding _mode is specified the default context rounding _mode is used instead. If the value doesn't fit in a long data type OverflowException is thrown.

root
D root(D x, T n)

Compute the value of x1/n, where n is an integer

round
D round(D x)

Returns the value of x rounded away from zero. This operation is silent, doesn't throw any exception.

rsqrt
D rsqrt(D x)

Computes the inverse square root of x

sameQuantum
bool sameQuantum(D1 x, D2 y)

Compares the exponents of two _decimal values

scalbn
D scalbn(D x, int n)
scaledProd
D scaledProd(const(D)[] x, int scale)

Multiplies elements of x using a higher precision, rounding only once at the end.

scaledProdDiff
D scaledProdDiff(const(D)[] x, const(D)[] y, int scale)

Multiplies results of xi - yi using a higher precision, rounding only once at the end.

scaledProdSum
D scaledProdSum(const(D)[] x, const(D)[] y, int scale)

Multiplies results of xi + yi using a higher precision, rounding only once at the end.

sgn
D sgn(D x)

Determines if x is negative This operation is silent, no error flags are set and no exceptions are thrown.

signbit
int signbit(D x)

Returns the sign bit of the specified value. This operation is silent, no error flags are set and no exceptions are thrown.

sin
D sin(D x)

Returns sine of x.

sinPi
D sinPi(D x)

Returns sine of x*π.

sinh
D sinh(D x)

Calculates the hyperbolic sine of x.

sqrt
D sqrt(D x)

Computes the square root of x

sum
D sum(const(D)[] x)

Sums elements of x using a higher precision, rounding only once at the end.</br>

sumAbs
D sumAbs(const(D)[] x)

Sums absolute elements of x using a higher precision, rounding only once at the end.

sumSquare
D sumSquare(const(D)[] x)

Sums squares of elements of x using a higher precision, rounding only once at the end.

tan
D tan(D x)

Returns tangent of x.

tanh
D tanh(D x)

Returns tangent of x.

to
T to(D x, RoundingMode mode)

Converts x to the specified integral type rounded if necessary by mode

to
F to(D x, RoundingMode mode)

Converts x to the specified binary floating point type rounded if necessary by mode

toDPD
decimal32 toDPD(decimal32 x)
decimal64 toDPD(decimal64 x)
decimal128 toDPD(decimal128 x)

Converts the specified value from internal encoding from/to densely packed decimal encoding Notes: Decimal values are represented internaly using binary integer _decimal encoding, supported by Intel (BID). This function converts the specified value to/from densely packed _decimal encoding, supported by IBM (DPD). Please note that a DPD encoded _decimal cannot be passed to a function from this module, there is no way to determine if a _decimal value is BID-encoded or DPD-encoded, all functions will assume a BID-encoding.

toExact
F toExact(D x, RoundingMode mode)

Converts x to the specified binary floating point type rounded if necessary by mode

toExact
T toExact(D x, RoundingMode mode)

Converts x to the specified integral type rounded if necessary by mode

toMsCurrency
long toMsCurrency(D x)

Converts the specified value to/from Microsoft currency data type;

toMsDecimal
DECIMAL toMsDecimal(D x)

Converts the specified value to/from Microsoft _decimal data type;

totalOrder
bool totalOrder(D1 x, D2 y)
totalOrderAbs
bool totalOrderAbs(D1 x, D2 y)

Checks the order between two _decimal values

trunc
D trunc(D x)

Returns the value of x rounded up or down, depending on sign (toward zero). This operation is silent, doesn't throw any exception.

truncPow10
D truncPow10(D x)

Gives the previous power of 10 before x.

Structs

DECIMAL
struct DECIMAL
Undocumented in source.
Decimal
struct Decimal(int bits)

Decimal floating-point computer numbering format that occupies 4, 8 or 16 bytes in computer memory.

DecimalControl
struct DecimalControl

Container for _decimal context control, provides methods to alter exception handling, manually edit error flags, adjust arithmetic precision and rounding mode

Templates

CommonDecimal
template CommonDecimal(T...)

Returns the most wide _decimal type among the specified types

isDecimal
template isDecimal(D...)

Returns true if all specified types are _decimal types.

Detailed Description

) )

Context:

All arithmetic operations are performed using a $(U thread local context). The context is setting various environment options:

  • precision - number of digits used. Each decimal data type has a default precision and all the calculations are performed using this precision. Setting the precision to a custom value will affect any subsequent operation and all the calculations will be performed using the specified number of digits. See Precision for details;
  • rounding - rounding method used to adjust operation results. If a result will have more digits than the current context precision, it will be rounded using the specified method. For available rounding modes, see RoundingMode;
  • flags - error flags. Every decimal operation may signal an error. The context will gather these errors for later introspection. See ExceptionFlags for details;
  • traps - exception traps. Any error flag which is set may trigger a DecimalException if the corresponding trap is installed. See ExceptionFlags for details;

Operators:

All floating point operators are implemented. Binary operators accept as left or right side argument any decimal, integral, character or binary floating point value.

Initialization:

Creating decimal floating point values can be done in several ways:

  • decimal32 d = 123;
    decimal64 e = 12.34;
    decimal128 f = "24.9";
    decimal32 g = 'Y';
    decimal32 h = true;
    by assigning a binary floating point, integral, char, bool, string or character range (including strings) value:
  • auto d = decimal32(7500);
    auto e = decimal64(52.16);
    auto f - decimal128("199.4E-12");
    auto g = decimal32('a');
    auto h = decimal32(false);
    by using one of the available contructors. Suported type are binary floating point, integrals, chars, bool, strings or character ranges:
  • auto d = decimal32.nan;
    auto e = decimal64.PI;
    auto f - decimal128.infinity;
    using one of predefined constants:

Error handling

Errors occuring in arithmetic operations using decimal values can be handled in two ways. By default, the thread local context will throw exceptions for errors considered severe (InvalidOperationException, DivisionByZeroException or OverflowException). Any other error is considered silent and the context will only set corresponding error flags (ExceptionFlags.inexact or ExceptionFlags.underflow)<br/> Most of the operations will throw InvalidOperationException if a signaling NaN is encountered, if not stated otherwise in the documentation. This behaviour is intended in order to avoid usage of unitialized variables (decimal values being by default always initialized to signaling NaN)

//these will throw:
auto a = decimal32() + 12;    //InvalidOperationException
auto b = decimal32.min / 0;   //DivisionByZeroException
auto c = decimal32.max * 2;   //OverflowException

//these will not throw:
auto d = decimal32(123456789);                  //inexact
auto e = decimal32.min_normal / decimal32.max;  //underflow

Default behaviour can be altered using DecimalControl by setting or clearing corresponding traps:

DecimalControl.disableExceptions(ExceptionFlags.overflow)
//from now on OverflowException will not be thrown;

DecimalControl.enableExceptions(ExceptionFlags.inexact)
//from now on InexactException will be thrown
  • Catching exceptions
  • try 
    {
       auto a = decimal32.min / 0;
    }
    catch (DivisionByZeroException)
    {
       //error occured
    }
  • Checking for errors
  • DecimalControl.disableExceptions(ExceptionFlags.divisionByZero)
    DecimalControl.resetFlags();
    auto a = decimal32.min / 0;
    if (DecimalControl.divisionByZero)
    {
       //error occured
    }

Exceptions and results

Values returned after an exception is thrown or after an error flag is set, depend on the current RoundingMode.

ExceptiontiesToEventiesToAwaytowardPositivetowardNegativetowardZero
OverflowException+∞+∞+∞+max+max
OverflowException-∞-∞-max-∞-max
UnderflowException±0.0±0.0+min_normal * epsilon-min_normal * epsilon±0.0
DivisionByZeroException±∞±∞±∞±∞±∞
InvalidOperationExceptionNaNNaNNaNNaNNaN

InexactException does not have a specific value associated.

The subnormal exception is not implemented because it is not part of the IEEE-754-2008 standard. If an operation results in a subnormal value (absolute value is smaller than min_normal), UnderflowException is always thrown or ExceptionFlag.underflow is always set. It's better to avoid subnormal values when performing calculations, the results of the operations involving such values are not exact.

Properties:

The following properties are defined for each decimal type:

ConstantNamedecimal32decimal64decimal128
initinitial valuesignaling NaNsignaling NaNsignaling NaN
nanNot a NumberNaNNaNNaN
infinitypositive infinity+∞+∞+∞
digprecision71634
epsilonsmallest increment to the value 110$(SUPERSCRIPT-6)10$(SUPERSCRIPT-15)10$(SUPERSCRIPT-33)
mant_dignumber of bits in mantissa2454114
max_10_expmaximum int value such that 10max_10_exp is representable963846144
min_10_expminimum int value such that 10min_10_exp is representable and normalized-95-383-6143
max_2_expmaximum int value such that 2max_2_exp is representable318127520409
min_2_expminimum int value such that 2min_2_exp is representable and normalized-315-1272-20406
maxlargest representable value that's not infinity9.(9) * 10969.(9) * 103849.(9) * 106144
min_normalsmallest normalized value that's not 010-9510-38310-6143

Useful constants

There are common constants defined for each type. Values int the tablebelow have 34 digits of precision corresponding to decimal128 data type; for decimal64 and decimal32, they are rounded away from 0 according to their respecive precision.

auto a = decimal32.PI;
auto b = decimal64.LN2;
auto c = decimal128.E;
ConstantFormulaValue
Ee2.7182818284590452353602874713526625
PIπ3.1415926535897932384626433832795029
PI_2π/21.5707963267948966192313216916397514
PI_4π/40.7853981633974483096156608458198757
M_1_PI1/π0.3183098861837906715377675267450287
M_2_PI2/π0.6366197723675813430755350534900574
M_2_SQRTPI2/√π1.1283791670955125738961589031215452
SQRT2√21.4142135623730950488016887242096981
SQRT1_2√½0.7071067811865475244008443621048490
LN10loge102.3025850929940456840179914546843642
LOG2Tlog2103.3219280948873623478703194294893902
LOG2Elog2e1.4426950408889634073599246810018921
LOG2log1020.3010299956639811952137388947244930
LOG10Elog10e0.4342944819032518276511289189166051
LN2loge20.6931471805599453094172321214581766

Interaction with binary floating point

Even all decimal operations allows the usage of binary floating point values, such mixing must be avoided; Internally, binary floating point values are converted to decimal counterparts before any operation:

float f = 1.1;
decimal32 d = "2.5";
decimal32 e = d + f;
//behind the scene this is roughly equivalent with e = d + decimal32(f);

It is impossible to represent binary floating point values in full decimal precision. By default, float values are converted using 9 digits of precision, double values using 17 digits of precision and real values using 21 digits of precision;

float f = 1.1; //internal representation is 1.10000002384185791015625;
decimal32 d1 = d;  //1.100000, 9 digits from float, but decimal32 has a 7 digits precision
decimal64 d2 = d;  //1.10000002000000, 9 digits from float
decimal128 d3 = d; //1.10000002000000000000000000000000, 9 digits from float;

An exact conversion is possible only if the binary floating point value is an exact power of 2 and fits in the destination type precision or if it's a power of 5.

float f = 4.0;   //internally represented as 1.0 * 2^^2
decimal32 d = f; //internally represented as 0.4 * 10^^1

float f = 25.0;  //internally represented as 1.5625 * 2^^4
decimal32 d = f; //internally represented as 0.25 * 10^^2

float f = 2147483648; //internally represented as 1.0 * 2^^31
decimal32 d = f;      //inexact, internally represented as 0.2147484 * 10^^7

Binary floating point conversion is dependent on the RoundingMode:

double d = 2.7; //internal representation is 2.7000000476837158203125;
DecimalControl.rounding = RoundingMode.tiesToAway;
decimal64 d1 = d;  //d1 will be 2.700000047683716;
DecimalControl.rounding = RoundingMode.towardZero;
decimal64 d2 = d;  //d2 will be 2.700000047683715;

Only Intel 80-bit reals are supported. Any other real type is cast to double before any conversion.

Special remarks

  • As stated above, avoid mixing binary floating point values with decimal values, binary foating point values cannot exactly represent 10-based exponents;
  • There are many representations for the same number (IEEE calls them cohorts). Comparing bit by bit two decimal values is error prone;
  • The comparison operator will return float.nan for an unordered result; There is no operator overloading for unordered comparisons;
  • Hexadecimal notation allows to define uncanonical coefficients (> 10 dig - 1). According to IEEE standard, these values are considered equal to 0;
  • All operations are available at compile time; Avoid exponential or trigonometry functions in CTFE, using them will significantly increase the compile time;
  • Under CTFE, operations are performed in full precision, values are rounded to nearest. InexactException and UnderflowException are never thrown during CTFE;

Performance tips

  • When performing decimal calculations, avoid binary floating point; conversion base-2 from/to base-10 is costly and error prone, especially if the exponents are very big or very small;
  • Avoid custom precisions; rounding is expensive since most of the time will involve a division operation;
  • Use decimal128 only if you truly need 34 digits of precision. decimal64 and decimal32 arithmetic is much faster;
  • Avoid traps and check yourself for flags; throwing and catching exceptions is expensive;
  • Contrary to usual approach, multiplication/division by 10 for decimal values is faster than multiplication/division by 2;

Meta

Authors

Răzvan Ștefănescu