Skip to content

Commit 367fa74

Browse files
authored
add sum!"decimal", wip: dynamic struct (#339)
* wip: dynamic struct * wip * wip * add decimal sum
1 parent 9507776 commit 367fa74

File tree

6 files changed

+731
-17
lines changed

6 files changed

+731
-17
lines changed

meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ sources_list = [
6969
'mir/series',
7070
'mir/small_array',
7171
'mir/small_string',
72+
'mir/string_map',
7273
'mir/type_info',
7374
]
7475

source/mir/bignum/decimal.d

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,59 @@ struct Decimal(size_t maxSize64)
752752
{
753753
return exponent == exponent.max && !coefficient.length;
754754
}
755+
756+
///
757+
ref opOpAssign(string op, size_t rhsMaxSize64)(ref const Decimal!rhsMaxSize64 rhs) @safe pure return
758+
if (op == "+" || op == "-")
759+
{
760+
BigInt!rhsMaxSize64 rhsCopy;
761+
BigIntView!(const size_t) rhsView;
762+
auto expDiff = exponent - rhs.exponent;
763+
if (expDiff >= 0)
764+
{
765+
exponent = rhs.exponent;
766+
coefficient.mulPow5(expDiff);
767+
coefficient.opOpAssign!"<<"(expDiff);
768+
rhsView = rhs.coefficient.view;
769+
}
770+
else
771+
{
772+
rhsCopy.copyFrom(rhs.coefficient.view);
773+
rhsCopy.mulPow5(-expDiff);
774+
rhsCopy.opOpAssign!"<<"(-expDiff);
775+
rhsView = rhsCopy.view;
776+
}
777+
coefficient.opOpAssign!op(rhsView);
778+
return this;
779+
}
780+
781+
static if (maxSize64 == 3)
782+
///
783+
version(mir_bignum_test) @safe pure @nogc unittest
784+
{
785+
import std.stdio;
786+
auto a = Decimal!1("777.7");
787+
auto b = Decimal!1("777");
788+
import mir.format;
789+
assert(stringBuf() << cast(double)a - cast(double)b << getData == "0.7000000000000455");
790+
a -= b;
791+
assert(stringBuf() << a << getData == "0.7");
792+
793+
a = Decimal!1("-777.7");
794+
b = Decimal!1("777");
795+
a += b;
796+
assert(stringBuf() << a << getData == "-0.7");
797+
798+
a = Decimal!1("777.7");
799+
b = Decimal!1("-777");
800+
a += b;
801+
assert(stringBuf() << a << getData == "0.7");
802+
803+
a = Decimal!1("777");
804+
b = Decimal!1("777.7");
805+
a -= b;
806+
assert(stringBuf() << a << getData == "-0.7");
807+
}
755808
}
756809

757810
///

source/mir/bignum/integer.d

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -324,22 +324,30 @@ struct BigInt(size_t maxSize64)
324324
Returns:
325325
overflow
326326
+/
327-
bool opOpAssign(string op)(ref const BigInt rhs)
327+
bool opOpAssign(string op, size_t rhsMaxSize64)(ref const BigInt!rhsMaxSize64 rhs)
328328
@safe pure nothrow @nogc
329329
if (op == "+" || op == "-")
330330
{
331-
int diff = length - rhs.length;
331+
return opOpAssign!op(rhs.view);
332+
}
333+
334+
/// ditto
335+
bool opOpAssign(string op)(BigIntView!(const size_t) rhs)
336+
@safe pure nothrow @nogc
337+
if (op == "+" || op == "-")
338+
{
339+
sizediff_t diff = length - rhs.coefficients.length;
332340
if (diff < 0)
333341
{
334342
auto oldLength = length;
335-
length = rhs.length;
343+
length = cast(int)rhs.coefficients.length;
336344
view.unsigned.leastSignificantFirst[oldLength .. $] = 0;
337345
}
338346
else
339-
if (rhs.length == 0)
347+
if (rhs.coefficients.length == 0)
340348
return false;
341349
auto thisView = view;
342-
auto overflow = thisView.opOpAssign!op(rhs.view);
350+
auto overflow = thisView.opOpAssign!op(rhs);
343351
this.sign = thisView.sign;
344352
if (overflow)
345353
{
@@ -519,7 +527,7 @@ struct BigInt(size_t maxSize64)
519527
+/
520528
bool copyFrom(W, WordEndian endian)(BigIntView!(const W, endian) view)
521529
{
522-
static if (W.sizeof > size_t.sizeof)
530+
static if (W.sizeof > size_t.sizeof && endian == TargetEndian)
523531
{
524532
return this.copyFrom(cast(BigIntView!(const size_t))view);
525533
}

source/mir/math/sum.d

Lines changed: 107 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,23 @@ unittest
2020
assert(r == ar.sum!"kbn");
2121
assert(r == ar.sum!"kb2");
2222
assert(r == ar.sum!"precise");
23+
assert(r == ar.sum!"decimal");
24+
}
25+
26+
/// Decimal precise summation
27+
version(mir_test)
28+
unittest
29+
{
30+
auto ar = [777.7, -777];
31+
assert(ar.sum!"decimal" == 0.7);
32+
33+
// The exact binary reuslt is 0.7000000000000455
34+
assert(ar[0] + ar[1] == 0.7000000000000455);
35+
assert(ar.sum!"fast" == 0.7000000000000455);
36+
assert(ar.sum!"kahan" == 0.7000000000000455);
37+
assert(ar.sum!"kbn" == 0.7000000000000455);
38+
assert(ar.sum!"kb2" == 0.7000000000000455);
39+
assert(ar.sum!"precise" == 0.7000000000000455);
2340
}
2441

2542
///
@@ -111,6 +128,7 @@ unittest
111128
assert(r == ar.sum!"kb2");
112129
}
113130
assert(r == ar.sum!"precise");
131+
assert(r == ar.sum!"decimal");
114132
}
115133

116134
///
@@ -317,7 +335,7 @@ enum Summation
317335
Precise summation algorithm.
318336
The value of the sum is rounded to the nearest representable
319337
floating-point number using the $(LUCKY round-half-to-even rule).
320-
The result can differ from the exact value on `X86`, `nextDown(proir) <= result && result <= nextUp(proir)`.
338+
The result can differ from the exact value on 32bit `x86`, `nextDown(proir) <= result && result <= nextUp(proir)`.
321339
The current implementation re-establish special value semantics across iterations (i.e. handling ±inf).
322340
323341
References: $(LINK2 http://www.cs.cmu.edu/afs/cs/project/quake/public/papers/robust-arithmetic.ps,
@@ -335,6 +353,17 @@ enum Summation
335353
+/
336354
precise,
337355

356+
/++
357+
Precise decimal summation algorithm.
358+
359+
The elements of the sum are converted to a shortest decimal representation that being converted back would result the same floating-point number.
360+
The resulting decimal elements are summed without rounding.
361+
The decimal sum is converted back to a binary floating point representation using round-half-to-even rule.
362+
363+
See_also: The $(HTTPS https://github.com/ulfjack/ryu, Ryu algorithm)
364+
+/
365+
decimal,
366+
338367
/++
339368
$(WEB en.wikipedia.org/wiki/Kahan_summation, Kahan summation) algorithm.
340369
+/
@@ -611,6 +640,13 @@ struct Summator(T, Summation summation)
611640
F s = summationInitValue!F;
612641
}
613642
else
643+
static if (summation == Summation.decimal)
644+
{
645+
import mir.bignum.decimal;
646+
Decimal!256 s;
647+
T ss = 0;
648+
}
649+
else
614650
static assert(0, "Unsupported summation type for std.numeric.Summator.");
615651

616652

@@ -675,6 +711,17 @@ public:
675711
s = n;
676712
}
677713
else
714+
static if (summation == Summation.decimal)
715+
{
716+
ss = 0;
717+
if (!(-n.infinity < n && n < n.infinity))
718+
{
719+
ss = n;
720+
n = 0;
721+
}
722+
s = n;
723+
}
724+
else
678725
static assert(0);
679726
}
680727

@@ -895,6 +942,20 @@ public:
895942
s += n;
896943
}
897944
else
945+
static if (summation == summation.decimal)
946+
{
947+
import mir.bignum.internal.ryu.generic_128: genericBinaryToDecimal;
948+
if (-n.infinity < n && n < n.infinity)
949+
{
950+
auto decimal = genericBinaryToDecimal(n);
951+
s += decimal;
952+
}
953+
else
954+
{
955+
ss += n;
956+
}
957+
}
958+
else
898959
static assert(0);
899960
}
900961

@@ -1134,7 +1195,12 @@ public:
11341195
return s;
11351196
}
11361197
else
1137-
static assert(0);
1198+
static if (summation == Summation.decimal)
1199+
{
1200+
return cast(T) s + ss;
1201+
}
1202+
else
1203+
static assert(0);
11381204
}
11391205

11401206
version(none)
@@ -1311,6 +1377,11 @@ public:
13111377
s = rhs;
13121378
}
13131379
else
1380+
static if (summation == summation.decimal)
1381+
{
1382+
__ctor(rhs);
1383+
}
1384+
else
13141385
static assert(0);
13151386
}
13161387

@@ -1671,13 +1742,21 @@ template sum(F, Summation summation = Summation.appropriate)
16711742
///
16721743
F sum(Range r)
16731744
{
1674-
static if (isComplex!F && summation == Summation.precise)
1745+
static if (isComplex!F && (summation == Summation.precise || summation == Summation.decimal))
16751746
{
16761747
return sum(r, summationInitValue!F);
16771748
}
16781749
else
16791750
{
1680-
Summator!(F, ResolveSummationType!(summation, Range, sumType!Range)) sum;
1751+
static if (summation == Summation.decimal)
1752+
{
1753+
Summator!(F, summation) sum = void;
1754+
sum = 0;
1755+
}
1756+
else
1757+
{
1758+
Summator!(F, ResolveSummationType!(summation, Range, sumType!Range)) sum;
1759+
}
16811760
sum.put(r.move);
16821761
return sum.sum;
16831762
}
@@ -1686,11 +1765,22 @@ template sum(F, Summation summation = Summation.appropriate)
16861765
///
16871766
F sum(Range r, F seed)
16881767
{
1689-
static if (isComplex!F && summation == Summation.precise)
1768+
static if (isComplex!F && (summation == Summation.precise || summation == Summation.decimal))
16901769
{
16911770
alias T = typeof(F.init.re);
1692-
auto sumRe = Summator!(T, Summation.precise)(seed.re);
1693-
auto sumIm = Summator!(T, Summation.precise)(seed.im);
1771+
static if (summation == Summation.decimal)
1772+
{
1773+
Summator!(T, summation) sumRe = void;
1774+
sumRe = seed.re;
1775+
1776+
Summator!(T, summation) sumIm = void;
1777+
sumIm = seed.im;
1778+
}
1779+
else
1780+
{
1781+
auto sumRe = Summator!(T, Summation.precise)(seed.re);
1782+
auto sumIm = Summator!(T, Summation.precise)(seed.im);
1783+
}
16941784
import mir.ndslice.slice: isSlice;
16951785
static if (isSlice!Range)
16961786
{
@@ -1713,7 +1803,15 @@ template sum(F, Summation summation = Summation.appropriate)
17131803
}
17141804
else
17151805
{
1716-
auto sum = Summator!(F, ResolveSummationType!(summation, Range, F))(seed);
1806+
static if (summation == Summation.decimal)
1807+
{
1808+
Summator!(F, summation) sum = void;
1809+
sum = seed;
1810+
}
1811+
else
1812+
{
1813+
auto sum = Summator!(F, ResolveSummationType!(summation, Range, F))(seed);
1814+
}
17171815
sum.put(r.move);
17181816
return sum.sum;
17191817
}
@@ -1723,7 +1821,7 @@ template sum(F, Summation summation = Summation.appropriate)
17231821
///
17241822
F sum(scope const F[] r...)
17251823
{
1726-
static if (isComplex!F && summation == Summation.precise)
1824+
static if (isComplex!F && (summation == Summation.precise || summation == Summation.decimal))
17271825
{
17281826
return sum(r, summationInitValue!F);
17291827
}

source/mir/ndslice/sorting.d

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -660,8 +660,8 @@ version(mir_test)
660660
assert(j == 3);
661661
auto upperBound = a[j .. $];
662662

663-
assert(a.transitionIndex(a[$-1]) == a.length - 1);
664-
assert(a.transitionIndex!"a <= b"(a[$-1]) == a.length);
663+
assert(a.transitionIndex(a[$ - 1]) == a.length - 1);
664+
assert(a.transitionIndex!"a <= b"(a[$ - 1]) == a.length);
665665
}
666666

667667
/++

0 commit comments

Comments
 (0)