Another take on decimal data types

kdevel kdevel at vogtner.de
Sat Jan 13 20:40:20 UTC 2018


On Saturday, 13 January 2018 at 19:28:40 UTC, rumbu wrote:
> On Saturday, 13 January 2018 at 18:37:10 UTC, kdevel wrote:
>
>> I get large numerical dicrepancies and an exception:
>
> That's because you are mixing floating point and decimal.
>
> Just to take one example: double 1.1 cannot be represented 
> exactly as floating point and it's in fact 
> 1.10000002384185791015625.

Sure. double has 53 mantissa bits but float only 24. But that is 
not my point.
I am *not* talking about the 1e-18 but about these lines:

      1.10     0.891207360061435339970703     
0.878166666666666700439167       -1e-02
      1.20     0.932039085967226349689098     
0.932735999999999982229600        1e-04
      1.30     0.963558185417192964729825     
0.964774416666666678037840
1e-03

and

      5.70    -0.550685542597637763537807   
-25.165500000000002545915000          -

At 5.7 the value is obviously out of range.

> sin is calculated using a Taylor series: sin(x) = x - x^3/3! + 
> x^5/5! - x^7/7! ... and so on. Raising to power all that junk 
> after 1.1 will lead finally to error. If you really want to 
> find out sin(1.1) using decimal, try sin(decimal128("1.1")) or 
> sin(decimal128(1)/10);

Chapter 9.2 of IEEE-754-2008 says the domain of sin(x) is (-inf, 
inf). So if the argument x is outside the radius of convergence 
of the Taylor series x must be reduced modulo 2pi such that it 
fits.

> For exact values like sin(1.0), I let you decide which one is 
> more exact:
>
> Wolfram Alpha: 0.8414709848078965066525023216302989
> real:          0.8414709848078965066645910000000000
> double:        0.8414709848078965048700000000000000
> float:         0.8414709568023681640600000000000000
> decimal128:    0.8414709848078965066329679978908351
> decimal64:     0.8414709848078965000000000000000000
> decimal32:     0.8414710000000000000000000000000000
>
> Anyway, I wouldn't call a difference at the 18th digit a "large 
> discrepancy" when we are talking about irrational numbers.

See above.

> Regarding the exception, I cannot reproduce it, but I'll look 
> into it.

Nice.

> Thank you for your exhaustive testing :)

There's more to come (sorry for the greek symbols, could not 
resist to check this utf-8 feature):

unity.d
```
import std.stdio;
import std.typecons;
import std.range;
import std.math;
import decimal;

immutable size_t N = 100;

void unity (T) ()
{
    writeln ("\n=== ", T.stringof, " ===\n");
    immutable one = T (1);
    immutable two = T (2);
    immutable π = atan (one) * 4;
    writefln!"π = <%30.24f>" (π);

    foreach (i; iota(N + 1)) {
       auto φ = two * π * i / N;
       auto sinφ = sin (φ);
       auto cosφ = cos (φ);
       auto unity = sinφ * sinφ + cosφ * cosφ;
       auto δ = one - unity;
       writeln ("φ = <", φ, ">, δ = <", δ, ">");
    }
}

void main ()
{
//   unity!float;
//   unity!double;
//   unity!real;
//   unity!decimal32;
    unity!decimal64;
    unity!decimal128;
}
```

Selected lines from the output produced here (Linux, DMD64 D 
Compiler v2.077.1):

=== Decimal!64 ===

π = <    3.141592653589793000000000>
φ = <0>, δ = <0>
φ = <0.0628319>, δ = <0>
φ = <0.125664>, δ = <1e-16>          possibly okay
:
φ = <0.942478>, δ = <2.41721e-06>    too large
:
φ = <2.45044>, δ = <-6.57811e-07>    ditto
φ = <2.51327>, δ = <-3.83012e-10>    ditto
φ = <2.57611>, δ = <0.479476>        ditto
:
:
:

=== Decimal!128 ===

π = <    3.141592653589793238612055>
φ = <0>, δ = <0>
φ = <1e-02>, δ = <-1.73780e-22>
:
Something went wrong with printing φ. And also this program 
crashes:

core.exception.RangeError at decimal/package.d(6652): Range violation
----------------
??:? _d_arrayboundsp [0x80bc65f]
??:? void decimal.sinkFloat!(char, 
decimal.integrals.unsigned!(128).unsigned).sinkFloat(ref 
const(std.format.FormatSpec!(char).FormatSpec), void 
delegate(const(char)[]), 
const(decimal.integrals.unsigned!(128).unsigned), const(int), 
const(bool), const(decimal.RoundingMode), const(bool)) [0x80b2976]
??:? void decimal.sinkGeneral!(char, 
decimal.integrals.unsigned!(128).unsigned).sinkGeneral(ref 
const(std.format.FormatSpec!(char).FormatSpec), void 
delegate(const(char)[]), 
const(decimal.integrals.unsigned!(128).unsigned), const(int), 
const(bool), const(decimal.RoundingMode)) [0x80b33a4]
??:? void decimal.sinkDecimal!(char, 
decimal.Decimal!(128).Decimal).sinkDecimal(ref 
const(std.format.FormatSpec!(char).FormatSpec), void 
delegate(const(char)[]), ref 
const(decimal.Decimal!(128).Decimal), 
const(decimal.RoundingMode)) [0x80b241a]
??:? const void 
decimal.Decimal!(128).Decimal.toString!(char).toString(scope void 
delegate(const(char)[]), std.format.FormatSpec!(char).FormatSpec) 
[0x80b22bb]
??:? void 
std.format.formatObject!(std.stdio.File.LockingTextWriter, 
decimal.Decimal!(128).Decimal, char).formatObject(ref 
std.stdio.File.LockingTextWriter, ref 
decimal.Decimal!(128).Decimal, ref 
const(std.format.FormatSpec!(char).FormatSpec)) [0x80b73cf]
??:? void 
std.format.formatValue!(std.stdio.File.LockingTextWriter, 
decimal.Decimal!(128).Decimal, char).formatValue(ref 
std.stdio.File.LockingTextWriter, ref 
decimal.Decimal!(128).Decimal, ref 
const(std.format.FormatSpec!(char).FormatSpec)) [0x80b7393]
??:? uint 
std.format.formattedWrite!(std.stdio.File.LockingTextWriter, 
char, decimal.Decimal!(128).Decimal).formattedWrite(ref 
std.stdio.File.LockingTextWriter, const(char[]), 
decimal.Decimal!(128).Decimal) [0x80b6efd]
??:? void std.stdio.File.write!(immutable(char)[], 
decimal.Decimal!(128).Decimal, immutable(char)[], 
decimal.Decimal!(128).Decimal, immutable(char)[], 
char).write(immutable(char)[], decimal.Decimal!(128).Decimal, 
immutable(char)[], decimal.Decimal!(128).Decimal, 
immutable(char)[], char) [0x8093176]
??:? void std.stdio.writeln!(immutable(char)[], 
decimal.Decimal!(128).Decimal, immutable(char)[], 
decimal.Decimal!(128).Decimal, 
immutable(char)[]).writeln(immutable(char)[], 
decimal.Decimal!(128).Decimal, immutable(char)[], 
decimal.Decimal!(128).Decimal, immutable(char)[]) [0x80930c8]
??:? void unity.unity!(decimal.Decimal!(128).Decimal).unity() 
[0x8092f62]
??:? _Dmain [0x80905ec]




More information about the Digitalmars-d-announce mailing list