@@ -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 }
0 commit comments