1 // Written in the D programming language.
2 
3 /**
4 
5 IEEE 754-2008 implementation of _decimal floating point data types.
6 _Decimal values are represented in memory using an $(B integral coefficient) and a $(B 10-based exponent).
7 Implementation is based on 
8 $(LINK2 https://en.wikipedia.org/wiki/Binary_Integer_Decimal, binary integer _decimal encoding), supported by Intel.
9 
10 _Decimal data types use the same semantics as the built-in floating point data type (NaNs, infinities, etc.), 
11 the main difference being that they use internally a 10 exponent instead of a 2 exponent. 
12 
13 The current implementation supports three _decimal data types, as specified by IEEE 754-2008 standard. 
14 The supported types are: $(MYREF decimal32), $(MYREF decimal64) and $(MYREF decimal128), but they can be easily extended
15 to other bit widths if a underlying unsigned integral type is provided.
16 
17 _Decimal data types are best used in financial applications because arithmetic operation results are exact. 
18 
19 $(SCRIPT inhibitQuickIndex = 1;)
20 $(DIVC quickindex,
21  $(BOOKTABLE ,
22   $(TR $(TH Category) $(TH Members) )
23     $(TR $(TDNW Classics) $(TD
24         $(MYREF copysign) $(MYREF fabs) $(MYREF fdim)
25         $(MYREF fmod) $(MYREF fma) $(MYREF getNaNPayload)  
26         $(MYREF modf) $(MYREF NaN) 
27         $(MYREF nextAfter)
28         $(MYREF nextDown) $(MYREF nextToward)  $(MYREF nextUp) $(MYREF remainder) $(MYREF sgn) 
29     ))
30     $(TR $(TDNW Comparison) $(TD   
31         $(MYREF approxEqual) 
32         $(MYREF cmp) 
33         $(MYREF fmax) $(MYREF fmaxAbs) $(MYREF fmin) $(MYREF fminAbs)
34         $(MYREF isEqual) $(MYREF isGreater) $(MYREF isGreaterOrEqual) $(MYREF isGreaterOrUnordered)
35         $(MYREF isIdentical)
36         $(MYREF isLess) $(MYREF isLessOrEqual) $(MYREF isLessOrUnordered)
37         $(MYREF isNotEqual)
38         $(MYREF isUnordered)
39         $(MYREF sameQuantum)
40         $(MYREF totalOrder) $(MYREF totalOrderAbs)
41     ))
42     $(TR $(TDNW Conversion) $(TD
43         $(MYREF fromDPD) $(MYREF fromMsCurrency) $(MYREF fromMsDecimal) $(MYREF to) $(MYREF toDPD) $(MYREF toExact) 
44         $(MYREF toMsCurrency) $(MYREF toMsDecimal) 
45     ))
46     $(TR $(TDNW Data types) $(TD
47         $(MYREF Decimal) $(MYREF decimal32) $(MYREF decimal64)  $(MYREF decimal128) 
48         $(MYREF DecimalClass) $(MYREF DecimalControl) $(MYREF ExceptionFlags)  $(MYREF Precision)
49         $(MYREF RoundingMode) 
50     ))
51     $(TR $(TDNW Exceptions) $(TD
52         $(MYREF DecimalException) $(MYREF DivisionByZeroException) 
53         $(MYREF InexactException) $(MYREF InvalidOperationException)
54         $(MYREF OverflowException) $(MYREF UnderflowException)  
55     ))
56     $(TR $(TDNW Exponentiations & logarithms) $(TD
57         $(MYREF cbrt) $(MYREF compound)
58         $(MYREF exp) $(MYREF exp10) $(MYREF exp10m1) $(MYREF exp2) $(MYREF exp2m1) $(MYREF expm1) $(MYREF frexp)
59         $(MYREF ilogb) $(MYREF ldexp) $(MYREF log) $(MYREF log10) $(MYREF log10p1) $(MYREF log2) $(MYREF log2p1) 
60         $(MYREF logp1) $(MYREF nextPow10) $(MYREF pow) $(MYREF quantexp) $(MYREF root) 
61         $(MYREF rsqrt) $(MYREF scalbn) $(MYREF sqrt)  
62         $(MYREF truncPow10)
63     ))
64     $(TR $(TDNW Introspection) $(TD
65         $(MYREF decimalClass) 
66         $(MYREF isCanonical) $(MYREF isFinite) $(MYREF isInfinity) $(MYREF isNaN) $(MYREF isNormal) 
67         $(MYREF isPowerOf10) $(MYREF isSignaling) $(MYREF isSubnormal) $(MYREF isZero) 
68         $(MYREF signbit) 
69     ))
70     $(TR $(TDNW Reduction) $(TD
71         $(MYREF dot) $(MYREF poly) $(MYREF scaledProd) $(MYREF scaledProdSum) $(MYREF scaledProdDiff)
72         $(MYREF sum) $(MYREF sumAbs) $(MYREF sumSquare) 
73     ))
74     $(TR $(TDNW Rounding) $(TD
75         $(MYREF ceil) $(MYREF floor) $(MYREF lrint) $(MYREF lround) $(MYREF nearbyint) $(MYREF quantize) $(MYREF rint) 
76         $(MYREF rndtonl) $(MYREF round) $(MYREF trunc)  
77     ))
78     $(TR $(TDNW Trigonometry) $(TD
79         $(MYREF acos) $(MYREF acosh) $(MYREF asin) $(MYREF asinh) $(MYREF atan) $(MYREF atan2) $(MYREF atan2pi) 
80         $(MYREF atanh) $(MYREF atanpi) $(MYREF cos) $(MYREF cosh) $(MYREF cospi)
81         $(MYREF hypot) $(MYREF sin) $(MYREF sinh) $(MYREF sinpi) $(MYREF tan) $(MYREF tanh)
82     ))
83     
84 
85  )   
86 )
87 
88 
89 Context:
90 
91 All arithmetic operations are performed using a $(U thread local context). The context is setting various 
92 environment options:
93 $(UL
94  $(LI $(B precision) - number of digits used. Each _decimal data type has a default precision and all the calculations
95                   are performed using this precision. Setting the precision to a custom value will affect
96                   any subsequent operation and all the calculations will be performed using the specified 
97                   number of digits. See $(MYREF Precision) for details;)
98  $(LI $(B rounding)  - rounding method used to adjust operation results. If a result will have more digits than the  
99                   current context precision, it will be rounded using the specified method. For available rounding 
100                   modes, see $(MYREF RoundingMode);)
101  $(LI $(B flags)     - error flags. Every _decimal operation may signal an error. The context will gather these errors  
102                   for later introspection. See $(MYREF ExceptionFlags) for details;)
103  $(LI $(B traps)     - exception traps. Any error flag which is set may trigger a $(MYREF DecimalException) if
104                   the corresponding trap is installed. See $(MYREF ExceptionFlags) for details;)
105 )
106 
107 Operators:
108 
109 All floating point operators are implemented. Binary operators accept as left or right side argument any _decimal, 
110 integral, character or binary floating point value.
111 
112 Initialization:
113 
114 Creating _decimal floating point values can be done in several ways:
115 $(UL
116  $(LI by assigning a binary floating point, integral, char, bool, string or character range (including strings) value:
117 ---
118 decimal32 d = 123;
119 decimal64 e = 12.34;
120 decimal128 f = "24.9";
121 decimal32 g = 'Y';
122 decimal32 h = true;
123 ---
124 )
125  $(LI by using one of the available contructors. 
126    Suported type are binary floating point, integrals, chars, bool, strings or character ranges:
127 ---
128 auto d = decimal32(7500);
129 auto e = decimal64(52.16);
130 auto f - decimal128("199.4E-12");
131 auto g = decimal32('a');
132 auto h = decimal32(false);
133 ---
134 )
135  $(LI using one of predefined constants:
136 ---
137 auto d = decimal32.nan;
138 auto e = decimal64.PI;
139 auto f - decimal128.infinity;
140 ---
141 )
142 )
143 
144 Error_handling:
145 
146 Errors occuring in arithmetic operations using _decimal values can be handled in two ways. By default, the thread local 
147 context will throw exceptions for errors considered severe ($(MYREF InvalidOperationException), 
148 $(MYREF DivisionByZeroException) or $(MYREF OverflowException)). 
149 Any other error is considered silent and the context will only 
150 set corresponding error flags ($(MYREF ExceptionFlags.inexact) or $(MYREF ExceptionFlags.underflow))<br/>
151 Most of the operations will throw $(MYREF InvalidOperationException) if a $(B signaling NaN) is encountered, 
152 if not stated otherwise in the documentation. This behaviour is intended in order to avoid usage of unitialized variables 
153 (_decimal values being by default always initialized to $(B signaling NaN))
154 ---
155 //these will throw:
156 auto a = decimal32() + 12;    //InvalidOperationException
157 auto b = decimal32.min / 0;   //DivisionByZeroException
158 auto c = decimal32.max * 2;   //OverflowException
159 
160 //these will not throw:
161 auto d = decimal32(123456789);                  //inexact
162 auto e = decimal32.min_normal / decimal32.max;  //underflow
163 ---
164 
165 Default behaviour can be altered using $(MYREF DecimalControl) by setting or clearing corresponding traps:
166 ---
167 DecimalControl.disableExceptions(ExceptionFlags.overflow)
168 //from now on OverflowException will not be thrown;
169 
170 DecimalControl.enableExceptions(ExceptionFlags.inexact)
171 //from now on InexactException will be thrown
172 ---
173 
174 $(UL
175   $(LI Catching exceptions)
176   ---
177   try 
178   {
179      auto a = decimal32.min / 0;
180   }
181   catch (DivisionByZeroException)
182   {
183      //error occured
184   }
185   ---
186   $(LI Checking for errors)
187   ---
188   DecimalControl.disableExceptions(ExceptionFlags.divisionByZero)
189   DecimalControl.resetFlags();
190   auto a = decimal32.min / 0;
191   if (DecimalControl.divisionByZero)
192   {
193      //error occured
194   }
195   ---
196 )
197 
198 Exceptions_and_results:
199 
200 Values returned after an exception is thrown or after an error flag is set, depend on the current $(MYREF RoundingMode).
201 
202 $(BOOKTABLE,
203   $(TR $(TH Exception) $(TH tiesToEven) $(TH tiesToAway) $(TH towardPositive) $(TH towardNegative) $(TH towardZero)) 
204   $(TR $(TD $(MYREF OverflowException))  $(TD +∞) $(TD +∞) $(TD +∞) $(TD $(B +max)) $(TD $(B +max)) )
205   $(TR $(TD $(MYREF OverflowException))  $(TD -∞) $(TD -∞) $(TD $(B -max)) $(TD -∞) $(TD $(B -max)) )
206   $(TR $(TD $(MYREF UnderflowException)) $(TD ±0.0) $(TD ±0.0) $(TD $(B +min_normal * epsilon)) $(TD $(B -min_normal * epsilon)) $(TD ±0.0) )
207   $(TR $(TD $(MYREF DivisionByZeroException)) $(TD ±∞) $(TD ±∞) $(TD ±∞) $(TD ±∞) $(TD ±∞) )
208   $(TR $(TD $(MYREF InvalidOperationException)) $(TD $(B NaN)) $(TD $(B NaN)) $(TD $(B NaN)) $(TD $(B NaN)) $(TD $(B NaN)) )
209  )  
210 
211 $(MYREF InexactException) does not have a specific value associated.
212 
213 The subnormal exception is not implemented because it is not part of the IEEE-754-2008 standard.
214 If an operation results in a subnormal value (absolute value is smaller than $(B min_normal)), 
215 $(MYREF UnderflowException) is always thrown or $(MYREF ExceptionFlag.underflow) is always set. It's better to avoid
216 subnormal values when performing calculations, the results of the operations involving such values are not exact.
217 
218 
219 Properties:
220 
221 The following properties are defined for each _decimal type:
222 
223 $(BOOKTABLE,
224  $(TR $(TH Constant) $(TH Name) $(TH decimal32) $(TH decimal64) $(TH decimal128))
225  $(TR $(TD $(D init)) $(TD initial value) $(TD $(B signaling NaN)) $(TD $(B signaling NaN)) $(TD $(B signaling NaN)))
226  $(TR $(TD $(D nan)) $(TD Not a Number) $(TD $(B NaN)) $(TD $(B NaN)) $(TD $(B NaN)))
227  $(TR $(TD $(D infinity)) $(TD positive infinity) $(TD +∞) $(TD +∞) $(TD +∞))
228  $(TR $(TD $(D dig)) $(TD precision) $(TD 7) $(TD 16) $(TD 34))
229  $(TR $(TD $(D epsilon)) $(TD smallest increment to the value 1) $(TD 10$(SUPERSCRIPT-6)) $(TD 10$(SUPERSCRIPT-15)) $(TD 10$(SUPERSCRIPT-33)))
230  $(TR $(TD $(D mant_dig)) $(TD number of bits in mantissa) $(TD 24) $(TD 54) $(TD 114))
231  $(TR $(TD $(D max_10_exp)) $(TD maximum int value such that 10$(SUPERSCRIPT max_10_exp) is representable) $(TD 96) $(TD 384) $(TD 6144))
232  $(TR $(TD $(D min_10_exp)) $(TD minimum int value such that 10$(SUPERSCRIPT min_10_exp) is representable and normalized) $(TD -95) $(TD -383) $(TD -6143))
233  $(TR $(TD $(D max_2_exp)) $(TD maximum int value such that 2$(SUPERSCRIPT max_2_exp) is representable) $(TD 318) $(TD 1275) $(TD 20409))
234  $(TR $(TD $(D min_2_exp)) $(TD minimum int value such that 2$(SUPERSCRIPT min_2_exp) is representable and normalized) $(TD -315) $(TD -1272) $(TD -20406))
235  $(TR $(TD $(D max)) $(TD largest representable value that's not infinity) $(TD 9.(9) * 10$(SUPERSCRIPT 96)) $(TD 9.(9) * 10$(SUPERSCRIPT 384)) $(TD 9.(9) * 10$(SUPERSCRIPT 6144)))
236  $(TR $(TD $(D min_normal)) $(TD smallest normalized value that's not 0) $(TD 10$(SUPERSCRIPT -95)) $(TD 10$(SUPERSCRIPT -383)) $(TD 10$(SUPERSCRIPT -6143)))
237 )
238 
239 
240 Useful_constants:
241 
242 There are common constants defined for each type. Values int the tablebelow have 34 digits of precision corresponding
243 to decimal128 data type; for decimal64 and decimal32, they are rounded away from 0 according to their respecive precision.
244 ---
245 auto a = decimal32.PI;
246 auto b = decimal64.LN2;
247 auto c = decimal128.E;
248 ---
249 
250 $(BOOKTABLE,
251  $(TR $(TH Constant) $(TH Formula) $(TH Value))
252  $(TR $(TD $(D E)) $(TD e) $(TD 2.7182818284590452353602874713526625))
253  $(TR $(TD $(D PI)) $(TD π) $(TD 3.1415926535897932384626433832795029))
254  $(TR $(TD $(D PI_2)) $(TD π/2) $(TD 1.5707963267948966192313216916397514))
255  $(TR $(TD $(D PI_4)) $(TD π/4) $(TD 0.7853981633974483096156608458198757))
256  $(TR $(TD $(D M_1_PI)) $(TD 1/π) $(TD 0.3183098861837906715377675267450287))
257  $(TR $(TD $(D M_2_PI)) $(TD 2/π) $(TD 0.6366197723675813430755350534900574))
258  $(TR $(TD $(D M_2_SQRTPI)) $(TD 2/√π) $(TD 1.1283791670955125738961589031215452))
259  $(TR $(TD $(D SQRT2)) $(TD √2) $(TD 1.4142135623730950488016887242096981))
260  $(TR $(TD $(D SQRT1_2)) $(TD √½) $(TD 0.7071067811865475244008443621048490))
261  $(TR $(TD $(D LN10)) $(TD log$(SUBSCRIPT e)10) $(TD 2.3025850929940456840179914546843642))
262  $(TR $(TD $(D LOG2T)) $(TD log$(SUBSCRIPT 2)10) $(TD 3.3219280948873623478703194294893902))
263  $(TR $(TD $(D LOG2E)) $(TD log$(SUBSCRIPT 2)e) $(TD 1.4426950408889634073599246810018921))
264  $(TR $(TD $(D LOG2)) $(TD log$(SUBSCRIPT 10)2) $(TD 0.3010299956639811952137388947244930))
265  $(TR $(TD $(D LOG10E)) $(TD log$(SUBSCRIPT 10)e) $(TD 0.4342944819032518276511289189166051))
266  $(TR $(TD $(D LN2)) $(TD log$(SUBSCRIPT e)2) $(TD 0.6931471805599453094172321214581766))
267 )
268 
269 Interaction_with_binary_floating_point:
270 
271 Even all _decimal operations allows the usage of binary floating point values, such mixing must be avoided;
272 Internally, binary floating point values are converted to _decimal counterparts before any operation:
273 ---
274 float f = 1.1;
275 decimal32 d = "2.5";
276 decimal32 e = d + f;
277 //behind the scene this is roughly equivalent with e = d + decimal32(f);
278 ---
279 
280 It is impossible to represent binary floating point values in full _decimal precision.
281 By default, $(B float) values are converted using 9 digits of precision, $(B double) values using 17 digits of precision and $(B real) values using 21 digits of precision;
282 ---
283 float f = 1.1; //internal representation is 1.10000002384185791015625;
284 decimal32 d1 = d;  //1.100000, 9 digits from float, but decimal32 has a 7 digits precision
285 decimal64 d2 = d;  //1.10000002000000, 9 digits from float
286 decimal128 d3 = d; //1.10000002000000000000000000000000, 9 digits from float;
287 ---
288 
289 An exact conversion is possible only if the binary floating point value is an exact power of 2 
290 and fits in the destination type precision or if it's a power of 5.
291 ---
292 float f = 4.0;   //internally represented as 1.0 * 2^^2
293 decimal32 d = f; //internally represented as 0.4 * 10^^1
294 
295 float f = 25.0;  //internally represented as 1.5625 * 2^^4
296 decimal32 d = f; //internally represented as 0.25 * 10^^2
297 
298 float f = 2147483648; //internally represented as 1.0 * 2^^31
299 decimal32 d = f;      //inexact, internally represented as 0.2147484 * 10^^7
300 ---
301 
302 Binary floating point conversion is dependent on the $(MYREF RoundingMode):
303 ---
304 double d = 2.7; //internal representation is 2.7000000476837158203125;
305 DecimalControl.rounding = RoundingMode.tiesToAway;
306 decimal64 d1 = d;  //d1 will be 2.700000047683716;
307 DecimalControl.rounding = RoundingMode.towardZero;
308 decimal64 d2 = d;  //d2 will be 2.700000047683715;
309 ---
310 
311 Only Intel 80-bit $(B reals) are supported. Any other $(B real) type is cast to $(B double) before any conversion.
312 
313 Special_remarks:
314 
315 $(UL
316  $(LI As stated above, avoid mixing binary floating point values with _decimal values, binary foating point values cannot exactly represent 10-based exponents;)
317  $(LI There are many representations for the same number (IEEE calls them cohorts). Comparing bit by bit two _decimal values is error prone;)
318  $(LI The comparison operator will return float.nan for an unordered result; There is no operator overloading for unordered comparisons;)
319  $(LI Hexadecimal notation allows to define uncanonical coefficients (> 10 $(SUPERSCRIPT $(B dig)) - 1). According to IEEE standard, these values are considered equal to 0;)
320  $(LI All operations are available at compile time; Avoid exponential or trigonometry functions in CTFE, using them will significantly increase the compile time;)
321  $(LI Under CTFE, operations are performed in full precision, values are rounded to nearest. $(MYREF InexactException) and $(MYREF UnderflowException) are never thrown during CTFE;)
322 )
323 
324 Performance_tips:
325 
326 $(UL
327  $(LI When performing _decimal calculations, avoid binary floating point; 
328       conversion base-2 from/to base-10 is costly and error prone, especially if the exponents are very big or very small;)
329  $(LI Avoid custom precisions; rounding is expensive since most of the time will involve a division operation;)
330  $(LI Use $(MYREF decimal128) only if you truly need 34 digits of precision. $(MYREF decimal64) and $(MYREF decimal32) arithmetic is much faster;)
331  $(LI Avoid traps and check yourself for flags; throwing and catching exceptions is expensive;)
332  $(LI Contrary to usual approach, multiplication/division by 10 for _decimal values is faster than multiplication/division by 2;)
333 )
334 
335 
336 Copyright: Copyright (c) Răzvan Ștefănescu 2018.
337 License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
338 Authors:   Răzvan Ștefănescu
339 Source:    $(LINK2 https://github.com/rumbu13/decimal/blob/master/src/package.d, _decimal.d)
340 
341 */
342 module decimal.decimal;
343 
344 public import std.traits: isIntegral, isFloatingPoint, isSomeChar, isSomeString;
345 public import std.format: FormatSpec, FormatException;
346 public import std.range.primitives: isInputRange, ElementType;
347 
348 
349 version(Windows)
350 {
351     public import core.sys.windows.wtypes: DECIMAL;
352 }
353 else
354 {
355     struct DECIMAL {
356         ushort wReserved;
357         struct {
358             ubyte scale;
359             ubyte sign;
360             enum ubyte DECIMAL_NEG = 0x80;
361         }
362         uint Hi32;
363         union {
364             struct {
365                 uint Lo32;
366                 uint Mid32;
367             }
368             ulong Lo64;
369         }
370     }
371 }
372 
373 private import decimal.integrals;
374 private import decimal.floats;
375 private import decimal.ranges;
376 
377 private alias fma = decimal.integrals.fma;
378 
379 version(D_BetterC)
380 {
381 
382 }
383 else
384 {
385     private import decimal.sinks;
386 }
387 
388 private import std.traits: Unqual, isUnsigned, Unsigned, isSigned;
389 private import core.checkedint: adds, subs;
390 private import std.math: isNaN, isInfinity, signbit, ieeeFlags, FloatingPointControl, resetIeeeFlags, ldexp, getNaNPayload;
391 private import std.format: singleSpec;
392 
393 
394 
395 
396 version (unittest)
397 {
398     import std.typetuple;
399     import std.stdio;
400     import std.format;
401 }
402 
403 /**
404 _Decimal floating-point computer numbering format that occupies 4, 8 or 16 bytes in computer memory.
405 */
406 struct Decimal(int bits) if (bits == 32 || bits == 64 || bits == 128)
407 {
408 private:
409     alias D = typeof(this);
410     alias U = DataType!D;
411     
412     U data = MASK_SNAN;
413 
414     enum expBits        = bits / 16 + 6;                 //8, 10, 14
415     enum trailingBits   = bits - expBits - 1;            //23, 53, 113    
416     enum PRECISION      = 9 * bits / 32 - 2;             //7, 16, 34
417     enum EMAX           = 3 * (2 ^^ (bits / 16 + 3));    //96, 384, 6144
418 
419     enum SHIFT_EXP1     = trailingBits;                  //23, 53, 113
420     enum SHIFT_EXP2     = trailingBits - 2;              //21, 51, 111
421 
422     enum EXP_BIAS       = EMAX + PRECISION - 2;          //101, 398, 6176
423     enum EXP_MIN        = -EXP_BIAS;
424     enum EXP_MAX        = EMAX - PRECISION + 1;          //90, 369, 6111
425 
426     enum MASK_QNAN      = U(0b01111100U) << (bits - 8);
427     enum MASK_SNAN      = U(0b01111110U) << (bits - 8);
428     enum MASK_SNANBIT   = U(0b00000010U) << (bits - 8);
429     enum MASK_INF       = U(0b01111000U) << (bits - 8);
430     enum MASK_SGN       = U(0b10000000U) << (bits - 8);
431     enum MASK_EXT       = U(0b01100000U) << (bits - 8);
432     enum MASK_EXP1      = ((U(1U) << expBits) - 1U) << SHIFT_EXP1;
433     enum MASK_EXP2      = ((U(1U) << expBits) - 1U) << SHIFT_EXP2;
434     enum MASK_COE1      = ~(MASK_SGN | MASK_EXP1);
435     enum MASK_COE2      = ~(MASK_SGN | MASK_EXP2 | MASK_EXT);
436     enum MASK_COEX      = U(1U) << trailingBits;
437     enum MASK_ZERO      = U(cast(uint)EXP_BIAS) << SHIFT_EXP1;
438     enum MASK_PAYL      = (U(1U) << (trailingBits - 3)) - 1U;
439     enum MASK_NONE      = U(0U);
440 
441     
442     enum COEF_MAX       = pow10!U[PRECISION] - 1U;
443     enum PAYL_MAX       = pow10!U[PRECISION - 1] - 1U;
444 
445     enum LOG10_2        = 0.30102999566398119521L;
446 
447     @nogc nothrow pure @safe
448     this(const U signMask, const U expMask, const U coefMask)
449     {
450         this.data = signMask | expMask | coefMask;
451     }
452 
453     @nogc nothrow pure @safe
454     this(const U coefficient, const int exponent, const bool isNegative)
455     {
456         pack(coefficient, exponent, isNegative);
457     }
458 
459     //packs valid components
460     @nogc nothrow pure @safe
461     void pack(const U coefficient, const int exponent, const bool isNegative)
462     in
463     {
464         assert (coefficient <= (MASK_COE2 | MASK_COEX));
465         assert (exponent >= EXP_MIN && exponent <= EXP_MAX);
466     }
467     out
468     {
469         assert ((this.data & MASK_INF) != MASK_INF);
470     }
471     body
472     {
473         U expMask = U(cast(uint)(exponent + EXP_BIAS));
474         U sgnMask = isNegative ? MASK_SGN : MASK_NONE;
475 
476         if (coefficient <= MASK_COE1)
477             this.data = sgnMask | (expMask << SHIFT_EXP1) | coefficient;
478         else
479             this.data = sgnMask | (expMask << SHIFT_EXP2) | (coefficient & MASK_COE2) | MASK_EXT;
480     }
481 
482     //packs components, but checks the limits before
483     @nogc nothrow pure @safe
484     ExceptionFlags checkedPack(const U coefficient, const int exponent, const bool isNegative, 
485                         int precision, const RoundingMode mode, const bool acceptNonCanonical)
486     {
487         if (exponent > EXP_MAX)
488             return overflowPack(isNegative, precision, mode);
489         if (exponent < EXP_MIN)
490             return underflowPack(isNegative, mode);
491         if (coefficient > COEF_MAX && !acceptNonCanonical)
492             return overflowPack(isNegative, precision, mode);
493         if (coefficient > (MASK_COE2 | MASK_COEX) && acceptNonCanonical)
494             return overflowPack(isNegative, precision, mode);
495 
496         U expMask = U(cast(uint)(exponent + EXP_BIAS));
497         U sgnMask = isNegative ? MASK_SGN : MASK_NONE;
498 
499         if (coefficient <= MASK_COE1)
500             this.data = sgnMask | (expMask << SHIFT_EXP1) | coefficient;
501         else
502             this.data = sgnMask | (expMask << SHIFT_EXP2) | (coefficient & MASK_COE2) | MASK_EXT;
503 
504         if (expMask < cast(uint)(D.PRECISION - 1))
505             if (prec(coefficient) < D.PRECISION - cast(uint)expMask)
506                 return ExceptionFlags.underflow;
507 
508         return ExceptionFlags.none;
509     }
510 
511 
512     //returns true if data was packed according to flags
513     @nogc nothrow pure @safe
514     bool errorPack(const bool isNegative, const ExceptionFlags flags, const int precision, const RoundingMode mode, const U payload = U(0U))
515     {
516         if (flags & ExceptionFlags.invalidOperation)
517             invalidPack(isNegative, payload);
518         else if (flags & ExceptionFlags.divisionByZero)
519             div0Pack(isNegative);
520         else if (flags & ExceptionFlags.overflow)
521             overflowPack(isNegative, precision, mode);
522         else if (flags & ExceptionFlags.underflow)
523             underflowPack(isNegative, mode);
524         else 
525             return false;
526         return true;
527     }
528 
529     @nogc nothrow pure @safe
530     ExceptionFlags maxPack(const bool isNegative, const int precision)
531     {
532         data = isNegative ? MASK_SGN : MASK_NONE;
533         auto p = realPrecision(precision);
534         if (p >= PRECISION)
535             data |= max.data;
536         else
537         {
538             U coefficient = (COEF_MAX / pow10!U[PRECISION - p]) * pow10!U[PRECISION - p];
539             int exponent = EXP_MAX;
540             pack(coefficient, exponent, isNegative);
541             return ExceptionFlags.inexact;
542         }
543         return ExceptionFlags.none;
544     }
545 
546     @nogc nothrow pure @safe
547     ExceptionFlags minPack(const bool isNegative)
548     {
549         data = isNegative ? MASK_SGN : MASK_NONE;
550         data |= subn.data;
551         return ExceptionFlags.underflow;
552     }
553 
554     //packs infinity or max, depending on the rounding mode
555     @nogc nothrow pure @safe
556     ExceptionFlags overflowPack(const bool isNegative, const int precision, const RoundingMode mode)
557     {      
558         switch (mode)
559         {
560             case RoundingMode.towardZero:
561                 return maxPack(isNegative, precision) | ExceptionFlags.overflow;
562             case RoundingMode.towardNegative:
563                 if (!isNegative)
564                     return maxPack(false, precision) | ExceptionFlags.overflow;
565                 goto default;
566             case RoundingMode.towardPositive:
567                 if (isNegative)
568                     return maxPack(true, precision) | ExceptionFlags.overflow;
569                 goto default;
570             default:
571                 data = MASK_INF;
572                 if (isNegative)
573                     data |= D.MASK_SGN;
574         }
575         return ExceptionFlags.overflow;
576     }
577 
578     //packs zero or min, depending on the rounding mode
579     @nogc nothrow pure @safe
580     ExceptionFlags underflowPack(const bool isNegative, const RoundingMode mode)
581     {      
582         switch (mode)
583         {
584             case RoundingMode.towardPositive:
585                 if (!isNegative)
586                     return minPack(false);
587                 goto default;
588             case RoundingMode.towardNegative:
589                 if (isNegative)
590                     return minPack(true);
591                 goto default;
592             default:
593                 data = MASK_ZERO;
594                 if (isNegative)
595                     data |= D.MASK_SGN;
596         }
597         return ExceptionFlags.underflow;
598     }
599 
600     //packs $(B NaN)
601     @nogc nothrow pure @safe
602     ExceptionFlags invalidPack(const bool isNegative, const U payload)
603     {
604         data = MASK_QNAN;
605         data |= (payload & MASK_PAYL);
606         if (isNegative)
607             data |= MASK_SGN;
608         return ExceptionFlags.invalidOperation;
609     }
610 
611     //packs infinity
612     @nogc nothrow pure @safe
613     ExceptionFlags div0Pack(const bool isNegative)
614     {
615         data = MASK_INF;
616         if (isNegative)
617             data |= MASK_SGN;
618         return ExceptionFlags.divisionByZero;
619     }
620 
621 
622     @nogc nothrow pure @safe
623     ExceptionFlags adjustedPack(T)(const T coefficient, const int exponent, const bool isNegative, 
624                                     const int precision, const RoundingMode mode, 
625                                     const ExceptionFlags previousFlags = ExceptionFlags.none)
626     {
627         if (!errorPack(isNegative, previousFlags, precision, mode, cvt!U(coefficient)))
628         {
629             bool stickyUnderflow = exponent < int.max - EXP_BIAS && exponent + EXP_BIAS < PRECISION - 1 && prec(coefficient) < PRECISION - (exponent + EXP_BIAS);
630             static if (T.sizeof <= U.sizeof)
631                 U cx = coefficient;
632             else
633                 Unqual!T cx = coefficient;
634             int ex = exponent; 
635             ExceptionFlags flags = coefficientAdjust(cx, ex, EXP_MIN, EXP_MAX, realPrecision(precision), isNegative, mode) | previousFlags; 
636             if (stickyUnderflow)
637                 flags |= ExceptionFlags.underflow;
638             return checkedPack(cvt!U(cx), ex, isNegative, precision, mode, false) | flags;
639         }
640         return previousFlags;
641     }
642 
643     @nogc nothrow pure @safe
644     bool unpack(out U coefficient, out int exponent) const
645     out
646     {
647         assert (exponent >= EXP_MIN && exponent <= EXP_MAX);
648         assert (coefficient <= (MASK_COE2 | MASK_COEX));
649     }
650     body
651     {
652         uint e;
653         bool isNegative = unpackRaw(coefficient, e);
654         exponent = cast(int)(e - EXP_BIAS);
655         return isNegative;
656     }
657 
658     @nogc nothrow pure @safe
659     bool unpackRaw(out U coefficient, out uint exponent) const
660     {
661         if ((data & MASK_EXT) == MASK_EXT)
662         {
663             coefficient = data & MASK_COE2 | MASK_COEX;
664             exponent = cast(uint)((data & MASK_EXP2) >>> SHIFT_EXP2);
665         }
666         else
667         {
668             coefficient = data & MASK_COE1;
669             exponent = cast(uint)((data & MASK_EXP1) >>> SHIFT_EXP1);
670         }
671         return (data & MASK_SGN) != 0U;
672     }
673 
674     @nogc nothrow pure @safe
675     static int realPrecision(const int precision)
676     {
677         if (precision <= 0 || precision > PRECISION)
678             return PRECISION;
679         else
680             return precision;
681     }
682 
683     ExceptionFlags packIntegral(T)(const T value, const int precision, const RoundingMode mode)
684     if (isIntegral!T)
685     {
686         alias V = CommonStorage!(D, T);
687         if (!value)
688         {
689             this.data = MASK_ZERO;
690             return ExceptionFlags.none;
691         }
692         else
693         {
694             static if (isSigned!T)
695             {
696                 bool isNegative = void;
697                 V coefficient = unsign!V(value, isNegative);
698             }
699             else
700             {
701                 enum isNegative = false;
702                 V coefficient = value;
703             }
704             int exponent = 0;
705             auto flags = coefficientAdjust(coefficient, exponent, cvt!V(COEF_MAX), isNegative, mode);
706             return adjustedPack(cvt!U(coefficient), exponent, isNegative, precision, mode, flags);
707         }
708     }
709 
710     ExceptionFlags packFloatingPoint(T)(const T value, const int precision, const RoundingMode mode) 
711     if (isFloatingPoint!T)
712     {
713         //float / decimal32  -> min(9, 7) = 7       
714         //float / decimal64  -> min(9, 16) = 9      
715         //float / decimal128 -> min(9, 34) = 9      
716 
717         //double / decimal32  -> min(16, 7) = 7      
718         //double / decimal64  -> min(16, 16) = 16    
719         //double / decimal128 -> min(16, 34) = 16    
720 
721         //real / decimal32   -> min(21, 7) = 7      
722         //real / decimal64   -> min(21, 16) = 16    
723         //real / decimal128  -> min(21, 34) = 21  
724 
725         ExceptionFlags flags;
726         DataType!D cx; int ex; bool sx;
727         switch (fastDecode(value, cx, ex, sx, mode, flags))
728         {
729             case FastClass.quietNaN:
730                 data = MASK_QNAN;
731                 if (sx)
732                     data |= MASK_SGN;
733                 data |= cx & MASK_PAYL;
734                 return ExceptionFlags.none;
735             case FastClass.infinite:
736                 data = MASK_INF;
737                 if (sx)
738                     data |= MASK_SGN;
739                 return ExceptionFlags.none;
740             case FastClass.zero:
741                 data = MASK_ZERO;
742                 if (sx)
743                     data |= MASK_SGN;
744                 return ExceptionFlags.none;
745             case FastClass.finite:
746                 auto targetPrecision = realPrecision(precision);
747                 static if (is(T == float))
748                 {
749                     if (targetPrecision > 9)
750                         targetPrecision = 9;
751                 }
752                 else static if (is(T == double))
753                 {
754                     if (targetPrecision > 17)
755                         targetPrecision = 17;
756                 }
757                 else
758                 {
759                     if (targetPrecision > 21)
760                         targetPrecision = 21;
761                 }
762                 flags |= coefficientAdjust(cx, ex, targetPrecision, sx, mode);
763                 return adjustedPack(cx, ex, sx, precision, mode, flags);                
764             default:
765                 assert(0);
766         }
767     }
768 
769 
770     ExceptionFlags packString(C)(const(C)[] value, const int precision, const RoundingMode mode)
771     if (isSomeChar!C)
772     {
773             U coefficient;
774             bool isinf, isnan, issnan, isnegative, wasHex;
775             int exponent;
776             const(C)[] ss = value;
777             auto flags = parseDecimal(ss, coefficient, exponent, isinf, isnan, issnan, isnegative, wasHex);
778 
779             if (!ss.empty)
780                 return invalidPack(isnegative, coefficient) | flags;
781 
782             if (flags & ExceptionFlags.invalidOperation)
783                 return invalidPack(isnegative, coefficient) | flags;
784 
785             if (issnan)
786                 data = MASK_SNAN | (coefficient & MASK_PAYL);
787             else if (isnan)
788                 data = MASK_QNAN | (coefficient & MASK_PAYL);
789             else if (isinf)
790                 data = MASK_INF;
791             else
792             {   
793                 if (!wasHex)
794                     return adjustedPack(coefficient, exponent, isnegative, precision, mode, flags);
795                 else
796                     return flags | checkedPack(coefficient, exponent, isnegative, precision, mode, true);
797             }
798 
799             if (isnegative)
800                 data |= MASK_SGN;
801 
802             return flags;
803     }
804 
805     ExceptionFlags packRange(R)(ref R range, const int precision, const RoundingMode mode)
806     if (isInputRange!R && isSomeChar!(ElementType!R) && !isSomeString!range)
807     {
808             U coefficient;
809             bool isinf, isnan, issnan, isnegative, wasHex;
810             int exponent;
811             auto flags = parseDecimal(range, coefficient, exponent, isinf, isnan, issnan, isnegative, wasHex);
812 
813             if (!ss.empty)
814                 flags |= ExceptionFlags.invalidOperation;
815 
816             if (flags & ExceptionFlags.invalidOperation)
817             {
818                 packErrors(isnegative, flags, coefficient);
819                 return flags;
820             }
821 
822             if (issnan)
823                 data = MASK_SNAN | (coefficient & MASK_PAYL);
824             else if (isnan)
825                 data = MASK_QNAN | (coefficient & MASK_PAYL);
826             else if (isinf)
827                 data = MASK_INF;
828             if (flags & ExceptionFlags.underflow)
829                 data = MASK_ZERO;
830             else if (flags & ExceptionFlags.overflow)
831                 data = MASK_INF;
832             else 
833             {
834                 flags |= adjustCoefficient(coefficient, exponent, EXP_MIN, EXP_MAX, COEF_MAX, isnegative, mode);
835                 flags |= adjustPrecision(coefficient, exponent, EXP_MIN, EXP_MAX, precision, isnegative, mode);
836             }
837             
838             if (flags & ExceptionFlags.underflow)
839                 data = MASK_ZERO;
840             else if (flags & ExceptionFlags.overflow)
841                 data = MASK_INF;
842 
843             if (isnegative)
844                 data |= MASK_SGN;
845 
846             return flags;
847     }
848      
849 
850     enum zero           = D(U(0U), 0, false);
851     enum minusZero      = D(U(0U), 0, true);
852     enum one            = D(U(1U), 0, false);
853     enum two            = D(U(2U), 0, false);
854     enum three          = D(U(3U), 0, false);
855     enum minusOne       = D(U(1U), 0, true);
856     enum minusInfinity  = -infinity;
857     enum ten            = D(U(10U), 0, false);
858     enum minusTen       = D(U(10U), 0, true);
859     enum qnan           = nan;
860     enum snan           = D(MASK_NONE, MASK_NONE, MASK_SNAN);
861     enum subn           = D(U(1U), EXP_MIN, false);
862     enum minusSubn      = D(U(1U), EXP_MIN, true);
863     enum min            = D(COEF_MAX, EXP_MAX, true);
864     enum half           = D(U(5U), -1, false);
865     enum threequarters  = D(U(75U), -2, false);
866     enum quarter        = D(U(25U), -2, false);
867 
868 
869     enum SQRT3          = fromString!D(s_sqrt3);
870     enum M_SQRT3        = fromString!D(s_m_sqrt3);
871     enum PI_3           = fromString!D(s_pi_3);
872     enum PI_6           = fromString!D(s_pi_6);
873     enum _5PI_6         = fromString!D(s_5pi_6);
874     enum _3PI_4         = fromString!D(s_3pi_4);
875     enum _2PI_3         = fromString!D(s_2pi_3);
876     enum SQRT3_2        = fromString!D(s_sqrt3_2);
877     enum SQRT2_2        = fromString!D(s_sqrt2_2);
878     enum onethird       = fromString!D(s_onethird);
879     enum twothirds      = fromString!D(s_twothirds);
880     enum _5_6           = fromString!D(s_5_6);
881     enum _1_6           = fromString!D(s_1_6);
882     enum M_1_2PI        = fromString!D(s_m_1_2pi);
883     enum PI2            = fromString!D(s_pi2);
884 public:
885 
886     
887     enum dig            = PRECISION;
888     enum epsilon        = D(U(1U), -PRECISION + 1, false);
889     enum infinity       = D(MASK_NONE, MASK_NONE, MASK_INF);
890     enum max            = D(COEF_MAX, EXP_MAX, false);
891     enum max_10_exp     = EMAX;
892     enum max_exp        = cast(int)(max_10_exp / LOG10_2);
893     enum mant_dig       = trailingBits;
894     enum min_10_exp     = -(max_10_exp - 1);
895     enum min_exp        = cast(int)(min_10_exp / LOG10_2);
896     enum min_normal     = D(U(1U), min_10_exp, false);    
897     enum nan            = D(MASK_NONE, MASK_NONE, MASK_QNAN);
898     
899 
900     enum E              = fromString!D(s_e);
901     enum PI             = fromString!D(s_pi);
902     enum PI_2           = fromString!D(s_pi_2);
903     enum PI_4           = fromString!D(s_pi_4);
904     enum M_1_PI         = fromString!D(s_m_1_pi);
905     enum M_2_PI         = fromString!D(s_m_2_pi);
906     enum M_2_SQRTPI     = fromString!D(s_m_2_sqrtpi);
907     enum SQRT2          = fromString!D(s_sqrt2);
908     enum SQRT1_2        = fromString!D(s_sqrt1_2);
909     enum LN10           = fromString!D(s_ln10);
910     enum LOG2T          = fromString!D(s_log2t);
911     enum LOG2E          = fromString!D(s_log2e);
912     enum LOG2           = fromString!D(s_log2);
913     enum LOG10E         = fromString!D(s_log10e);
914     enum LN2            = fromString!D(s_ln2);
915 
916     ///always 10 for _decimal data types
917     @IEEECompliant("radix", 25)
918     enum radix          = 10;
919 
920     /**
921     Constructs a Decimal data type using the specified _value
922     Params:
923         value = any integral, char, bool, floating point, decimal, string or character range _value
924     Exceptions: 
925         $(BOOKTABLE,
926             $(TR $(TH Data type) $(TH Invalid) $(TH Overflow) $(TH Underflow) $(TH Inexact))
927             $(TR $(TD integral)  $(TD        ) $(TD         ) $(TD          ) $(TD ✓     ))
928             $(TR $(TD char    )  $(TD        ) $(TD         ) $(TD          ) $(TD ✓     ))
929             $(TR $(TD float   )  $(TD        ) $(TD ✓      ) $(TD ✓       ) $(TD ✓     ))
930             $(TR $(TD bool    )  $(TD        ) $(TD         ) $(TD          ) $(TD        ))
931             $(TR $(TD decimal )  $(TD        ) $(TD ✓      ) $(TD ✓       ) $(TD ✓     ))
932             $(TR $(TD string  )  $(TD ✓     ) $(TD ✓      ) $(TD ✓       ) $(TD ✓     ))
933             $(TR $(TD range   )  $(TD ✓     ) $(TD ✓      ) $(TD ✓       ) $(TD ✓     ))
934         )
935     Using_integral_values:
936         ---
937         auto a = decimal32(112);       //represented as 112 x 10^^0;
938         auto b = decimal32(123456789); //inexact, represented as 1234568 * x 10^^2
939         ---
940     Using_floating_point_values:
941         ---
942         auto a = decimal32(1.23);
943         //inexact, represented as 123 x 10^^-2, 
944         //because floating point data cannot exactly represent 1.23 
945         //in fact 1.23 as float is 1.230000019073486328125
946         auto b = decimal64(float.nan); 
947         ---
948     Using_other_decimal_values:
949         ---
950         auto a = decimal32(decimal64(10)); 
951         auto b = decimal64(a);
952         auto c = decimal64(decimal128.nan);
953         ---
954     Using_strings_or_ranges:
955         A _decimal value can be defined based on _decimal, scientific or hexadecimal representation:
956         $(UL
957             $(LI values are rounded away from zero in case of precision overflow;)
958             ---
959             auto d = decimal32("2.3456789")
960             //internal representation will be 2.345679
961             //because decimal32 has a 7-digit precision
962             ---
963             $(LI the exponent in hexadecimal notation is 10-based;)
964             ---
965             auto d1 = decimal64("0x00003p+21");
966             auto d2 = decimal64("3e+21");
967             assert (d1 == d2);
968             ---
969             $(LI the hexadecimal notation doesn't have any _decimal point, 
970                 because there is no leading 1 as for binary floating point values;)
971             $(LI there is no octal notation, any leading zero before the decimal point is ignored;)
972             $(LI digits can be grouped using underscores;)
973             $(LI case insensitive special values are accepted: $(B nan, qnan, snan, inf, infinity);)
974             $(LI there is no digit count limit for _decimal representation, very large values are rounded and adjusted by 
975                 increasing the 10-exponent;)
976             ---
977             auto d1 = decimal32("123_456_789_123_456_789_123_456_789_123"); //30 digits
978             //internal representation will be 1.234568 x 10^^30
979             ---
980             $(LI $(B NaN) payloads can be defined betwen optional brackets ([], (), {}, <>). 
981             The payload is unsigned and is accepted in decimal or hexadecimal format;)
982         )   
983             ---
984             auto d = decimal32("10");              //integral
985             auto e = decimal64("125.43")           //floating point
986             auto f = decimal128("123.456E-32");    //scientific
987             auto g = decimal32("0xABCDEp+21");     //hexadecimal 0xABCD * 10^^21
988             auto h = decimal64("NaN1234");         //$(B NaN) with 1234 payload
989             auto i = decimal128("sNaN<0xABCD>")    //signaling $(B NaN) with a 0xABCD payload
990             auto j = decimal32("inf");             //infinity
991             ---
992     Using_char_or_bool_values:
993         These constructors are provided only from convenience, and to 
994         offer support for conversion function $(PHOBOS conv, to, to).
995         Char values are cast to unsigned int.
996         Bool values are converted to 0.0 (false) or 1.0 (true)
997         ---
998         auto a = decimal32(true); //1.0
999         auto b = decimal32('a');  //'a' ascii code (97)
1000 
1001         auto c = to!decimal32(false); //phobos to!(bool, decimal32)
1002         auto d = to!decimal128('Z');  //phobos to!(char, decimal128)
1003         ---
1004     */
1005     @IEEECompliant("convertFormat", 22)
1006     @IEEECompliant("convertFromDecimalCharacter", 22)
1007     @IEEECompliant("convertFromHexCharacter", 22)
1008     @IEEECompliant("convertFromInt", 21)
1009     @IEEECompliant("decodeBinary", 23)
1010     this(T)(auto const ref T value)
1011     {
1012         static if (isIntegral!T)
1013         {
1014             auto flags = packIntegral(value, 
1015                                  __ctfe ? 0 : DecimalControl.precision, 
1016                                  __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1017             DecimalControl.raiseFlags(flags);
1018         }
1019         else static if (isSomeChar!T)
1020         {
1021             auto flags = packIntegral(cast(uint)value, 
1022                                  __ctfe ? 0 : DecimalControl.precision, 
1023                                  __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1024             DecimalControl.raiseFlags(flags);
1025         }
1026         else static if (isFloatingPoint!T)
1027         {
1028             auto flags = packFloatingPoint(value, 
1029                                  __ctfe ? 0 : DecimalControl.precision, 
1030                                  __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1031             DecimalControl.raiseFlags(flags);
1032         }
1033         else static if (isSomeString!T)
1034         {
1035             auto flags = packString(value, 
1036                                  __ctfe ? 0 : DecimalControl.precision, 
1037                                  __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1038             DecimalControl.raiseFlags(flags);
1039         }
1040         else static if (isInputRange!T && isSomeChar!(ElementType!T) && !isSomeString!T)
1041         {
1042             auto flags = packRange(value, 
1043                                  __ctfe ? 0 : DecimalControl.precision, 
1044                                  __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1045             DecimalControl.raiseFlags(flags);
1046         }
1047         else static if (is(T: D))
1048             this.data = value.data;
1049         else static if (is(T: bool))
1050         {
1051             this.data = value ? one.data : zero.data;
1052         }
1053         else static if (isDecimal!T)
1054         {
1055             auto flags = decimalToDecimal(value, this, 
1056                                  __ctfe ? 0 : DecimalControl.precision, 
1057                                  __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1058             DecimalControl.raiseFlags(flags);
1059         }
1060         else
1061             static assert (0, "Cannot convert expression of type '" ~ 
1062                            Unqual!T.stringof ~ "' to '" ~
1063                            Unqual!D.stringof ~ "'");
1064     }  
1065 
1066 
1067 
1068     /**
1069     Implementation of assignnment operator. It supports the same semantics as the constructor.
1070     */
1071     @IEEECompliant("copy", 23)
1072     auto ref opAssign(T)(auto const ref T value)
1073     {
1074         auto result = Unqual!D(value);
1075         this.data = result.data;
1076     }
1077 
1078     /**
1079     Implementation of cast operator. Supported casts: integral, floating point, _decimal, char, bool
1080     Exceptions: 
1081         $(BOOKTABLE,
1082             $(TR $(TH Data type) $(TH Invalid) $(TH Overflow) $(TH Underflow) $(TH Inexact))
1083             $(TR $(TD integral)  $(TD      ✓) $(TD ✓      ) $(TD ✓       ) $(TD ✓     ))
1084             $(TR $(TD char    )  $(TD      ✓) $(TD ✓      ) $(TD ✓       ) $(TD ✓     ))
1085             $(TR $(TD float   )  $(TD        ) $(TD ✓      ) $(TD ✓       ) $(TD ✓     ))
1086             $(TR $(TD bool    )  $(TD        ) $(TD         ) $(TD          ) $(TD        ))
1087             $(TR $(TD decimal )  $(TD        ) $(TD ✓      ) $(TD ✓       ) $(TD ✓     ))
1088         )
1089     */
1090     @IEEECompliant("convertFormat", 22)
1091     @IEEECompliant("encodeBinary", 23)
1092     T opCast(T)() const
1093     {
1094         Unqual!T result;
1095         static if (isUnsigned!T)
1096         {
1097             auto flags = decimalToUnsigned(this, result, 
1098                                       __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1099             DecimalControl.raiseFlags(flags);
1100         }
1101         else static if (isIntegral!T)
1102         {
1103             auto flags = decimalToSigned(this, result, 
1104                                     __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1105             DecimalControl.raiseFlags(flags);
1106         }
1107         else static if (is(T: D))
1108             result = this;
1109         else static if (is(D: decimal32) && (is(T: decimal64) || is(T: decimal128)))
1110             decimalToDecimal(this, result, 0, RoundingMode.implicit);
1111         else static if (is(D: decimal64) && is(T: decimal128))
1112             decimalToDecimal(this, result, 0, RoundingMode.implicit);
1113         else static if (isDecimal!T)
1114         {
1115             auto flags = decimalToDecimal(this, result, 
1116                                           __ctfe ? 0 : DecimalControl.precision,
1117                                           __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1118             DecimalControl.raiseFlags(flags);
1119         }
1120         else static if (isFloatingPoint!T)
1121         {
1122             auto flags = decimalToFloat(this, result, 
1123                                         __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1124             DecimalControl.raiseFlags(flags);
1125         }
1126         else static if (isSomeChar!T)
1127         {
1128             uint r;
1129             auto flags = decimalToUnsigned(this, r, 
1130                                            __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1131             result = cast(Unqual!T)r;
1132             DecimalControl.raiseFlags(flags);
1133         }
1134         else static if (is(T: bool))
1135             result = !isZero(this);
1136         else
1137             static assert(0, "Cannot cast a value of type '" ~ 
1138                           Unqual!D.stringof ~ "' to '" ~ 
1139                           Unqual!T.stringof ~ "'");
1140         
1141         return result;
1142     }
1143     
1144 
1145     /**
1146     Implementation of +/- unary operators. These operations are silent, no exceptions are thrown
1147     */
1148     @safe pure nothrow @nogc
1149     auto opUnary(string op: "+")() const
1150     {
1151         return this;
1152     }
1153 
1154     ///ditto
1155     @IEEECompliant("negate", 23)
1156     @safe pure nothrow @nogc
1157     auto opUnary(string op: "-")() const
1158     {
1159         D result = this;
1160         static if (is(D: decimal128))
1161             result.data.hi ^= D.MASK_SGN.hi;
1162         else
1163             result.data ^= D.MASK_SGN;
1164         return result;
1165     }
1166 
1167     /**
1168     Implementation of ++/-- unary operators.
1169     Exceptions: 
1170         $(BOOKTABLE,
1171             $(TR $(TH Value) $(TH ++/-- ) $(TH Invalid) $(TH Overflow) $(TH Inexact))
1172             $(TR $(TD $(B NaN)  ) $(TD $(B NaN)   ) $(TD ✓     ) $(TD         ) $(TD        ))
1173             $(TR $(TD ±∞   ) $(TD ±∞    ) $(TD        ) $(TD         ) $(TD        ))
1174             $(TR $(TD any  ) $(TD any   ) $(TD        ) $(TD ✓      ) $(TD ✓     ))
1175         )
1176     */
1177     @safe
1178     auto ref opUnary(string op: "++")()
1179     {
1180         auto flags = decimalInc(this,
1181                                 __ctfe ? 0 : DecimalControl.precision, 
1182                                 __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1183         DecimalControl.raiseFlags(flags);
1184         return this;
1185     }
1186 
1187     ///ditto
1188     @safe
1189     auto ref opUnary(string op: "--")()
1190     {
1191         auto flags = decimalDec(this,
1192                                 __ctfe ? 0 : DecimalControl.precision, 
1193                                 __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1194         DecimalControl.raiseFlags(flags);
1195         return this;
1196     }
1197 
1198 
1199     /**
1200     Implementation of == operator. This operation is silent, no exceptions are thrown.
1201     Supported types : _decimal, floating point, integral, char    
1202     */
1203     @IEEECompliant("compareQuietEqual", 24)
1204     @IEEECompliant("compareQuietNotEqual", 24)
1205     bool opEquals(T)(auto const ref T value) const
1206     {
1207         static if (isDecimal!T || isIntegral!T || isFloatingPoint!T)
1208         {
1209             int result = decimalEqu(this, value);
1210             if (result < -2)
1211             {
1212                 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
1213                 return false;
1214             }
1215             return result == 1;
1216         }
1217         else static if (isSomeChar!T)
1218             return opEquals(cast(uint)value);
1219         else
1220             static assert (0, "Cannot compare values of type '" ~ 
1221                 Unqual!D.stringof ~ "' and '" ~ 
1222                 Unqual!T.stringof ~ "'");
1223     }
1224 
1225     /**
1226     Implementation of comparison operator. 
1227     Supported types : _decimal, floating point, integral, char   
1228     $(BOOKTABLE,
1229             $(TR $(TH this) $(TH Value) $(TH Result)    $(TH Invalid)) 
1230             $(TR $(TD $(B NaN) ) $(TD any  ) $(TD $(B NaN)   )    $(TD ✓     ))
1231             $(TR $(TD any ) $(TD $(B NaN)  ) $(TD $(B NaN)   )    $(TD ✓     )) 
1232             $(TR $(TD any ) $(TD any  ) $(TD ±1.0, 0.0) $(TD        )) 
1233         )
1234     */
1235     @IEEECompliant("compareSignalingGreater", 24)
1236     @IEEECompliant("compareSignalingGreaterEqual", 24)
1237     @IEEECompliant("compareSignalingGreaterUnordered", 24)
1238     @IEEECompliant("compareSignalingLess", 24)
1239     @IEEECompliant("compareSignalingLessEqual", 24)
1240     @IEEECompliant("compareSignalingLessUnordered", 24)
1241     @IEEECompliant("compareSignalingNotGreater", 24)
1242     @IEEECompliant("compareSignalingNotLess", 24)
1243     float opCmp(T)(auto const ref T value) const
1244     {
1245         static if (isDecimal!T || isIntegral!T || isFloatingPoint!T)
1246         {
1247             int result = decimalCmp(this, value);
1248             if (result < -1)
1249             {
1250                 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
1251                 return float.nan;
1252             }
1253             else
1254                 return cast(float)(result);
1255         }
1256         else static if (isSomeChar!T)
1257         {
1258             int result = decimalCmp(this, cast(uint)value);
1259             if (result < -1)
1260             {
1261                 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
1262                 return float.nan;
1263             }
1264             else
1265                 return cast(float)(result);
1266         }
1267         else
1268             static assert (0, "Cannot compare values of type '" ~ 
1269                            Unqual!D.stringof ~ "' and '" ~ 
1270                            Unqual!T.stringof ~ "'");
1271     }
1272 
1273     
1274     /**
1275     Implementation of binary and assignment operators (+, -, *, /, %, ^^). 
1276     Returns:
1277         the widest _decimal value as result of the operation
1278     Supported_types:
1279         _decimal, floating point, integral, char   
1280     Exceptions:
1281     $(BOOKTABLE,
1282         $(TR $(TH Left) $(TH Op) $(TH Right) $(TH Result) $(TH Invalid) $(TH Div0) $(TH Overflow) $(TH Underflow) $(TH Inexact))
1283         $(TR $(TD $(B NaN)) $(TD any) $(TD any) $(TD $(B NaN))      $(TD ✓     ) $(TD     ) $(TD         ) $(TD         )  $(TD        ))
1284         $(TR $(TD any) $(TD any) $(TD $(B NaN)) $(TD $(B NaN))      $(TD ✓     ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1285         $(TR $(TD +∞) $(TD +) $(TD -∞) $(TD $(B NaN))          $(TD ✓     ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1286         $(TR $(TD +∞) $(TD +) $(TD any) $(TD +∞)          $(TD        ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1287         $(TR $(TD any) $(TD +) $(TD +∞) $(TD +∞)          $(TD        ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1288         $(TR $(TD -∞) $(TD +) $(TD +∞) $(TD $(B NaN))          $(TD ✓     ) $(TD     ) $(TD         ) $(TD         )  $(TD        ))
1289         $(TR $(TD -∞) $(TD +) $(TD any) $(TD -∞)          $(TD        ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1290         $(TR $(TD any) $(TD +) $(TD -∞) $(TD -∞)          $(TD        ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1291         $(TR $(TD any) $(TD +) $(TD any) $(TD any)        $(TD        ) $(TD     ) $(TD ✓      ) $(TD ✓      )  $(TD ✓     )) 
1292         $(TR $(TD +∞) $(TD -) $(TD +∞) $(TD $(B NaN))          $(TD ✓     ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1293         $(TR $(TD +∞) $(TD -) $(TD any) $(TD +∞)          $(TD        ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1294         $(TR $(TD any) $(TD -) $(TD +∞) $(TD -∞)          $(TD        ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1295         $(TR $(TD -∞) $(TD -) $(TD -∞) $(TD $(B NaN))          $(TD ✓     ) $(TD     ) $(TD         ) $(TD         )  $(TD        ))  
1296         $(TR $(TD -∞) $(TD -) $(TD any) $(TD -∞)          $(TD        ) $(TD     ) $(TD         ) $(TD         )  $(TD        ))  
1297         $(TR $(TD any) $(TD -) $(TD -∞) $(TD -∞)          $(TD        ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1298         $(TR $(TD any) $(TD -) $(TD any) $(TD any)        $(TD        ) $(TD     ) $(TD ✓      ) $(TD ✓      )  $(TD ✓     )) 
1299         $(TR $(TD ±∞) $(TD *) $(TD 0.0) $(TD $(B NaN))         $(TD ✓     ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1300         $(TR $(TD ±∞) $(TD *) $(TD any) $(TD ±∞)          $(TD        ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1301         $(TR $(TD any) $(TD *) $(TD any) $(TD any)        $(TD        ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1302         $(TR $(TD ±∞) $(TD /) $(TD ±∞) $(TD $(B NaN))          $(TD ✓     ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1303         $(TR $(TD 0.0) $(TD /) $(TD 0.0) $(TD $(B NaN))        $(TD ✓     ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1304         $(TR $(TD ±∞) $(TD /) $(TD any) $(TD ±∞)          $(TD        ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1305         $(TR $(TD any) $(TD /) $(TD 0.0) $(TD ±∞)         $(TD        ) $(TD ✓  ) $(TD         ) $(TD         )  $(TD        )) 
1306         $(TR $(TD any) $(TD /) $(TD any) $(TD any)        $(TD        ) $(TD     ) $(TD ✓      ) $(TD ✓      )  $(TD ✓     ))  
1307         $(TR $(TD ±∞) $(TD %) $(TD any) $(TD $(B NaN))         $(TD ✓     ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1308         $(TR $(TD any) $(TD %) $(TD ±∞) $(TD $(B NaN))         $(TD ✓     ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1309         $(TR $(TD any) $(TD %) $(TD 0.0) $(TD $(B NaN))        $(TD ✓     ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1310         $(TR $(TD any) $(TD %) $(TD any) $(TD any)        $(TD        ) $(TD     ) $(TD ✓      ) $(TD ✓      )  $(TD ✓     )) 
1311     )
1312     */
1313     @IEEECompliant("addition", 21)
1314     @IEEECompliant("division", 21)
1315     @IEEECompliant("multiplication", 21)
1316     @IEEECompliant("pow", 42)
1317     @IEEECompliant("pown", 42)
1318     @IEEECompliant("powr", 42)
1319     @IEEECompliant("remainder", 25)
1320     @IEEECompliant("substraction", 21)
1321     auto opBinary(string op, T)(auto const ref T value) const
1322     if (op == "+" || op == "-" || op == "*" || op == "/" || op == "%" || op == "^^")
1323     {
1324         static if (isDecimal!T)
1325             CommonDecimal!(D, T) result = this;
1326         else
1327             Unqual!D result = this;
1328 
1329         static if (op == "+")
1330             alias decimalOp = decimalAdd;
1331         else static if (op == "-")
1332             alias decimalOp = decimalSub;
1333         else static if (op == "*")
1334             alias decimalOp = decimalMul;
1335         else static if (op == "/")
1336             alias decimalOp = decimalDiv;
1337         else static if (op == "%")
1338             alias decimalOp = decimalMod;
1339         else static if (op == "^^")
1340             alias decimalOp = decimalPow;
1341         else 
1342             static assert(0);
1343 
1344         static if (isIntegral!T || isFloatingPoint!T || isDecimal!T)
1345             auto flags = decimalOp(result, value, 
1346                                    __ctfe ? 0 : DecimalControl.precision, 
1347                                    __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1348         else static if (isSomeChar!T)
1349             auto flags = decimalOp(result, cast(uint)value, 
1350                                    __ctfe ? 0 : DecimalControl.precision, 
1351                                    __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1352         else
1353             static assert (0, "Cannot perform binary operation: '" ~ 
1354                             Unqual!D.stringof ~ "' " ~ op ~" '" ~ 
1355                             Unqual!T.stringof ~ "'");
1356 
1357         DecimalControl.raiseFlags(flags);
1358         return result;
1359     }
1360 
1361     ///ditto
1362     auto opBinaryRight(string op, T)(auto const ref T value) const
1363     if (op == "+" || op == "-" || op == "*" || op == "/" || op == "%" || op == "^^")
1364     {
1365         static if (isDecimal!T)
1366             CommonDecimal!(D, T) result = value;
1367         else
1368             Unqual!D result;
1369         static if (op == "+")
1370             alias decimalOp = decimalAdd;
1371         else static if (op == "-")
1372             alias decimalOp = decimalSub;
1373         else static if (op == "*")
1374             alias decimalOp = decimalMul;
1375         else static if (op == "/")
1376             alias decimalOp = decimalDiv;
1377         else static if (op == "%")
1378             alias decimalOp = decimalMod;
1379         else static if (op == "^^")
1380             alias decimalOp = decimalPow;
1381         else 
1382             static assert(0);
1383 
1384         static if (isDecimal!T)
1385         {
1386             
1387             auto flags = decimalOp(result, this, 
1388                                    __ctfe ? 0 : DecimalControl.precision, 
1389                                    __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1390         }
1391         else static if (isIntegral!T || isFloatingPoint!T)
1392             auto flags = decimalOp(value, this, result,
1393                                    __ctfe ? 0 : DecimalControl.precision, 
1394                                    __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1395         else static if (isSomeChar!T)
1396             auto flags = decimalOp(cast(uint)value, this, result,
1397                                    __ctfe ? 0 : DecimalControl.precision, 
1398                                    __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1399         else
1400             static assert (0, "Cannot perform binary operation: '" ~ 
1401                             Unqual!T.stringof ~ "' " ~ op ~" '" ~ 
1402                             Unqual!D.stringof ~ "'");
1403 
1404         DecimalControl.raiseFlags(flags);
1405         return result;
1406     }
1407 
1408     ///ditto
1409     auto opOpAssign(string op, T)(auto const ref T value)
1410     if (op == "+" || op == "-" || op == "*" || op == "/" || op == "%" || op == "^^")
1411     {
1412         static if (op == "+")
1413             alias decimalOp = decimalAdd;
1414         else static if (op == "-")
1415             alias decimalOp = decimalSub;
1416         else static if (op == "*")
1417             alias decimalOp = decimalMul;
1418         else static if (op == "/")
1419             alias decimalOp = decimalDiv;
1420         else static if (op == "%")
1421             alias decimalOp = decimalMod;
1422         else static if (op == "^^")
1423             alias decimalOp = decimalPow;
1424         else 
1425             static assert(0);
1426 
1427 
1428 
1429         static if (isIntegral!T || isFloatingPoint!T || isDecimal!T)
1430             auto flags = decimalOp(this, value, 
1431                                    __ctfe ? 0 : DecimalControl.precision, 
1432                                    __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1433         else static if (isSomeChar!T)
1434             auto flags = decimalOp(this, cast(uint)value, 
1435                                    __ctfe ? 0 : DecimalControl.precision, 
1436                                    __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1437         else
1438             static assert (0, "Cannot perform assignment operation: '" ~ 
1439                             Unqual!D.stringof ~ "' " ~ op ~"= '" ~ 
1440                             Unqual!T.stringof ~ "'");
1441 
1442         DecimalControl.raiseFlags(flags);
1443         return this;
1444     }
1445     
1446     version (D_BetterC) {}
1447     else {   
1448    
1449     /**
1450     Converts current value to string, passing it to the given sink using
1451     the specified format.
1452     Params:
1453       sink = a delegate used to sink character arrays;
1454       fmt  = a format specification;
1455     Notes:
1456       This function is not intended to be used directly, it is used by the format, output or conversion
1457       family of functions from Phobos. All standard format options are supported, except digit grouping. 
1458     Supported_formats:
1459       $(UL
1460         $(LI $(B f, F) - floating point notation)
1461         $(LI $(B e, E) - scientific notation)
1462         $(LI $(B a, A) - hexadecimal floating point notation)
1463         $(LI $(B g, G) - shortest representation between floating point and scientific notation)
1464         $(LI $(B s, S) - same as $(B g, G))
1465       )
1466     Throws:
1467       $(PHOBOS format, FormatException, FormatException) if the format specifier is not supported
1468     See_Also:
1469        $(PHOBOS format, FormatSpec, FormatSpec)
1470        $(PHOBOS format, format, format)
1471        $(PHOBOS conv, to, to)
1472        $(PHOBOS stdio, writef, writef)
1473        $(PHOBOS stdio, writefln, writefln)
1474     */
1475     @IEEECompliant("convertToDecimalCharacter", 22)
1476     @IEEECompliant("convertToHexCharacter", 22)
1477     void toString(C)(scope void delegate(const(C)[]) sink, FormatSpec!C fmt) const
1478     if (isSomeChar!C)
1479     {
1480         if (__ctfe)
1481             sinkDecimal(fmt, sink, this, RoundingMode.tiesToAway);
1482         else
1483             sinkDecimal(fmt, sink, this, DecimalControl.rounding);
1484     }
1485 
1486     ///ditto
1487     @IEEECompliant("convertToDecimalCharacter", 22)
1488     void toString(C)(scope void delegate(const(C)[]) sink) const
1489     if (isSomeChar!C)
1490     {
1491         sinkDecimal(singleSpec("%g"), sink, this, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1492     }
1493 
1494     ///Converts current value to string in floating point or scientific notation,
1495     ///which one is shorter.
1496     @IEEECompliant("convertToDecimalCharacter", 22)
1497     string toString() const
1498     {
1499         return decimalToString!char(this, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1500     }
1501 
1502     ///Converts current value to string according to the 
1503     ///format specification
1504     @IEEECompliant("convertToDecimalCharacter", 22)
1505     @IEEECompliant("convertToHexCharacter", 22)
1506     string toString(C)(FormatSpec!C fmt) const
1507     {
1508         return decimalToString!C(fmt, this, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1509     }
1510 
1511     ///ditto
1512     @IEEECompliant("convertToDecimalCharacter", 22)
1513     @IEEECompliant("convertToHexCharacter", 22)
1514     string toString(C)(const(C)[] fmt) const
1515     {
1516         FormatSpec!C spec = singleSpec(fmt);
1517         return decimalToString!C(spec, this, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1518     }
1519 
1520     } //!D_BetterC
1521 
1522     /**
1523     Returns a unique hash of the _decimal value suitable for use in a hash table.
1524     Notes:
1525        This function is not intended for direct use, it's provided as support for associative arrays.
1526     */
1527     @safe pure nothrow @nogc
1528     size_t toHash()
1529     {
1530         static if (bits == 32)
1531             return data;
1532         else static if (bits == 64)
1533         {
1534             static if (size_t.sizeof == uint.sizeof)
1535                 return cast(uint)data ^ cast(uint)(data >>> 32);
1536             else
1537                 return data;
1538         }
1539         else
1540         {
1541             static if (size_t.sizeof == uint.sizeof)
1542                 return cast(uint)data.hi ^ cast(uint)(data.hi >>> 32) ^
1543                        cast(uint)data.lo ^ cast(uint)(data.lo >>> 32);
1544             else
1545                 return data.hi ^ data.lo;
1546         }
1547     }
1548 }
1549 
1550 @("Compilation tests")
1551 unittest
1552 {
1553     struct DumbRange(C)
1554     {
1555         bool empty;
1556         C front;
1557         void popFront() {}
1558     }
1559 
1560     alias DecimalTypes = TypeTuple!(decimal32, decimal64, decimal128);
1561     alias IntegralTypes = TypeTuple!(byte, short, int, long, ubyte, ushort, uint, ulong);
1562     alias FloatTypes = TypeTuple!(float, double, real);
1563     alias CharTypes = TypeTuple!(char, wchar, dchar);
1564     alias StringTypes = TypeTuple!(string, wstring, dstring);
1565     alias RangeTypes = TypeTuple!(DumbRange!char, DumbRange!wchar, DumbRange!dchar);
1566 
1567     auto x = decimal128(real.nan);
1568 
1569     //constructors
1570     foreach (D; DecimalTypes)
1571     {
1572         foreach (T; DecimalTypes)
1573             static assert (is(typeof(D(T.init)) == D));
1574         foreach (T; IntegralTypes)
1575             static assert (is(typeof(D(T.init)) == D));
1576         foreach (T; FloatTypes)
1577             static assert (is(typeof(D(T.init)) == D));
1578         foreach (T; CharTypes)
1579             static assert (is(typeof(D(T.init)) == D));
1580         foreach (T; StringTypes)
1581             static assert (is(typeof(D(T.init)) == D));
1582         static assert (is(typeof(D(true)) == D));
1583     }
1584 
1585     //assignment
1586     foreach (D; DecimalTypes)
1587     {
1588         foreach (T; DecimalTypes)
1589             static assert (__traits(compiles, { D d = T.init; }));
1590         foreach (T; IntegralTypes)
1591             static assert (__traits(compiles, { D d = T.init; }));
1592         foreach (T; FloatTypes)
1593             static assert (__traits(compiles, { D d = T.init; }));
1594         foreach (T; CharTypes)
1595             static assert (__traits(compiles, { D d = T.init; }));
1596         foreach (T; StringTypes)
1597             static assert (__traits(compiles, { D d = T.init; }));
1598         static assert (__traits(compiles, { D d = true; }));
1599     }
1600 
1601     auto b = cast(float)decimal32();
1602     //cast
1603     foreach (D; DecimalTypes)
1604     {
1605         foreach (T; DecimalTypes)
1606             static assert (is(typeof(cast(T)(D.init)) == T));
1607         foreach (T; IntegralTypes)
1608             static assert (is(typeof(cast(T)(D.init)) == T));
1609         foreach (T; FloatTypes)
1610             static assert (is(typeof(cast(T)(D.init)) == T));
1611         foreach (T; CharTypes)
1612             static assert (is(typeof(cast(T)(D.init)) == T));
1613         static assert (is(typeof(cast(bool)(D.init)) == bool));
1614     }
1615 
1616 
1617     //unary ops
1618     foreach (D; DecimalTypes)
1619     {
1620         static assert(is(typeof(+D.init) == const D));
1621         static assert(is(typeof(-D.init) == D));
1622         static assert(is(typeof(++D.init) == D));
1623         static assert(is(typeof(--D.init) == D));
1624     }
1625 
1626 
1627     //equality
1628     foreach (D; DecimalTypes)
1629     {
1630         foreach (T; DecimalTypes)
1631             static assert (is(typeof(D.init == T.init) == bool));
1632         foreach (T; IntegralTypes)
1633             static assert (is(typeof(D.init == T.init) == bool));
1634         foreach (T; FloatTypes)
1635             static assert (is(typeof(D.init == T.init) == bool));
1636         foreach (T; CharTypes)
1637             static assert (is(typeof(D.init == T.init) == bool));
1638     }
1639 
1640     auto c = decimal128() > 0.0;
1641   
1642     //comparison
1643     foreach (D; DecimalTypes)
1644     {
1645         foreach (T; DecimalTypes)
1646             static assert (is(typeof(D.init > T.init) == bool));
1647         foreach (T; IntegralTypes)
1648             static assert (is(typeof(D.init > T.init) == bool));
1649         foreach (T; FloatTypes)
1650             static assert (is(typeof(D.init > T.init) == bool));
1651         foreach (T; CharTypes)
1652             static assert (is(typeof(D.init > T.init) == bool));
1653     }
1654 
1655     //binary left
1656     foreach (D; DecimalTypes)
1657     {
1658         foreach (T; DecimalTypes)
1659         {
1660             static assert (is(typeof(D.init + T.init) == CommonDecimal!(D, T)));
1661             static assert (is(typeof(D.init - T.init) == CommonDecimal!(D, T)));
1662             static assert (is(typeof(D.init * T.init) == CommonDecimal!(D, T)));
1663             static assert (is(typeof(D.init / T.init) == CommonDecimal!(D, T)));
1664             static assert (is(typeof(D.init % T.init) == CommonDecimal!(D, T)));
1665             static assert (is(typeof(D.init ^^ T.init) == CommonDecimal!(D, T)));
1666         }
1667 
1668         foreach (T; IntegralTypes)
1669         {
1670             static assert (is(typeof(D.init + T.init) == D));
1671             static assert (is(typeof(D.init - T.init) == D));
1672             static assert (is(typeof(D.init * T.init) == D));
1673             static assert (is(typeof(D.init / T.init) == D));
1674             static assert (is(typeof(D.init % T.init) == D));
1675             static assert (is(typeof(D.init ^^ T.init) == D));
1676         }
1677 
1678         auto z = decimal32.nan + float.nan;
1679 
1680         foreach (T; FloatTypes)
1681         {
1682             static assert (is(typeof(D.init + T.init) == D));
1683             static assert (is(typeof(D.init - T.init) == D));
1684             static assert (is(typeof(D.init * T.init) == D));
1685             static assert (is(typeof(D.init / T.init) == D));
1686             static assert (is(typeof(D.init % T.init) == D));
1687             static assert (is(typeof(D.init ^^ T.init) == D));
1688         }
1689 
1690         foreach (T; CharTypes)
1691         {
1692             static assert (is(typeof(D.init + T.init) == D));
1693             static assert (is(typeof(D.init - T.init) == D));
1694             static assert (is(typeof(D.init * T.init) == D));
1695             static assert (is(typeof(D.init / T.init) == D));
1696             static assert (is(typeof(D.init % T.init) == D));
1697             static assert (is(typeof(D.init ^^ T.init) == D));
1698         }
1699     }
1700 
1701     //binary right
1702     foreach (D; DecimalTypes)
1703     {
1704         foreach (T; DecimalTypes)
1705         {
1706             static assert (is(typeof(T.init + D.init) == CommonDecimal!(D, T)));
1707             static assert (is(typeof(T.init - D.init) == CommonDecimal!(D, T)));
1708             static assert (is(typeof(T.init * D.init) == CommonDecimal!(D, T)));
1709             static assert (is(typeof(T.init / D.init) == CommonDecimal!(D, T)));
1710             static assert (is(typeof(T.init % D.init) == CommonDecimal!(D, T)));
1711             static assert (is(typeof(T.init ^^ D.init) == CommonDecimal!(D, T)));
1712         }
1713 
1714 
1715         foreach (T; IntegralTypes)
1716         {
1717             static assert (is(typeof(T.init + D.init) == D));
1718             static assert (is(typeof(T.init - D.init) == D));
1719             static assert (is(typeof(T.init * D.init) == D));
1720             static assert (is(typeof(T.init / D.init) == D));
1721             static assert (is(typeof(T.init % D.init) == D));
1722             static assert (is(typeof(T.init ^^ D.init) == D));
1723         }
1724 
1725         foreach (T; FloatTypes)
1726         {
1727             static assert (is(typeof(T.init + D.init) == D));
1728             static assert (is(typeof(T.init - D.init) == D));
1729             static assert (is(typeof(T.init * D.init) == D));
1730             static assert (is(typeof(T.init / D.init) == D));
1731             static assert (is(typeof(T.init % D.init) == D));
1732             static assert (is(typeof(T.init ^^ D.init) == D));
1733         }
1734 
1735         foreach (T; CharTypes)
1736         {
1737             static assert (is(typeof(T.init + D.init) == D));
1738             static assert (is(typeof(T.init - D.init) == D));
1739             static assert (is(typeof(T.init * D.init) == D));
1740             static assert (is(typeof(T.init / D.init) == D));
1741             static assert (is(typeof(T.init % D.init) == D));
1742             static assert (is(typeof(T.init ^^ D.init) == D));
1743         }
1744     }
1745 
1746     //op assignment
1747     foreach (D; DecimalTypes)
1748     {
1749         foreach (T; DecimalTypes)
1750         {
1751             static assert (is(typeof(D.init += T.init) == D));
1752             static assert (is(typeof(D.init -= T.init) == D));
1753             static assert (is(typeof(D.init *= T.init) == D));
1754             static assert (is(typeof(D.init /= T.init) == D));
1755             static assert (is(typeof(D.init %= T.init) == D));
1756             static assert (is(typeof(D.init ^^= T.init) == D));
1757         }
1758 
1759         foreach (T; IntegralTypes)
1760         {
1761            static assert (is(typeof(D.init += T.init) == D));
1762             static assert (is(typeof(D.init -= T.init) == D));
1763             static assert (is(typeof(D.init *= T.init) == D));
1764             static assert (is(typeof(D.init /= T.init) == D));
1765             static assert (is(typeof(D.init %= T.init) == D));
1766             static assert (is(typeof(D.init ^^= T.init) == D));
1767         }
1768 
1769         foreach (T; FloatTypes)
1770         {
1771             static assert (is(typeof(D.init += T.init) == D));
1772             static assert (is(typeof(D.init -= T.init) == D));
1773             static assert (is(typeof(D.init *= T.init) == D));
1774             static assert (is(typeof(D.init /= T.init) == D));
1775             static assert (is(typeof(D.init %= T.init) == D));
1776             static assert (is(typeof(D.init ^^= T.init) == D));
1777         }
1778 
1779         foreach (T; CharTypes)
1780         {
1781             static assert (is(typeof(D.init += T.init) == D));
1782             static assert (is(typeof(D.init -= T.init) == D));
1783             static assert (is(typeof(D.init *= T.init) == D));
1784             static assert (is(typeof(D.init /= T.init) == D));
1785             static assert (is(typeof(D.init %= T.init) == D));
1786             static assert (is(typeof(D.init ^^= T.init) == D));
1787         }
1788     }
1789 
1790     //expected constants
1791     foreach (D; DecimalTypes)
1792     {
1793         static assert (is(typeof(D.init) == D));
1794         static assert (is(typeof(D.nan) == D));
1795         static assert (is(typeof(D.infinity) == D));
1796         static assert (is(typeof(D.max) == D));
1797         static assert (is(typeof(D.min_normal) == D));
1798         static assert (is(typeof(D.epsilon) == D));
1799         static assert (is(typeof(D.dig) == int));
1800         static assert (is(typeof(D.mant_dig) == int));
1801         static assert (is(typeof(D.min_10_exp) == int));
1802         static assert (is(typeof(D.max_10_exp) == int));
1803         static assert (is(typeof(D.min_exp) == int));
1804         static assert (is(typeof(D.max_exp) == int));
1805 
1806         static assert (is(typeof(D.E) == D));
1807         static assert (is(typeof(D.PI) == D));
1808         static assert (is(typeof(D.PI_2) == D));
1809         static assert (is(typeof(D.PI_4) == D));
1810         static assert (is(typeof(D.M_1_PI) == D));
1811         static assert (is(typeof(D.M_2_PI) == D));
1812         static assert (is(typeof(D.M_2_SQRTPI) == D));
1813         static assert (is(typeof(D.LN10) == D));
1814         static assert (is(typeof(D.LN2) == D));
1815         static assert (is(typeof(D.LOG2) == D));
1816         static assert (is(typeof(D.LOG2E) == D));
1817         static assert (is(typeof(D.LOG2T) == D));
1818         static assert (is(typeof(D.LOG10E) == D));
1819         static assert (is(typeof(D.SQRT2) == D));
1820         static assert (is(typeof(D.SQRT1_2) == D));
1821     }
1822 
1823     //expected members
1824     foreach (D; DecimalTypes)
1825     {
1826         static assert (is(typeof(D.init.toHash()) == size_t));
1827         static assert (is(typeof(D.init.toString()) == string));
1828     }
1829 }
1830 
1831 
1832 
1833 @("Decimal should support decimal + float")
1834 unittest
1835 {
1836     immutable expected = decimal128("2");
1837 
1838     auto sut = decimal128("1");
1839     auto result = sut + 1.0f;
1840 
1841     assert(expected == result);
1842 }
1843 
1844 @("Decimal should support decimal - float")
1845 unittest
1846 {
1847     immutable expected = decimal128("5");
1848 
1849     auto sut = decimal128("9");
1850     auto result = sut - 4.0f;
1851 
1852     assert(expected == result);
1853 }
1854 
1855 @("Decimal should support decimal * float")
1856 unittest
1857 {
1858     immutable expected = decimal128("13.3");
1859 
1860     auto sut = decimal128("1.33");
1861     auto result = sut * 10.0f;
1862 
1863     assert(expected == result);
1864 }
1865 
1866 @("Decimal should support decimal / float")
1867 unittest
1868 {
1869     immutable expected = decimal128("0.5");
1870 
1871     auto sut = decimal128("1");
1872     auto result = sut / 2.0f;
1873 
1874     assert(expected == result);
1875 }
1876 
1877 @("Decimal should support decimal % float")
1878 unittest
1879 {
1880     immutable expected = decimal128("1");
1881 
1882     auto sut = decimal128("10");
1883     auto result = sut % 3.0f;
1884 
1885     assert(expected == result);
1886 }
1887 
1888 
1889 @("Decimal should support decimal + integral")
1890 unittest
1891 {
1892     immutable expected = decimal128("3");
1893 
1894     auto sut = decimal128("2");
1895     auto result = sut + 1;
1896 
1897     assert(expected == result);
1898 }
1899 
1900 @("Decimal should support decimal - integral")
1901 unittest
1902 {
1903     immutable expected = decimal128("1");
1904 
1905     auto sut = decimal128("3");
1906     auto result = sut - 2;
1907 
1908     assert(expected == result);
1909 }
1910 
1911 @("Decimal should support decimal * integral")
1912 unittest
1913 {
1914     immutable expected = decimal128("123.4");
1915 
1916     auto sut = decimal128("12.34");
1917     auto result = sut * 10;
1918 
1919     assert(expected == result);
1920 }
1921 
1922 @("Decimal should support decimal / integral")
1923 unittest
1924 {
1925     immutable expected = decimal128("0.5");
1926 
1927     auto sut = decimal128("1");
1928     auto result = sut / 2;
1929 
1930     assert(expected == result);
1931 }
1932 
1933 @("Decimal should support decimal % integral")
1934 unittest
1935 {
1936     immutable expected = decimal128("1");
1937 
1938     auto sut = decimal128("10");
1939     auto result = sut % 3;
1940 
1941     assert(expected == result);
1942 }
1943 
1944 @("Decimal should support decimal % unsigned integral")
1945 unittest
1946 {
1947     immutable expected = decimal128("1");
1948 
1949     auto sut = decimal128("10");
1950     auto result = sut % 3u;
1951 
1952     assert(expected == result);
1953 }
1954 
1955 ///Shorthand notations for $(MYREF Decimal) types
1956 alias decimal32 = Decimal!32;
1957 ///ditto
1958 alias decimal64 = Decimal!64;
1959 ///ditto
1960 alias decimal128 = Decimal!128;
1961 
1962 
1963 ///Returns true if all specified types are _decimal types.
1964 template isDecimal(D...)
1965 {
1966     static if (D.length == 0)
1967         enum isDecimal = false;
1968     static if (D.length == 1)
1969         enum isDecimal = is(D[0] == decimal32) || is(D[0] == decimal64) || is(D[0] == decimal128);
1970     else
1971         enum isDecimal = isDecimal!(D[0]) && isDecimal!(D[1 .. $]);
1972 }
1973 
1974 ///
1975 unittest
1976 {
1977     static assert(isDecimal!decimal32);
1978     static assert(isDecimal!(decimal32, decimal64));
1979     static assert(!isDecimal!int);
1980     static assert(!isDecimal!(decimal128, byte));
1981 }
1982 
1983 ///Returns the most wide _decimal type among the specified types
1984 template CommonDecimal(T...) if (isDecimal!T)
1985 {
1986     static if (T.length == 1)
1987         alias CommonDecimal = T[0];
1988     else static if (is(T[0] == decimal128) || is(T[1] == decimal128))
1989         alias CommonDecimal = decimal128;
1990     else static if (T.length == 2)
1991     {
1992         static if (is(T[0] == decimal32))
1993             alias CommonDecimal = T[1];
1994         else static if (is(T[1] == decimal32))
1995             alias CommonDecimal = T[0];
1996         else static if (is(T[0] == decimal64) && is(T[1] == decimal128))
1997             alias CommonDecimal = decimal128;
1998         else static if (is(T[1] == decimal64) && is(T[0] == decimal128))
1999             alias CommonDecimal = decimal128;
2000         else static if (is(T[1] == T[0]))
2001             alias CommonDecimal = T[0];
2002         else
2003             static assert(false, "Never happen");
2004     }
2005     else
2006         alias CommonDecimal = CommonDecimal!(CommonDecimal!(T[0 .. 1], CommonDecimal!(T[2 .. $])));
2007 }
2008 
2009 ///
2010 unittest
2011 {
2012     static assert(is(CommonDecimal!(decimal32, decimal64) == decimal64));
2013     static assert(is(CommonDecimal!(decimal32, decimal128) == decimal128));
2014     static assert(is(CommonDecimal!(decimal64, decimal128) == decimal128));
2015 }
2016 
2017 version(D_BetterC) 
2018 {
2019 
2020 }
2021 else 
2022 {
2023 
2024     ///Root object for all _decimal exceptions
2025     abstract class DecimalException : Exception
2026     {
2027         mixin ExceptionConstructors;
2028     }
2029 
2030     ///Thrown if any operand of a _decimal operation is not a number or si not finite
2031     class InvalidOperationException : DecimalException
2032     {
2033 	    mixin ExceptionConstructors;
2034     }
2035 
2036     ///Thrown if the denominator of a _decimal division operation is zero. 
2037     class DivisionByZeroException : DecimalException
2038     {
2039 	    mixin ExceptionConstructors;
2040     }
2041 
2042     ///Thrown if the result of a _decimal operation exceeds the largest finite number of the destination format. 
2043     class OverflowException : DecimalException
2044     {
2045 	    mixin ExceptionConstructors;
2046     }
2047 
2048     ///Thrown if the result of a _decimal operation is smaller the smallest finite number of the destination format. 
2049     class UnderflowException : DecimalException
2050     {
2051 	    mixin ExceptionConstructors;
2052     }
2053 
2054     ///Thrown if the result of a _decimal operation was rounded to fit in the destination format. 
2055     class InexactException : DecimalException
2056     {
2057 	    mixin ExceptionConstructors;
2058     }
2059 } 
2060 /**
2061 These flags indicate that an error has occurred. They indicate that a 0, $(B NaN) or an infinity value has been generated, 
2062 that a result is inexact, or that a signalling $(B NaN) has been encountered. 
2063 If the corresponding traps are set using $(MYREF DecimalControl), 
2064 an exception will be thrown after setting these error flags.
2065 
2066 By default the context will have all error flags lowered and exceptions are thrown only for severe errors.
2067 */
2068 enum ExceptionFlags : uint
2069 {
2070     ///no error
2071     none             = 0U,
2072     ///$(MYREF InvalidOperationException) is thrown if trap is set
2073 	invalidOperation = 1U << 0,
2074     ///$(MYREF DivisionByZeroException) is thrown if trap is set
2075 	divisionByZero   = 1U << 1,
2076     ///$(MYREF OverflowException) is thrown if trap is set
2077 	overflow         = 1U << 2,
2078     ///$(MYREF UnderflowException) is thrown if trap is set
2079 	underflow        = 1U << 3,
2080     ///$(MYREF InexactException) is thrown if trap is set
2081 	inexact          = 1U << 4,
2082     ///group of errors considered severe: invalidOperation, divisionByZero, overflow
2083 	severe           = invalidOperation | divisionByZero | overflow,
2084     ///all errors
2085 	all              = severe | underflow | inexact
2086 }
2087 
2088 /**
2089 * Rounding modes. To better understand how rounding is performed, consult the table below. 
2090 *
2091 * $(BOOKTABLE,
2092 *  $(TR $(TH Value) $(TH tiesToEven) $(TH tiesToAway) $(TH towardPositive) $(TH towardNegative) $(TH towardZero)) 
2093 *  $(TR $(TD +1.3)  $(TD +1)         $(TD +1)         $(TD +2)             $(TD +1)             $(TD +1))
2094 *  $(TR $(TD +1.5)  $(TD +2)         $(TD +2)         $(TD +2)             $(TD +1)             $(TD +1))
2095 *  $(TR $(TD +1.8)  $(TD +2)         $(TD +2)         $(TD +2)             $(TD +1)             $(TD +1))
2096 *  $(TR $(TD -1.3)  $(TD -1)         $(TD -1)         $(TD -1)             $(TD -2)             $(TD -1)) 
2097 *  $(TR $(TD -1.5)  $(TD -2)         $(TD -2)         $(TD -1)             $(TD -2)             $(TD -1)) 
2098 *  $(TR $(TD -1.8)  $(TD -2)         $(TD -2)         $(TD -1)             $(TD -2)             $(TD -1)) 
2099 *  $(TR $(TD +2.3)  $(TD +2)         $(TD +2)         $(TD +3)             $(TD +2)             $(TD +2)) 
2100 *  $(TR $(TD +2.5)  $(TD +2)         $(TD +3)         $(TD +3)             $(TD +2)             $(TD +2)) 
2101 *  $(TR $(TD +2.8)  $(TD +3)         $(TD +3)         $(TD +3)             $(TD +2)             $(TD +2)) 
2102 *  $(TR $(TD -2.3)  $(TD -2)         $(TD -2)         $(TD -2)             $(TD -3)             $(TD -2)) 
2103 *  $(TR $(TD -2.5)  $(TD -2)         $(TD -3)         $(TD -2)             $(TD -3)             $(TD -2)) 
2104 *  $(TR $(TD -2.8)  $(TD -3)         $(TD -3)         $(TD -2)             $(TD -3)             $(TD -2)) 
2105 * )  
2106 */
2107 enum RoundingMode
2108 {
2109     ///rounded away from zero; halfs are rounded to the nearest even number
2110 	tiesToEven,
2111     ///rounded away from zero
2112 	tiesToAway,
2113     ///truncated toward positive infinity
2114 	towardPositive,
2115     ///truncated toward negative infinity
2116 	towardNegative,
2117     ///truncated toward zero
2118 	towardZero,
2119 
2120     implicit = tiesToEven,
2121 }
2122 
2123 /**
2124 _Precision used to round _decimal operation results. Every result will be adjusted
2125 to fit the specified precision. Use $(MYREF DecimalControl) to query or set the 
2126 context precision
2127 */
2128 alias Precision = uint;
2129 ///ditto
2130 enum : Precision
2131 {
2132     ///use the default precision of the current type 
2133     ///(7 digits for decimal32, 16 digits for decimal64 or 34 digits for decimal128)
2134 	precisionDefault = 0,
2135     ///use 32 bits precision (7 digits)
2136 	precision32 = Decimal!32.PRECISION,
2137     ///use 64 bits precision (16 digits)
2138 	precision64 = Decimal!64.PRECISION,
2139     ////use 128 bits precision (34 digits)
2140     precision128 = Decimal!128.PRECISION,
2141 }
2142 
2143 /**
2144     Container for _decimal context control, provides methods to alter exception handling,
2145     manually edit error flags, adjust arithmetic precision and rounding mode
2146 */
2147 struct DecimalControl
2148 {
2149 private:
2150 	static ExceptionFlags flags;
2151 	static ExceptionFlags traps;
2152 
2153     @safe
2154     static void checkFlags(const ExceptionFlags group, const ExceptionFlags traps)
2155     {
2156         version(D_BetterC) 
2157         {
2158             if (__ctfe)
2159             {
2160                 if ((group & ExceptionFlags.invalidOperation) && (traps & ExceptionFlags.invalidOperation))
2161                     assert(0, "Invalid operation");
2162                 if ((group & ExceptionFlags.divisionByZero) && (traps & ExceptionFlags.divisionByZero))
2163                     assert(0, "Division by zero");
2164                 if ((group & ExceptionFlags.overflow) && (traps & ExceptionFlags.overflow))
2165                     assert(0, "Overflow");
2166             }
2167         }
2168         else 
2169         {
2170             if ((group & ExceptionFlags.invalidOperation) && (traps & ExceptionFlags.invalidOperation))
2171                 throw new InvalidOperationException("Invalid operation");
2172             if ((group & ExceptionFlags.divisionByZero) && (traps & ExceptionFlags.divisionByZero))
2173                 throw new DivisionByZeroException("Division by zero");
2174             if ((group & ExceptionFlags.overflow) && (traps & ExceptionFlags.overflow))
2175                 throw new OverflowException("Overflow");
2176             if ((group & ExceptionFlags.underflow) && (traps & ExceptionFlags.underflow))
2177                 throw new UnderflowException("Underflow");
2178             if ((group & ExceptionFlags.inexact) && (traps & ExceptionFlags.inexact))
2179                 throw new InexactException("Inexact");
2180         }
2181 
2182     }
2183 
2184 public:
2185 
2186     /**
2187     Gets or sets the rounding mode used when the result of an operation exceeds the _decimal precision.
2188     See $(MYREF RoundingMode) for details.
2189     ---
2190     DecimalControl.rounding = RoundingMode.tiesToEven;
2191     decimal32 d1 = 123456789;
2192     assert(d1 == 123456800);
2193 
2194     DecimalControl.rounding = RoundingMode.towardNegative;
2195     decimal32 d2 = 123456789;
2196     assert(d2 == 123456700);
2197     ---
2198     */
2199     @IEEECompliant("defaultModes", 46)
2200     @IEEECompliant("getDecimalRoundingDirection", 46)
2201     @IEEECompliant("restoreModes", 46)
2202     @IEEECompliant("saveModes", 46)
2203     @IEEECompliant("setDecimalRoundingDirection", 46)
2204     static RoundingMode rounding;
2205 
2206     /**
2207     Gets or sets the precision applied to peration results.
2208     See $(MYREF Precision) for details.
2209     ---
2210     DecimalControl.precision = precisionDefault;
2211     decimal32 d1 = 12345;
2212     assert(d1 == 12345);
2213     
2214     DecimalControl.precision = 4;
2215     decimal32 d2 = 12345;
2216     assert(d2 == 12350);
2217     ---
2218     */
2219     static Precision precision;
2220 
2221     /**
2222     Sets specified error flags. Multiple errors may be ORed together.
2223     ---
2224     DecimalControl.raiseFlags(ExceptionFlags.overflow | ExceptionFlags.underflow);
2225     assert (DecimalControl.overflow);
2226     assert (DecimalControl.underflow);
2227     ---
2228 	*/
2229     @IEEECompliant("raiseFlags", 26)
2230 	@safe
2231 	static void raiseFlags(const ExceptionFlags group)
2232 	{
2233         if (__ctfe)
2234             checkFlags(group, ExceptionFlags.severe);
2235         else
2236         {
2237             ExceptionFlags newFlags = flags ^ (group & ExceptionFlags.all);
2238             flags |= group & ExceptionFlags.all;
2239 		    checkFlags(newFlags, traps);
2240         }
2241 	}
2242 
2243     /**
2244     Unsets specified error flags. Multiple errors may be ORed together.
2245     ---
2246     DecimalControl.resetFlags(ExceptionFlags.inexact);
2247     assert(!DecimalControl.inexact);
2248     ---
2249 	*/
2250     @IEEECompliant("lowerFlags", 26)
2251     @nogc @safe nothrow
2252 	static void resetFlags(const ExceptionFlags group)
2253 	{
2254 		flags &= ~(group & ExceptionFlags.all);
2255 	}
2256 
2257     ///ditto
2258     @IEEECompliant("lowerFlags", 26)
2259     @nogc @safe nothrow
2260 	static void resetFlags()
2261 	{
2262 		flags = ExceptionFlags.none;
2263 	}
2264 
2265     /**
2266     Enables specified error flags (group) without throwing corresponding exceptions.
2267     ---
2268     DecimalControl.restoreFlags(ExceptionFlags.underflow | ExceptionsFlags.inexact);
2269     assert (DecimalControl.testFlags(ExceptionFlags.underflow | ExceptionFlags.inexact));
2270     ---
2271 	*/
2272     @IEEECompliant("restoreFlags", 26)
2273 	@nogc @safe nothrow
2274 	static void restoreFlags(const ExceptionFlags group)
2275 	{
2276 		flags |= group & ExceptionFlags.all;
2277 	}
2278 
2279     /**
2280     Checks if the specified error flags are set. Multiple exceptions may be ORed together.
2281     ---
2282     DecimalControl.raiseFlags(ExceptionFlags.overflow | ExceptionFlags.underflow | ExceptionFlags.inexact);
2283     assert (DecimalControl.hasFlags(ExceptionFlags.overflow | ExceptionFlags.inexact));
2284     ---
2285 	*/
2286     @IEEECompliant("testFlags", 26)
2287     @IEEECompliant("testSavedFlags", 26)
2288 	@nogc @safe nothrow
2289 	static bool hasFlags(const ExceptionFlags group)
2290 	{
2291 		return (flags & (group & ExceptionFlags.all)) != 0;
2292 	}
2293 
2294 
2295      /**
2296     Returns the current set flags.
2297     ---
2298     DecimalControl.restoreFlags(ExceptionFlags.inexact);
2299     assert (DecimalControl.saveFlags() & ExceptionFlags.inexact);
2300     ---
2301 	*/
2302     @IEEECompliant("saveAllFlags", 26)
2303 	@nogc @safe nothrow
2304 	static ExceptionFlags saveFlags()
2305 	{
2306 		return flags;
2307 	}
2308 
2309     /**
2310     Disables specified exceptions. Multiple exceptions may be ORed together.
2311     ---
2312     DecimalControl.disableExceptions(ExceptionFlags.overflow);
2313     auto d = decimal64.max * decimal64.max;
2314     assert (DecimalControl.overflow);
2315     assert (isInfinity(d));
2316     ---
2317 	*/
2318 	@nogc @safe nothrow
2319 	static void disableExceptions(const ExceptionFlags group)
2320 	{
2321 		traps &= ~(group & ExceptionFlags.all);
2322 	}
2323 
2324     ///ditto
2325     @nogc @safe nothrow
2326 	static void disableExceptions()
2327 	{
2328 		traps = ExceptionFlags.none;
2329 	}
2330 
2331     
2332 
2333     /**
2334     Enables specified exceptions. Multiple exceptions may be ORed together.
2335     ---
2336     DecimalControl.enableExceptions(ExceptionFlags.overflow);
2337     try
2338     {
2339         auto d = decimal64.max * 2;
2340     }
2341     catch (OverflowException)
2342     {
2343         writeln("Overflow error")
2344     }
2345     ---
2346 	*/
2347 	@nogc @safe nothrow
2348 	static void enableExceptions(const ExceptionFlags group)
2349 	{
2350 		traps |= group & ExceptionFlags.all;
2351 	}  
2352 
2353     /**
2354     Extracts current enabled exceptions.
2355     ---
2356     auto saved = DecimalControl.enabledExceptions;
2357     DecimalControl.disableExceptions(ExceptionFlags.all);
2358     DecimalControl.enableExceptions(saved);
2359     ---
2360 	*/
2361 	@nogc @safe nothrow
2362 	static @property ExceptionFlags enabledExceptions()
2363 	{
2364 		return traps;
2365 	}
2366 
2367     /**
2368     IEEE _decimal context errors. By default, no error is set.
2369     ---
2370     DecimalControl.disableExceptions(ExceptionFlags.all);
2371     decimal32 uninitialized;
2372     decimal64 d = decimal64.max * 2;
2373     decimal32 e = uninitialized + 5.0;
2374     assert(DecimalControl.overflow);
2375     assert(DecimalControl.invalidOperation);
2376     ---
2377     */
2378 	@nogc @safe nothrow
2379 	static @property bool invalidOperation()
2380 	{
2381 		return (flags & ExceptionFlags.invalidOperation) != 0;
2382 	}
2383 
2384     ///ditto
2385 	@nogc @safe nothrow
2386 	static @property bool divisionByZero()
2387 	{
2388 		return (flags & ExceptionFlags.divisionByZero) != 0;
2389 	}
2390 
2391     ///ditto
2392 	@nogc @safe nothrow
2393 	static @property bool overflow()
2394 	{
2395 		return (flags & ExceptionFlags.overflow) != 0;
2396 	}
2397 
2398     ///ditto
2399 	@nogc @safe nothrow
2400 	static @property bool underflow()
2401 	{
2402 		return (flags & ExceptionFlags.underflow) != 0;
2403 	}
2404 
2405     ///ditto
2406 	@nogc @safe nothrow
2407 	static @property bool inexact()
2408 	{
2409 		return (flags & ExceptionFlags.inexact) != 0;
2410 	}
2411 
2412     ///true if this programming environment conforms to IEEE 754-1985
2413     @IEEECompliant("is754version1985", 24)
2414     enum is754version1985 = true;
2415 
2416     ///true if this programming environment conforms to IEEE 754-2008
2417     @IEEECompliant("is754version2008", 24)
2418     enum is754version2008 = true;
2419 }
2420 
2421 
2422 /**
2423 Calculates the arc cosine of x, returning a value ranging from 0 to π.
2424 Exceptions:
2425 $(BOOKTABLE,
2426     $(TR $(TD $(MYREF InvalidOperationException)) 
2427          $(TD x is signaling $(B NaN) or |x| > 1.0))
2428     $(TR $(TD $(MYREF InexactException)) 
2429          $(TD the result is inexact))
2430 )
2431 Special_values:
2432 $(BOOKTABLE,
2433     $(TR $(TH x) $(TH acos(x)))
2434     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
2435     $(TR $(TD -1.0) $(TD π))
2436     $(TR $(TD +1.0) $(TD +0.0))
2437     $(TR $(TD < -1.0) $(TD $(B NaN)))
2438     $(TR $(TD > +1.0) $(TD $(B NaN)))
2439 )
2440 */
2441 @IEEECompliant("acos", 43)
2442 D acos(D)(auto const ref D x)
2443 if (isDecimal!D)
2444 {
2445     Unqual!D result = x;
2446     auto flags = decimalAcos(result, 
2447                              __ctfe ? D.PRECISION : DecimalControl.precision, 
2448                              __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
2449     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation);
2450     DecimalControl.raiseFlags(flags);
2451     return result;
2452 }
2453 
2454 ///
2455 unittest
2456 {
2457     decimal32 x = 0;
2458     assert(acos(x) == decimal32.PI_2);
2459 }
2460 
2461 unittest
2462 {
2463     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
2464     {
2465         assert (acos(-T.one) == T.PI);
2466         assert (acos(T.one) == 0);
2467         assert (acos(T.zero) == T.PI_2);
2468         assert (isNaN(acos(T.nan)));
2469     }
2470 }
2471 
2472 /**
2473 Calculates the inverse hyperbolic cosine of x
2474 Exceptions:
2475 $(BOOKTABLE,
2476     $(TR $(TD $(MYREF InvalidOperationException)) 
2477          $(TD x is signaling $(B NaN) or x < 1.0))
2478     $(TR $(TD $(MYREF InexactException)) 
2479          $(TD the result is inexact))
2480 )
2481 Special_values:
2482 $(BOOKTABLE,
2483     $(TR $(TH x) $(TH acosh(x)))
2484     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
2485     $(TR $(TD +1.0) $(TD +0.0))
2486     $(TR $(TD +∞) $(TD +∞))
2487     $(TR $(TD < 1.0) $(TD $(B NaN)))
2488 )
2489 */
2490 @IEEECompliant("acosh", 43)
2491 D acosh(D)(auto const ref D x)
2492 if (isDecimal!D)
2493 {
2494     Unqual!D result = x;
2495     auto flags = decimalAcosh(result, 
2496                              __ctfe ? D.PRECISION : DecimalControl.precision, 
2497                              __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
2498     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation);
2499     DecimalControl.raiseFlags(flags);
2500     return result;
2501 }
2502 
2503 ///
2504 unittest
2505 {
2506     decimal32 x = 1;
2507     assert (acosh(x) == 0);
2508 }
2509 
2510 unittest
2511 {
2512     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
2513     {
2514         assert (acosh(T.one) == T.zero);
2515         assert (acosh(T.infinity) == T.infinity);
2516         assert (isNaN(acosh(T.nan)));
2517     }
2518 }
2519 
2520 
2521 /**
2522 Computes whether two values are approximately equal, admitting a maximum relative difference, 
2523 or a maximum absolute difference.
2524 Params:
2525     x = First item to compare
2526     y = Second item to compare
2527     maxRelDiff = Maximum allowable relative difference (defaults to 1e-5)
2528     maxAbsDiff = Maximum allowable absolute difference (defaults to 1e-2)
2529 Returns:
2530     true if the two items are approximately equal under either criterium.
2531 Notes:
2532     This operation is silent, does not throw any exceptions and it doesn't set any error flags.
2533 */
2534 bool approxEqual(D1, D2, D3, D4)(auto const ref D1 x, auto const ref D2 y,
2535                                  auto const ref D3 maxRelDiff, 
2536                                  auto const ref D4 maxAbsDiff)
2537 if (isDecimal!(D1, D2, D3, D4))
2538 {
2539     if (isInfinity(x) && isInfinity(y))
2540         return signbit(x) == signbit(y);
2541     else
2542     {
2543         alias D = CommonDecimal!(D1, D2, D3, D4);
2544         D d;
2545         decimalToDecimal(x, d, D.PRECISION, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
2546         decimalSub(d, y, D.PRECISION, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
2547         d = fabs(d);
2548         if (decimalCmp(maxAbsDiff, d) >= 0)
2549             return true;
2550         decimalDiv(d, y, D.PRECISION, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
2551         if (decimalCmp(maxRelDiff, d) >= 0)
2552             return true;
2553     }
2554     return false;
2555 }
2556 
2557 ///ditto
2558 bool approxEqual(D1, D2, D3)(auto const ref D1 x, auto const ref D2 y,
2559                                  auto const ref D3 maxRelDiff)
2560 if (isDecimal!(D1, D2, D3))
2561 {
2562     enum maxAbsDiff = CommonDecimal!(D1, D2, D3)("1e-5");
2563     return approxEqual(x, y, maxRelDiff, maxAbsDiff);
2564 }
2565 
2566 ///ditto
2567 bool approxEqual(D1, D2)(auto const ref D1 x, auto const ref D2 y)
2568 if (isDecimal!(D1, D2))
2569 {
2570     enum maxAbsDiff = CommonDecimal!(D1, D2)("1e-5");
2571     enum maxRelDiff = CommonDecimal!(D1, D2)("1e-2");
2572     return approxEqual(x, y, maxRelDiff, maxAbsDiff);
2573 }
2574 
2575 
2576 
2577 /**
2578 Calculates the arc sine of x, returning a value ranging from -π/2 to +π/2.
2579 Exceptions:
2580 $(BOOKTABLE,
2581     $(TR $(TD $(MYREF InvalidOperationException)) 
2582          $(TD x is signaling $(B NaN) or |x| > 1.0))
2583     $(TR $(TD $(MYREF InexactException)) 
2584          $(TD the result is inexact))
2585 )
2586 Special_values:
2587 $(BOOKTABLE,
2588     $(TR $(TH x) $(TH asin(x)))
2589     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
2590     $(TR $(TD -1.0) $(TD -π/2))
2591     $(TR $(TD +1.0) $(TD +π/2))
2592     $(TR $(TD < -1.0) $(TD $(B NaN)))
2593     $(TR $(TD > +1.0) $(TD $(B NaN)))
2594 )
2595 */
2596 @IEEECompliant("asin", 43)
2597 D asin(D)(auto const ref D x)
2598 if (isDecimal!D)
2599 {
2600     Unqual!D result = x;
2601     auto flags = decimalAsin(result, 
2602                               __ctfe ? D.PRECISION : DecimalControl.precision, 
2603                               __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
2604     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation);
2605     DecimalControl.raiseFlags(flags);
2606     return result;
2607 }
2608 
2609 ///
2610 unittest
2611 {
2612     decimal32 x = 1;
2613     assert(asin(x) == decimal32.PI_2);
2614     assert(asin(-x) == -decimal32.PI_2);
2615 }
2616 
2617 unittest
2618 {
2619     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
2620     {
2621         assert (asin(-T.one) == -T.PI_2);
2622         assert (asin(T.zero) == 0);
2623         assert (asin(T.one) == T.PI_2);
2624         assert (isNaN(asin(T.nan)));
2625     }
2626 }
2627 
2628 
2629 /**
2630 Calculates the inverse hyperbolic sine of x
2631 Exceptions:
2632 $(BOOKTABLE,
2633     $(TR $(TD $(MYREF InvalidOperationException)) 
2634          $(TD x is signaling $(B NaN)))
2635     $(TR $(TD $(MYREF UnderflowException)) 
2636          $(TD the result is too small to be represented))
2637     $(TR $(TD $(MYREF InexactException)) 
2638          $(TD the result is inexact))
2639 )
2640 Special_values:
2641 $(BOOKTABLE,
2642     $(TR $(TH x) $(TH asinh(x)))
2643     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
2644     $(TR $(TD ±0.0) $(TD ±0.0))
2645     $(TR $(TD ±∞) $(TD ±∞))
2646 )
2647 */
2648 @IEEECompliant("asinh", 43)
2649 D asinh(D)(auto const ref D x)
2650 if (isDecimal!D)
2651 {
2652     Unqual!D result = x;
2653     auto flags = decimalAsinh(result, 
2654                              __ctfe ? D.PRECISION : DecimalControl.precision, 
2655                              __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
2656     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.underflow);
2657     DecimalControl.raiseFlags(flags);
2658     return result;
2659 }
2660 
2661 ///
2662 unittest
2663 {
2664     decimal32 x = 0;
2665     assert (asinh(x) == 0);
2666 }
2667 
2668 unittest
2669 {
2670     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
2671     {
2672         assert (asinh(T.zero) == T.zero);
2673         assert (asinh(T.infinity) == T.infinity);
2674         assert (isNaN(asinh(T.nan)));
2675     }
2676 }
2677 
2678 
2679 
2680 /**
2681 Calculates the arc tangent of x, returning a value ranging from -π/2 to π/2.
2682 Exceptions:
2683 $(BOOKTABLE,
2684     $(TR $(TD $(MYREF InvalidOperationException)) 
2685          $(TD x is signaling $(B NaN)))
2686     $(TR $(TD $(MYREF InexactException)) 
2687          $(TD the result is inexact))
2688     $(TR $(TD $(MYREF UnderflowException)) 
2689          $(TD the result is too small to be represented))
2690 )
2691 Special_values:
2692 $(BOOKTABLE,
2693     $(TR $(TH x) $(TH atan(x)))
2694     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
2695     $(TR $(TD ±0.0) $(TD ±0.0))
2696     $(TR $(TD ±∞) $(TD ±π/2))
2697 )
2698 */
2699 @IEEECompliant("atan", 43)
2700 D atan(D)(auto const ref D x)
2701 if (isDecimal!D)
2702 {
2703     Unqual!D result = x;
2704     auto flags = decimalAtan(result, 
2705                              __ctfe ? D.PRECISION : DecimalControl.precision, 
2706                              __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
2707     flags &= ExceptionFlags.invalidOperation | ExceptionFlags.underflow | ExceptionFlags.inexact;
2708     DecimalControl.raiseFlags(flags);
2709     return result;
2710 }
2711 
2712 ///
2713 unittest
2714 {
2715     decimal32 radians = 1;
2716     assert(atan(radians) == decimal32.PI_4);
2717 }
2718 
2719 
2720 unittest
2721 {
2722     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
2723     {
2724         assert (isIdentical(atan(T.zero), T.zero));
2725         assert (isIdentical(atan(-T.zero), -T.zero));
2726         assert (isIdentical(atan(T.infinity), T.PI_2));
2727         assert (isIdentical(atan(-T.infinity), -T.PI_2));
2728         assert (isNaN(atan(T.nan)));
2729     }
2730 }
2731 
2732 /**
2733 Calculates the arc tangent of y / x, returning a value ranging from -π to π.
2734 Exceptions:
2735 $(BOOKTABLE,
2736     $(TR $(TD $(MYREF InvalidOperationException)) 
2737          $(TD x or y is signaling $(B NaN)))
2738     $(TR $(TD $(MYREF InexactException)) 
2739          $(TD the result is inexact))
2740     $(TR $(TD $(MYREF UnderflowException)) 
2741          $(TD the result is too small to be represented))
2742 )
2743 Special_values:
2744 $(BOOKTABLE,
2745     $(TR $(TH y) $(TH x) $(TH atan2(y, x)))
2746     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
2747     $(TR $(TD any) $(TD $(B NaN)) $(TD $(B NaN)))
2748     $(TR $(TD ±0.0) $(TD -0.0) $(TD ±π))
2749     $(TR $(TD ±0.0) $(TD +0.0) $(TD ±0.0))
2750     $(TR $(TD ±0.0) $(TD <0.0) $(TD ±π))
2751     $(TR $(TD ±0.0) $(TD >0.0) $(TD ±0.0))
2752     $(TR $(TD ±∞) $(TD -∞) $(TD ±3π/4))
2753     $(TR $(TD ±∞) $(TD +∞) $(TD ±π/4))
2754     $(TR $(TD ±∞) $(TD any) $(TD ±π/2))
2755     $(TR $(TD any) $(TD -∞) $(TD ±π))
2756     $(TR $(TD any) $(TD +∞) $(TD ±0.0))
2757 )
2758 */
2759 @IEEECompliant("atan2", 43)
2760 auto atan2(D1, D2)(auto const ref D1 y, auto const ref D2 x)
2761 if (isDecimal!(D1, D2))
2762 {
2763     alias D = CommonDecimal!(D1, D2);
2764     D result;
2765     auto flags = decimalAtan2(y, x, result, 
2766                              __ctfe ? D.PRECISION : DecimalControl.precision, 
2767                              __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
2768     flags &= ExceptionFlags.invalidOperation | ExceptionFlags.underflow | ExceptionFlags.inexact;
2769     DecimalControl.raiseFlags(flags);
2770     return result;
2771 }
2772 
2773 ///
2774 unittest
2775 {
2776     decimal32 y = 10;
2777     decimal32 x = 0;
2778     assert (atan2(y, x) == decimal32.PI_2);
2779 }
2780 
2781 unittest
2782 {
2783 
2784     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
2785     {
2786         assert (isNaN(atan2(T.nan, T.zero)));
2787         assert (isNaN(atan2(T.one, T.nan)));
2788         assert (atan2(T.zero, -T.zero) == T.PI); 
2789         assert (atan2(-T.zero, -T.zero) == -T.PI); 
2790         assert (atan2(T.zero, T.zero) == T.zero);
2791         assert (atan2(-T.zero, T.zero) == -T.zero); 
2792         assert (atan2(T.zero, -T.one) == T.PI);
2793         assert (atan2(-T.zero, -T.one) == -T.PI);
2794         assert (atan2(T.zero, T.one) == T.zero);
2795         assert (atan2(-T.zero, T.one) == -T.zero);
2796         assert (atan2(-T.one, T.zero) == -T.PI_2);
2797         assert (atan2(T.one, T.zero) == T.PI_2);
2798         assert (atan2(T.one, -T.infinity) == T.PI);
2799         assert (atan2(-T.one, -T.infinity) == -T.PI);
2800         assert (atan2(T.one, T.infinity) == T.zero);
2801         assert (atan2(-T.one, T.infinity) == -T.zero);
2802         assert (atan2(-T.infinity, T.one) == -T.PI_2);
2803         assert (atan2(T.infinity, T.one) == T.PI_2);
2804         assert (atan2(-T.infinity, -T.infinity) == -T._3PI_4);
2805         assert (atan2(T.infinity, -T.infinity) == T._3PI_4);
2806         assert (atan2(-T.infinity, T.infinity) == -T.PI_4);
2807         assert (atan2(T.infinity, T.infinity) == T.PI_4);
2808     }
2809 }
2810 
2811 /**
2812 Calculates the arc tangent of y / x divided by π, returning a value ranging from -1 to 1.
2813 Exceptions:
2814 $(BOOKTABLE,
2815     $(TR $(TD $(MYREF InvalidOperationException)) 
2816          $(TD x or y is signaling $(B NaN)))
2817     $(TR $(TD $(MYREF InexactException)) 
2818          $(TD the result is inexact))
2819     $(TR $(TD $(MYREF UnderflowException)) 
2820          $(TD the result is too small to be represented))
2821 )
2822 Special_values:
2823 $(BOOKTABLE,
2824     $(TR $(TH y) $(TH x) $(TH atan2pi(y, x)))
2825     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
2826     $(TR $(TD any) $(TD $(B NaN)) $(TD $(B NaN)))
2827     $(TR $(TD ±0.0) $(TD -0.0) $(TD ±1.0))
2828     $(TR $(TD ±0.0) $(TD +0.0) $(TD ±0.0))
2829     $(TR $(TD ±0.0) $(TD <0.0) $(TD ±1.0))
2830     $(TR $(TD ±0.0) $(TD >0.0) $(TD ±0.0))
2831     $(TR $(TD ±∞) $(TD -∞) $(TD ±3/4))
2832     $(TR $(TD ±∞) $(TD +∞) $(TD ±1/4))
2833     $(TR $(TD ±∞) $(TD any) $(TD ±1/2))
2834     $(TR $(TD any) $(TD -∞) $(TD ±1.0))
2835     $(TR $(TD any) $(TD +∞) $(TD ±0.0))
2836 )
2837 */
2838 @IEEECompliant("atan2Pi", 43)
2839 auto atan2pi(D1, D2)(auto const ref D1 y, auto const ref D2 x)
2840 if (isDecimal!(D1, D2))
2841 {
2842     alias D = CommonDecimal!(D1, D2);
2843     D result;
2844     auto flags = decimalAtan2Pi(y, x, result, 
2845                               __ctfe ? D.PRECISION : DecimalControl.precision, 
2846                               __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
2847     flags &= ExceptionFlags.invalidOperation | ExceptionFlags.underflow | ExceptionFlags.inexact;
2848     DecimalControl.raiseFlags(flags);
2849     return result;
2850 }
2851 
2852 ///
2853 unittest
2854 {
2855     decimal32 y = 10;
2856     decimal32 x = 0;
2857     assert (atan2pi(y, x) == decimal32("0.5"));
2858 }
2859 
2860 unittest
2861 {
2862 
2863     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
2864     {
2865         assert (isNaN(atan2(T.nan, T.zero)));
2866         assert (isNaN(atan2(T.one, T.nan)));
2867         assert (atan2pi(T.zero, -T.zero) == T.one); 
2868         assert (atan2pi(-T.zero, -T.zero) == -T.one); 
2869         assert (atan2pi(T.zero, T.zero) == T.zero);
2870         assert (atan2pi(-T.zero, T.zero) == -T.zero); 
2871         assert (atan2pi(T.zero, -T.one) == T.one);
2872         assert (atan2pi(-T.zero, -T.one) == -T.one);
2873         assert (atan2pi(T.zero, T.one) == T.zero);
2874         assert (atan2pi(-T.zero, T.one) == -T.zero);
2875         assert (atan2pi(-T.one, T.zero) == -T.half);
2876         assert (atan2pi(T.one, T.zero) == T.half);
2877         assert (atan2pi(T.one, -T.infinity) == T.one);
2878         assert (atan2pi(-T.one, -T.infinity) == -T.one);
2879         assert (atan2pi(T.one, T.infinity) == T.zero);
2880         assert (atan2pi(-T.one, T.infinity) == -T.zero);
2881         assert (atan2pi(-T.infinity, T.one) == -T.half);
2882         assert (atan2pi(T.infinity, T.one) == T.half);
2883         assert (atan2pi(-T.infinity, -T.infinity) == -T.threequarters);
2884         assert (atan2pi(T.infinity, -T.infinity) == T.threequarters);
2885         assert (atan2pi(-T.infinity, T.infinity) == -T.quarter);
2886         assert (atan2pi(T.infinity, T.infinity) == T.quarter);
2887     }
2888 }
2889 
2890 /**
2891 Calculates the inverse hyperbolic tangent of x
2892 Exceptions:
2893 $(BOOKTABLE,
2894     $(TR $(TD $(MYREF InvalidOperationException)) 
2895          $(TD x is signaling $(B NaN) or |x| > 1.0))
2896     $(TR $(TD $(MYREF DivisionByZeroException)) 
2897          $(TD |x| = 1.0))
2898     $(TR $(TD $(MYREF UnderflowException)) 
2899          $(TD the result is too small to be represented))
2900     $(TR $(TD $(MYREF InexactException)) 
2901          $(TD the result is inexact))
2902 )
2903 Special_values:
2904 $(BOOKTABLE,
2905     $(TR $(TH x) $(TH atanh(x)))
2906     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
2907     $(TR $(TD ±0.0) $(TD ±0.0))
2908     $(TR $(TD ±1.0) $(TD ±∞))
2909     $(TR $(TD >1.0) $(TD $(B NaN)))
2910     $(TR $(TD <1.0) $(TD $(B NaN)))
2911 )
2912 */
2913 @IEEECompliant("atanh", 43)
2914 D atanh(D)(auto const ref D x)
2915 if (isDecimal!D)
2916 {
2917     Unqual!D result = x;
2918     auto flags = decimalAtanh(result, 
2919                              __ctfe ? D.PRECISION : DecimalControl.precision, 
2920                              __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
2921     flags &= ExceptionFlags.invalidOperation | ExceptionFlags.underflow | 
2922              ExceptionFlags.inexact | ExceptionFlags.divisionByZero;
2923     DecimalControl.raiseFlags(flags);
2924     return result;
2925 }
2926 
2927 ///
2928 unittest
2929 {
2930     decimal32 x = 0;
2931     assert (atanh(x) == 0);
2932 }
2933 
2934 /**
2935 Calculates the arc tangent of x divided by π, returning a value ranging from -1/2 to 1/2.
2936 Exceptions:
2937 $(BOOKTABLE,
2938     $(TR $(TD $(MYREF InvalidOperationException)) 
2939          $(TD x is signaling $(B NaN)))
2940     $(TR $(TD $(MYREF InexactException)) 
2941          $(TD the result is inexact))
2942     $(TR $(TD $(MYREF UnderflowException)) 
2943          $(TD the result is too small to be represented))
2944 )
2945 Special_values:
2946 $(BOOKTABLE,
2947     $(TR $(TH x) $(TH atan(x)))
2948     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
2949     $(TR $(TD ±0.0) $(TD ±0.0))
2950     $(TR $(TD ±∞) $(TD ±1/2))
2951 )
2952 */
2953 @IEEECompliant("atanPi", 43)
2954 D atanpi(D)(auto const ref D x)
2955 if (isDecimal!D)
2956 {
2957     Unqual!D result = x;
2958     auto flags = decimalAtanPi(result, 
2959                               __ctfe ? D.PRECISION : DecimalControl.precision, 
2960                               __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
2961     flags &= ExceptionFlags.invalidOperation | ExceptionFlags.underflow | ExceptionFlags.inexact;
2962     DecimalControl.raiseFlags(flags);
2963     return result;
2964 }
2965 
2966 ///
2967 unittest
2968 {
2969     decimal32 radians = 1;
2970     assert (atanpi(radians) == decimal32("0.25"));
2971 }
2972 
2973 
2974 unittest
2975 {
2976     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
2977     {
2978         assert (isIdentical(atanpi(T.zero), T.zero));
2979         assert (isIdentical(atanpi(-T.zero), -T.zero));
2980         assert (isIdentical(atanpi(T.infinity), T.half));
2981         assert (isIdentical(atanpi(-T.infinity), -T.half));
2982         assert (isNaN(atanpi(T.nan)));
2983     }
2984 }
2985 
2986 /**
2987 Computes the cubic root of x
2988 Throws:
2989 $(BOOKTABLE,
2990     $(TR $(TD $(MYREF InvalidOperationException)) 
2991          $(TD x is signaling $(B NaN)))
2992     $(TR $(TD $(MYREF UnderflowException)) 
2993          $(TD cubic root of x is too small to be represented))
2994     $(TR $(TD $(MYREF InexactException)) 
2995          $(TD the result is inexact))
2996 )
2997 Special_values:
2998 $(BOOKTABLE,
2999     $(TR $(TH x) $(TH cbrt(x)))
3000     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3001     $(TR $(TD ±0.0) $(TD ±0.0))
3002     $(TR $(TD ±∞) $(TD ±∞))
3003 )
3004 */
3005 D cbrt(D)(auto const ref D x)
3006 if (isDecimal!D)
3007 {
3008     Unqual!D result = x;
3009     auto flags = decimalCbrt(result, 
3010                             __ctfe ? D.PRECISION : DecimalControl.precision, 
3011                             __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3012     DecimalControl.raiseFlags(flags);
3013     return result;
3014 }
3015 
3016 ///
3017 unittest
3018 {
3019     decimal32 x = 27;
3020     assert (cbrt(x) == 3);
3021 }
3022 
3023 /**
3024 Returns the value of x rounded upward to the next integer (toward positive infinity).
3025 This operation is silent, doesn't throw any exception.
3026 Special_values:
3027 $(BOOKTABLE,
3028     $(TR $(TH x) $(TH ceil(x)))
3029     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3030     $(TR $(TD ±0.0) $(TD ±0.0))
3031     $(TR $(TD ±∞) $(TD ±∞))
3032 )
3033 */
3034 D ceil(D)(auto const ref D x)
3035 if (isDecimal!D)
3036 {
3037     Unqual!D result = x;
3038     decimalRound(result, 0, RoundingMode.towardPositive);
3039     return result;
3040 }
3041 
3042 ///
3043 unittest
3044 {
3045     assert (ceil(decimal32("123.456")) == 124);
3046     assert (ceil(decimal32("-123.456")) == -123);
3047 }
3048 
3049 /**
3050 Defines a total order on all _decimal values.
3051 Params:
3052     x = a _decimal value
3053     y = a _decimal value
3054 Returns:
3055     -1 if x precedes y, 0 if x is equal to y, +1 if x follows y
3056 Notes:
3057     The total order is defined as:<br/>
3058     - -sNaN < -$(B NaN) < -infinity < -finite < -0.0 < +0.0 < +finite < +infinity < +$(B NaN) < +sNaN<br/>
3059     - for two $(B NaN) values the total order is defined based on the payload 
3060 */
3061 int cmp(D1, D2)(auto const ref D1 x, auto const ref D2 y)
3062 if (isDecimal!(D1, D2))
3063 {
3064     static if (is(D1 : D2))
3065     {
3066         if (x.data == y.data)
3067             return 0;
3068     }
3069     alias U = CommonStorage!(D1, D2);
3070     U cx, cy; int ex, ey; bool sx, sy;
3071     auto fx = fastDecode(x, cx, ex, sx);
3072     auto fy = fastDecode(y, cy, ey, sy);
3073     
3074     if (sx != sy)
3075         return sx ? -1 : 1;
3076     
3077     if (fx == FastClass.quietNaN)
3078     {
3079         if (fy == FastClass.quietNaN)
3080         {
3081             if (cx > cy)
3082                 return sx ? -1 : 1;
3083             else if (cx < cy)
3084                 return sx ? 1 : -1;
3085             return 0;
3086         }
3087         return sx ? -1 : 1;
3088     }
3089 
3090     if (fy == FastClass.quietNaN)
3091         return sx ? 1 : -1;
3092 
3093     if (fx == FastClass.signalingNaN)
3094     {
3095         if (fy == FastClass.signalingNaN)
3096         {
3097             if (cx > cy)
3098                 return sx ? -1 : 1;
3099             else if (cx < cy)
3100                 return sx ? 1 : -1;
3101             return 0;
3102         }
3103         return sx ? -1 : 1;
3104     }
3105 
3106     if (fy == FastClass.signalingNaN)
3107         return sx ? 1 : -1;
3108 
3109     
3110 
3111     if (fx == FastClass.infinite)
3112     {
3113         if (fy == FastClass.infinite)
3114             return 0;
3115         return sx ? -1 : 1;
3116     }
3117 
3118     if (fy == FastClass.infinite)
3119         return sx ? 1 : -1;
3120 
3121     //if (fx == FastClass.zero)
3122     //{
3123     //    if (fy == FastClass.zero)
3124     //        return 0;
3125     //    return sx ? 1 : -1;
3126     //}
3127     //
3128     //if (fy == FastClass.zero)
3129     //    return sx ? -1 : 1;
3130 
3131     int c = coefficientCmp(cx, ex, cy, ey);
3132 
3133     if (c == 0)
3134     {
3135         if (ex > ey)
3136             c = sx ? -1 : 1;
3137         else if (ex < ey)
3138             c = sx ? 1 : -1;
3139     }
3140     else if (sx)
3141         c = -c;
3142 
3143     return c;
3144 
3145 }
3146 
3147 ///
3148 unittest
3149 {
3150     assert (cmp(-decimal32.nan, decimal64.max) == -1);
3151     assert (cmp(decimal32.max, decimal128.min_normal) == 1);
3152     assert (cmp(decimal64(0), -decimal64(0)) == 1);
3153 }
3154 /**
3155 Computes (1 + x)$(SUPERSCRIPT n) where n is an integer
3156 Throws:
3157 $(BOOKTABLE,
3158     $(TR $(TD $(MYREF InvalidOperationException)) 
3159          $(TD x is signaling $(B NaN) or x < -1.0))
3160     $(TR $(TD $(MYREF DivisionByZeroException)) 
3161          $(TD x = -1.0 and n < 0))
3162     $(TR $(TD $(MYREF OverflowException)) 
3163          $(TD result is too big to be represented))
3164     $(TR $(TD $(MYREF UnderflowException)) 
3165          $(TD result is too small to be represented))
3166     $(TR $(TD $(MYREF InexactException)) 
3167          $(TD the result is inexact))
3168 )
3169 Special_values:
3170 $(BOOKTABLE,
3171     $(TR $(TH x) $(TH n) $(TH compound(x, n)))
3172     $(TR $(TD sNaN) $(TD any) $(TD $(B NaN)))
3173     $(TR $(TD any) $(TD 0) $(TD +1.0))
3174     $(TR $(TD -1.0) $(TD <0) $(TD +∞))
3175     $(TR $(TD -1.0) $(TD >0) $(TD +0.0))
3176     $(TR $(TD +∞) $(TD any) $(TD +∞))
3177 )
3178 */
3179 @IEEECompliant("compound", 42)
3180 auto compound(D)(auto const ref D x, const int n)
3181 if (isDecimal!D)
3182 {
3183     Unqual!D result = x;
3184     auto flags = decimalCompound(result, n,
3185                                __ctfe ? D.PRECISION : DecimalControl.precision, 
3186                                __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3187     DecimalControl.raiseFlags(flags);
3188     return result;
3189 }
3190 
3191 unittest
3192 {
3193     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
3194     {
3195         assert (compound(T.ten, 0) == 1);
3196         assert (compound(T.infinity, 0) == 1);
3197         assert (compound(-T.one, 0) == 1);
3198         assert (compound(T.zero, 0) == 1);
3199         assert (compound(-T.one, 5) == 0);
3200         assert (compound(T.infinity, 5) == T.infinity);
3201     }
3202 }
3203 
3204 ///
3205 unittest
3206 {
3207     decimal32 x = "0.2";
3208     assert (compound(x, 2) == decimal32("1.44"));
3209 }
3210 
3211 /**
3212 Copies the sign of a _decimal value _to another.
3213 This operation is silent, no error flags are set and no exceptions are thrown.
3214 Params:
3215     to = a _decimal value to copy
3216     from = a _decimal value from which the sign is copied
3217 Returns: 
3218     to with the sign of from
3219 */
3220 @IEEECompliant("copySign", 23)
3221 D1 copysign(D1, D2)(auto const ref D1 to, auto const ref D2 from)
3222 if (isDecimal!(D1, D2))
3223 {
3224     Unqual!D1 result = to;
3225     static if (is(D2: decimal32) || is(D2: decimal64))
3226     {
3227         bool sx = cast(bool)((from.data & D2.MASK_SGN) == D2.MASK_SGN);
3228         if (sx)
3229             result.data |= D1.MASK_SGN;
3230         else
3231             result.data &= ~D1.MASK_SGN;
3232     }
3233     else
3234     {
3235         bool sx = cast(bool)((from.data.hi & D2.MASK_SGN.hi) == D2.MASK_SGN.hi);
3236         if (sx)
3237             result.data.hi |= D1.MASK_SGN.hi;
3238         else
3239             result.data.hi &= ~D1.MASK_SGN.hi;
3240     }
3241 
3242     return result;
3243 }
3244 
3245 ///
3246 unittest
3247 {
3248     decimal32 negative = -decimal32.min_normal;
3249     decimal64 test = decimal64.max;
3250     assert(copysign(test, negative) == -decimal64.max);
3251 
3252 }
3253 
3254 /**
3255 Returns cosine of x.
3256 Throws:
3257 $(BOOKTABLE,
3258     $(TR $(TD $(MYREF InvalidOperationException)) 
3259          $(TD x is signaling $(B NaN) or ±∞))
3260     $(TR $(TD $(MYREF UnderflowException)) 
3261          $(TD result is too small to be represented))
3262     $(TR $(TD $(MYREF InexactException)) 
3263          $(TD the result is inexact))
3264 )
3265 Special_values:
3266 $(BOOKTABLE,
3267     $(TR $(TH x) $(TH cos(x)))
3268     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3269     $(TR $(TD ±∞) $(TD $(B NaN)))
3270     $(TR $(TD ±0.0) $(TD +1.0))
3271     $(TR $(TD π/6) $(TD +√3/2))
3272     $(TR $(TD π/4) $(TD +√2/2))
3273     $(TR $(TD π/3) $(TD +0.5))
3274     $(TR $(TD π/2) $(TD +0.0))
3275     $(TR $(TD 2π/3) $(TD -0.5))
3276     $(TR $(TD 3π/4) $(TD -√2/2))
3277     $(TR $(TD 5π/6) $(TD -√3/2))
3278     $(TR $(TD π) $(TD -1.0))
3279 )
3280 */
3281 @IEEECompliant("cos", 42)
3282 D cos(D)(auto const ref D x)
3283 if (isDecimal!D)
3284 {
3285     Unqual!D result = x;
3286     auto flags = decimalCos(result, 
3287                              __ctfe ? D.PRECISION : DecimalControl.precision, 
3288                              __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3289     DecimalControl.raiseFlags(flags);
3290     return result;
3291 }
3292 
3293 
3294 /**
3295 Calculates the hyperbolic cosine of x.
3296 Throws:
3297 $(BOOKTABLE,
3298     $(TR $(TD $(MYREF InvalidOperationException)) 
3299          $(TD x is signaling $(B NaN)))
3300     $(TR $(TD $(MYREF OverflowException)) 
3301          $(TD result is too big to be represented))
3302     $(TR $(TD $(MYREF InexactException)) 
3303          $(TD the result is inexact))
3304 )
3305 Special_values:
3306 $(BOOKTABLE,
3307     $(TR $(TH x) $(TH cosh(x)))
3308     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3309     $(TR $(TD ±∞) $(TD +∞))
3310     $(TR $(TD ±0.0) $(TD +1.0))
3311 )
3312 */
3313 @IEEECompliant("cosh", 42)
3314 D cosh(D)(auto const ref D x)
3315 if (isDecimal!D)
3316 {
3317     Unqual!D result = x;
3318     auto flags = decimalCosh(result, 
3319                             __ctfe ? D.PRECISION : DecimalControl.precision, 
3320                             __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3321     DecimalControl.raiseFlags(flags);
3322     return result;
3323 }
3324 
3325 //unittest
3326 //{
3327 //    import std.stdio;
3328 //    import std.math;
3329 //    for(int i = 1; i < 10; ++i)
3330 //    {
3331 //        writefln("+%3.2f %35.34f %35.34f", i/10.0, cosh(decimal128(i)/10), std.math.cosh(i/10.0));
3332 //    }
3333 //}
3334 
3335 /**
3336 Returns cosine of xπ.
3337 Throws:
3338 $(BOOKTABLE,
3339     $(TR $(TD $(MYREF InvalidOperationException)) 
3340          $(TD x is signaling $(B NaN) or ±∞))
3341     $(TR $(TD $(MYREF UnderflowException)) 
3342          $(TD result is too small to be represented))
3343     $(TR $(TD $(MYREF InexactException)) 
3344          $(TD the result is inexact))
3345 )
3346 Special_values:
3347 $(BOOKTABLE,
3348     $(TR $(TH x) $(TH cospi(x)))
3349     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3350     $(TR $(TD ±∞) $(TD $(B NaN)))
3351     $(TR $(TD ±0.0) $(TD +1.0))
3352     $(TR $(TD 1/6) $(TD +√3/2))
3353     $(TR $(TD 1/4) $(TD +√2/2))
3354     $(TR $(TD 1/3) $(TD +0.5))
3355     $(TR $(TD 1/2) $(TD +0.0))
3356     $(TR $(TD 2/3) $(TD -0.5))
3357     $(TR $(TD 3/4) $(TD -√2/2))
3358     $(TR $(TD 5/6) $(TD -√3/2))
3359     $(TR $(TD 1.0) $(TD -1.0))
3360 )
3361 */
3362 @IEEECompliant("cosPi", 42)
3363 D cospi(D)(auto const ref D x)
3364 if (isDecimal!D)
3365 {
3366     Unqual!D result = x;
3367     auto flags = decimalCosPi(result, 
3368                              __ctfe ? D.PRECISION : DecimalControl.precision, 
3369                              __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3370     DecimalControl.raiseFlags(flags);
3371     return result;
3372 }
3373 
3374 ///IEEE-754-2008 floating point categories
3375 enum DecimalClass
3376 {
3377     ///a signalling $(B NaN) represents most of the time an uninitialized variable; 
3378     ///a quiet $(B NaN) represents the result of an invalid operation
3379     signalingNaN,
3380     ///ditto
3381     quietNaN,
3382     ///value represents infinity
3383     negativeInfinity,
3384     ///ditto
3385     positiveInfinity,
3386     ///value represents a normalized _decimal value
3387     negativeNormal,
3388     ///ditto
3389     positiveNormal,
3390     ///value represents a subnormal _decimal value
3391     negativeSubnormal,
3392     ///ditto
3393     positiveSubnormal,
3394     ///value is 0
3395     negativeZero,
3396     ///ditto
3397     positiveZero,
3398 }
3399 
3400 /**
3401 Returns the decimal class where x falls into.
3402 This operation is silent, no exception flags are set and no exceptions are thrown.
3403 Params:
3404     x = a _decimal value
3405 Returns: 
3406     One of the members of $(MYREF DecimalClass) enumeration
3407 */
3408 @IEEECompliant("class", 25)
3409 DecimalClass decimalClass(D)(auto const ref D x) 
3410 if (isDecimal!D)
3411 {
3412     DataType!D coefficient;
3413     uint exponent;
3414 
3415     static if (is(D: decimal32) || is(D: decimal64))
3416     {
3417         if ((x.data & D.MASK_INF) == D.MASK_INF)
3418             if ((x.data & D.MASK_QNAN) == D.MASK_QNAN)
3419                 if ((x.data & D.MASK_SNAN) == D.MASK_SNAN)
3420                     return DecimalClass.signalingNaN;
3421                 else
3422                     return DecimalClass.quietNaN;
3423             else
3424                 return x.data & D.MASK_SGN ? DecimalClass.negativeInfinity : DecimalClass.positiveInfinity;
3425         else if ((x.data & D.MASK_EXT) == D.MASK_EXT)
3426         {
3427             coefficient = (x.data & D.MASK_COE2) | D.MASK_COEX;
3428             if (coefficient > D.COEF_MAX)
3429                 return x.data & D.MASK_SGN ? DecimalClass.negativeZero : DecimalClass.positiveZero; 
3430             exponent = cast(uint)((x.data & D.MASK_EXP2) >>> D.SHIFT_EXP2);
3431         }
3432         else
3433         {
3434             coefficient = x.data & D.MASK_COE1;
3435             if (coefficient == 0U)
3436                 return (x.data & D.MASK_SGN) == D.MASK_SGN ? DecimalClass.negativeZero : DecimalClass.positiveZero; 
3437             exponent = cast(uint)((x.data & D.MASK_EXP1) >>> D.SHIFT_EXP1);
3438         }
3439         bool sx = (x.data & D.MASK_SGN) == D.MASK_SGN;
3440     }
3441     else
3442     {
3443         if ((x.data.hi & D.MASK_INF.hi) == D.MASK_INF.hi)
3444             if ((x.data.hi & D.MASK_QNAN.hi) == D.MASK_QNAN.hi)
3445                 if ((x.data.hi & D.MASK_SNAN.hi) == D.MASK_SNAN.hi)
3446                     return DecimalClass.signalingNaN;
3447                 else
3448                     return DecimalClass.quietNaN;
3449             else
3450                 return x.data.hi & D.MASK_SGN.hi ? DecimalClass.negativeInfinity : DecimalClass.positiveInfinity;
3451         else if ((x.data.hi & D.MASK_EXT.hi) == D.MASK_EXT.hi)
3452             return (x.data.hi & D.MASK_SGN.hi) == D.MASK_SGN.hi ? DecimalClass.negativeZero : DecimalClass.positiveZero; 
3453         else
3454         {
3455             coefficient = x.data & D.MASK_COE1;
3456             if (coefficient == 0U || coefficient > D.COEF_MAX)
3457                 return (x.data.hi & D.MASK_SGN.hi) == D.MASK_SGN.hi ? DecimalClass.negativeZero : DecimalClass.positiveZero; 
3458             exponent = cast(uint)((x.data & D.MASK_EXP1) >>> D.SHIFT_EXP1);
3459         }
3460         bool sx = (x.data.hi & D.MASK_SGN.hi) == D.MASK_SGN.hi;
3461     }
3462 
3463     if (exponent < D.PRECISION - 1)
3464     {
3465         if (prec(coefficient) < D.PRECISION - exponent)
3466             return sx ? DecimalClass.negativeSubnormal : DecimalClass.positiveSubnormal;
3467     }
3468     return sx ? DecimalClass.negativeNormal : DecimalClass.positiveNormal;
3469 }
3470 
3471 ///
3472 unittest
3473 {
3474     assert(decimalClass(decimal32.nan) == DecimalClass.quietNaN);
3475     assert(decimalClass(decimal64.infinity) == DecimalClass.positiveInfinity);
3476     assert(decimalClass(decimal128.max) == DecimalClass.positiveNormal);
3477     assert(decimalClass(-decimal32.max) == DecimalClass.negativeNormal);
3478     assert(decimalClass(decimal128.epsilon) == DecimalClass.positiveNormal);
3479 }
3480 
3481 unittest
3482 {
3483     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
3484     {
3485         assert(decimalClass(T.snan) == DecimalClass.signalingNaN);
3486         assert(decimalClass(T.qnan) == DecimalClass.quietNaN);
3487         assert(decimalClass(T.minusInfinity) == DecimalClass.negativeInfinity);
3488         assert(decimalClass(T.infinity) == DecimalClass.positiveInfinity);
3489         assert(decimalClass(T.zero) == DecimalClass.positiveZero);
3490         assert(decimalClass(T.minusZero) == DecimalClass.negativeZero);
3491         assert(decimalClass(T.subn) == DecimalClass.positiveSubnormal);
3492         assert(decimalClass(T.minusSubn) == DecimalClass.negativeSubnormal);
3493         assert(decimalClass(T.ten) == DecimalClass.positiveNormal);
3494         assert(decimalClass(T.minusTen) == DecimalClass.negativeNormal);
3495         assert(decimalClass(T.max) == DecimalClass.positiveNormal);
3496         assert(decimalClass(-T.max) == DecimalClass.negativeNormal);
3497         assert(decimalClass(T.min_normal) == DecimalClass.positiveNormal);
3498         assert(decimalClass(T.epsilon) == DecimalClass.positiveNormal);
3499     }
3500 }
3501 
3502 
3503 
3504 /**
3505 Sums x$(SUBSCRIPT i) * y$(SUBSCRIPT i) using a higher precision, rounding only once at the end.
3506 Returns:
3507     x$(SUBSCRIPT 0) * y$(SUBSCRIPT 0) + x$(SUBSCRIPT 1) * y$(SUBSCRIPT 1) + ... + x$(SUBSCRIPT n) * y$(SUBSCRIPT n)
3508 Notes:
3509     If x and y arrays are not of the same length, operation is performed for min(x.length, y.length);
3510 Throws:
3511 $(BOOKTABLE,
3512     $(TR $(TD $(MYREF InvalidOperationException)) 
3513          $(TD any x is signaling $(B NaN)))
3514     $(TR $(TD $(MYREF InvalidOperationException)) 
3515          $(TD any combination of elements is (±∞, ±0.0) or (±0.0, ±∞)))
3516     $(TR $(TD $(MYREF InvalidOperationException)) 
3517          $(TD there are two products resulting in infinities of different sign))
3518     $(TR $(TD $(MYREF OverflowException)) 
3519          $(TD result is too big to be represented))
3520     $(TR $(TD $(MYREF UnderflowException)) 
3521          $(TD result is too small to be represented))
3522     $(TR $(TD $(MYREF InexactException)) 
3523          $(TD result is inexact))
3524 )
3525 */
3526 @IEEECompliant("dot", 47)
3527 D dot(D)(const(D)[] x, const(D)[] y)
3528 if (isDecimal!D)
3529 {
3530     Unqual!D result = x;
3531     auto flags = decimalDot(x, y, result, 
3532                             __ctfe ? D.PRECISION : DecimalControl.precision, 
3533                             __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3534     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.overflow | ExceptionFlags.underflow);
3535     DecimalControl.raiseFlags(flags);
3536     return result;
3537 }
3538 
3539 /**
3540 Calculates e$(SUPERSCRIPT x)
3541 Throws:
3542 $(BOOKTABLE,
3543     $(TR $(TD $(MYREF InvalidOperationException)) 
3544          $(TD x is signaling $(B NaN)))
3545     $(TR $(TD $(MYREF UnderflowException)) 
3546          $(TD e$(SUPERSCRIPT x) is too small to be represented))
3547     $(TR $(TD $(MYREF OverflowException)) 
3548          $(TD e$(SUPERSCRIPT x) is too big to be represented))
3549     $(TR $(TD $(MYREF InexactException)) 
3550          $(TD the result is inexact))
3551 )
3552 Special_values:
3553 $(BOOKTABLE,
3554     $(TR $(TH x) $(TH exp(x)))
3555     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3556     $(TR $(TD ±0.0) $(TD +1.0))
3557     $(TR $(TD -∞) $(TD 0))
3558     $(TR $(TD +∞) $(TD +∞))
3559 )
3560 */
3561 @IEEECompliant("exp", 42)
3562 D exp(D)(auto const ref D x)
3563 if (isDecimal!D)
3564 {
3565     Unqual!D result = x;
3566     auto flags = decimalExp(result, 
3567                             __ctfe ? D.PRECISION : DecimalControl.precision, 
3568                             __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3569     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.overflow | ExceptionFlags.underflow);
3570     DecimalControl.raiseFlags(flags);
3571     return result;
3572 }
3573 
3574 ///
3575 unittest
3576 {
3577     decimal32 power = 1;
3578     assert (exp(power) == decimal32.E);
3579 }
3580 
3581 unittest
3582 {
3583     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
3584     {
3585         assert (exp(T.zero) == T.one);
3586         assert (exp(-T.infinity) == T.zero);
3587         assert (exp(T.infinity) == T.infinity);
3588         assert (isNaN(exp(T.nan)));
3589     }
3590 }
3591 
3592 /**
3593 Calculates 10$(SUPERSCRIPT x)
3594 Throws:
3595 $(BOOKTABLE,
3596     $(TR $(TD $(MYREF InvalidOperationException)) 
3597          $(TD x is signaling $(B NaN)))
3598     $(TR $(TD $(MYREF UnderflowException)) 
3599          $(TD 10$(SUPERSCRIPT x) is too small to be represented))
3600     $(TR $(TD $(MYREF OverflowException)) 
3601          $(TD 10$(SUPERSCRIPT x) is too big to be represented))
3602     $(TR $(TD $(MYREF InexactException)) 
3603          $(TD the result is inexact))
3604 )
3605 Special_values:
3606 $(BOOKTABLE,
3607     $(TR $(TH x) $(TH exp10(x)))
3608     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3609     $(TR $(TD ±0.0) $(TD +1.0))
3610     $(TR $(TD -∞) $(TD +0.0))
3611     $(TR $(TD +∞) $(TD +∞))
3612 )
3613 */
3614 @IEEECompliant("exp10", 42)
3615 D exp10(D)(auto const ref D x)
3616 if (isDecimal!D)
3617 {
3618     Unqual!D result = x;
3619     auto flags = decimalExp10(result, 
3620                             __ctfe ? D.PRECISION : DecimalControl.precision, 
3621                             __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3622     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.overflow | ExceptionFlags.underflow);
3623     DecimalControl.raiseFlags(flags);
3624     return result;
3625 }
3626 
3627 ///
3628 unittest
3629 {
3630     decimal32 x = 3;
3631     assert(exp10(x) == 1000);
3632 }
3633 
3634 
3635 /**
3636 Calculates 10$(SUPERSCRIPT x) - 1
3637 Throws:
3638 $(BOOKTABLE,
3639     $(TR $(TD $(MYREF InvalidOperationException)) 
3640          $(TD x is signaling $(B NaN)))
3641     $(TR $(TD $(MYREF UnderflowException)) 
3642          $(TD 10$(SUPERSCRIPT x) - 1 is too small to be represented))
3643     $(TR $(TD $(MYREF OverflowException)) 
3644          $(TD 10$(SUPERSCRIPT x) - 1 is too big to be represented))
3645     $(TR $(TD $(MYREF InexactException)) 
3646          $(TD the result is inexact))
3647 )
3648 Special_values:
3649 $(BOOKTABLE,
3650     $(TR $(TH x) $(TH exp10m1(x)))
3651     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3652     $(TR $(TD ±0.0) $(TD ±0.0))
3653     $(TR $(TD -∞) $(TD -1.0))
3654     $(TR $(TD +∞) $(TD +∞))
3655 )
3656 */
3657 @IEEECompliant("exp10m1", 42)
3658 D exp10m1(D)(auto const ref D x)
3659 if (isDecimal!D)
3660 {
3661     Unqual!D result = x;
3662     auto flags = decimalExp10m1(result, 
3663                               __ctfe ? D.PRECISION : DecimalControl.precision, 
3664                               __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3665     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.overflow | ExceptionFlags.underflow);
3666     DecimalControl.raiseFlags(flags);
3667     return result;
3668 }
3669 
3670 ///
3671 unittest
3672 {
3673     decimal32 x = 3;
3674     assert(exp10m1(x) == 999);
3675 }
3676 
3677 /**
3678 Calculates 2$(SUPERSCRIPT x)
3679 Throws:
3680 $(BOOKTABLE,
3681     $(TR $(TD $(MYREF InvalidOperationException)) 
3682          $(TD x is signaling $(B NaN)))
3683     $(TR $(TD $(MYREF UnderflowException)) 
3684          $(TD 2$(SUPERSCRIPT x) is too small to be represented))
3685     $(TR $(TD $(MYREF OverflowException)) 
3686          $(TD 2$(SUPERSCRIPT x) is too big to be represented))
3687     $(TR $(TD $(MYREF InexactException)) 
3688          $(TD the result is inexact))
3689 )
3690 Special_values:
3691 $(BOOKTABLE,
3692     $(TR $(TH x) $(TH exp2(x)))
3693     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3694     $(TR $(TD ±0.0) $(TD +1.0))
3695     $(TR $(TD -∞) $(TD +0.0))
3696     $(TR $(TD +∞) $(TD +∞))
3697 )
3698 */
3699 @IEEECompliant("exp2", 42)
3700 D exp2(D)(auto const ref D x)
3701 if (isDecimal!D)
3702 {
3703     Unqual!D result = x;
3704     auto flags = decimalExp2(result, 
3705                               __ctfe ? D.PRECISION : DecimalControl.precision, 
3706                               __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3707     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.overflow | ExceptionFlags.underflow);
3708     DecimalControl.raiseFlags(flags);
3709     return result;
3710 }
3711 
3712 ///
3713 unittest
3714 {
3715     decimal32 x = 3;
3716     assert(exp2(x) == 8);
3717 }
3718 
3719 /**
3720 Calculates 2$(SUPERSCRIPT x) - 1
3721 Throws:
3722 $(BOOKTABLE,
3723     $(TR $(TD $(MYREF InvalidOperationException)) 
3724          $(TD x is signaling $(B NaN)))
3725     $(TR $(TD $(MYREF UnderflowException)) 
3726          $(TD 2$(SUPERSCRIPT x) - 1 is too small to be represented))
3727     $(TR $(TD $(MYREF OverflowException)) 
3728          $(TD 2$(SUPERSCRIPT x) - 1 is too big to be represented))
3729     $(TR $(TD $(MYREF InexactException)) 
3730          $(TD the result is inexact))
3731 )
3732 Special_values:
3733 $(BOOKTABLE,
3734     $(TR $(TH x) $(TH exp2m1(x)))
3735     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3736     $(TR $(TD ±0.0) $(TD ±0.0))
3737     $(TR $(TD -∞) $(TD -1.0))
3738     $(TR $(TD +∞) $(TD +∞))
3739 )
3740 */
3741 @IEEECompliant("exp2m1", 42)
3742 D exp2m1(D)(auto const ref D x)
3743 if (isDecimal!D)
3744 {
3745     Unqual!D result = x;
3746     auto flags = decimalExp2m1(result, 
3747                              __ctfe ? D.PRECISION : DecimalControl.precision, 
3748                              __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3749     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.overflow | ExceptionFlags.underflow);
3750     DecimalControl.raiseFlags(flags);
3751     return result;
3752 }
3753 
3754 ///
3755 unittest
3756 {
3757     decimal32 x = 3;
3758     assert(exp2m1(x) == 7);
3759 }
3760 
3761 /**
3762 Calculates e$(SUPERSCRIPT x) - 1
3763 Throws:
3764 $(BOOKTABLE,
3765     $(TR $(TD $(MYREF InvalidOperationException)) 
3766          $(TD x is signaling $(B NaN)))
3767     $(TR $(TD $(MYREF UnderflowException)) 
3768          $(TD e$(SUPERSCRIPT x) - 1 is too small to be represented))
3769     $(TR $(TD $(MYREF OverflowException)) 
3770          $(TD e$(SUPERSCRIPT x) - 1 is too big to be represented))
3771     $(TR $(TD $(MYREF InexactException)) 
3772          $(TD the result is inexact))
3773 )
3774 Special_values:
3775 $(BOOKTABLE,
3776     $(TR $(TH x) $(TH expm1(x)))
3777     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3778     $(TR $(TD ±0.0) $(TD ±0.0))
3779     $(TR $(TD -∞) $(TD -1.0))
3780     $(TR $(TD +∞) $(TD +∞))
3781 )
3782 */
3783 @IEEECompliant("expm1", 42)
3784 D expm1(D)(auto const ref D x)
3785 if (isDecimal!D)
3786 {
3787     Unqual!D result = x;
3788     auto flags = decimalExpm1(result, 
3789                                __ctfe ? D.PRECISION : DecimalControl.precision, 
3790                                __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3791     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.overflow | ExceptionFlags.underflow);
3792     DecimalControl.raiseFlags(flags);
3793     return result;
3794 }
3795 
3796 /**
3797 Calculates |x|.
3798 This operation is silent, no error flags are set and no exceptions are thrown.
3799 */
3800 @IEEECompliant("abs", 23)
3801 D fabs(D)(auto const ref D x)
3802 if (isDecimal!D)
3803 {
3804     Unqual!D result = x;
3805     static if (is(D: decimal128))
3806         result.data.hi &= ~D.MASK_SGN.hi;
3807     else
3808         result.data &= ~D.MASK_SGN;
3809     return result;
3810 }
3811 
3812 ///
3813 unittest
3814 {
3815     assert(fabs(-decimal32.max) == decimal32.max);
3816     assert(fabs(decimal64.infinity) == decimal64.infinity);
3817 }
3818 
3819 
3820 /**
3821 Returns the positive difference between x and y. If x ≤ y, retuns 0.0
3822 Throws:
3823 $(BOOKTABLE,
3824     $(TR $(TD $(MYREF InvalidOperationException)) 
3825          $(TD either x or y is $(B signaling NaN)))
3826     $(TR $(TD $(MYREF UnderflowException)) 
3827          $(TD result is subnormal))
3828     $(TR $(TD $(MYREF InexactException)) 
3829          $(TD result is inexact))
3830 )
3831 Special_values:
3832 $(BOOKTABLE,
3833     $(TR $(TH x) $(TH y) $(TH fdim(x, y)))
3834     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
3835     $(TR $(TD any) $(TD $(B NaN)) $(TD $(B NaN)))
3836     $(TR $(TD x > y) $(TD) $(TD x - y))
3837     $(TR $(TD x ≤ y) $(TD) $(TD 0.0))
3838 )
3839 */
3840 auto fdim(D1, D2)(auto const ref D1 x, auto const ref D2 y)
3841 {
3842     alias D = CommonDecimal!(D1, D2);
3843     D result = x;
3844 
3845     if (isInfinity(x) && isInfinity(y))
3846     {
3847         if (signbit(x) == signbit(y))
3848             return D.zero;
3849         else
3850             return result;
3851     }
3852 
3853     if (decimalCmp(y, x) >= 0)
3854         return D.zero;
3855 
3856     auto flags = decimalSub(result, y,
3857                        __ctfe ? 0 : DecimalControl.precision,
3858                        __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
3859     if (!isNaN(result) && signbit(result))
3860         result = D.zero;
3861     DecimalControl.raiseFlags(flags);
3862     return result;
3863 }
3864 
3865 ///
3866 unittest
3867 {
3868     decimal32 x = "10.4";
3869     decimal32 y = "7.3";
3870 
3871     assert (fdim(x, y) == decimal32("3.1"));
3872     assert (fdim(y, x) == 0);
3873 }
3874 
3875 /**
3876 Returns the value of x rounded downward to the previous integer (toward negative infinity).
3877 This operation is silent, doesn't throw any exception.
3878 Special_values:
3879 $(BOOKTABLE,
3880     $(TR $(TH x) $(TH floor(x)))
3881     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3882     $(TR $(TD ±0.0) $(TD ±0.0))
3883     $(TR $(TD ±∞) $(TD ±∞))
3884 )
3885 */
3886 D floor(D)(auto const ref D x)
3887 if (isDecimal!D)
3888 {
3889     Unqual!D result = x;
3890     decimalRound(result, 0, RoundingMode.towardNegative);
3891     return result;
3892 }
3893 
3894 ///
3895 unittest
3896 {
3897     assert (floor(decimal32("123.456")) == 123);
3898     assert (floor(decimal32("-123.456")) == -124);
3899 }
3900 
3901 /**
3902 Returns (x * y) + z, rounding only once according to the current precision and rounding mode
3903 Throws:
3904 $(BOOKTABLE,
3905     $(TR $(TD $(MYREF InvalidOperationException)) 
3906          $(TD x, y or z is signaling $(B NaN)))
3907     $(TR $(TD $(MYREF InvalidOperationException)) 
3908          $(TD (x, y) = (±∞, ±0.0) or (±0.0, ±∞)))
3909     $(TR $(TD $(MYREF InvalidOperationException)) 
3910          $(TD x or y is infinite, z is infinite but has opposing sign))
3911     $(TR $(TD $(MYREF UnderflowException)) 
3912          $(TD result is too small to be represented))
3913     $(TR $(TD $(MYREF OverflowException)) 
3914          $(TD result is too big to be represented))
3915     $(TR $(TD $(MYREF InexactException)) 
3916          $(TD the result is inexact))
3917 )
3918 Special_values:
3919 $(BOOKTABLE,
3920     $(TR $(TH x) $(TH y) $(TH z) $(TH fma(x, y, z)))
3921     $(TR $(TD $(B NaN)) $(TD any) $(TD any) $(TD $(B NaN)))
3922     $(TR $(TD any) $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
3923     $(TR $(TD any) $(TD any) $(TD $(B NaN)) $(TD $(B NaN)))
3924     $(TR $(TD ±∞) $(TD ±0.0) $(TD any) $(TD $(B NaN)))
3925     $(TR $(TD ±0.0) $(TD ±∞) $(TD any) $(TD $(B NaN)))
3926     $(TR $(TD +∞) $(TD >0.0) $(TD -∞) $(TD $(B NaN)))
3927     $(TR $(TD -∞) $(TD <0.0) $(TD -∞) $(TD $(B NaN)))
3928     $(TR $(TD -∞) $(TD <0.0) $(TD -∞) $(TD $(B NaN)))
3929     $(TR $(TD +∞) $(TD >0.0) $(TD -∞) $(TD $(B NaN)))
3930     $(TR $(TD -∞) $(TD >0.0) $(TD +∞) $(TD $(B NaN)))
3931     $(TR $(TD +∞) $(TD <0.0) $(TD +∞) $(TD $(B NaN)))
3932     $(TR $(TD +∞) $(TD <0.0) $(TD +∞) $(TD $(B NaN)))
3933     $(TR $(TD -∞) $(TD >0.0) $(TD +∞) $(TD $(B NaN)))
3934     $(TR $(TD >0.0) $(TD +∞) $(TD -∞) $(TD $(B NaN)))
3935     $(TR $(TD <0.0) $(TD -∞) $(TD -∞) $(TD $(B NaN)))
3936     $(TR $(TD <0.0) $(TD -∞) $(TD -∞) $(TD $(B NaN)))
3937     $(TR $(TD >0.0) $(TD +∞) $(TD -∞) $(TD $(B NaN)))
3938     $(TR $(TD >0.0) $(TD -∞) $(TD +∞) $(TD $(B NaN)))
3939     $(TR $(TD <0.0) $(TD +∞) $(TD +∞) $(TD $(B NaN)))
3940     $(TR $(TD <0.0) $(TD +∞) $(TD +∞) $(TD $(B NaN)))
3941     $(TR $(TD >0.0) $(TD -∞) $(TD +∞) $(TD $(B NaN)))
3942     $(TR $(TD +∞) $(TD >0.0) $(TD +∞) $(TD +∞))
3943     $(TR $(TD -∞) $(TD <0.0) $(TD +∞) $(TD +∞))
3944     $(TR $(TD +∞) $(TD <0.0) $(TD -∞) $(TD -∞))
3945     $(TR $(TD -∞) $(TD >0.0) $(TD -∞) $(TD -∞))
3946     $(TR $(TD >0.0) $(TD +∞) $(TD +∞) $(TD +∞))
3947     $(TR $(TD <0.0) $(TD -∞) $(TD +∞) $(TD +∞))
3948     $(TR $(TD <0.0) $(TD +∞) $(TD -∞) $(TD -∞))
3949     $(TR $(TD >0.0) $(TD -∞) $(TD -∞) $(TD -∞))
3950     $(TR $(TD +∞) $(TD >0.0) $(TD any) $(TD +∞))
3951     $(TR $(TD -∞) $(TD <0.0) $(TD any) $(TD +∞))
3952     $(TR $(TD +∞) $(TD <0.0) $(TD any) $(TD -∞))
3953     $(TR $(TD -∞) $(TD >0.0) $(TD any) $(TD -∞))
3954     $(TR $(TD >0.0) $(TD +∞) $(TD any) $(TD +∞))
3955     $(TR $(TD <0.0) $(TD -∞) $(TD any) $(TD +∞))
3956     $(TR $(TD <0.0) $(TD +∞) $(TD any) $(TD -∞))
3957     $(TR $(TD >0.0) $(TD -∞) $(TD any) $(TD -∞))
3958 )
3959 */
3960 @IEEECompliant("fusedMultiplyAdd", 4)
3961 auto fma(D1, D2, D3)(auto const ref D1 x, auto const ref D2 y, auto const ref D3 z)
3962 if (isDecimal!(D1, D2, D3))
3963 {
3964     alias D = CommonDecimal!(D1, D2, D3);
3965     D result;
3966     auto flags = decimalFMA!(D1, D2, D3)(x, y, z, result, 
3967                         __ctfe ? D.PRECISION : DecimalControl.precision, 
3968                         __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
3969     DecimalControl.raiseFlags(flags);
3970     return result;
3971 }
3972 
3973 ///
3974 unittest
3975 {
3976     decimal32 x = 2;
3977     decimal64 y = 3;
3978     decimal128 z = 5;
3979     assert (fma(x, y, z) == 11);
3980 }
3981 
3982 /**
3983 Returns the larger _decimal value between x and y
3984 Throws:
3985     $(MYREF InvalidOperationException) if x or y is signaling $(B NaN)
3986 Special_values:
3987 $(BOOKTABLE,
3988     $(TR $(TH x) $(TH y) $(TH fmax(x, y)))
3989     $(TR $(TD $(B NaN)) $(TD any) $(TD y))
3990     $(TR $(TD any) $(TD $(B NaN)) $(TD x))
3991 )
3992 */
3993 @IEEECompliant("maxNum", 19)
3994 auto fmax(D1, D2)(auto const ref D1 x, auto const ref D2 y)
3995 if (isDecimal!D1 && isDecimal!D2)
3996 {
3997     CommonDecimal!(D1, D2) result;
3998     auto flags = decimalMax(x, y, result);
3999     DecimalControl.raiseFlags(flags);
4000     return result;
4001 }
4002 
4003 ///
4004 unittest
4005 {
4006     decimal32 x = 3;
4007     decimal64 y = -4;
4008     assert (fmax(x, y) == 3);
4009 }
4010 
4011 /**
4012 Returns the larger _decimal value between absolutes of x and y
4013 Throws:
4014     $(MYREF InvalidOperationException) if x or y is signaling $(B NaN)
4015 Special_values:
4016 $(BOOKTABLE,
4017     $(TR $(TH x) $(TH y) $(TH fmaxAbs(x, y)))
4018     $(TR $(TD $(B NaN)) $(TD any) $(TD y))
4019     $(TR $(TD any) $(TD $(B NaN)) $(TD x))
4020 )
4021 */
4022 @IEEECompliant("maxNumMag", 19)
4023 auto fmaxAbs(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4024 if (isDecimal!D1 && isDecimal!D2)
4025 {
4026     CommonDecimal!(D1, D2) result;
4027     auto flags = decimalMaxAbs(x, y, result) & ExceptionFlags.invalidOperation;
4028     DecimalControl.raiseFlags(flags);
4029     return result;
4030 }
4031 
4032 ///
4033 unittest
4034 {
4035     decimal32 x = 3;
4036     decimal64 y = -4;
4037     assert (fmaxAbs(x, y) == -4);
4038 }
4039 
4040 /**
4041 Returns the smaller _decimal value between x and y
4042 Throws:
4043     $(MYREF InvalidOperationException) if x or y is signaling $(B NaN)
4044 Special_values:
4045 $(BOOKTABLE,
4046     $(TR $(TH x) $(TH y) $(TH fmin(x, y)))
4047     $(TR $(TD $(B NaN)) $(TD any) $(TD y))
4048     $(TR $(TD any) $(TD $(B NaN)) $(TD x))
4049 )
4050 */
4051 @IEEECompliant("minNum", 19)
4052 auto fmin(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4053 if (isDecimal!D1 && isDecimal!D2)
4054 {
4055     CommonDecimal!(D1, D2) result;
4056     auto flags = decimalMin(x, y, result) & ExceptionFlags.invalidOperation;
4057     DecimalControl.raiseFlags(flags);
4058     return result;
4059 }
4060 
4061 ///
4062 unittest
4063 {
4064     decimal32 x = 3;
4065     decimal64 y = -4;
4066     assert (fmin(x, y) == -4);
4067 }
4068 
4069 /**
4070 Returns the smaller _decimal value between absolutes of x and y
4071 Throws:
4072     $(MYREF InvalidOperationException) if x or y is signaling $(B NaN)
4073 Special_values:
4074 $(BOOKTABLE,
4075     $(TR $(TH x) $(TH y) $(TH fminAbs(x, y)))
4076     $(TR $(TD $(B NaN)) $(TD any) $(TD y))
4077     $(TR $(TD any) $(TD $(B NaN)) $(TD x))
4078 )
4079 */
4080 @IEEECompliant("minNumMag", 19)
4081 auto fminAbs(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4082 if (isDecimal!D1 && isDecimal!D2)
4083 {
4084     CommonDecimal!(D1, D2) result;
4085     auto flags = decimalMinAbs(x, y, result) & ExceptionFlags.invalidOperation;
4086     DecimalControl.raiseFlags(flags);
4087     return result;
4088 }
4089 
4090 ///
4091 unittest
4092 {
4093     decimal32 x = 3;
4094     decimal64 y = -4;
4095     assert (fminAbs(x, y) == 3);
4096 }
4097 
4098 /**
4099 Calculates the remainder of the division x / y
4100 Params:
4101     x = dividend
4102     y = divisor
4103 Returns:
4104     The value of x - n * y, where n is the quotient rounded toward zero of the division x / y  
4105 Throws:
4106 $(BOOKTABLE,
4107     $(TR $(TD $(MYREF InvalidOperationException)) 
4108          $(TD x or y is signaling $(B NaN), x = ±∞, y = ±0.0))
4109     $(TR $(TD $(MYREF UnderflowException)) 
4110          $(TD result is too small to be represented))
4111     $(TR $(TD $(MYREF DivisionByZeroException)) 
4112          $(TD y = 0.0))
4113     $(TR $(TD $(MYREF InexactException)) 
4114          $(TD the result is inexact))
4115 )
4116 Special_values:
4117 $(BOOKTABLE,
4118     $(TR $(TH x) $(TH y) $(TH fmod(x, y)))
4119     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
4120     $(TR $(TD any) $(TD $(B NaN)) $(TD $(B NaN)))
4121     $(TR $(TD ±∞) $(TD any) $(TD $(B NaN)))
4122     $(TR $(TD any) $(TD 0.0) $(TD $(B NaN)))
4123     $(TR $(TD any) $(TD ±∞) $(TD $(B NaN)))
4124 )
4125 */
4126 auto fmod(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4127 {
4128     alias D = CommonDecimal!(D1, D2);
4129     D result = x;
4130     auto flags = decimalMod(result, y, 
4131                             __ctfe ? D.PRECISION : DecimalControl.precision, 
4132                             RoundingMode.towardZero);
4133     DecimalControl.raiseFlags(flags & ~ExceptionFlags.underflow);
4134     return result;
4135 }
4136 
4137 ///
4138 unittest
4139 {
4140     decimal32 x = "18.5";
4141     decimal32 y = "4.2";
4142     assert (fmod(x, y) == decimal32("1.7"));
4143 }
4144 
4145 
4146 /**
4147 Separates _decimal _value into coefficient and exponent. 
4148 This operation is silent, doesn't throw any exception.
4149 Returns:
4150     a result such as x = result * 10$(SUPERSCRIPT y) and |result| < 1.0
4151 Special_values:
4152 $(BOOKTABLE,
4153     $(TR $(TH x) $(TH y) $(TH frexp(x, y)))
4154     $(TR $(TD $(B NaN)) $(TD 0) $(TD $(B NaN)))
4155     $(TR $(TD +∞) $(TD 0) $(TD +∞))
4156     $(TR $(TD -∞) $(TD 0) $(TD -∞))
4157     $(TR $(TD ±0.0) $(TD 0) $(TD ±0.0))
4158 )
4159 Notes:
4160     This operation is silent, doesn't throw any exceptions and doesn't set any error flags.
4161     Signaling NaNs are quieted by this operation
4162 
4163 */
4164 D frexp(D)(auto const ref D x, out int y)
4165 {
4166     DataType!D cx; int ex; bool sx;
4167     Unqual!D result;
4168     final switch(fastDecode(x, cx, ex, sx))
4169     {
4170         case FastClass.signalingNaN:
4171             result.invalidPack(sx, cx);
4172             return result;
4173         case FastClass.quietNaN:
4174             y = 0;
4175             return x;
4176         case FastClass.infinite:
4177             y = 0;
4178             return x;
4179         case FastClass.zero:
4180             y = 0;
4181             return sx ? -D.zero : D.zero;
4182         case FastClass.finite:
4183             auto targetPower = -prec(cx);
4184             y = ex - targetPower;
4185             result.adjustedPack(cx, targetPower, sx, 0, RoundingMode.implicit);
4186             return result;
4187     }
4188 }
4189 /**
4190 Extracts the current payload from a $(B NaN) value
4191 Note:
4192     These functions do not check if x is truly a $(B NaN) value
4193     before extracting the payload. Using them on finite values will extract a part of the coefficient
4194 */
4195 @nogc nothrow pure @safe
4196 uint getNaNPayload(const decimal32 x)
4197 {
4198     return x.data & decimal32.MASK_PAYL;
4199 }
4200 
4201 ///ditto
4202 @nogc nothrow pure @safe
4203 ulong getNaNPayload(const decimal64 x)
4204 {
4205     return x.data & decimal64.MASK_PAYL;
4206 }
4207 
4208 ///ditto
4209 @nogc nothrow pure @safe
4210 ulong getNaNPayload(const decimal128 x, out ulong payloadHi)
4211 {
4212     auto payload = x.data & decimal128.MASK_PAYL;
4213     payloadHi = payload.hi;
4214     return payload.lo;
4215 }
4216 
4217 ///
4218 unittest
4219 {
4220     decimal32 x = decimal32("nan(123)");
4221     decimal64 y = decimal64("nan(456)");
4222     decimal128 z = decimal128("nan(789)");
4223 
4224     assert (getNaNPayload(x) == 123);
4225     assert (getNaNPayload(y) == 456);
4226     ulong hi;
4227     assert (getNaNPayload(z, hi) == 789 && hi == 0);
4228 
4229 }
4230 
4231 
4232 /**
4233 Calculates the length of the hypotenuse of a right-angled triangle with sides 
4234 of length x and y. The hypotenuse is the value of the square root of the sums 
4235 of the squares of x and y.
4236 Throws:
4237 $(BOOKTABLE,
4238     $(TR $(TD $(MYREF InvalidOperationException)) 
4239          $(TD x, y is signaling $(B NaN)))
4240     $(TR $(TD $(MYREF OverflowException)) 
4241          $(TD result is too big to be represented))
4242     $(TR $(TD $(MYREF InexactException)) 
4243          $(TD the result is inexact))
4244 )
4245 Special_values:
4246 $(BOOKTABLE,
4247     $(TR $(TH x) $(TH y) $(TH hypot(x, y)))
4248     $(TR $(TD $(B NaN)) $(TD $(B NaN)) $(TD nan))
4249     $(TR $(TD ±∞) $(TD any) $(TD +∞))
4250     $(TR $(TD any) $(TD ±∞) $(TD +∞))
4251     $(TR $(TD $(B NaN)) $(TD any) $(TD nan))
4252     $(TR $(TD any) $(TD $(B NaN)) $(TD nan))
4253     $(TR $(TD 0.0) $(TD any) $(TD y))
4254     $(TR $(TD any) $(TD 0.0) $(TD x))
4255 )
4256 */
4257 @IEEECompliant("hypot", 42)
4258 auto hypot(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4259 if (isDecimal!D1 && isDecimal!D2)
4260 {
4261     alias D = CommonDecimal!(D1, D2);
4262     D result;
4263     auto flags = decimalHypot(x, y, result, 
4264                               __ctfe ? D.PRECISION : DecimalControl.precision,
4265                               __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
4266     DecimalControl.raiseFlags(flags);
4267     return result;
4268 }
4269 
4270 ///
4271 unittest
4272 {
4273     decimal32 x = 3;
4274     decimal32 y = 4;
4275     assert (hypot(x, y) == 5);
4276 }
4277 
4278 /**
4279 Returns the 10-exponent of x as a signed integral value..
4280 Throws:
4281     $(MYREF InvalidOperationException) if x is $(B NaN), infinity or 0
4282 Special_values:
4283 $(BOOKTABLE,
4284     $(TR $(TH x) $(TH ilogb(x)))
4285     $(TR $(TD $(B NaN)) $(TD int.min))
4286     $(TR $(TD ±∞) $(TD int min + 1))
4287     $(TR $(TD ±0.0) $(TD int.min + 2))
4288     $(TR $(TD ±1.0) $(TD 0))
4289 )
4290 */
4291 @IEEECompliant("logB", 17)
4292 int ilogb(D)(auto const ref D x)
4293 if (isDecimal!D)
4294 {
4295     int result;
4296     auto flags = decimalLog(x, result);
4297     DecimalControl.raiseFlags(flags);
4298     return result;
4299 }
4300 
4301 ///
4302 unittest
4303 {
4304     assert (ilogb(decimal32(1234)) == 3);
4305 }
4306 
4307 /**
4308 Determines if x is canonical.
4309 This operation is silent, no error flags are set and no exceptions are thrown.
4310 Params:
4311 x = a _decimal value
4312 Returns: 
4313     true if x is canonical, false otherwise
4314 Notes:
4315     A _decimal value is considered canonical:<br/>
4316     - if the value is $(B NaN), the payload must be less than 10 $(SUPERSCRIPT precision - 1);<br/>
4317     - if the value is infinity, no trailing bits are accepted;<br/>
4318     - if the value is finite, the coefficient must be less than 10 $(SUPERSCRIPT precision). 
4319 */
4320 @IEEECompliant("isCanonical", 25)
4321 bool isCanonical(D)(auto const ref D x)
4322 if (isDecimal!D)
4323 {
4324     static if (is(D: decimal32) || is(D: decimal64))
4325     {
4326         if ((x.data & D.MASK_QNAN) == D.MASK_QNAN)
4327             return (x.data & D.MASK_PAYL) <= D.PAYL_MAX && (x.data & ~(D.MASK_SNAN | D.MASK_SGN | D.MASK_PAYL)) == 0U;
4328         if ((x.data & D.MASK_INF) == D.MASK_INF)
4329             return (x.data & ~(D.MASK_INF | D.MASK_SGN)) == 0U;
4330         if ((x.data & D.MASK_EXT) == D.MASK_EXT)
4331             return ((x.data & D.MASK_COE2) | D.MASK_COEX) <= D.COEF_MAX;
4332         else
4333             return ((x.data & D.MASK_COE1) <= D.COEF_MAX);
4334     }
4335     else
4336     {
4337         if ((x.data.hi & D.MASK_QNAN.hi) == D.MASK_QNAN.hi)
4338             return (x.data & D.MASK_PAYL) <= D.PAYL_MAX && (x.data & ~(D.MASK_SNAN | D.MASK_SGN | D.MASK_PAYL)) == 0U;
4339         if ((x.data.hi & D.MASK_INF.hi) == D.MASK_INF.hi)
4340             return (x.data.hi & ~(D.MASK_INF.hi | D.MASK_SGN.hi)) == 0U && x.data.lo == 0U;
4341         if ((x.data.hi & D.MASK_EXT.hi) == D.MASK_EXT.hi)
4342             return false;
4343         else
4344             return ((x.data & D.MASK_COE1) <= D.COEF_MAX);
4345     }
4346 
4347 
4348 }
4349 
4350 ///
4351 unittest
4352 {
4353     assert(isCanonical(decimal32.max));
4354     assert(isCanonical(decimal64.max));
4355     assert(!isCanonical(decimal32("nan(0x3fffff)")));
4356 
4357 }
4358 
4359 unittest
4360 {
4361 
4362     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
4363     {
4364         assert(isCanonical(T.zero));
4365         assert(isCanonical(T.max));
4366         assert(isCanonical(T.nan));
4367         assert(isCanonical(T.snan));
4368         assert(isCanonical(T.infinity));
4369     }
4370 }
4371 
4372 /**
4373 Determines if x is a finite value.
4374 This operation is silent, no error flags are set and no exceptions are thrown.
4375 Params:
4376     x = a _decimal value
4377 Returns: 
4378     true if x is finite, false otherwise ($(B NaN) or infinity) 
4379 */
4380 @IEEECompliant("isFinite", 25)
4381 bool isFinite(D: Decimal!bits, int bits)(auto const ref D x)
4382 {
4383     static if (is(D: decimal32) || is(D: decimal64))
4384     {
4385         return (x.data & D.MASK_INF) != D.MASK_INF; 
4386     }
4387     else
4388     {
4389         return (x.data.hi & D.MASK_INF.hi) != D.MASK_INF.hi;
4390     }
4391 }
4392 
4393 ///
4394 unittest
4395 {
4396     assert(isFinite(decimal32.max));
4397     assert(!isFinite(decimal64.nan));
4398     assert(!isFinite(decimal128.infinity));
4399 }
4400 
4401 unittest
4402 {
4403     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
4404     {
4405         assert(isFinite(T.max));
4406         assert(!isFinite(T.infinity));
4407         assert(!isFinite(T.snan));
4408         assert(!isFinite(T.qnan));
4409     }
4410 }
4411 
4412 /**
4413 Checks if two _decimal values are identical
4414 Params:
4415     x = a _decimal value
4416     y = a _decimal value
4417 Returns:
4418     true if x has the same internal representation as y
4419 Notes:
4420     Even if two _decimal values are equal, their internal representation can be different:<br/>
4421     - $(B NaN) values must have the same sign and the same payload to be considered identical; 
4422       $(B NaN)(12) is not identical to $(B NaN)(13)<br/>
4423     - Zero values must have the same sign and the same exponent to be considered identical; 
4424       0 * 10$(SUPERSCRIPT 3) is not identical to 0 * 10$(SUPERSCRIPT 5)<br/>
4425     - Finite _values must be represented based on same exponent to be considered identical;
4426       123 * 10$(SUPERSCRIPT -3) is not identical to 1.23 * 10$(SUPERSCRIPT -1)
4427 */
4428 bool isIdentical(D)(auto const ref D x, auto const ref D y)
4429 if (isDecimal!D)
4430 {
4431     return x.data == y.data;
4432 }
4433 
4434 ///
4435 unittest
4436 {
4437     assert (isIdentical(decimal32.min_normal, decimal32.min_normal));
4438     assert (!isIdentical(decimal64("nan"), decimal64("nan<200>")));
4439 }
4440 
4441 /**
4442 Determines if x represents infinity.
4443 This operation is silent, no error flags are set and no exceptions are thrown.
4444 Params:
4445     x = a _decimal value
4446 Returns: 
4447     true if x is infinite, false otherwise ($(B NaN) or any finite value)
4448 */
4449 @IEEECompliant("isInfinite", 25)
4450 bool isInfinity(D)(auto const ref D x)
4451 if (isDecimal!D)
4452 {
4453     static if (is(D: decimal32) || is(D: decimal64))
4454     {
4455         return (x.data & D.MASK_QNAN) == D.MASK_INF;  
4456     }
4457     else
4458     {
4459         return (x.data.hi & D.MASK_QNAN.hi) == D.MASK_INF.hi;  
4460     }
4461 }
4462 
4463 ///
4464 unittest
4465 {
4466     assert(isInfinity(decimal32.infinity));
4467     assert(isInfinity(-decimal64.infinity));
4468     assert(!isInfinity(decimal128.nan));
4469 }
4470 
4471 unittest
4472 {
4473     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
4474     {
4475         assert(isInfinity(T.infinity));
4476         assert(isInfinity(-T.infinity));
4477         assert(!isInfinity(T.ten));
4478         assert(!isInfinity(T.snan));
4479         assert(!isInfinity(T.qnan));
4480     }
4481 }
4482 
4483 /**
4484 Determines if x represents a $(B NaN).
4485 This operation is silent, no error flags are set and no exceptions are thrown.
4486 Params:
4487     x = a _decimal value
4488 Returns: 
4489     true if x is $(B NaN) (quiet or signaling), false otherwise (any other value than $(B NaN))
4490 */
4491 @IEEECompliant("isNaN", 25)
4492 bool isNaN(D)(auto const ref D x)
4493 if (isDecimal!D)
4494 {
4495     static if (is(D: decimal32) || is(D: decimal64))
4496     {
4497         return (x.data & D.MASK_QNAN) == D.MASK_QNAN;  
4498     }
4499     else
4500     {
4501         return (x.data.hi & D.MASK_QNAN.hi) == D.MASK_QNAN.hi;  
4502     }
4503 }
4504 
4505 ///
4506 unittest
4507 {
4508     assert(isNaN(decimal32()));
4509     assert(isNaN(decimal64.nan));
4510     assert(!isNaN(decimal128.max));
4511 }
4512 
4513 unittest
4514 {
4515     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
4516     {
4517         assert(isNaN(T.snan));
4518         assert(isNaN(T()));
4519         assert(!isSignaling(T.ten));
4520         assert(!isSignaling(T.min_normal));
4521         assert(isNaN(T.qnan));
4522     }
4523 }
4524 
4525 /**
4526 Determines if x is normalized.
4527 This operation is silent, no error flags are set and no exceptions are thrown.
4528 Params:
4529     x = a _decimal value
4530 Returns: 
4531     true if x is normal, false otherwise ($(B NaN), infinity, zero, subnormal)
4532 */
4533 @IEEECompliant("isNormal", 25)
4534 bool isNormal(D)(auto const ref D x)
4535 if (isDecimal!D)
4536 {
4537     DataType!D coefficient;
4538     uint exponent;
4539 
4540     static if (is(D: decimal32) || is(D: decimal64))
4541     {
4542         if ((x.data & D.MASK_INF) == D.MASK_INF)
4543             return false;
4544         if ((x.data & D.MASK_EXT) == D.MASK_EXT)
4545         {
4546             coefficient = (x.data & D.MASK_COE2) | D.MASK_COEX;
4547             if (coefficient > D.COEF_MAX)
4548                 return false;
4549             exponent = cast(uint)((x.data & D.MASK_EXP2) >>> D.SHIFT_EXP2);
4550         }
4551         else
4552         {
4553             coefficient = x.data & D.MASK_COE1;
4554             if (coefficient == 0U)
4555                 return false;
4556             exponent = cast(uint)((x.data & D.MASK_EXP1) >>> D.SHIFT_EXP1);
4557         }  
4558     }
4559     else
4560     {
4561         if ((x.data.hi & D.MASK_INF.hi) == D.MASK_INF.hi)
4562             return false;
4563         if ((x.data.hi & D.MASK_EXT.hi) == D.MASK_EXT.hi)
4564             return false;
4565         coefficient = x.data & D.MASK_COE1;
4566         if (coefficient == 0U || coefficient > D.COEF_MAX)
4567             return false;
4568         exponent = cast(uint)((x.data.hi & D.MASK_EXP1.hi) >>> (D.SHIFT_EXP1 - 64));
4569     }
4570 
4571     if (exponent < D.PRECISION - 1)
4572         return prec(coefficient) >= D.PRECISION - exponent;
4573 
4574     return true;
4575 }
4576 
4577 ///
4578 unittest
4579 {
4580     assert(isNormal(decimal32.max));
4581     assert(!isNormal(decimal64.nan));
4582     assert(!isNormal(decimal32("0x1p-101")));
4583 }
4584 
4585 unittest
4586 {
4587    
4588     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
4589     {
4590         assert(!isNormal(T.zero));
4591         assert(isNormal(T.ten));
4592         assert(!isNormal(T.nan));
4593         assert(isNormal(T.min_normal));
4594         assert(!isNormal(T.subn));
4595     }
4596 }
4597 
4598 /**
4599 Checks whether a _decimal value is a power of ten. This operation is silent, 
4600 no exception flags are set and no exceptions are thrown.
4601 Params:
4602     x = any _decimal value
4603 Returns:
4604     true if x is power of ten, false otherwise ($(B NaN), infinity, 0, negative)
4605 */
4606 bool isPowerOf10(D)(auto const ref D x)
4607 if (isDecimal!D)
4608 {
4609     if (isNaN(x) || isInfinity(x) || isZero(x) || signbit(x) != 0U)
4610         return false;
4611 
4612     alias U = DataType!D;
4613     U c;
4614     int e;
4615     x.unpack(c, e);
4616     coefficientShrink(c, e);
4617     return c == 1U;
4618 }
4619 
4620 ///
4621 unittest
4622 {
4623     assert (isPowerOf10(decimal32("1000")));
4624     assert (isPowerOf10(decimal32("0.001")));
4625 }
4626 
4627 /**
4628 Determines if x represents a signaling $(B NaN).
4629 This operation is silent, no error flags are set and no exceptions are thrown.
4630 Params:
4631     x = a _decimal value
4632 Returns: 
4633     true if x is $(B NaN) and is signaling, false otherwise (quiet $(B NaN), any other value)
4634 */
4635 @IEEECompliant("isSignaling", 25)
4636 bool isSignaling(D)(auto const ref D x)
4637 if (isDecimal!D)
4638 {
4639     static if (is(D: decimal32) || is(D: decimal64))
4640     {
4641         return (x.data & D.MASK_SNAN) == D.MASK_SNAN;  
4642     }
4643     else
4644     {
4645         return (x.data.hi & D.MASK_SNAN.hi) == D.MASK_SNAN.hi;  
4646     }
4647 }
4648 
4649 ///
4650 unittest
4651 {
4652     assert(isSignaling(decimal32()));
4653     assert(!isSignaling(decimal64.nan));
4654     assert(!isSignaling(decimal128.max));
4655 }
4656 
4657 unittest
4658 {
4659     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
4660     {
4661         assert(isSignaling(T.snan));
4662         assert(isSignaling(T()));
4663         assert(!isSignaling(T.ten));
4664         assert(!isSignaling(T.min_normal));
4665         assert(!isSignaling(T.qnan));
4666     }
4667 }
4668 
4669 /**
4670 Determines if x is subnormal (denormalized).
4671 This operation is silent, no error flags are set and no exceptions are thrown.
4672 Params:
4673     x = a _decimal value
4674 Returns: 
4675     true if x is subnormal, false otherwise ($(B NaN), infinity, zero, normal)
4676 */
4677 @IEEECompliant("isSubnormal", 25)
4678 bool isSubnormal(D)(auto const ref D x)
4679 if (isDecimal!D)
4680 {
4681     DataType!D coefficient;
4682     uint exponent;
4683 
4684     static if (is(D: decimal32) || is(D: decimal64))
4685     {
4686         if ((x.data & D.MASK_INF) == D.MASK_INF)
4687             return false;
4688         if ((x.data & D.MASK_EXT) == D.MASK_EXT)
4689         {
4690             coefficient = (x.data & D.MASK_COE2) | D.MASK_COEX;
4691             if (coefficient > D.COEF_MAX)
4692                 return false;
4693             exponent = cast(uint)((x.data & D.MASK_EXP2) >>> D.SHIFT_EXP2);
4694         }
4695         else
4696         {
4697             coefficient = x.data & D.MASK_COE1;
4698             if (coefficient == 0U)
4699                 return false;
4700             exponent = cast(uint)((x.data & D.MASK_EXP1) >>> D.SHIFT_EXP1);
4701         }  
4702     }
4703     else
4704     {
4705         if ((x.data.hi & D.MASK_INF.hi) == D.MASK_INF.hi)
4706             return false;
4707         if ((x.data.hi & D.MASK_EXT.hi) == D.MASK_EXT.hi)
4708             return false;
4709         coefficient = x.data & D.MASK_COE1;
4710         if (coefficient == 0U || coefficient > D.COEF_MAX)
4711             return false;
4712         exponent = cast(uint)((x.data.hi & D.MASK_EXP1.hi) >>> (D.SHIFT_EXP1 - 64));
4713     }
4714 
4715     if (exponent < D.PRECISION - 1)
4716         return prec(coefficient) < D.PRECISION - exponent;
4717 
4718     return false;
4719 }
4720 
4721 ///
4722 unittest
4723 {
4724     assert(isSubnormal(decimal32("0x1p-101")));
4725     assert(!isSubnormal(decimal32.max));
4726     assert(!isSubnormal(decimal64.nan));
4727     
4728 }
4729 
4730 unittest
4731 {
4732 
4733     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
4734     {
4735         assert(!isSubnormal(T.zero));
4736         assert(!isSubnormal(T.ten));
4737         assert(!isSubnormal(T.nan));
4738         assert(!isSubnormal(T.min_normal));
4739         assert(isSubnormal(T.subn));
4740         assert(isSubnormal(-T.subn));
4741     }
4742 }
4743 
4744 
4745 
4746 /**
4747 Determines if x represents the value zero.
4748 This operation is silent, no error flags are set and no exceptions are thrown.
4749 Params:
4750     x = a _decimal value
4751 Returns: 
4752     true if x is zero, false otherwise (any other value than zero)
4753 Standards: 
4754     If the internal representation of the _decimal data type has a coefficient 
4755     greater that 10$(SUPERSCRIPT precision) - 1, is considered 0 according to 
4756     IEEE standard.
4757 */
4758 @("this must be fast")
4759 @IEEECompliant("isZero", 25)
4760 bool isZero(D)(auto const ref D x)
4761 if (isDecimal!D)
4762 {
4763     static if (is(D: decimal32) || is(D: decimal64))
4764     {
4765         if ((x.data & D.MASK_INF) != D.MASK_INF)
4766         {
4767             if ((x.data & D.MASK_EXT) == D.MASK_EXT)
4768                 return ((x.data & D.MASK_COE2) | D.MASK_COEX) > D.COEF_MAX;
4769             else
4770                 return (x.data & D.MASK_COE1) == 0;
4771         }
4772         else
4773             return false;
4774     }
4775     else
4776     {
4777         if ((x.data.hi & D.MASK_INF.hi) != D.MASK_INF.hi)
4778         {
4779             if ((x.data.hi & D.MASK_EXT.hi) == D.MASK_EXT.hi)
4780                 return true;
4781             else
4782             {
4783                 auto cx = x.data & D.MASK_COE1;
4784                 return !cx || cx > D.COEF_MAX;
4785             }
4786         }
4787         else
4788             return false;
4789     }
4790     
4791 }
4792 
4793 ///
4794 unittest
4795 {
4796     assert(isZero(decimal32(0)));
4797     assert(!isZero(decimal64.nan));
4798     assert(isZero(decimal32("0x9FFFFFp+10")));
4799 }
4800 
4801 unittest
4802 {
4803     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
4804     {
4805         assert(isZero(T.zero));
4806         assert(isZero(T.minusZero));
4807         assert(!isZero(T.ten));
4808         assert(isZero(T(T.MASK_NONE, T.MASK_EXT, T.MASK_COE2 | T.MASK_COEX)));
4809     }
4810 }
4811 
4812 
4813 
4814 /**
4815 Compares two _decimal operands.
4816 This operation is silent, no exception flags are set and no exceptions are thrown.
4817 Returns:
4818     true if the specified condition is satisfied
4819 Notes:
4820     By default, comparison operators will throw $(MYREF InvalidOperationException) or will 
4821     set the $(MYREF ExceptionFlags.invalidOperation) context flag if a trap is not set.
4822     The equivalent functions are silent and will not throw any exception (or will not set any flag)
4823     if a $(B NaN) value is encountered.
4824 */
4825 @IEEECompliant("compareQuietGreater", 24)
4826 bool isGreater(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4827 if (isDecimal!(D1, D2))
4828 {
4829     auto c = decimalCmp(x, y);
4830     if (c == -3)
4831         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
4832     return c > 0;
4833 }
4834 
4835 ///ditto
4836 @IEEECompliant("compareQuietGreaterEqual", 24)
4837 bool isGreaterOrEqual(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4838 if (isDecimal!(D1, D2))
4839 {
4840     auto c = decimalCmp(x, y);
4841     if (c == -3)
4842         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
4843     return c >= 0;
4844 }
4845 
4846 ///ditto
4847 @IEEECompliant("compareQuietGreaterUnordered", 24)
4848 bool isGreaterOrUnordered(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4849 if (isDecimal!(D1, D2))
4850 {
4851     auto c = decimalCmp(x, y);
4852     if (c == -3)
4853         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
4854     return c > 0 || c < -1;
4855 }
4856 
4857 ///ditto
4858 @IEEECompliant("compareQuietLess", 24)
4859 @IEEECompliant("compareQuietNotLess", 24)
4860 bool isLess(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4861 if (isDecimal!(D1, D2))
4862 {
4863     auto c = decimalCmp(x, y);
4864     if (c == -3)
4865         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
4866     return c == -1;
4867 }
4868 
4869 ///ditto
4870 @IEEECompliant("compareQuietLessEqual", 24)
4871 bool isLessOrEqual(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4872 if (isDecimal!(D1, D2))
4873 {
4874     auto c = decimalCmp(x, y);
4875     if (c == -3)
4876         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
4877     return c <= 0 && c > -2;
4878 }
4879 
4880 ///ditto
4881 @IEEECompliant("compareQuietLessUnordered", 24)
4882 bool isLessOrUnordered(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4883 if (isDecimal!(D1, D2))
4884 {
4885     auto c = decimalCmp(x, y);
4886     if (c == -3)
4887         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
4888     return c < 0;
4889 }
4890 
4891 ///ditto
4892 @IEEECompliant("compareQuietOrdered", 24)
4893 @IEEECompliant("compareQuietUnordered", 24)
4894 bool isUnordered(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4895 if (isDecimal!(D1, D2))
4896 {
4897     auto c = decimalCmp(x, y);
4898     if (c == -3)
4899         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
4900     return c < -1;
4901 }
4902 
4903 ///
4904 unittest
4905 {
4906     assert(isUnordered(decimal32.nan, decimal64.max));
4907     assert(isGreater(decimal32.infinity, decimal128.max));
4908     assert(isGreaterOrEqual(decimal32.infinity, decimal64.infinity));
4909     assert(isLess(decimal64.max, decimal128.max));
4910     assert(isLessOrEqual(decimal32.min_normal, decimal32.min_normal));
4911 }
4912 
4913 unittest
4914 {
4915     
4916 
4917     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
4918     {
4919         assert(isUnordered(T.nan, T.one));
4920         assert(isUnordered(T.one, T.nan));
4921         assert(isUnordered(T.nan, T.nan));
4922 
4923         assert(isGreater(T.max, T.ten));
4924         assert(isGreater(T.ten, T.one));
4925         assert(isGreater(-T.ten, -T.max));
4926         assert(isGreater(T.zero, -T.max));
4927         assert(isGreater(T.max, T.zero));
4928         
4929         assert(isLess(T.one, T.ten), T.stringof);
4930         assert(isLess(T.ten, T.max));
4931         assert(isLess(-T.max, -T.one));
4932         assert(isLess(T.zero, T.max));
4933         assert(isLess(T.max, T.infinity));
4934     }
4935 }
4936 
4937 /**
4938 Compares two _decimal operands for equality
4939 Returns:
4940     true if the specified condition is satisfied, false otherwise or if any of the operands is $(B NaN).
4941 Notes:
4942     By default, $(MYREF Decimal.opEquals) is silent, returning false if a $(B NaN) value is encountered.
4943     isEqual and isNotEqual will throw $(MYREF InvalidOperationException) or will 
4944     set the $(MYREF ExceptionFlags.invalidOperation) context flag if a trap is not set.
4945 */
4946 
4947 @IEEECompliant("compareSignalingEqual", 24)
4948 bool isEqual(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4949 if (isDecimal!(D1, D2))
4950 {
4951     auto c = decimalEqu(x, y);
4952     if (c < 0)
4953         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
4954     return c == 1;
4955 }
4956 
4957 ///ditto
4958 @IEEECompliant("compareSignalingNotEqual", 24)
4959 bool isNotEqual(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4960 if (isDecimal!(D1, D2))
4961 {
4962     auto c = decimalEqu(x, y);
4963     if (c < 0)
4964         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
4965     return c != 1;
4966 }
4967 
4968 ///
4969 unittest
4970 {
4971     assert (isEqual(decimal32.max, decimal32.max));
4972     assert (isNotEqual(decimal32.max, decimal32.min_normal));
4973 }
4974 
4975 /**
4976 Efficiently calculates 2 * 10$(SUPERSCRIPT n).
4977 $(BOOKTABLE,
4978     $(TR $(TD $(MYREF InvalidOperationException)) 
4979          $(TD x is $(B signaling NaN)))
4980     $(TR $(TD $(MYREF UnderflowException)) 
4981          $(TD result is subnormal or too small to be represented)
4982     $(TR $(TD $(MYREF OverflowException)) 
4983          $(TD result is too big to be represented)
4984     $(TR $(TD $(MYREF InexactException)) 
4985          $(TD result is inexact)
4986 )
4987 Special_values:
4988 $(BOOKTABLE,
4989     $(TR $(TH x) $(TH n) $(TH ldexp(x, n)))
4990     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
4991     $(TR $(TD ±∞) $(TD any) $(TD ±∞))
4992     $(TR $(TD ±0) $(TD any) $(TD ±0))
4993     $(TR $(TD any) $(TD 0) $(TD x))
4994 )
4995 */
4996 D ldexp(D)(auto const ref D x, const int n)
4997 if (isDecimal!D)
4998 {
4999     Unqual!D result = x;
5000     auto flags = decimalMulPow2(result, n,
5001                                 __ctfe ? D.PRECISION : DecimalControl.precision, 
5002                                 __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
5003     DecimalControl.raiseFlags(flags);
5004     return result;
5005 }
5006 
5007 ///
5008 unittest
5009 {
5010     decimal32 d = "1.0";
5011     assert (ldexp(d, 3) == 8);
5012 }
5013 
5014 /**
5015 Calculates the natural logarithm of log$(SUBSCRIPT e)x.
5016 Throws:
5017 $(BOOKTABLE,
5018     $(TR $(TD $(MYREF InvalidOperationException)) 
5019          $(TD x is signaling $(B NaN) or x < 0))
5020     $(TR $(TD $(MYREF DivisionByZero)) 
5021          $(TD x is ±0.0))
5022     $(TR $(TD $(MYREF Underflow)) 
5023          $(TD result is too small to be represented))
5024     $(TR $(TD $(MYREF InexactException)) 
5025          $(TD the result is inexact))
5026 )
5027 Special_values:
5028 $(BOOKTABLE,
5029     $(TR $(TH x) $(TH log(x)))
5030     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5031     $(TR $(TD ±0.0) $(TD -∞))
5032     $(TR $(TD -∞) $(TD $(B NaN)))
5033     $(TR $(TD +∞) $(TD +∞))
5034     $(TR $(TD e) $(TD +1.0))
5035     $(TR $(TD < 0.0) $(TD $(B NaN)))
5036 )
5037 */
5038 @IEEECompliant("log", 42)
5039 D log(D)(auto const ref D x)
5040 if (isDecimal!D)
5041 {
5042     Unqual!D result = x;
5043     auto flags = decimalLog(result, 
5044                              __ctfe ? D.PRECISION : DecimalControl.precision, 
5045                              __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
5046     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero);
5047     DecimalControl.raiseFlags(flags);
5048     return result;
5049 }
5050 
5051 ///
5052 unittest
5053 {
5054     assert (log(decimal32.E) == 1);
5055 }
5056 
5057 
5058 /**
5059 Calculates log$(SUBSCRIPT 10)x.
5060 Throws:
5061 $(BOOKTABLE,
5062     $(TR $(TD $(MYREF InvalidOperationException)) 
5063          $(TD x is signaling $(B NaN) or x < 0.0))
5064     $(TR $(TD $(MYREF DivisionByZero)) 
5065          $(TD x is ±0.0))
5066     $(TR $(TD $(MYREF Underflow)) 
5067          $(TD result is too small to be represented))
5068     $(TR $(TD $(MYREF InexactException)) 
5069          $(TD the result is inexact))
5070 )
5071 Special_values:
5072 $(BOOKTABLE,
5073     $(TR $(TH x) $(TH log(x)))
5074     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5075     $(TR $(TD ±0.0) $(TD -∞))
5076     $(TR $(TD -∞) $(TD $(B NaN)))
5077     $(TR $(TD +∞) $(TD +∞))
5078     $(TR $(TD +10.0) $(TD +1.0))
5079     $(TR $(TD < 0.0) $(TD $(B NaN)))
5080 )
5081 */
5082 @IEEECompliant("log10", 42)
5083 D log10(D)(auto const ref D x)
5084 if (isDecimal!D)
5085 {
5086     Unqual!D result = x;
5087     auto flags = decimalLog10(result, 
5088                             __ctfe ? D.PRECISION : DecimalControl.precision, 
5089                             __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
5090     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero);
5091     DecimalControl.raiseFlags(flags);
5092     return result;
5093 }
5094 
5095 /**
5096 Calculates log$(SUBSCRIPT 10)(x + 1).
5097 Throws:
5098 $(BOOKTABLE,
5099     $(TR $(TD $(MYREF InvalidOperationException)) 
5100          $(TD x is signaling $(B NaN) or x < 1.0))
5101     $(TR $(TD $(MYREF DivisionByZero)) 
5102          $(TD x is -1.0))
5103     $(TR $(TD $(MYREF Underflow)) 
5104          $(TD result is too small to be represented))
5105     $(TR $(TD $(MYREF InexactException)) 
5106          $(TD the result is inexact))
5107 )
5108 Special_values:
5109 $(BOOKTABLE,
5110     $(TR $(TH x) $(TH log(x)))
5111     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5112     $(TR $(TD -1.0) $(TD -∞))
5113     $(TR $(TD -∞) $(TD $(B NaN)))
5114     $(TR $(TD +∞) $(TD +∞))
5115     $(TR $(TD +9.0) $(TD +1.0))
5116     $(TR $(TD < -1.0) $(TD $(B NaN)))
5117 )
5118 */
5119 @IEEECompliant("log10p1", 42)
5120 D log10p1(D)(auto const ref D x)
5121 if (isDecimal!D)
5122 {
5123     Unqual!D result = x;
5124     auto flags = decimalLog10p1(result, 
5125                               __ctfe ? D.PRECISION : DecimalControl.precision, 
5126                               __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
5127     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero);
5128     DecimalControl.raiseFlags(flags);
5129     return result;
5130 }
5131 
5132 /**
5133 Calculates log$(SUBSCRIPT 2)x.
5134 Throws:
5135 $(BOOKTABLE,
5136     $(TR $(TD $(MYREF InvalidOperationException)) 
5137          $(TD x is signaling $(B NaN) or x < 0))
5138     $(TR $(TD $(MYREF DivisionByZero)) 
5139          $(TD x is ±0.0))
5140     $(TR $(TD $(MYREF Underflow)) 
5141          $(TD result is too small to be represented))
5142     $(TR $(TD $(MYREF InexactException)) 
5143          $(TD the result is inexact))
5144 )
5145 Special_values:
5146 $(BOOKTABLE,
5147     $(TR $(TH x) $(TH log(x)))
5148     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5149     $(TR $(TD ±0.0) $(TD -∞))
5150     $(TR $(TD -∞) $(TD $(B NaN)))
5151     $(TR $(TD +∞) $(TD +∞))
5152     $(TR $(TD +2.0) $(TD +1.0))
5153     $(TR $(TD < 0.0) $(TD $(B NaN)))
5154 )
5155 */
5156 @IEEECompliant("log2", 42)
5157 D log2(D)(auto const ref D x)
5158 if (isDecimal!D)
5159 {
5160     Unqual!D result = x;
5161     auto flags = decimalLog2(result, 
5162                               __ctfe ? D.PRECISION : DecimalControl.precision, 
5163                               __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
5164     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero);
5165     DecimalControl.raiseFlags(flags);
5166     return result;
5167 }
5168 
5169 /**
5170 Calculates log$(SUBSCRIPT 2)(x + 1).
5171 Throws:
5172 $(BOOKTABLE,
5173     $(TR $(TD $(MYREF InvalidOperationException)) 
5174          $(TD x is signaling $(B NaN) or x < 0))
5175     $(TR $(TD $(MYREF DivisionByZero)) 
5176          $(TD x is -1.0))
5177     $(TR $(TD $(MYREF Underflow)) 
5178          $(TD result is too small to be represented))
5179     $(TR $(TD $(MYREF InexactException)) 
5180          $(TD the result is inexact))
5181 )
5182 Special_values:
5183 $(BOOKTABLE,
5184     $(TR $(TH x) $(TH log(x)))
5185     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5186     $(TR $(TD ±0.0) $(TD -∞))
5187     $(TR $(TD -∞) $(TD $(B NaN)))
5188     $(TR $(TD +∞) $(TD +∞))
5189     $(TR $(TD +1.0) $(TD +1.0))
5190     $(TR $(TD < -1.0) $(TD $(B NaN)))
5191 )
5192 */
5193 @IEEECompliant("log2p1", 42)
5194 D log2p1(D)(auto const ref D x)
5195 if (isDecimal!D)
5196 {
5197     Unqual!D result = x;
5198     auto flags = decimalLog2p1(result, 
5199                              __ctfe ? D.PRECISION : DecimalControl.precision, 
5200                              __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
5201     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero);
5202     DecimalControl.raiseFlags(flags);
5203     return result;
5204 }
5205 
5206 /**
5207 Calculates log$(SUBSCRIPT e)(x + 1).
5208 Throws:
5209 $(BOOKTABLE,
5210     $(TR $(TD $(MYREF InvalidOperationException)) 
5211          $(TD x is signaling $(B NaN) or x < 0))
5212     $(TR $(TD $(MYREF DivisionByZero)) 
5213          $(TD x is -1.0))
5214     $(TR $(TD $(MYREF Underflow)) 
5215          $(TD result is too small to be represented))
5216     $(TR $(TD $(MYREF InexactException)) 
5217          $(TD the result is inexact))
5218 )
5219 Special_values:
5220 $(BOOKTABLE,
5221     $(TR $(TH x) $(TH log(x)))
5222     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5223     $(TR $(TD ±0.0) $(TD -∞))
5224     $(TR $(TD -∞) $(TD $(B NaN)))
5225     $(TR $(TD +∞) $(TD +∞))
5226     $(TR $(TD e - 1) $(TD +1.0))
5227     $(TR $(TD < -1.0) $(TD $(B NaN)))
5228 )
5229 */
5230 @IEEECompliant("logp1", 42)
5231 D logp1(D)(auto const ref D x)
5232 if (isDecimal!D)
5233 {
5234     Unqual!D result = x;
5235     auto flags = decimalLogp1(result, 
5236                                __ctfe ? D.PRECISION : DecimalControl.precision, 
5237                                __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
5238     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero);
5239     DecimalControl.raiseFlags(flags);
5240     return result;
5241 }
5242 
5243 /**
5244 Returns the value of x rounded using the specified rounding _mode.
5245 If no rounding _mode is specified the default context rounding _mode is used instead.
5246 Throws:
5247 $(BOOKTABLE,
5248     $(TR $(TD $(MYREF InvalidOperationException)) 
5249          $(TD x is $(B NaN) or ±∞))
5250    $(TR $(TD $(MYREF OverflowException)) 
5251          $(TD result is too big to be represented))
5252     $(TR $(TD $(MYREF InexactException)) 
5253          $(TD the result is inexact))
5254 )
5255 Special_values:
5256 $(BOOKTABLE,
5257     $(TR $(TH x) $(TH lrint(x)))
5258     $(TR $(TD $(B NaN)) $(TD 0))
5259     $(TR $(TD -∞) $(TD long.min))
5260     $(TR $(TD +∞) $(TD long.max))
5261 )
5262 */
5263 long lrint(D)(auto const ref D x, const RoundingMode mode)
5264 if (isDecimal!D)
5265 {
5266     long result;
5267     auto flags = decimalToSigned(x, result, mode);
5268     DecimalControl.raiseFlags(flags & (ExceptionFlags.invalidOperation | ExceptionFlags.inexact));
5269     return result;
5270 }
5271 
5272 ///ditto
5273 long lrint(D)(auto const ref D x)
5274 if (isDecimal!D)
5275 {
5276     return lrint(x, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
5277 }
5278 
5279 /**
5280 Returns the value of x rounded away from zero.
5281 Throws:
5282     $(BOOKTABLE,
5283     $(TR $(TD $(MYREF InvalidOperationException)) 
5284          $(TD x is $(B NaN) or ±∞))
5285     $(TR $(TD $(MYREF OverflowException)) 
5286          $(TD result is too big to be represented))
5287 )
5288 Special_values:
5289 $(BOOKTABLE,
5290     $(TR $(TH x) $(TH lround(x)))
5291     $(TR $(TD $(B NaN)) $(TD 0))
5292     $(TR $(TD -∞) $(TD long.min))
5293     $(TR $(TD +∞) $(TD long.max))
5294 )
5295 */
5296 long lround(D)(auto const ref D x)
5297 {
5298     long result;
5299     auto flags = decimalToSigned(x, result, RoundingMode.tiesToAway);
5300     DecimalControl.raiseFlags(flags & ExceptionFlags.invalidOperation);
5301     //todo: intel does not set ovf, is that correct?
5302     return result;
5303 }
5304 
5305 /**
5306 Splits x in integral and fractional part.
5307 Params:
5308     x = value to split
5309     y = value of x truncated toward zero
5310 Returns:
5311     Fractional part of x. 
5312 Throws:
5313 $(BOOKTABLE,
5314     $(TR $(TD $(MYREF InvalidOperationException)) 
5315          $(TD x is $(B signaling NaN)))
5316 Special_values:
5317 $(BOOKTABLE,
5318     $(TR $(TH x) $(TH modf(x)) $(TH y))
5319     $(TR $(TD $(B NaN)) $(TD $(B NaN)) $(TD $(B NaN)))
5320     $(TR $(TD 0.0) $(TD 0.0) $(TD 0.0))
5321     $(TR $(TD ±∞) $(TD 0.0) $(TD ±∞))
5322 )
5323 */
5324 D modf(D)(auto const ref D x, ref D y)
5325 if (isDecimal!D)
5326 {
5327     if (isSignaling(x))
5328     {
5329         y = copysign(D.nan, x);
5330         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
5331         return y;
5332     }
5333     else if (isNaN(x))
5334     {
5335         y = copysign(D.nan, x);
5336         return y;
5337     }
5338     else if (isZero(x))
5339     {
5340         y = copysign(D.zero, x);
5341         return y;
5342     }
5343     else if (isInfinity(x))
5344     {
5345         y = x;
5346         return copysign(D.zero, x);
5347     }
5348     else
5349     {
5350         Unqual!D fractional = x;
5351         y = x;
5352         decimalRound(y, 0, RoundingMode.towardZero);
5353         decimalSub(fractional, y, 0, RoundingMode.tiesToAway);
5354         return copysign(fractional, x);
5355     }
5356 }
5357 
5358 /**
5359 Creates a quiet $(B NaN) value using the specified payload
5360 Notes:
5361    Payloads are masked to fit the current representation, having a limited bit width of to $(B mant_dig) - 2;
5362 */
5363 D NaN(D, T)(const T payload)
5364 if (isDecimal!D && isUnsigned!T)
5365 {
5366     D result = void;
5367     result.data = D.MASK_QNAN | (cast(DataType!D)payload & D.MASK_PAYL);
5368     return result;
5369 }
5370 
5371 ///ditto
5372 decimal128 NaN(T)(const T payloadHi, const T payloadLo)
5373 if (isUnsigned!T)
5374 {
5375     decimal128 result = void;
5376     result.data = decimal128.MASK_QNAN | (uint128(payloadHi, payloadLo) & decimal128.MASK_PAYL);
5377     return result;
5378 }
5379 
5380 ///
5381 unittest
5382 {
5383     auto a = NaN!decimal32(12345U);
5384     auto b = NaN!decimal64(12345UL);
5385     decimal128 c = NaN(123U, 456U);
5386 }
5387 
5388 /**
5389 Returns the value of x rounded using the specified rounding _mode.
5390 If no rounding _mode is specified the default context rounding _mode is used instead.
5391 Throws:
5392     $(MYREF InvalidOperationException) if x is signaling $(B NaN)
5393 Special_values:
5394 $(BOOKTABLE,
5395     $(TR $(TH x) $(TH nearbyint(x)))
5396     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5397     $(TR $(TD ±∞) $(TD ±∞))
5398     $(TR $(TD ±0.0) $(TD ±0.0))
5399 )
5400 */
5401 @IEEECompliant("roundToIntegralTiesToAway", 19)
5402 @IEEECompliant("roundToIntegralTiesToEven", 19)
5403 @IEEECompliant("roundToIntegralTowardNegative", 19)
5404 @IEEECompliant("roundToIntegralTowardPositive", 19)
5405 @IEEECompliant("roundToIntegralTowardZero", 19)
5406 D nearbyint(D)(auto const ref D x, const RoundingMode mode)
5407 if (isDecimal!D)
5408 {
5409     Unqual!D result = x;
5410     auto flags = decimalRound(result, __ctfe ? D.PRECISION : DecimalControl.precision, mode);
5411     flags &= ExceptionFlags.invalidOperation;
5412     DecimalControl.raiseFlags(flags);
5413     return result;
5414 }
5415 
5416 ///ditto
5417 D nearbyint(D)(auto const ref D x)
5418 if (isDecimal!D)
5419 {
5420     return nearbyint(x, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
5421 }
5422 
5423 ///
5424 unittest
5425 {
5426     assert(nearbyint(decimal32("1.2"), RoundingMode.tiesToEven) == 1);
5427     assert(nearbyint(decimal64("2.7"), RoundingMode.tiesToAway) == 3);
5428     assert(nearbyint(decimal128("-7.9"), RoundingMode.towardZero) == -7);
5429     assert(nearbyint(decimal128("6.66")) == 7);
5430 }
5431 
5432 
5433 /**
5434 Returns the previous _decimal value before x.
5435 Throws:
5436     $(MYREF InvalidOperationException) if x is signaling $(B NaN)
5437 Special_values:
5438 $(BOOKTABLE,
5439     $(TR $(TH x) $(TH nextDown(x)))
5440     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5441     $(TR $(TD -∞) $(TD -∞))
5442     $(TR $(TD -max) $(TD -∞))
5443     $(TR $(TD ±0.0) $(TD -min_normal * epsilon))
5444     $(TR $(TD +∞) $(TD D.max))
5445 )
5446 */
5447 @IEEECompliant("nextDown", 19)
5448 D nextDown(D)(auto const ref D x)
5449 if (isDecimal!D)
5450 {
5451     Unqual!D result = x;
5452     auto flags = decimalNextDown(result) & ExceptionFlags.invalidOperation;
5453     DecimalControl.raiseFlags(flags);
5454     return result;
5455 }
5456 
5457 /**
5458 Gives the next power of 10 after x. 
5459 Throws:
5460 $(BOOKTABLE,
5461     $(TR $(TD $(MYREF InvalidOperationException)) 
5462          $(TD x is signaling $(B NaN)))
5463     $(TR $(TD $(MYREF OverflowException)) 
5464          $(TD result is too big to be represented))
5465 )
5466 Special_values:
5467 $(BOOKTABLE,
5468     $(TR $(TH x) $(TH nextPow10(x)))
5469     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5470     $(TR $(TD ±∞) $(TD ±∞))
5471     $(TR $(TD ±0.0) $(TD +1.0))
5472 )
5473 */
5474 D nextPow10(D)(auto const ref D x)
5475 if (isDecimal!D)
5476 {
5477     ExceptionFlags flags;
5478     Unqual!D result;
5479 
5480     if (isSignaling(x))
5481     {
5482         result = D.nan;
5483         flags = ExceptionFlags.invalidOperation;
5484     }
5485     else if (isNaN(x) || isInfinity(x))
5486         result = x;
5487     else if (isZero(x))
5488         result = D.one;
5489     else
5490     {
5491         alias U = DataType!D;
5492         U c;
5493         int e;
5494         bool s = x.unpack(c, e);
5495         for (size_t i = 0; i < pow10!U.length; ++i)
5496         {
5497             if (c == pow10!U[i])
5498             {
5499                 ++e;
5500                 break;
5501             }
5502             else if (c < pow10!U[i])
5503             {
5504                 c = pow10!U[i];
5505                 break;
5506             }
5507         }
5508         if (i == pow10!U.length)
5509         {
5510             c = pow10!U[$ - 1];
5511             ++e;
5512         }
5513         
5514         flags = result.adjustedPack(c, e, s, RoundingMode.towardZero, ExceptionFlags.none);
5515     }
5516 
5517     DecimalControl.raiseFlags(flags);
5518     return result;
5519 }
5520 
5521 /**
5522 Returns the next value after or before x, toward y.
5523 Throws:
5524     $(BOOKTABLE,
5525     $(TR $(TD $(MYREF InvalidOperationException)) 
5526          $(TD either x or y is $(B signaling NaN)))
5527     $(TR $(TD $(MYREF OverflowException)) 
5528          $(TD result is ±∞))
5529     $(TR $(TD $(MYREF UnderflowException)) 
5530          $(TD result is subnormal or ±0.0))
5531     $(TR $(TD $(MYREF InexactException)) 
5532          $(TD result is ±∞, subnormal or ±0.0))
5533 )
5534 Special_values:
5535 $(BOOKTABLE,
5536     $(TR $(TH x) $(TH y) $(TH nextAfter(x, y)))
5537     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)) )
5538     $(TR $(TD any) $(TD $(B NaN)) $(TD $(B NaN)) )
5539     $(TR $(TD x = y)  $(TD) $(TD x) )
5540     $(TR $(TD x < y)  $(TD) $(TD $(MYREF nextUp)(x)) )
5541     $(TR $(TD x > y)  $(TD) $(TD $(MYREF nextDown)(x)) )
5542 )
5543 */
5544 D1 nextAfter(D1, D2)(auto const ref D1 x, auto const ref D2 y)
5545 if (isDecimal!(D1, D2))
5546 {
5547     if (isSignaling(x))
5548     {
5549         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
5550         return copysign(D1.nan, x);
5551     }
5552 
5553     if (isSignaling(y))
5554     {
5555         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
5556         return copysign(D1.nan, y);
5557     }
5558 
5559     if (isNaN(x))
5560         return copysign(D1.nan, x);
5561 
5562     if (isNaN(y))
5563         return copysign(D1.nan, y);
5564 
5565     Unqual!D result = x;
5566     ExceptionFlags flags;
5567     int c = decimalCmp(x, y);
5568     if (c != 0)
5569        flags = c < 0 ? decimalNextUp(result) : decimalNextDown(result);
5570     if (isInfinity(result))
5571         flags |= ExceptionFlags.overflow | ExceptionFlags.inexact;
5572     else if (isZero(result) || isSubnormal(result))
5573         flags |= ExceptionFlags.underflow | ExceptionFlags.inexact;
5574     DecimalControl.raiseFlags(flags);
5575     return result;
5576 }
5577 
5578 ///ditto
5579 alias nextToward = nextAfter;
5580 
5581 /**
5582 Returns the next representable _decimal value after x.
5583 Throws:
5584     $(MYREF InvalidOperationException) if x is signaling $(B NaN)
5585 Special_values:
5586 $(BOOKTABLE,
5587     $(TR $(TH x) $(TH nextUp(x)))
5588     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5589     $(TR $(TD -∞) $(TD -D.max))
5590     $(TR $(TD ±0.0) $(TD D.min_normal * epsilon))
5591     $(TR $(TD D.max) $(TD +∞))
5592     $(TR $(TD +∞) $(TD +∞))
5593 )
5594 */
5595 @IEEECompliant("nextUp", 19)
5596 D nextUp(D)(auto const ref D x)
5597 if (isDecimal!D)
5598 {
5599     Unqual!D result = x;
5600     auto flags = decimalNextUp(result) & ExceptionFlags.invalidOperation;
5601     DecimalControl.raiseFlags(flags);
5602     return result;
5603 }
5604 
5605 
5606 
5607 
5608 /**
5609 Calculates a$(SUBSCRIPT 0) + a$(SUBSCRIPT 1)x + a$(SUBSCRIPT 2)x$(SUPERSCRIPT 2) + .. + a$(SUBSCRIPT n)x$(SUPERSCRIPT n)
5610 Throws:
5611     $(BOOKTABLE,
5612     $(TR $(TD $(MYREF InvalidOperationException)) 
5613          $(TD x is signaling $(B NaN) or any a$(SUBSCRIPT i) is signaling $(B NaN)))
5614     $(TR $(TD $(MYREF InvalidOperationException)) 
5615          $(TD x is ±∞ and any a$(SUBSCRIPT i) is ±0.0))
5616     $(TR $(TD $(MYREF InvalidOperationException)) 
5617          $(TD x is ±0.0 and any a$(SUBSCRIPT i) is ±∞))
5618     $(TR $(TD $(MYREF OverflowException)) 
5619          $(TD result is too big to be represented))
5620     $(TR $(TD $(MYREF UnderflowException)) 
5621          $(TD result is too small to be represented))
5622     $(TR $(TD $(MYREF InexactException)) 
5623          $(TD result is inexact))
5624 )
5625 */
5626 auto poly(D1, D2)(auto const ref D1 x, const(D2)[] a)
5627 if (isDecimal!(D1, D2))
5628 {
5629     ExceptionFlags flags;
5630     alias D = CommonDecimal!(D1, D2);
5631     D result;
5632     auto flags = decimalPoly(x, a, result, 
5633                             __ctfe ? D.PRECISION : DecimalControl.precision,
5634                             __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
5635     DecimalControl.raiseFlags(flags);
5636     return result;
5637 }
5638 
5639 /**
5640 Compute the value of x$(SUPERSCRIPT n), where n is integral
5641 Throws:
5642     $(BOOKTABLE,
5643     $(TR $(TD $(MYREF InvalidOperationException)) 
5644          $(TD x is signaling $(B NaN)))
5645     $(TR $(TD $(MYREF DivisionByZeroException)) 
5646          $(TD x = ±0.0 and n < 0))
5647     $(TR $(TD $(MYREF OverflowException)) 
5648          $(TD result is too big to be represented))
5649     $(TR $(TD $(MYREF UnderflowException)) 
5650          $(TD result is too small to be represented))
5651     $(TR $(TD $(MYREF InexactException)) 
5652          $(TD result is inexact))
5653 )
5654 Special_values:
5655 $(BOOKTABLE,
5656     $(TR $(TH x) $(TH n) $(TH pow(x, n)) )
5657     $(TR $(TD sNaN) $(TD any) $(TD $(B NaN)) )
5658     $(TR $(TD any) $(TD 0) $(TD +1.0) )
5659     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
5660     $(TR $(TD ±∞) $(TD any) $(TD ±∞) )
5661     $(TR $(TD ±0.0) $(TD odd n < 0) $(TD ±∞))
5662     $(TR $(TD ±0.0) $(TD even n < 0) $(TD +∞) )
5663     $(TR $(TD ±0.0) $(TD odd n > 0) $(TD ±0.0)  )
5664     $(TR $(TD ±0.0) $(TD even n > 0) $(TD +0.0) )
5665 )
5666 */
5667 @IEEECompliant("pown", 42)
5668 D pow(D, T)(auto const ref D x, const T n)
5669 if (isDecimal!D && isIntegral!T)
5670 {
5671     ExceptionFlags flags;
5672     Unqual!D result = x;
5673     auto flags = decimalPow(result, n, 
5674                            __ctfe ? D.PRECISION : DecimalControl.precision,
5675                            __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
5676     DecimalControl.raiseFlags(flags);
5677     return result;
5678 }
5679 
5680 /**
5681 Compute the value of x$(SUPERSCRIPT y)
5682 Throws:
5683     $(BOOKTABLE,
5684     $(TR $(TD $(MYREF InvalidOperationException)) 
5685          $(TD x is signaling $(B NaN)))
5686     $(TR $(TD $(MYREF DivisionByZeroException)) 
5687          $(TD x = ±0.0 and y < 0.0))
5688     $(TR $(TD $(MYREF OverflowException)) 
5689          $(TD result is too big to be represented))
5690     $(TR $(TD $(MYREF UnderflowException)) 
5691          $(TD result is too small to be represented))
5692     $(TR $(TD $(MYREF InexactException)) 
5693          $(TD result is inexact))
5694 )
5695 Special_values:
5696 $(BOOKTABLE,
5697     $(TR $(TH x) $(TH y) $(TH pow(x, y)) )
5698     $(TR $(TD sNaN) $(TD any) $(TD $(B NaN)) )
5699     $(TR $(TD any) $(TD 0) $(TD +1.0) )
5700     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
5701     $(TR $(TD ±∞) $(TD any) $(TD ±∞) )
5702     $(TR $(TD ±0.0) $(TD odd n < 0) $(TD ±∞))
5703     $(TR $(TD ±0.0) $(TD even n < 0) $(TD +∞) )
5704     $(TR $(TD ±0.0) $(TD odd n > 0) $(TD ±0.0)  )
5705     $(TR $(TD ±0.0) $(TD even n > 0) $(TD +0.0) )
5706 )
5707 */
5708 @IEEECompliant("pow", 42)
5709 @IEEECompliant("powr", 42)
5710 auto pow(D1, D2)(auto const ref D1 x, auto const ref D2 x)
5711 {
5712     ExceptionFlags flags;
5713     Unqual!D1 result = x;
5714     auto flags = decimalPow(result, y, 
5715                             __ctfe ? D.PRECISION : DecimalControl.precision,
5716                             __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
5717     DecimalControl.raiseFlags(flags);
5718     return result;
5719 }
5720 
5721 
5722 
5723 
5724 /**
5725 Express a value using another value exponent
5726 Params:
5727     x = source value
5728     y = value used as exponent source
5729 Returns:
5730     a value with the same numerical value as x but with the exponent of y
5731 Throws:
5732     $(BOOKTABLE,
5733     $(TR $(TD $(MYREF InvalidOperationException)) 
5734          $(TD x is signaling $(B NaN)))
5735     $(TR $(TD $(MYREF InvalidOperationException)) 
5736          $(TD only one of x or y is ±∞))
5737     $(TR $(TD $(MYREF InexactException)) 
5738          $(TD result is inexact))
5739 )
5740 Special_values:
5741 $(BOOKTABLE,
5742     $(TR $(TH x) $(TH y) $(TH quantize(x, y)))
5743     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
5744     $(TR $(TD any) $(TD $(B NaN)) $(TD $(B NaN)))
5745     $(TR $(TD ±∞) $(TD ±∞) $(TD ±∞))
5746     $(TR $(TD ±∞) $(TD any) $(TD $(B NaN)))
5747     $(TR $(TD any) $(TD ±∞) $(TD $(B NaN)))
5748 )
5749 */
5750 @IEEECompliant("quantize", 18)
5751 D1 quantize(D1, D2)(auto const ref D1 x, auto const ref D2 y)
5752 if (isDecimal!(D1, D2))
5753 {
5754     D1 result = x;
5755     auto flags = decimalQuantize(result, y,
5756                                  __ctfe ? D1.PRECISION : DecimalControl.precision,
5757                                  __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
5758     flags &= ExceptionFlags.invalidOperation | ExceptionFlags.inexact; 
5759     DecimalControl.raiseFlags(flags);
5760     return result;
5761 }
5762 
5763 /**
5764 Returns the exponent encoded into the specified _decimal value;
5765 Throws:
5766     $(BOOKTABLE,
5767     $(TR $(TD $(MYREF InvalidOperationException)) 
5768          $(TD x is $(B NaN) or ±∞))
5769 )
5770 Special_values:
5771 $(BOOKTABLE,
5772     $(TR $(TH x) $(TH quantexp(x)))
5773     $(TR $(TD $(B NaN)) $(TD int.min) )
5774     $(TR $(TD ±∞) $(TD int.min) )
5775 )
5776 Notes:
5777 Unlike $(MYREF frexp) where the exponent is calculated for a |coefficient| < 1.0, this
5778 functions returns the raw encoded exponent.
5779 */
5780 int quantexp(D)(auto const ref D x)
5781 if (isDecimal!D)
5782 {
5783     DataType!D cx; int ex; bool sx;
5784     switch (fastDecode(x, cx, ex, sx))
5785     {
5786         case FastClass.finite:
5787         case FastClass.zero:
5788             return ex;
5789         default:
5790             DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
5791             return int.min;
5792     }
5793 }
5794 
5795 ///
5796 unittest
5797 {
5798     auto d = decimal32("0x0001p+12"); //1 * 10^^12
5799     auto z = decimal64("0x0000p-3");  //0 * 10^^-3
5800 
5801     int calculatedExponent, rawExponent;
5802 
5803     //d is 0.1 * 10^^13
5804     frexp(d, calculatedExponent);
5805     rawExponent = quantexp(d);
5806     assert (calculatedExponent == 13  && rawExponent == 12);
5807 
5808     //z is 0.0
5809     frexp(z, calculatedExponent);
5810     rawExponent = quantexp(z);
5811     assert (calculatedExponent == 0  && rawExponent == -3);
5812 }
5813 
5814 /**
5815 Calculates the _remainder of the division x / y
5816 Params:
5817     x = dividend
5818     y = divisor
5819 Returns:
5820     The value of x - n * y, where n is the quotient rounded to nearest even of the division x / y  
5821 Throws:
5822 $(BOOKTABLE,
5823     $(TR $(TD $(MYREF InvalidOperationException)) 
5824          $(TD x or y is signaling $(B NaN), x = ±∞, y = ±0.0))
5825     $(TR $(TD $(MYREF UnderflowException)) 
5826          $(TD result is too small to be represented))
5827     $(TR $(TD $(MYREF DivisionByZeroException)) 
5828          $(TD y = 0.0))
5829     $(TR $(TD $(MYREF InexactException)) 
5830          $(TD the result is inexact))
5831 )
5832 Special_values:
5833 $(BOOKTABLE,
5834     $(TR $(TH x) $(TH y) $(TH remainder(x, y)))
5835     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
5836     $(TR $(TD any) $(TD $(B NaN)) $(TD $(B NaN)))
5837     $(TR $(TD ±∞) $(TD any) $(TD $(B NaN)))
5838     $(TR $(TD any) $(TD 0.0) $(TD $(B NaN)))
5839     $(TR $(TD any) $(TD ±∞) $(TD $(B NaN)))
5840 )
5841 */
5842 @IEEECompliant("remainder", 25)
5843 auto remainder(D1, D2)(auto const ref D1 x, auto const ref D2 y)
5844 {
5845     CommonDecimal!(D1, D2) result = x;
5846     auto flags = decimalMod(result, y, 
5847                             __ctfe ? D1.PRECISION : DecimalControl.precision,
5848                             RoundingMode.tiesToEven);
5849     DecimalControl.raiseFlags(flags);
5850     return result;
5851 }
5852 
5853 
5854 
5855 /**
5856 Returns the value of x rounded using the specified rounding _mode.
5857 If no rounding _mode is specified the default context rounding _mode is used instead.
5858 This function is similar to $(MYREF nearbyint), but if the rounded value is not exact it will throw
5859 $(MYREF InexactException)
5860 Throws:
5861     $(BOOKTABLE,
5862     $(TR $(TD $(MYREF InvalidOperationException)) 
5863          $(TD x is signaling $(B NaN)))
5864     $(TR $(TD $(MYREF InexactException)) 
5865          $(TD the result is inexact))
5866 )
5867 Special_values:
5868 $(BOOKTABLE,
5869     $(TR $(TH x) $(TH rint(x)))
5870     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5871     $(TR $(TD ±∞) $(TD ±∞))
5872     $(TR $(TD ±0.0) $(TD ±0.0))
5873 )
5874 */
5875 @IEEECompliant("roundToIntegralExact", 25)
5876 D rint(D)(auto const ref D x, const RoundingMode mode)
5877 if (isDecimal!D)
5878 {
5879     Unqual!D result = x;
5880     auto flags = decimalRound(result, __ctfe ? D.PRECISION : DecimalControl.precision, mode);
5881     flags &= ExceptionFlags.invalidOperation | ExceptionFlags.inexact;
5882     DecimalControl.raiseFlags(flags);
5883     return result;
5884 }
5885 
5886 ///ditto
5887 @IEEECompliant("roundToIntegralExact", 25)
5888 D rint(D)(auto const ref D x)
5889 if (isDecimal!D)
5890 {
5891     return rint(x, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
5892 }
5893 
5894 ///
5895 unittest
5896 {
5897     DecimalControl.resetFlags(ExceptionFlags.inexact);
5898     assert(rint(decimal32("9.9")) == 10);
5899     assert(DecimalControl.inexact);
5900 
5901     DecimalControl.resetFlags(ExceptionFlags.inexact);
5902     assert(rint(decimal32("9.0")) == 9);
5903     assert(!DecimalControl.inexact);
5904 }
5905 
5906 /**
5907 Returns the value of x rounded using the specified rounding _mode.
5908 If no rounding _mode is specified the default context rounding _mode is used instead.
5909 If the value doesn't fit in a long data type $(MYREF OverflowException) is thrown.
5910 Throws:
5911 $(BOOKTABLE,
5912     $(TR $(TD $(MYREF InvalidOperationException)) 
5913          $(TD x is $(B NaN)))
5914     $(TR $(TD $(MYREF OverflowException)) 
5915          $(TD result does not fit in a long data type))
5916     $(TR $(TD $(MYREF InexactException)) 
5917          $(TD the result is inexact))
5918 )
5919 Special_values:
5920 $(BOOKTABLE,
5921     $(TR $(TH x) $(TH rndtonl(x)))
5922     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5923     $(TR $(TD ±∞) $(TD ±∞))
5924     $(TR $(TD ±0.0) $(TD ±0.0))
5925 )
5926 */
5927 D rndtonl(D)(auto const ref D x, const RoundingMode mode)
5928 if (isDecimal!D)
5929 {
5930     Unqual!D result = x;
5931     ExceptionFlags flags;
5932     long l;
5933     if (isNaN(x))
5934     {
5935         flags = ExceptionFlags.invalidOperation;
5936         result = signbit(x) ? -D.nan : D.nan;
5937     }
5938     else if (isInfinity(x))
5939         flags = ExceptionFlags.overflow;
5940     else 
5941     {
5942         flags = decimalToSigned(x, l, mode);
5943         result.packIntegral(l, 0, mode);
5944     }
5945     DecimalControl.raiseFlags(flags);
5946     return result;
5947 }
5948 
5949 ///ditto
5950 @safe
5951 D rndtonl(D)(auto const ref D x)
5952 if (isDecimal!D)
5953 {
5954     return rndtonl(x, __ctfe ? RoundingMode.tiesToAway : DecimalControl.rounding);
5955 }
5956 
5957 /**
5958 Compute the value of x$(SUPERSCRIPT 1/n), where n is an integer
5959 Throws:
5960 $(BOOKTABLE,
5961     $(TR $(TD $(MYREF InvalidOperationException)) 
5962          $(TD x is signaling $(B NaN)))
5963     $(TR $(TD $(MYREF DivisionByZeroException)) 
5964          $(TD x = ±0.0 and n < 0.0))
5965     $(TR $(TD $(MYREF OverflowException)) 
5966          $(TD result is too big to be represented or n = -1))
5967     $(TR $(TD $(MYREF UnderflowException)) 
5968          $(TD result is too small to be represented or n = -1))
5969     $(TR $(TD $(MYREF InexactException)) 
5970          $(TD result is inexact))
5971 )
5972 Special_values:
5973 $(BOOKTABLE,
5974     $(TR $(TH x) $(TH y) $(TH root(x, n)) )
5975     $(TR $(TD sNaN) $(TD any) $(TD $(B NaN)) )
5976     $(TR $(TD any) $(TD 0) $(TD $(B NaN)) )
5977     $(TR $(TD any) $(TD -1) $(TD $(B NaN)) )
5978     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
5979     $(TR $(TD ±∞) $(TD any) $(TD ±∞) )
5980     $(TR $(TD ±0.0) $(TD odd n < 0) $(TD ±∞))
5981     $(TR $(TD ±0.0) $(TD even n < 0) $(TD +∞) )
5982     $(TR $(TD ±0.0) $(TD odd n > 0) $(TD ±0.0)  )
5983     $(TR $(TD ±0.0) $(TD even n > 0) $(TD +0.0) )
5984 )
5985 */
5986 @IEEECompliant("rootn", 42)
5987 D root(D)(auto const ref D x, const T n)
5988 if (isDecimal!D & isIntegral!T)
5989 {
5990     ExceptionFlags flags;
5991     Unqual!D1 result = x;
5992     auto flags = decimalRoot(result, n, 
5993                             __ctfe ? D.PRECISION : DecimalControl.precision,
5994                             __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
5995     DecimalControl.raiseFlags(flags);
5996     return result;
5997 }
5998 
5999 /**
6000 Returns the value of x rounded away from zero.
6001 This operation is silent, doesn't throw any exception.
6002 Special_values:
6003 $(BOOKTABLE,
6004     $(TR $(TH x) $(TH round(x)))
6005     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
6006     $(TR $(TD ±0.0) $(TD ±0.0))
6007     $(TR $(TD ±∞) $(TD ±∞))
6008 )
6009 */
6010 D round(D)(auto const ref D x)
6011 if (isDecimal!D)
6012 {
6013     Unqual!D result = x;
6014     decimalRound(result, 0, RoundingMode.tiesToAway);
6015     return result;
6016 }
6017 
6018 /**
6019 Computes the inverse square root of x
6020 Throws:
6021     $(MYREF InvalidOperationException) if x is signaling $(B NaN) or negative,
6022     $(MYREF InexactException), $(MYREF UnderflowException),
6023     $(MYREF DivisionByZeroException)
6024 Special_values:
6025 $(BOOKTABLE,
6026     $(TR $(TH x) $(TH rsqrt(x)))
6027     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
6028     $(TR $(TD < 0.0) $(TD $(B NaN)))
6029     $(TR $(TD ±0.0) $(TD $(B NaN)))
6030     $(TR $(TD +∞) $(TD +∞))
6031 )
6032 */
6033 @IEEECompliant("rSqrt", 42)
6034 D rsqrt(D)(auto const ref D x)
6035 if (isDecimal!D)
6036 {
6037     ExceptionFlags flags;
6038 
6039     Unqual!D result = x;
6040 
6041     flags = decimalRSqrt(result, 
6042                             __ctfe ? D.PRECISION : DecimalControl.precision, 
6043                             __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6044     DecimalControl.raiseFlags(flags);
6045     return result;
6046 }
6047 
6048 /**
6049 Compares the exponents of two _decimal values
6050 Params:
6051     x = a _decimal value
6052     y = a _decimal value
6053 Returns:
6054     true if the internal representation of x and y use the same exponent, false otherwise
6055 Notes:
6056     Returns also true if both operands are $(B NaN) or both operands are infinite.
6057 */
6058 @IEEECompliant("sameQuantum", 26)
6059 bool sameQuantum(D1, D2)(auto const ref D1 x, auto const ref D2 y)
6060 if (isDecimal!(D1, D2))
6061 {
6062     if ((x.data & D1.MASK_INF) == D1.MASK_INF)
6063     {
6064         if ((x.data & D1.MASK_QNAN) == D1.MASK_QNAN)
6065             return (y.data & D2.MASK_QNAN) == D2.MASK_QNAN;
6066         return (y.data & D2.MASK_SNAN) == D2.MASK_INF;
6067     }
6068 
6069     if ((y.data & D2.MASK_INF) == D2.MASK_INF)
6070         return false;
6071 
6072     auto expx = (x.data & D1.MASK_EXT) == D1.MASK_EXT ?
6073         (x.data & D1.MASK_EXP2) >>> D1.SHIFT_EXP2 :
6074         (x.data & D1.MASK_EXP1) >>> D1.SHIFT_EXP1;
6075     auto expy = (x.data & D2.MASK_EXT) == D2.MASK_EXT ?
6076         (y.data & D2.MASK_EXP2) >>> D2.SHIFT_EXP2 :
6077         (y.data & D2.MASK_EXP1) >>> D2.SHIFT_EXP1;
6078 
6079     int ex = cast(int)cast(uint)expx;
6080     int ey = cast(int)cast(uint)expy;
6081     return ex - D1.EXP_BIAS == ey - D2.EXP_BIAS;
6082 }
6083 
6084 ///
6085 unittest
6086 {
6087     assert(sameQuantum(decimal32.infinity, -decimal64.infinity));
6088 
6089     auto x = decimal32("123456e+23");
6090     auto y = decimal64("911911e+23");
6091     assert(sameQuantum(x, y));
6092 
6093 }
6094 
6095 /**
6096 Returns:
6097     x efficiently multiplied by 10$(SUPERSCRIPT n)
6098 Throws:
6099     $(MYREF InvalidOperationException) if x is signaling $(B NaN), $(MYREF OverflowException), 
6100     $(MYREF UnderflowException), $(MYREF InexactException)   
6101 Special_values:
6102 $(BOOKTABLE,
6103     $(TR $(TH x) $(TH n) $(TH scalbn(x, n)))
6104     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
6105     $(TR $(TD ±∞) $(TD any) $(TD ±∞))
6106     $(TR $(TD ±0) $(TD any) $(TD ±0))
6107     $(TR $(TD any) $(TD 0) $(TD x))
6108 )
6109 */
6110 @IEEECompliant("scaleB", 17)
6111 D scalbn(D)(auto const ref D x, const int n)
6112 if (isDecimal!D)
6113 {
6114     Unqual!D result = x;
6115     auto flags = decimalScale(result, n, 
6116                             __ctfe ? D.PRECISION : DecimalControl.precision,
6117                             __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6118     DecimalControl.raiseFlags(flags);
6119     return result;
6120 }
6121 
6122 /**
6123 Multiplies elements of x using a higher precision, rounding only once at the end.
6124 Returns:
6125     x$(SUBSCRIPT 0) * x$(SUBSCRIPT 1) * ... * x$(SUBSCRIPT n)
6126 Notes:
6127     To avoid overflow, an additional scale is provided that the final result is to be multiplied py 10$(SUPERSCRIPT scale)
6128 Throws:
6129 $(BOOKTABLE,
6130     $(TR $(TD $(MYREF InvalidOperationException)) 
6131          $(TD any x is signaling $(B NaN)))
6132     $(TR $(TD $(MYREF InvalidOperationException)) 
6133          $(TD there is one infinite element and one 0.0 element))
6134     $(TR $(TD $(MYREF OverflowException)) 
6135          $(TD result is too big to be represented))
6136     $(TR $(TD $(MYREF UnderflowException)) 
6137          $(TD result is too small to be represented))
6138     $(TR $(TD $(MYREF InexactException)) 
6139          $(TD result is inexact))
6140 )
6141 */
6142 @IEEECompliant("scaledProd", 47)
6143 D scaledProd(D)(const(D)[] x, out int scale)
6144 if (isDecimal!D)
6145 {
6146     Unqual!D result;
6147     flags = decimalProd(x, result, scale, 
6148                          __ctfe ? D.PRECISION : DecimalControl.precision,
6149                          __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6150     DecimalControl.raiseFlags(flags);
6151     return result;
6152 }
6153 
6154 /**
6155 Multiplies results of x$(SUBSCRIPT i) + y$(SUBSCRIPT i) using a higher precision, rounding only once at the end.
6156 Returns:
6157     (x$(SUBSCRIPT 0) + y$(SUBSCRIPT 0)) * (x$(SUBSCRIPT 1) + y$(SUBSCRIPT 1)) * ... * (x$(SUBSCRIPT n) + y$(SUBSCRIPT n))
6158 Notes:
6159     To avoid overflow, an additional scale is provided that the final result is to be multiplied py 10$(SUPERSCRIPT scale).<br/>
6160     If x and y arrays are not of the same length, operation is performed for min(x.length, y.length);
6161 Throws:
6162 $(BOOKTABLE,
6163     $(TR $(TD $(MYREF InvalidOperationException)) 
6164          $(TD any x is signaling $(B NaN)))
6165     $(TR $(TD $(MYREF InvalidOperationException)) 
6166          $(TD any x[i] and y[i] are infinite and with different sign))
6167     $(TR $(TD $(MYREF InvalidOperationException)) 
6168          $(TD there is one infinite element and one x$(SUBSCRIPT i) + y$(SUBSCRIPT i) == 0.0))
6169     $(TR $(TD $(MYREF OverflowException)) 
6170          $(TD result is too big to be represented))
6171     $(TR $(TD $(MYREF UnderflowException)) 
6172          $(TD result is too small to be represented))
6173     $(TR $(TD $(MYREF InexactException)) 
6174          $(TD result is inexact))
6175 )
6176 */
6177 @IEEECompliant("scaledProdSum", 47)
6178 D scaledProdSum(D)(const(D)[] x, const(D)[] y, out int scale)
6179 if (isDecimal!D)
6180 {
6181     Unqual!D result;
6182     flags = decimalProdSum(x, y, result, scale, 
6183                         __ctfe ? D.PRECISION : DecimalControl.precision,
6184                         __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6185     DecimalControl.raiseFlags(flags);
6186     return result;
6187 }
6188 
6189 /**
6190 Multiplies results of x$(SUBSCRIPT i) - y$(SUBSCRIPT i) using a higher precision, rounding only once at the end.
6191 Returns:
6192     (x$(SUBSCRIPT 0) - y$(SUBSCRIPT 0)) * (x$(SUBSCRIPT 1) - y$(SUBSCRIPT 1)) * ... * (x$(SUBSCRIPT n) - y$(SUBSCRIPT n))
6193 Notes:
6194     To avoid overflow, an additional scale is provided that the final result is to be multiplied py 10$(SUPERSCRIPT scale)</br>
6195     If x and y arrays are not of the same length, operation is performed for min(x.length, y.length);
6196 Throws:
6197 $(BOOKTABLE,
6198     $(TR $(TD $(MYREF InvalidOperationException)) 
6199          $(TD any x is signaling $(B NaN)))
6200     $(TR $(TD $(MYREF InvalidOperationException)) 
6201          $(TD any x$(SUBSCRIPT i) and y$(SUBSCRIPT i) are infinite and with different sign))
6202     $(TR $(TD $(MYREF InvalidOperationException)) 
6203          $(TD there is one infinite element and one x$(SUBSCRIPT i) - y$(SUBSCRIPT i) == 0.0))
6204     $(TR $(TD $(MYREF OverflowException)) 
6205          $(TD result is too big to be represented))
6206     $(TR $(TD $(MYREF UnderflowException)) 
6207          $(TD result is too small to be represented))
6208     $(TR $(TD $(MYREF InexactException)) 
6209          $(TD result is inexact))
6210 )
6211 */
6212 @IEEECompliant("scaledProdDiff", 47)
6213 D scaledProdDiff(D)(const(D)[] x, const(D)[] y, out int scale)
6214 if (isDecimal!D)
6215 {
6216     Unqual!D result;
6217     flags = decimalProdDiff(x, y, result, scale, 
6218                            __ctfe ? D.PRECISION : DecimalControl.precision,
6219                            __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6220     DecimalControl.raiseFlags(flags);
6221     return result;
6222 }
6223 
6224 /**
6225 Determines if x is negative
6226 This operation is silent, no error flags are set and no exceptions are thrown.
6227 Params:
6228     x = a _decimal value
6229 Returns: 
6230     -1.0 if x is negative, 0.0 if x is zero, 1.0 if x is positive
6231 */
6232 @safe pure nothrow @nogc
6233 D sgn(D: Decimal!bits, int bits)(auto const ref D x)
6234 {
6235     if (isZero(x))
6236         return D.zero;
6237     return (x.data & D.MASK_SGN) ? D.minusOne : D.one;
6238 }
6239 
6240 
6241 
6242 ///
6243 unittest
6244 {
6245     assert(sgn(decimal32.max) == 1);
6246     assert(sgn(-decimal32.max) == -1);
6247     assert(sgn(decimal64(0)) == 0);
6248 }
6249 
6250 unittest
6251 {
6252 
6253     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
6254     {
6255         assert(sgn(T.nan) == 1);
6256         assert(sgn(T.infinity) == 1);
6257         assert(sgn(T.minusInfinity) == -1);
6258     }
6259 }
6260 
6261 /**
6262 Returns the sign bit of the specified value.
6263 This operation is silent, no error flags are set and no exceptions are thrown.
6264 Params:
6265     x = a _decimal value
6266 Returns: 
6267     1 if the sign bit is set, 0 otherwise
6268 */
6269 @IEEECompliant("isSignMinus", 25)
6270 int signbit(D: Decimal!bits, int bits)(auto const ref D x)
6271 {
6272     static if (is(D: decimal32) || is(D: decimal64))
6273     {
6274         return cast(uint)((x.data & D.MASK_SGN) >>> ((D.sizeof * 8) - 1)); 
6275     }
6276     else
6277     {
6278         return cast(uint)((x.data.hi & D.MASK_SGN.hi) >>> ((D.sizeof * 4) - 1));
6279     }
6280 }
6281 
6282 ///
6283 unittest
6284 {
6285     assert(signbit(-decimal32.infinity) == 1);
6286     assert(signbit(decimal64.min_normal) == 0);
6287     assert(signbit(-decimal128.max) == 1);
6288 }
6289 
6290 unittest
6291 {
6292     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
6293     {
6294         assert(signbit(T.snan) == 0);
6295         assert(signbit(T.minusInfinity) == 1);
6296         assert(signbit(T.zero) == 0);
6297         assert(signbit(T.minusZero) == 1);
6298     }
6299 }
6300 
6301 /**
6302 Returns sine of x.
6303 Throws:
6304 $(BOOKTABLE,
6305     $(TR $(TD $(MYREF InvalidOperationException)) 
6306          $(TD x is signaling $(B NaN) or ±∞))
6307     $(TR $(TD $(MYREF UnderflowException)) 
6308          $(TD result is too small to be represented))
6309     $(TR $(TD $(MYREF InexactException)) 
6310          $(TD the result is inexact))
6311 )
6312 Special_values:
6313 $(BOOKTABLE,
6314     $(TR $(TH x) $(TH sin(x)))
6315     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
6316     $(TR $(TD ±∞) $(TD $(B NaN)))
6317     $(TR $(TD -π/2) $(TD -1.0))
6318     $(TR $(TD -π/3) $(TD -√3/2))
6319     $(TR $(TD -π/4) $(TD -√2/2))
6320     $(TR $(TD -π/6) $(TD -0.5))
6321     $(TR $(TD ±0.0) $(TD +0.0))
6322     $(TR $(TD +π/6) $(TD +0.5))
6323     $(TR $(TD +π/4) $(TD +√2/2))
6324     $(TR $(TD +π/3) $(TD +√3/2))
6325     $(TR $(TD +π/2) $(TD +1.0))
6326 )
6327 */
6328 @IEEECompliant("sin", 42)
6329 D sin(D)(auto const ref D x)
6330 if (isDecimal!D)
6331 {
6332     Unqual!D result = x;
6333     auto flags = decimalSin(result, 
6334                              __ctfe ? D.PRECISION : DecimalControl.precision, 
6335                              __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6336 
6337     DecimalControl.raiseFlags(flags);
6338     return result;
6339 }
6340 
6341 /**
6342 Calculates the hyperbolic sine of x.
6343 Throws:
6344 $(BOOKTABLE,
6345     $(TR $(TD $(MYREF InvalidOperationException)) 
6346          $(TD x is signaling $(B NaN)))
6347     $(TR $(TD $(MYREF OverflowException)) 
6348          $(TD result is too big to be represented))
6349     $(TR $(TD $(MYREF InexactException)) 
6350          $(TD the result is inexact))
6351 )
6352 Special_values:
6353 $(BOOKTABLE,
6354     $(TR $(TH x) $(TH sinh(x)))
6355     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
6356     $(TR $(TD ±∞) $(TD +∞))
6357     $(TR $(TD ±0.0) $(TD +0.0))
6358 )
6359 */
6360 @IEEECompliant("sinh", 42)
6361 D sinh(D)(auto const ref D x)
6362 if (isDecimal!D)
6363 {
6364     Unqual!D result = x;
6365     auto flags = decimalSinh(result, 
6366                             __ctfe ? D.PRECISION : DecimalControl.precision, 
6367                             __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6368 
6369     DecimalControl.raiseFlags(flags);
6370     return result;
6371 }
6372 
6373 /**
6374 Returns sine of x*π.
6375 Throws:
6376 $(BOOKTABLE,
6377     $(TR $(TD $(MYREF InvalidOperationException)) 
6378          $(TD x is signaling $(B NaN) or ±∞))
6379     $(TR $(TD $(MYREF UnderflowException)) 
6380          $(TD result is too small to be represented))
6381     $(TR $(TD $(MYREF InexactException)) 
6382          $(TD the result is inexact))
6383 )
6384 Special_values:
6385 $(BOOKTABLE,
6386     $(TR $(TH x) $(TH sin(x)))
6387     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
6388     $(TR $(TD ±∞) $(TD $(B NaN)))
6389     $(TR $(TD -1/2) $(TD -1.0))
6390     $(TR $(TD -1/3) $(TD -√3/2))
6391     $(TR $(TD -1/4) $(TD -√2/2))
6392     $(TR $(TD -1/6) $(TD -0.5))
6393     $(TR $(TD ±0.0) $(TD +0.0))
6394     $(TR $(TD +1/6) $(TD +0.5))
6395     $(TR $(TD +1/4) $(TD +√2/2))
6396     $(TR $(TD +1/3) $(TD +√3/2))
6397     $(TR $(TD +1/2) $(TD +1.0))
6398 )
6399 */
6400 @IEEECompliant("sinPi", 42)
6401 D sinPi(D)(auto const ref D x)
6402 if (isDecimal!D)
6403 {
6404     Unqual!D result = x;
6405     auto flags = decimalSinPi(result, 
6406                              __ctfe ? D.PRECISION : DecimalControl.precision, 
6407                              __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6408 
6409     DecimalControl.raiseFlags(flags);
6410     return result;
6411 }
6412 
6413 
6414 /**
6415 Computes the square root of x
6416 Throws:
6417     $(MYREF InvalidOperationException) if x is signaling $(B NaN) or negative,
6418     $(MYREF InexactException), $(MYREF UnderflowException)
6419 Special_values:
6420 $(BOOKTABLE,
6421     $(TR $(TH x) $(TH sqrt(x)))
6422     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
6423     $(TR $(TD < 0.0) $(TD $(B NaN)))
6424     $(TR $(TD ±0.0) $(TD ±0.0))
6425     $(TR $(TD +∞) $(TD +∞))
6426 )
6427 */
6428 @IEEECompliant("squareRoot", 42)
6429 D sqrt(D)(auto const ref D x)
6430 if (isDecimal!D)
6431 {
6432 
6433     Unqual!D result = x;
6434     auto flags = decimalSqrt(result, 
6435                         __ctfe ? D.PRECISION : DecimalControl.precision, 
6436                         __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6437 
6438     DecimalControl.raiseFlags(flags);
6439     return result;
6440 }
6441 
6442 /**
6443 Sums elements of x using a higher precision, rounding only once at the end.</br>
6444 Returns:
6445     x$(SUBSCRIPT 0) + x$(SUBSCRIPT 1) + ... + x$(SUBSCRIPT n)
6446 Throws:
6447 $(BOOKTABLE,
6448     $(TR $(TD $(MYREF InvalidOperationException)) 
6449          $(TD any x is signaling $(B NaN)))
6450     $(TR $(TD $(MYREF InvalidOperationException)) 
6451          $(TD there are two infinite elements with different sign))
6452     $(TR $(TD $(MYREF OverflowException)) 
6453          $(TD result is too big to be represented))
6454     $(TR $(TD $(MYREF UnderflowException)) 
6455          $(TD result is too small to be represented))
6456     $(TR $(TD $(MYREF InexactException)) 
6457          $(TD result is inexact))
6458 )
6459 */
6460 @IEEECompliant("sum", 47)
6461 D sum(D)(const(D)[] x)
6462 if (isDecimal!D)
6463 {
6464     Unqual!D result;
6465     auto flags = decimalSum(x, result, 
6466                              __ctfe ? D.PRECISION : DecimalControl.precision, 
6467                              __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6468 
6469     DecimalControl.raiseFlags(flags);
6470     return result;
6471 }
6472 
6473 /**
6474 Sums absolute elements of x using a higher precision, rounding only once at the end.
6475 Returns:
6476     |x$(SUBSCRIPT 0)| + |x$(SUBSCRIPT 1)| + ... + |x$(SUBSCRIPT n)|
6477 Throws:
6478 $(BOOKTABLE,
6479     $(TR $(TD $(MYREF InvalidOperationException)) 
6480          $(TD any x is signaling $(B NaN)))
6481     $(TR $(TD $(MYREF OverflowException)) 
6482          $(TD result is too big to be represented))
6483     $(TR $(TD $(MYREF UnderflowException)) 
6484          $(TD result is too small to be represented))
6485     $(TR $(TD $(MYREF InexactException)) 
6486          $(TD result is inexact))
6487 )
6488 */
6489 @IEEECompliant("sumAbs", 47)
6490 D sumAbs(D)(const(D)[] x)
6491 if (isDecimal!D)
6492 {
6493     Unqual!D result;
6494     auto flags = decimalSumAbs(x, result, 
6495                             __ctfe ? D.PRECISION : DecimalControl.precision, 
6496                             __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6497 
6498     DecimalControl.raiseFlags(flags);
6499     return result;
6500 }
6501 
6502 /**
6503 Sums squares of elements of x using a higher precision, rounding only once at the end.
6504 Returns:
6505     x$(SUBSCRIPT 0)$(SUPERSCRIPT 2) + x$(SUBSCRIPT 1)$(SUPERSCRIPT 2) + ... + x$(SUBSCRIPT n)$(SUPERSCRIPT 2)
6506 Throws:
6507 $(BOOKTABLE,
6508     $(TR $(TD $(MYREF InvalidOperationException)) 
6509          $(TD any x is signaling $(B NaN)))
6510     $(TR $(TD $(MYREF OverflowException)) 
6511          $(TD result is too big to be represented))
6512     $(TR $(TD $(MYREF UnderflowException)) 
6513          $(TD result is too small to be represented))
6514     $(TR $(TD $(MYREF InexactException)) 
6515          $(TD result is inexact))
6516 )
6517 */
6518 @IEEECompliant("sumSquare", 47)
6519 D sumSquare(D)(const(D)[] x)
6520 if (isDecimal!D)
6521 {
6522     Unqual!D result;
6523     auto flags = decimalSumSquare(x, result, 
6524                             __ctfe ? D.PRECISION : DecimalControl.precision, 
6525                             __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6526 
6527     DecimalControl.raiseFlags(flags);
6528     return result;
6529 }
6530 
6531 /**
6532 Returns tangent of x.
6533 Throws:
6534 $(BOOKTABLE,
6535     $(TR $(TD $(MYREF InvalidOperationException)) 
6536          $(TD x is signaling $(B NaN) or ±∞))
6537     $(TR $(TD $(MYREF UnderflowException)) 
6538          $(TD result is too small to be represented))
6539     $(TR $(TD $(MYREF OverflowException)) 
6540          $(TD result is too big to be represented))
6541     $(TR $(TD $(MYREF InexactException)) 
6542          $(TD the result is inexact))
6543 )
6544 Special_values:
6545 $(BOOKTABLE,
6546     $(TR $(TH x) $(TH tan(x)))
6547     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
6548     $(TR $(TD ±∞) $(TD $(B NaN)))
6549     $(TR $(TD -π/2) $(TD -∞))
6550     $(TR $(TD -π/3) $(TD -√3))
6551     $(TR $(TD -π/4) $(TD -1.0))
6552     $(TR $(TD -π/6) $(TD -1/√3))
6553     $(TR $(TD ±0.0) $(TD +0.0))
6554     $(TR $(TD +π/6) $(TD +1/√3))
6555     $(TR $(TD +π/4) $(TD +1.0))
6556     $(TR $(TD +π/3) $(TD +√3))
6557     $(TR $(TD +π/2) $(TD +∞))
6558 )
6559 */
6560 @IEEECompliant("tan", 42)
6561 D tan(D)(auto const ref D x)
6562 if (isDecimal!D)
6563 {
6564     Unqual!D result = x;
6565     auto flags = decimalTan(result, 
6566                              __ctfe ? D.PRECISION : DecimalControl.precision, 
6567                              __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6568 
6569     DecimalControl.raiseFlags(flags);
6570     return result;
6571 }
6572 
6573 /**
6574 Returns tangent of x.
6575 Throws:
6576 $(BOOKTABLE,
6577     $(TR $(TD $(MYREF InvalidOperationException)) 
6578          $(TD x is signaling $(B NaN) ))
6579     $(TR $(TD $(MYREF UnderflowException)) 
6580          $(TD result is too small to be represented))
6581     $(TR $(TD $(MYREF OverflowException)) 
6582          $(TD result is too big to be represented))
6583     $(TR $(TD $(MYREF InexactException)) 
6584          $(TD the result is inexact))
6585 )
6586 Special_values:
6587 $(BOOKTABLE,
6588     $(TR $(TH x) $(TH tanh(x)))
6589     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
6590     $(TR $(TD ±∞) $(TD ±1.0))
6591     $(TR $(TD ±0.0) $(TD ±0.0))
6592 )
6593 */
6594 @IEEECompliant("tanh", 42)
6595 D tanh(D)(auto const ref D x)
6596 if (isDecimal!D)
6597 {
6598     Unqual!D result = x;
6599     auto flags = decimalTanh(result, 
6600                             __ctfe ? D.PRECISION : DecimalControl.precision, 
6601                             __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6602 
6603     DecimalControl.raiseFlags(flags);
6604     return result;
6605 }
6606 
6607 
6608 /**
6609 Converts x to the specified integral type rounded if necessary by mode
6610 Throws:
6611     $(MYREF InvalidOperationException) if x is $(B NaN),
6612     $(MYREF UnderflowException), $(MYREF OverflowException)
6613 Special_values:
6614 $(BOOKTABLE,
6615     $(TR $(TH x) $(TH to!T(x)))
6616     $(TR $(TD $(B NaN)) $(TD 0))
6617     $(TR $(TD +∞) $(TD T.max))
6618     $(TR $(TD -∞) $(TD T.min))
6619     $(TR $(TD ±0.0) $(TD 0))
6620 )
6621 */
6622 @IEEECompliant("convertToIntegerTiesToAway", 22)
6623 @IEEECompliant("convertToIntegerTiesToEven", 22)
6624 @IEEECompliant("convertToIntegerTowardNegative", 22)
6625 @IEEECompliant("convertToIntegerTowardPositive", 22)
6626 @IEEECompliant("convertToIntegerTowardZero", 22)
6627 T to(T, D)(auto const ref D x, const RoundingMode mode)
6628 if (isIntegral!T && isDecimal!D)
6629 {
6630     Unqual!T result;
6631     static if (isUnsigned!T)
6632         auto flags = decimalToUnsigned(x, result, mode);
6633     else
6634         auto flags = decimalToSigned(x, result, mode);
6635     DecimalControl.raiseFlags(flags & ExceptionFlags.invalidOperation);
6636     return result;
6637 }
6638 
6639 
6640 /**
6641 Converts x to the specified binary floating point type rounded if necessary by mode
6642 Throws:
6643     $(MYREF UnderflowException), $(MYREF OverflowException)
6644 */
6645 F to(F, D)(auto const ref D x, const RoundingMode mode)
6646 if (isFloatingPoint!F && isDecimal!D)
6647 {
6648     Unqual!F result;
6649     flags = decimalToFloat(x, result, mode);
6650     flags &= ~ExceptionFlags.inexact;
6651     if (__ctfe)
6652         DecimalControl.checkFlags(flags, ExceptionFlags.severe);
6653     else
6654     {
6655         if (flags)
6656             DecimalControl.raiseFlags(flags);
6657     }
6658     return result;
6659 }
6660 
6661 /**
6662 Converts the specified value from internal encoding from/to densely packed decimal encoding
6663 Notes:
6664    _Decimal values are represented internaly using 
6665    $(LINK2 https://en.wikipedia.org/wiki/Binary_Integer_Decimal, binary integer _decimal encoding), 
6666    supported by Intel (BID).
6667    This function converts the specified value to/from 
6668    $(LINK2 https://en.wikipedia.org/wiki/Densely_Packed_Decimal, densely packed _decimal encoding), 
6669    supported by IBM (DPD).
6670    Please note that a DPD encoded _decimal cannot be passed to a function from this module, there is no way
6671    to determine if a _decimal value is BID-encoded or DPD-encoded, all functions will assume a BID-encoding.
6672 */
6673 @IEEECompliant("encodeDecimal", 23)
6674 @safe pure nothrow @nogc
6675 decimal32 toDPD(const decimal32 x) 
6676 {
6677     if (isNaN(x) || isInfinity(x) || isZero(x))
6678         return canonical(x);
6679 
6680     uint cx;
6681     int ex;
6682     bool sx = x.unpack(cx, ex);
6683 
6684     uint[7] digits;
6685     size_t index = digits.length;
6686     while (cx)
6687         digits[--index] = divrem(cx, 10U);
6688     
6689     cx = packDPD(digits[$ - 3], digits[$ - 2], digits[$ - 1]);
6690     cx |= packDPD(digits[$ - 6], digits[$ - 5], digits[$ - 4]) << 10;
6691     cx |= cast(uint)digits[0] << 20;
6692 
6693     decimal32 result;
6694     result.pack(cx, ex, sx); 
6695     return result;
6696 }
6697 
6698 ///ditto
6699 @IEEECompliant("encodeDecimal", 23)
6700 @safe pure nothrow @nogc
6701 decimal64 toDPD(const decimal64 x) 
6702 {
6703     if (isNaN(x) || isInfinity(x) || isZero(x))
6704         return canonical(x);
6705 
6706     ulong cx;
6707     int ex;
6708     bool sx = x.unpack(cx, ex);
6709 
6710     uint[16] digits;
6711     size_t index = digits.length;
6712     while (cx)
6713         digits[--index] = cast(uint)(divrem(cx, 10U));
6714 
6715     cx = cast(ulong)(packDPD(digits[$ - 3], digits[$ - 2], digits[$ - 1]));
6716     cx |= cast(ulong)packDPD(digits[$ - 6], digits[$ - 5], digits[$ - 4]) << 10;
6717     cx |= cast(ulong)packDPD(digits[$ - 9], digits[$ - 8], digits[$ - 7]) << 20;
6718     cx |= cast(ulong)packDPD(digits[$ - 12], digits[$ - 11], digits[$ - 10]) << 30;
6719     cx |= cast(ulong)packDPD(digits[$ - 15], digits[$ - 14], digits[$ - 13]) << 40;
6720     cx |= cast(ulong)digits[0] << 50;
6721 
6722     decimal64 result;
6723     result.pack(cx, ex, sx); 
6724     return result;
6725 }
6726 
6727 ///ditto
6728 @IEEECompliant("encodeDecimal", 23)
6729 @safe pure nothrow @nogc
6730 decimal128 toDPD(const decimal128 x) 
6731 {
6732     if (isNaN(x) || isInfinity(x) || isZero(x))
6733         return canonical(x);
6734 
6735     uint128 cx;
6736     int ex;
6737     bool sx = x.unpack(cx, ex);
6738 
6739     uint[34] digits;
6740     size_t index = digits.length;
6741     while (cx)
6742         digits[--index] = cast(uint)(divrem(cx, 10U));
6743 
6744     cx = uint128(packDPD(digits[$ - 3], digits[$ - 2], digits[$ - 1]));
6745     cx |= uint128(packDPD(digits[$ - 6], digits[$ - 5], digits[$ - 4])) << 10;
6746     cx |= uint128(packDPD(digits[$ - 9], digits[$ - 8], digits[$ - 7])) << 20;
6747     cx |= uint128(packDPD(digits[$ - 12], digits[$ - 11], digits[$ - 10])) << 30;
6748     cx |= uint128(packDPD(digits[$ - 15], digits[$ - 14], digits[$ - 13])) << 40;
6749     cx |= uint128(packDPD(digits[$ - 18], digits[$ - 17], digits[$ - 16])) << 50;
6750     cx |= uint128(packDPD(digits[$ - 21], digits[$ - 20], digits[$ - 19])) << 60;
6751     cx |= uint128(packDPD(digits[$ - 24], digits[$ - 23], digits[$ - 22])) << 70;
6752     cx |= uint128(packDPD(digits[$ - 27], digits[$ - 26], digits[$ - 25])) << 80;
6753     cx |= uint128(packDPD(digits[$ - 30], digits[$ - 29], digits[$ - 28])) << 90;
6754     cx |= uint128(packDPD(digits[$ - 33], digits[$ - 32], digits[$ - 31])) << 100;
6755     cx |= uint128(digits[0]) << 110;
6756 
6757     decimal128 result;
6758     result.pack(cx, ex, sx); 
6759     return result;
6760 }
6761 
6762 ///ditto
6763 @IEEECompliant("decodeDecimal", 23)
6764 @safe pure nothrow @nogc
6765 decimal32 fromDPD(const decimal32 x) 
6766 {
6767     if (isNaN(x) || isInfinity(x) || isZero(x))
6768         return canonical(x);
6769 
6770     uint[7] digits;
6771     uint cx;
6772     int ex;
6773     bool sx = x.unpack(cx, ex);
6774 
6775     unpackDPD(cx & 1023, digits[$ - 1], digits[$ - 2], digits[$ - 3]);
6776     unpackDPD((cx >>> 10) & 1023, digits[$ - 4], digits[$ - 5], digits[$ - 6]);
6777     digits[0] = (cx >>> 20) & 15;
6778 
6779     cx = 0U;
6780     for (size_t i = 0; i < digits.length; ++i)
6781         cx += digits[i] * pow10!uint[6 - i];
6782 
6783     decimal32 result;
6784     result.pack(cx, ex, sx); 
6785     return result;
6786 }
6787 
6788 ///ditto
6789 @IEEECompliant("decodeDecimal", 23)
6790 @safe pure nothrow @nogc
6791 decimal64 fromDPD(const decimal64 x) 
6792 {
6793     if (isNaN(x) || isInfinity(x) || isZero(x))
6794         return canonical(x);
6795 
6796     uint[16] digits;
6797     ulong cx;
6798     int ex;
6799     bool sx = x.unpack(cx, ex);
6800 
6801     unpackDPD(cast(uint)cx & 1023, digits[$ - 1], digits[$ - 2], digits[$ - 3]);
6802     unpackDPD(cast(uint)(cx >>> 10) & 1023, digits[$ - 4], digits[$ - 5], digits[$ - 6]);
6803     unpackDPD(cast(uint)(cx >>> 20) & 1023, digits[$ - 7], digits[$ - 8], digits[$ - 9]);
6804     unpackDPD(cast(uint)(cx >>> 30) & 1023, digits[$ - 10], digits[$ - 11], digits[$ - 12]);
6805     unpackDPD(cast(uint)(cx >>> 40) & 1023, digits[$ - 13], digits[$ - 14], digits[$ - 15]);
6806     digits[0] = cast(uint)(cx >>> 50) & 15;
6807 
6808     cx = 0U;
6809     for (size_t i = 0; i < digits.length; ++i)
6810         cx += digits[i] * pow10!ulong[15 - i];
6811 
6812     decimal64 result;
6813     result.pack(cx, ex, sx); 
6814     return result;
6815 }
6816 
6817 ///ditto
6818 @safe pure nothrow @nogc
6819 @IEEECompliant("decodeDecimal", 23)
6820 decimal128 fromDPD(const decimal128 x) 
6821 {
6822     if (isNaN(x) || isInfinity(x) || isZero(x))
6823         return canonical(x);
6824 
6825     uint[34] digits;
6826     uint128 cx;
6827     int ex;
6828     bool sx = x.unpack(cx, ex);
6829 
6830     unpackDPD(cast(uint)cx & 1023U, digits[$ - 1], digits[$ - 2], digits[$ - 3]);
6831     unpackDPD(cast(uint)(cx >>> 10) & 1023, digits[$ - 4], digits[$ - 5], digits[$ - 6]);
6832     unpackDPD(cast(uint)(cx >>> 20) & 1023, digits[$ - 7], digits[$ - 8], digits[$ - 9]);
6833     unpackDPD(cast(uint)(cx >>> 30) & 1023, digits[$ - 10], digits[$ - 11], digits[$ - 12]);
6834     unpackDPD(cast(uint)(cx >>> 40) & 1023, digits[$ - 13], digits[$ - 14], digits[$ - 15]);
6835     unpackDPD(cast(uint)(cx >>> 50) & 1023, digits[$ - 16], digits[$ - 17], digits[$ - 18]);
6836     unpackDPD(cast(uint)(cx >>> 60) & 1023, digits[$ - 19], digits[$ - 20], digits[$ - 21]);
6837     unpackDPD(cast(uint)(cx >>> 70) & 1023, digits[$ - 22], digits[$ - 23], digits[$ - 24]);
6838     unpackDPD(cast(uint)(cx >>> 80) & 1023, digits[$ - 25], digits[$ - 26], digits[$ - 27]);
6839     unpackDPD(cast(uint)(cx >>> 90) & 1023, digits[$ - 28], digits[$ - 29], digits[$ - 30]);
6840     unpackDPD(cast(uint)(cx >>> 100) & 1023, digits[$ - 31], digits[$ - 32], digits[$ - 33]);
6841     digits[0] = cast(uint)(cx >>> 110) & 15;
6842 
6843     cx = 0U;
6844     for (size_t i = 0; i < digits.length; ++i)
6845         cx += pow10!uint128[34 - i] * digits[i];
6846 
6847     decimal128 result;
6848     result.pack(cx, ex, sx); 
6849     return result;
6850 }
6851 
6852 /**
6853 Converts x to the specified integral type rounded if necessary by mode
6854 Throws:
6855 $(MYREF InvalidOperationException) if x is $(B NaN),
6856 $(MYREF InexactException)
6857 $(MYREF UnderflowException), $(MYREF OverflowException)
6858 Special_values:
6859 $(BOOKTABLE,
6860 $(TR $(TH x) $(TH toExact!T(x)))
6861 $(TR $(TD $(B NaN)) $(TD 0))
6862 $(TR $(TD +∞) $(TD T.max))
6863 $(TR $(TD -∞) $(TD T.min))
6864 $(TR $(TD ±0.0) $(TD 0))
6865 )
6866 */
6867 @IEEECompliant("convertToIntegerExactTiesToAway", 22)
6868 @IEEECompliant("convertToIntegerExactTiesToEven", 22)
6869 @IEEECompliant("convertToIntegerExactTowardNegative", 22)
6870 @IEEECompliant("convertToIntegerExactTowardPositive", 22)
6871 @IEEECompliant("convertToIntegerExactTowardZero", 22)
6872 T toExact(T, D)(auto const ref D x, const RoundingMode mode)
6873 if (isIntegral!T && isDecimal!D)
6874 {
6875     Unqual!T result;
6876     static if (isUnsigned!T)
6877         auto flags = decimalToUnsigned(x, result, mode);
6878     else
6879         auto flags = decimalToSigned(x, result, mode);
6880     DecimalControl.raiseFlags(flags & (ExceptionFlags.invalidOperation | ExceptionFlags.inexact));
6881     return result;
6882 }
6883 
6884 /**
6885 Converts x to the specified binary floating point type rounded if necessary by mode
6886 Throws:
6887     $(MYREF UnderflowException), $(MYREF OverflowException),
6888     $(MYREF InexactException)
6889 */
6890 F toExact(F, D)(auto const ref D x, const RoundingMode mode)
6891 if (isFloatingPoint!F && isDecimal!D)
6892 {
6893     Unqual!F result;
6894     flags = decimalToFloat(x, result, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6895     DecimalControl.raiseFlags(flags);
6896     return result;
6897 }
6898 
6899 /**
6900 Converts the specified value to/from Microsoft currency data type;
6901 Throws:
6902 $(BOOKTABLE,
6903     $(TR $(TD $(MYREF InvalidOperationException)) 
6904         $(TD x is $(B NaN)))
6905     $(TR $(TD $(MYREF OverflowException)) 
6906         $(TD x is infinite or outside the Currency limits))
6907     $(TR $(TD $(MYREF UnderflowException)) 
6908         $(TD x is too small to be represented as Currency))
6909     $(TR $(TD $(MYREF InexactException)) 
6910          $(TD x cannot be represented exactly))
6911 )
6912 Notes:
6913     The Microsoft currency data type is stored as long 
6914     always scaled by 10$(SUPERSCRIPT -4)
6915 */
6916 long toMsCurrency(D)(auto const ref D x)
6917 if (isDecimal!D)
6918 {
6919     ExceptionFlags flags;
6920 
6921     if (isNaN(x))
6922     {
6923         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
6924         return 0;
6925     }
6926 
6927     if (isInfinity(x))
6928     {
6929         DecimalControl.raiseFlags(ExceptionFlags.overflow);
6930         return signbit(x) ? long.max : long.min;
6931     }
6932 
6933     if (isZero(x))
6934         return 0;
6935 
6936     ex +=4;
6937 
6938     long result;
6939     flags = decimalToSigned!long(x, result, 
6940                                  __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6941     DecimalControl.raiseFlags(flags);
6942     return result;
6943 }
6944 
6945 ///ditto
6946 D fromMsCurrency(D)(const ulong x)
6947 if (isDecimal!D)
6948 {
6949     ExceptionFlags flags;
6950     Unqual!D result;
6951     flags = result.packIntegral(result, D.PRECISION, RoundingMode.implicit);
6952     flags |= decimalDiv(result, 100, 
6953                         __ctfe ? D.PRECISION : DecimalControl.precision, 
6954                         __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6955     DecimalControl.raiseFlags(flags);
6956     return result;
6957 }
6958 
6959 /**
6960 Converts the specified value to/from Microsoft _decimal data type;
6961 Throws:
6962 $(BOOKTABLE,
6963     $(TR $(TD $(MYREF InvalidOperationException)) 
6964         $(TD x is $(B NaN)))
6965     $(TR $(TD $(MYREF OverflowException)) 
6966         $(TD x is infinite or outside the DECIMAL limits))
6967     $(TR $(TD $(MYREF UnderflowException)) 
6968         $(TD x is too small to be represented as DECIMAL))
6969     $(TR $(TD $(MYREF InexactException)) 
6970          $(TD x cannot be represented exactly))
6971 )
6972 Notes:
6973     The Microsoft _decimal data type is stored as a 96 bit integral 
6974     scaled by a variable exponent between 10$(SUPERSCRIPT -28) and 10$(SUPERSCRIPT 0). 
6975 */
6976 DECIMAL toMsDecimal(D)(auto const ref D x)
6977 {
6978     ExceptionFlags flags;
6979     DECIMAL result;
6980 
6981     if (isNaN(x))
6982     {
6983         if (__ctfe)
6984             DecimalControl.checkFlags(ExceptionFlags.invalidOperation, ExceptionFlags.severe);
6985         else
6986         {
6987             DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
6988         }
6989         return result;
6990     }
6991 
6992     if (isInfinity(x))
6993     {
6994         if (__ctfe)
6995             DecimalControl.checkFlags(ExceptionFlags.overflow, ExceptionFlags.severe);
6996         else
6997         {
6998             DecimalControl.raiseFlags(ExceptionFlags.overflow);
6999         }
7000         result.Lo64 = ulong.max;
7001         result.Hi32 = uint.max;
7002         if (signbit(x))
7003             result.sign = DECIMAL.DECIMAL_NEG;
7004         return result;
7005     }
7006 
7007     if (isZero(x))
7008         return result;
7009 
7010     DataType!D cx;
7011     int ex;
7012     bool sx = x.unpack(cx, ex);
7013 
7014         
7015     static if (is(D == decimal128))
7016         alias cxx = cx;
7017     else
7018         uint128 cxx = cx;
7019 
7020     enum cmax = uint128(cast(ulong)(uint.max), ulong.max);
7021 
7022     flags = coefficientAdjust(cxx, ex, -28, 0, cmax, sx, 
7023                                 __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
7024 
7025     if (flags & ExceptionFlags.overflow)
7026     {
7027         result.Lo64 = ulong.max;
7028         result.Hi32 = uint.max;
7029         if (signbit(x))
7030             result.sign = DECIMAL.DECIMAL_NEG;
7031     }
7032     else if (flags & ExceptionFlags.underflow)
7033     {
7034         result.Lo64 = 0;
7035         result.Hi32 = 0;
7036         if (sx)
7037             result.sign = DECIMAL.DECIMAL_NEG;
7038     }
7039     else
7040     {
7041         result.Lo64 = cxx.lo;
7042         result.Hi32 = cast(uint)(cxx.hi);
7043         result.scale = -ex;
7044         if (sx)
7045             result.sign = DECIMAL.DECIMAL_NEG;
7046     }
7047         
7048     DecimalControl.raiseFlags(flags);
7049     return result;
7050 }
7051 
7052 
7053 ///ditto
7054 D fromMsDecimal(D)(auto const ref DECIMAL x)
7055 {
7056     ExceptionFlags flags;
7057     Unqual!D result;
7058 
7059     uint128 cx = uint128(cast(ulong)(x.Hi32), x.Lo64);
7060     int ex = -x.scale;
7061     bool sx = (x.sign & DECIMAL.DECIMAL_NEG) == DECIMAL.DECIMAL_NEG; 
7062         
7063     flags = coefficientAdjust(cx, ex, cvt!uint128(D.COEF_MAX), RoundingMode.implicit);
7064 
7065     flags |= result.adjustedPack(cvt!(DataType!D)(cx), ex, sx,
7066                                     __ctfe ?  D.PRECISION : DecimalControl.precision,
7067                                     __ctfe ? RoundingMode.implicit  : DecimalControl.rounding,
7068                                     flags);
7069     DecimalControl.raiseFlags(flags);
7070     return result;
7071 }
7072 
7073 
7074 
7075 /**
7076 Checks the order between two _decimal values
7077 Params:
7078     x = a _decimal value
7079     y = a _decimal value
7080 Returns:
7081     true if x precedes y, false otherwise
7082 Notes:
7083     totalOrderAbs checks the order between |x| and |y|
7084 See_Also:
7085     $(MYREF cmp)
7086 */
7087 @IEEECompliant("totalOrder", 25)
7088 bool totalOrder(D1, D2)(auto const ref D1 x, auto const ref D2 y)
7089 if (isDecimal!(D1, D2))
7090 {
7091     return cmp(x, y) <= 0;
7092 }
7093 
7094 ///ditto
7095 @IEEECompliant("totalOrderAbs", 25)
7096 bool totalOrderAbs(D1, D2)(auto const ref D1 x, auto const ref D2 y)
7097 if (isDecimal!(D1, D2))
7098 {
7099     return cmp(fabs(x), fabs(y)) <= 0;
7100 }
7101 
7102 ///
7103 unittest
7104 {
7105     assert (totalOrder(decimal32.min_normal, decimal64.max));
7106     assert (!totalOrder(decimal32.max, decimal128.min_normal));
7107     assert (totalOrder(-decimal64(0), decimal64(0)));
7108     assert (totalOrderAbs(decimal64(0), -decimal64(0)));
7109 }
7110 
7111 /**
7112 Returns the value of x rounded up or down, depending on sign (toward zero).
7113 This operation is silent, doesn't throw any exception.
7114 Special_values:
7115 $(BOOKTABLE,
7116 $(TR $(TH x) $(TH trunc(x)))
7117 $(TR $(TD $(B NaN)) $(TD $(B NaN)))
7118 $(TR $(TD ±0.0) $(TD ±0.0))
7119 $(TR $(TD ±∞) $(TD ±∞))
7120 )
7121 */
7122 @safe pure nothrow @nogc
7123 D trunc(D)(auto const ref D x)
7124 if (isDecimal!D)
7125 {
7126     Unqual!D result = x;
7127     decimalRound(result, 0, RoundingMode.towardZero);
7128     return result;
7129 }
7130 
7131 /**
7132 Gives the previous power of 10 before x. 
7133 Throws:
7134     $(MYREF InvalidOperationException),
7135     $(MYREF OverflowException),
7136     $(MYREF UnderflowException),
7137     $(MYREF InexactException)
7138 Special_values:
7139 $(BOOKTABLE,
7140     $(TR $(TH x) $(TH truncPow10(x)))
7141     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
7142     $(TR $(TD ±∞) $(TD ±∞))
7143     $(TR $(TD ±0.0) $(TD ±0.0))
7144 )
7145 */
7146 D truncPow10(D)(auto const ref D x)
7147 if (isDecimal!D)
7148 {
7149     ExceptionFlags flags;
7150     Unqual!D result;
7151 
7152     if (isSignaling(x))
7153     {
7154         result = D.nan;
7155         flags = ExceptionFlags.invalidOperation;
7156     }
7157     else if (isNaN(x) || isInfinity(x) || isZero(x))
7158         result = x;
7159     else
7160     {
7161         alias U = DataType!D;
7162         U c;
7163         int e;
7164         bool s = x.unpack(c, e);
7165         for (size_t i = 0; i < pow10!U.length; ++i)
7166         {
7167             if (c == pow10!U[i])
7168                 break;
7169             else if (c < pow10!U[i])
7170             {
7171                 c = pow10!U[i - 1];
7172                 break;
7173             }
7174         }
7175         if (i == pow10!U.length)
7176             c = pow10!U[$ - 1];
7177         flags = adjustCoefficient(c, e, D.EXP_MIN, D.EXP_MAX, D.COEF_MAX, s, RoundingMode.towardZero);
7178         flags |= result.pack(c, e, s, flags);
7179     }
7180 
7181     if (__ctfe)
7182         DecimalControl.checkFlags(flags, ExceptionFlags.severe);
7183     else
7184     {
7185         if (flags)
7186             DecimalControl.raiseFlags(flags);
7187     }
7188     return result;
7189 }
7190 
7191 
7192 private:
7193 
7194 template DataType(D)
7195 {
7196     static if (is(Unqual!D == decimal32))
7197         alias DataType = uint;
7198     else static if (is(Unqual!D == decimal64))
7199         alias DataType = ulong;
7200     else static if (is(Unqual!D == decimal128))
7201         alias DataType = uint128;
7202     else
7203         static assert(0);
7204 }
7205 
7206 mixin template ExceptionConstructors()
7207 {
7208     @nogc @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null)
7209     {
7210         super(msg, file, line, next);
7211     }
7212 
7213     @nogc @safe pure nothrow this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__)
7214     {
7215         super(msg, file, line, next);
7216     }
7217 }
7218 
7219 
7220 /* ****************************************************************************************************************** */
7221 /* DECIMAL STRING CONVERSION                                                                                          */
7222 /* ****************************************************************************************************************** */
7223 
7224 
7225 //sinks %a
7226 void sinkHexadecimal(C, T)(auto const ref FormatSpec!C spec, scope void delegate(const(C)[]) sink, 
7227                            auto const ref T coefficient, const int exponent, const bool signed) 
7228 if (isSomeChar!C && isAnyUnsigned!T)
7229 {
7230     int w = 4; //0x, p, exponent sign
7231     if (spec.flPlus || spec.flSpace || signed)
7232         ++w;
7233 
7234     int p = prec(coefficient);
7235     if (p == 0)
7236         p = 1;
7237 
7238     int precision = spec.precision == spec.UNSPECIFIED || spec.precision <= 0 ? p : spec.precision;
7239 
7240     Unqual!T c = coefficient;
7241     int e = exponent;
7242 
7243     coefficientAdjust(c, e, precision, signed, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
7244 
7245 
7246     Unqual!C[T.sizeof / 2] buffer;
7247     Unqual!C[prec(uint.max)] exponentBuffer;
7248 
7249     int digits = dumpUnsignedHex(buffer, c, spec.spec <= 'Z');
7250 
7251     bool signedExponent = e < 0;
7252     uint ex = signedExponent ? -e : e;
7253     int exponentDigits = dumpUnsigned(exponentBuffer, ex);
7254 
7255     w += digits;
7256     w += exponentDigits;
7257 
7258     int pad = spec.width - w;
7259     sinkPadLeft(spec, sink, pad);
7260     sinkSign(spec, sink, signed);
7261     sink("0");
7262     sink(spec.spec <= 'Z' ? "X" : "x");
7263     sinkPadZero(spec, sink, pad);
7264     sink(buffer[$ - digits .. $]);
7265     sink(spec.spec < 'Z' ? "P" : "p");
7266     sink(signedExponent ? "-" : "+");
7267     sink(exponentBuffer[$ - exponentDigits .. $]);
7268     sinkPadRight(sink, pad);
7269 }
7270 
7271 
7272 //sinks %f
7273 void sinkFloat(C, T)(auto const ref FormatSpec!C spec, scope void delegate(const(C)[]) sink, const T coefficient, 
7274                      const int exponent, const bool signed, const RoundingMode mode, const bool skipTrailingZeros = false) 
7275 if (isSomeChar!C)
7276 {
7277     if (coefficient == 0U)
7278         sinkZero(spec, sink, signed, skipTrailingZeros);
7279     else
7280     {
7281         Unqual!T c = coefficient;
7282         int e = exponent;
7283         coefficientShrink(c, e);
7284 
7285         Unqual!C[40] buffer;
7286         int w = spec.flPlus || spec.flSpace || signed ? 1 : 0;
7287 
7288         if (e >= 0) //coefficient[0...].[0...]
7289         {
7290             ptrdiff_t digits = dumpUnsigned(buffer, c);
7291             w += digits;
7292             w += e;
7293             int requestedDecimals = spec.precision == spec.UNSPECIFIED ? 6 : spec.precision;
7294             if (skipTrailingZeros)
7295                 requestedDecimals = 0;
7296             if (requestedDecimals || spec.flHash)
7297                 w += requestedDecimals + 1;
7298             int pad = spec.width - w;
7299             sinkPadLeft(spec, sink, pad);
7300             sinkSign(spec, sink, signed);
7301             sinkPadZero(spec, sink, pad);
7302             sink(buffer[$ - digits .. $]);
7303             sinkRepeat(sink, '0', e);
7304             if (requestedDecimals || spec.flHash)
7305             {
7306                 sink(".");
7307                 sinkRepeat(sink, '0', requestedDecimals);
7308             }
7309             sinkPadRight(sink, pad);
7310         }
7311         else
7312         {
7313             int digits = prec(c);
7314             int requestedDecimals = spec.precision == spec.UNSPECIFIED ? 6 : spec.precision;
7315 
7316             if (-e < digits) //coef.ficient[0...]
7317             {
7318                 int integralDigits = digits + e;
7319                 int fractionalDigits = digits - integralDigits;
7320                 if (fractionalDigits > requestedDecimals)
7321                 {
7322                     divpow10(c, fractionalDigits - requestedDecimals, signed, mode);
7323                     digits = prec(c);
7324                     fractionalDigits = digits - integralDigits;
7325                     if (fractionalDigits > requestedDecimals)
7326                     {
7327                         c /= 10U;
7328                         --fractionalDigits;
7329                     }
7330                 }
7331                 if (requestedDecimals > fractionalDigits && skipTrailingZeros)
7332                     requestedDecimals = fractionalDigits;
7333                 w += integralDigits;
7334                 if (requestedDecimals || spec.flHash)
7335                     w += requestedDecimals + 1;
7336                 int pad = spec.width - w;
7337                 sinkPadLeft(spec, sink, pad);
7338                 sinkSign(spec, sink, signed);
7339                 sinkPadZero(spec, sink, pad);
7340                 dumpUnsigned(buffer, c);
7341                 sink(buffer[$ - digits .. $ - fractionalDigits]);
7342                 if (requestedDecimals || spec.flHash)
7343                 {
7344                     sink(".");
7345                     if (fractionalDigits)
7346                         sink(buffer[$ - fractionalDigits .. $]);
7347                     sinkRepeat(sink, '0', requestedDecimals - fractionalDigits);
7348                 }
7349                 sinkPadRight(sink, pad);
7350             }
7351             else if (-e == digits) //0.coefficient[0...]
7352             {
7353                 if (skipTrailingZeros && requestedDecimals > digits)
7354                     requestedDecimals = digits;
7355                 if (requestedDecimals == 0) //special case, no decimals, round
7356                 {
7357                     divpow10(c, digits - 1, signed, mode);
7358                     divpow10(c, 1, signed, mode);
7359                     w += 1;
7360                     if (spec.flHash)
7361                         ++w;
7362                     int pad = spec.width - w;
7363                     sinkPadLeft(spec, sink, pad);
7364                     sinkSign(spec, sink, signed);
7365                     sinkPadZero(spec, sink, pad);
7366                     sink(c != 0U ? "1": "0");
7367                     if (spec.flHash)
7368                         sink(".");
7369                     sinkPadRight(sink, pad);
7370                 }
7371                 else
7372                 {
7373                     w += 2;
7374                     w += requestedDecimals;
7375                     if (digits > requestedDecimals)
7376                     {
7377                         divpow10(c, digits - requestedDecimals, signed, mode);
7378                         digits = prec(c);
7379                         if (digits > requestedDecimals)
7380                         {
7381                             c /= 10U;
7382                             --digits;
7383                         }
7384                     }
7385                     int pad = spec.width - w;
7386                     sinkPadLeft(spec, sink, pad);
7387                     sinkSign(spec, sink, signed);
7388                     sinkPadZero(spec, sink, pad);
7389                     sink("0.");
7390                     dumpUnsigned(buffer, c);
7391                     sink(buffer[$ - digits .. $]);
7392                     sinkRepeat(sink, '0', requestedDecimals - digits);
7393                     sinkPadRight(sink, pad);
7394                 }
7395             }
7396             else //-e > 0.[0...][coefficient]
7397             {
7398                 int zeros = -e - digits;
7399                 
7400                 if (requestedDecimals > digits - e && skipTrailingZeros)
7401                     requestedDecimals = digits - e - 1;
7402 
7403                 if (requestedDecimals <= zeros) //special case, coefficient does not fit
7404                 {
7405                     divpow10(c, digits - 1, signed, mode);
7406                     divpow10(c, 1, signed, mode);
7407                     if (requestedDecimals == 0)  //special case, 0 or 1
7408                     {
7409                         w += 1;
7410                         int pad = spec.width - w;
7411                         sinkPadLeft(spec, sink, pad);
7412                         sinkSign(spec, sink, signed);
7413                         sinkPadZero(spec, sink, pad);
7414                         sink(c != 0U ? "1": "0");
7415                         sinkPadRight(sink, pad);
7416                     }
7417                     else  //special case 0.[0..][0/1]
7418                     {
7419                         w += 2;
7420                         w += requestedDecimals;
7421                         int pad = spec.width - w;
7422                         sinkPadLeft(spec, sink, pad);
7423                         sinkSign(spec, sink, signed);
7424                         sinkPadZero(spec, sink, pad);
7425                         sink("0.");
7426                         sinkRepeat(sink, '0', requestedDecimals - 1);
7427                         sink(c != 0U ? "1": "0");
7428                         sinkPadRight(sink, pad);
7429                     }
7430                 }
7431                 else //0.[0...]coef
7432                 {
7433                     if (digits > requestedDecimals - zeros)
7434                     {
7435                         divpow10(c, digits - (requestedDecimals - zeros), signed, mode);
7436                         digits = prec(c);
7437                         if (digits > requestedDecimals - zeros)
7438                             c /= 10U;
7439                         digits = prec(c);
7440                     }
7441                     w += 2;
7442                     w += requestedDecimals;
7443                     int pad = spec.width - w;
7444                     sinkPadLeft(spec, sink, pad);
7445                     sinkSign(spec, sink, signed);
7446                     sinkPadZero(spec, sink, pad);
7447                     sink("0.");
7448                     sinkRepeat(sink, '0', zeros);
7449                     digits = dumpUnsigned(buffer, c);
7450                     sink(buffer[$ - digits .. $]);
7451                     sinkRepeat(sink, '0', requestedDecimals - digits - zeros);
7452                     sinkPadRight(sink, pad);
7453                 }
7454             }
7455         }
7456     }
7457 }
7458 
7459 //sinks %e
7460 void sinkExponential(C, T)(auto const ref FormatSpec!C spec, scope void delegate(const(C)[]) sink, const T coefficient, 
7461                      const int exponent, const bool signed, const RoundingMode mode, const bool skipTrailingZeros = false) 
7462 if (isSomeChar!C)
7463 {
7464     int w = 3; /// N e +/-
7465     if (spec.flPlus || spec.flSpace || signed)
7466         ++w;
7467     Unqual!C[T.sizeof * 8 / 3 + 1] buffer;
7468     Unqual!C[10] exponentBuffer;
7469     Unqual!T c = coefficient;
7470     int ex = exponent;
7471     coefficientShrink(c, ex);
7472     int digits = prec(c);
7473     int e = digits == 0 ? 0 : ex + (digits - 1);    
7474     int requestedDecimals = spec.precision == spec.UNSPECIFIED ? 6 : spec.precision;
7475 
7476     int targetPrecision = requestedDecimals + 1;
7477 
7478     if (digits > targetPrecision)
7479     {
7480         divpow10(c, digits - targetPrecision, signed, mode);
7481         digits = prec(c);
7482         if (digits > targetPrecision)
7483             c /= 10U;
7484         --digits;
7485     }
7486     
7487 
7488     bool signedExponent = e < 0;
7489     uint ue = signedExponent ? -e : e;
7490     int exponentDigits = dumpUnsigned(exponentBuffer, ue);
7491     w += exponentDigits <= 2 ? 2 : exponentDigits;
7492     digits = dumpUnsigned(buffer, c);
7493 
7494     if (skipTrailingZeros && requestedDecimals > digits - 1)
7495         requestedDecimals = digits - 1;
7496 
7497     if (requestedDecimals || spec.flHash)
7498         w += requestedDecimals + 1;
7499     
7500     int pad = spec.width - w;
7501     sinkPadLeft(spec, sink, pad);
7502     sinkSign(spec, sink, signed);
7503     sinkPadZero(spec, sink, pad);
7504     sink(buffer[$ - digits .. $ - digits + 1]);
7505     if (requestedDecimals || spec.flHash)
7506     {
7507         sink(".");
7508         if (digits > 1)
7509             sink(buffer[$ - digits + 1 .. $]);
7510         sinkRepeat(sink, '0', requestedDecimals - (digits - 1));
7511     }
7512     sink(spec.spec <= 'Z' ? "E" : "e");
7513     sink(signedExponent ? "-" : "+");
7514     if (exponentDigits < 2)
7515         sink("0");
7516     sink(exponentBuffer[$ - exponentDigits .. $]);
7517     sinkPadRight(sink, pad);    
7518 }
7519 
7520 //sinks %g
7521 void sinkGeneral(C, T)(auto const ref FormatSpec!C spec, scope void delegate(const(C)[]) sink, const T coefficient, 
7522                            const int exponent, const bool signed, const RoundingMode mode) 
7523 if (isSomeChar!C)
7524 {
7525     int precision = spec.precision == spec.UNSPECIFIED ? 6 : (spec.precision <= 0 ? 1 : spec.precision);
7526     Unqual!T c = coefficient;
7527     int e = exponent;
7528     coefficientShrink(c, e);
7529     coefficientAdjust(c, e, precision, signed, mode);
7530     if (c == 0U)
7531         e = 0;
7532     int cp = prec(c);
7533 
7534     int expe = cp > 0 ? e + cp - 1 : 0;
7535 
7536     if (precision > expe && expe >= -4)
7537     {
7538         FormatSpec!C fspec = spec;
7539         fspec.precision = precision - 1 - expe;
7540         sinkFloat(fspec, sink, coefficient, exponent, signed, mode, !fspec.flHash);
7541     }
7542     else
7543     {
7544         FormatSpec!C espec = spec;
7545         espec.precision = precision - 1;
7546         sinkExponential(espec, sink, coefficient, exponent, signed, mode, !espec.flHash);
7547     }
7548 
7549 }
7550 
7551 //sinks a decimal value
7552 void sinkDecimal(C, D)(auto const ref FormatSpec!C spec, scope void delegate(const(C)[]) sink, auto const ref D decimal,
7553                        const RoundingMode mode)
7554 if (isDecimal!D && isSomeChar!C)
7555 {
7556     DataType!D coefficient; int exponent; bool isNegative;
7557     auto fx = fastDecode(decimal, coefficient, exponent, isNegative);
7558     if (fx == FastClass.signalingNaN)
7559         sinkNaN(spec, sink, isNegative, true, coefficient, spec.spec == 'a' || spec.spec == 'A');
7560     else if (fx == FastClass.quietNaN)
7561         sinkNaN(spec, sink, isNegative, false, coefficient, spec.spec == 'a' || spec.spec == 'A');
7562     else if (fx == FastClass.infinite)
7563         sinkInfinity(spec, sink, signbit(decimal) != 0);
7564     else
7565     {
7566         switch (spec.spec)
7567         {
7568             case 'f':
7569             case 'F':
7570                 sinkFloat(spec, sink, coefficient, exponent, isNegative, mode);
7571                 break;
7572             case 'e':
7573             case 'E':
7574                 sinkExponential(spec, sink, coefficient, exponent, isNegative, mode);
7575                 break;
7576             case 'g':
7577             case 'G':
7578             case 's':
7579             case 'S':
7580                 sinkGeneral(spec, sink, coefficient, exponent, isNegative, mode);
7581                 break;
7582             case 'a':
7583             case 'A':
7584                 sinkHexadecimal(spec, sink, coefficient, exponent, isNegative);
7585                 break;
7586             default:
7587                 throw new FormatException("Unsupported format specifier");
7588         }
7589     }
7590 }
7591 
7592 //converts decimal to string using %g
7593 immutable(C)[] decimalToString(C, D)(auto const ref D decimal, const RoundingMode mode)
7594 if (isDecimal!D && isSomeChar!C) 
7595 {
7596     immutable(C)[] result;
7597     void localSink(const(C)[] s)
7598     {
7599         result ~= s;
7600     }
7601 
7602     sinkDecimal(FormatSpec!C("%g"), &localSink, decimal, mode);
7603 
7604     return result;
7605 }
7606 
7607 //converts decimal to string
7608 immutable(C)[] decimalToString(C, D)(auto const ref FormatSpec!C spec, auto const ref D decimal, const RoundingMode mode)
7609 if (isDecimal!D && isSomeChar!C) 
7610 {
7611     immutable(C)[] result;
7612     void localSink(const(C)[] s)
7613     {
7614         result ~= s;
7615     }
7616 
7617     sinkDecimal(spec, &localSink, decimal, mode);
7618 
7619     return result;
7620 }
7621 
7622 unittest
7623 {
7624     import std.format;
7625     decimal32 x = "1.234567";
7626     assert (format("%0.7f", x) == "1.2345670");
7627     assert (format("%0.6f", x) == "1.234567");
7628     assert (format("%0.5f", x) == "1.23457");
7629     assert (format("%0.4f", x) == "1.2346");
7630     assert (format("%0.3f", x) == "1.235");
7631     assert (format("%0.2f", x) == "1.23");
7632     assert (format("%0.1f", x) == "1.2");
7633     assert (format("%0.0f", x) == "1");
7634     assert (format("%+0.1f", x) == "+1.2");
7635     assert (format("%+0.1f", -x) == "-1.2");
7636     assert (format("% 0.1f", x) == " 1.2");
7637     assert (format("% 0.1f", -x) == "-1.2");
7638     assert (format("%8.2f", x) == "    1.23");
7639     assert (format("%+8.2f", x) == "   +1.23");
7640     assert (format("%+8.2f", -x) == "   -1.23");
7641     assert (format("% 8.2f", x) == "    1.23");
7642     assert (format("%-8.2f", x) == "1.23    ");
7643     assert (format("%-8.2f", -x) == "-1.23   ");
7644 
7645     struct S 
7646     {
7647         string fmt;
7648         string v;
7649         string expected;
7650     }
7651     
7652     S[] tests = 
7653     [
7654         S("%+.3e","0.0","+0.000e+00"),
7655   	    S("%+.3e","1.0","+1.000e+00"),
7656   	    S("%+.3f","-1.0","-1.000"),
7657   	    S("%+.3F","-1.0","-1.000"),
7658   	    S("%+07.2f","1.0","+001.00"),
7659   	    S("%+07.2f","-1.0","-001.00"),
7660   	    S("%-07.2f","1.0","1.00   "),
7661   	    S("%-07.2f","-1.0","-1.00  "),
7662   	    S("%+-07.2f","1.0","+1.00  "),
7663   	    S("%+-07.2f","-1.0","-1.00  "),
7664   	    S("%-+07.2f","1.0","+1.00  "),
7665   	    S("%-+07.2f","-1.0","-1.00  "),
7666   	    S("%+10.2f","+1.0","     +1.00"),
7667   	    S("%+10.2f","-1.0","     -1.00"),
7668   	    S("% .3E","-1.0","-1.000E+00"),
7669   	    S("% .3e","1.0"," 1.000e+00"),
7670   	    S("%+.3g","0.0","+0"),
7671   	    S("%+.3g","1.0","+1"),
7672   	    S("%+.3g","-1.0","-1"),
7673   	    S("% .3g","-1.0","-1"),
7674   	    S("% .3g","1.0"," 1"),
7675   	    S("%a","1","0x1p+0"),
7676   	    S("%#g","1e-32","1.00000e-32"),
7677   	    S("%#g","-1.0","-1.00000"),
7678   	    S("%#g","1.1","1.10000"),
7679   	    S("%#g","123456.0","123456."),
7680   	    S("%#g","1234567.0","1.23457e+06"),
7681   	    S("%#g","1230000.0","1.23000e+06"),
7682   	    S("%#g","1000000.0","1.00000e+06"),
7683   	    S("%#.0f","1.0","1."),
7684   	    S("%#.0e","1.0","1.e+00"),
7685   	    S("%#.0g","1.0","1."),
7686   	    S("%#.0g","1100000.0","1.e+06"),
7687   	    S("%#.4f","1.0","1.0000"),
7688   	    S("%#.4e","1.0","1.0000e+00"),
7689   	    S("%#.4g","1.0","1.000"),
7690   	    S("%#.4g","100000.0","1.000e+05"),
7691   	    S("%#.0f","123.0","123."),
7692   	    S("%#.0e","123.0","1.e+02"),
7693   	    S("%#.0g","123.0","1.e+02"),
7694   	    S("%#.4f","123.0","123.0000"),
7695   	    S("%#.4e","123.0","1.2300e+02"),
7696   	    S("%#.4g","123.0","123.0"),
7697   	    S("%#.4g","123000.0","1.230e+05"),
7698   	    S("%#9.4g","1.0","    1.000"),
7699   	    S("%.4a","1","0x1p+0"),
7700   	    S("%.4a","-1","-0x1p+0"),
7701   	    S("%f","+inf","inf"),
7702   	    S("%.1f","-inf","-inf"),
7703   	    S("% f","$(B NaN)"," nan"),
7704   	    S("%20f","+inf","                 inf"),
7705   	    S("% 20F","+inf","                 INF"),
7706   	    S("% 20e","-inf","                -inf"),
7707   	    S("%+20E","-inf","                -INF"),
7708   	    S("% +20g","-Inf","                -inf"),
7709   	    S("%+-20G","+inf","+INF                "),
7710   	    S("%20e","$(B NaN)","                 nan"),
7711   	    S("% +20E","$(B NaN)","                +NAN"),
7712   	    S("% -20g","$(B NaN)"," nan                "),
7713   	    S("%+-20G","$(B NaN)","+NAN                "),
7714   	    S("%+020e","+inf","                +inf"),
7715   	    S("%-020f","-inf","-inf                "),
7716   	    S("%-020E","$(B NaN)","NAN                 "),
7717         S("%e","1.0","1.000000e+00"),
7718   	    S("%e","1234.5678e3","1.234568e+06"),
7719   	    S("%e","1234.5678e-8","1.234568e-05"),
7720   	    S("%e","-7.0","-7.000000e+00"),
7721   	    S("%e","-1e-9","-1.000000e-09"),
7722   	    S("%f","1234.567e2","123456.700000"),
7723   	    S("%f","1234.5678e-8","0.000012"),
7724   	    S("%f","-7.0","-7.000000"),
7725   	    S("%f","-1e-9","-0.000000"),
7726   	    S("%g","1234.5678e3","1.23457e+06"),
7727   	    S("%g","1234.5678e-8","1.23457e-05"),
7728   	    S("%g","-7.0","-7"),
7729   	    S("%g","-1e-9","-1e-09"),
7730   	    S("%E","1.0","1.000000E+00"),
7731   	    S("%E","1234.5678e3","1.234568E+06"),
7732   	    S("%E","1234.5678e-8","1.234568E-05"),
7733   	    S("%E","-7.0","-7.000000E+00"),
7734   	    S("%E","-1e-9","-1.000000E-09"),
7735   	    S("%G","1234.5678e3","1.23457E+06"),
7736   	    S("%G","1234.5678e-8","1.23457E-05"),
7737   	    S("%G","-7.0","-7"),
7738   	    S("%G","-1e-9","-1E-09"),
7739   	    S("%20.6e","1.2345e3","        1.234500e+03"),
7740   	    S("%20.6e","1.2345e-3","        1.234500e-03"),
7741   	    S("%20e","1.2345e3","        1.234500e+03"),
7742   	    S("%20e","1.2345e-3","        1.234500e-03"),
7743   	    S("%20.8e","1.2345e3","      1.23450000e+03"),
7744   	    S("%20f","1.23456789e3","         1234.568000"),
7745   	    S("%20f","1.23456789e-3","            0.001235"),
7746   	    S("%20f","12345678901.23456789","  12345680000.000000"),
7747   	    S("%-20f","1.23456789e3","1234.568000         "),
7748         S("%20.8f","1.23456789e3","       1234.56800000"),
7749         S("%20.8f","1.23456789e-3","          0.00123457"),
7750         S("%g","1.23456789e3","1234.57"),
7751         S("%g","1.23456789e-3","0.00123457"),
7752         S("%g","1.23456789e20","1.23457e+20"),
7753         S("%.2f","1.0","1.00"),
7754   	    S("%.2f","-1.0","-1.00"),
7755   	    S("% .2f","1.0"," 1.00"),
7756   	    S("% .2f","-1.0","-1.00"),
7757   	    S("%+.2f","1.0","+1.00"),
7758   	    S("%+.2f","-1.0","-1.00"),
7759   	    S("%7.2f","1.0","   1.00"),
7760   	    S("%7.2f","-1.0","  -1.00"),
7761   	    S("% 7.2f","1.0","   1.00"),
7762   	    S("% 7.2f","-1.0","  -1.00"),
7763   	    S("%+7.2f","1.0","  +1.00"),
7764   	    S("%+7.2f","-1.0","  -1.00"),
7765   	    S("% +7.2f","1.0","  +1.00"),
7766   	    S("% +7.2f","-1.0","  -1.00"),
7767   	    S("%07.2f","1.0","0001.00"),
7768   	    S("%07.2f","-1.0","-001.00"),
7769   	    S("% 07.2f","1.0"," 001.00"),
7770   	    S("% 07.2f","-1.0","-001.00"),
7771   	    S("%+07.2f","1.0","+001.00"),
7772   	    S("%+07.2f","-1.0","-001.00"),
7773   	    S("% +07.2f","1.0","+001.00"),
7774   	    S("% +07.2f","-1.0","-001.00"),
7775   
7776   
7777     ];
7778 
7779     foreach(s; tests)
7780     {
7781         string result = format(s.fmt, decimal32(s.v));
7782         assert(result == s.expected, "value: '" ~ s.v ~ "', format: '" ~ s.fmt ~ "', result :'" ~ result ~ "', expected: '" ~ s.expected ~ "'");
7783     }
7784 }
7785 
7786 
7787 //returns true if a decimal number can be read in value, stops if doesn't fit in value
7788 ExceptionFlags parseNumberAndExponent(R, T)(ref R range, out T value, out int exponent, bool zeroPrefix) 
7789 if (isInputRange!R && isSomeChar!(ElementType!R))
7790 {
7791     bool afterDecimalPoint = false;
7792     bool atLeastOneDigit = parseZeroes(range) > 0 || zeroPrefix;
7793     bool atLeastOneFractionalDigit = false;
7794     ExceptionFlags flags = ExceptionFlags.none;
7795     while (!range.empty)
7796     {
7797         if (range.front >= '0' && range.front <= '9')
7798         {
7799             uint digit = range.front - '0';
7800             bool overflow = false;
7801             Unqual!T v = fma(value, 10U, digit, overflow);
7802             if (overflow)
7803             {
7804                 //try to shrink the coefficient, this will loose some zeros
7805                 coefficientShrink(value, exponent);
7806                 overflow = false;
7807                 v = fma(value, 10U, digit, overflow);
7808                 if (overflow)
7809                     break;
7810             }
7811             range.popFront();
7812             value = v;
7813             if (afterDecimalPoint)
7814             {
7815                 atLeastOneFractionalDigit = true;
7816                 --exponent;
7817             }
7818             else
7819                 atLeastOneDigit = true;
7820         }
7821         else if (range.front == '.' && !afterDecimalPoint)
7822         {
7823             afterDecimalPoint = true;
7824             range.popFront();
7825         }
7826         else if (range.front == '_')
7827             range.popFront();
7828         else
7829             break;
7830     }
7831 
7832     //no more space in coefficient, just increase exponent before decimal point
7833     //detect if rounding is necessary
7834     int lastDigit = 0;
7835     bool mustRoundUp = false;
7836     while (!range.empty)
7837     {
7838         if (range.front >= '0' && range.front <= '9')
7839         {       
7840             uint digit = range.front - '0';
7841             if (afterDecimalPoint)
7842                 atLeastOneFractionalDigit = true;
7843             else
7844                 ++exponent;
7845             range.popFront();
7846             if (digit != 0)
7847                 flags = ExceptionFlags.inexact;
7848             if (digit <= 3)
7849                 break;
7850             else if (digit >= 5)
7851             {
7852                 if (lastDigit == 4)
7853                 {
7854                     mustRoundUp = true;
7855                     break;
7856                 }
7857             }
7858             else
7859                 lastDigit = 4;
7860 
7861         }
7862         else if (range.front == '.' && !afterDecimalPoint)
7863         {
7864             afterDecimalPoint = true;
7865             range.popFront();
7866         }
7867         else if (range.front == '_')
7868             range.popFront();
7869         else
7870             break;
7871     }
7872 
7873     //just increase exponent before decimal point
7874     while (!range.empty)
7875     {
7876         if (range.front >= '0' && range.front <= '9')
7877         {       
7878             if (range.front != '0')
7879                 flags = ExceptionFlags.inexact;
7880             if (!afterDecimalPoint)
7881                ++exponent;
7882             else
7883                 atLeastOneFractionalDigit = true;
7884             range.popFront();
7885         }
7886         else if (range.front == '.' && !afterDecimalPoint)
7887         {
7888             afterDecimalPoint = true;
7889             range.popFront();
7890         }
7891         else if (range.front == '_')
7892             range.popFront();
7893         else
7894             break;
7895     }
7896 
7897     if (mustRoundUp)
7898     {
7899         if (value < T.max)
7900             ++value;
7901         else
7902         {
7903             auto r = divrem(value, 10U);
7904             ++value;
7905             if (r >= 5U)
7906                 ++value;
7907             else if (r == 4U && mustRoundUp)
7908                 ++value;
7909         }
7910     }
7911 
7912 
7913     if (afterDecimalPoint)
7914         return flags;
7915         //return atLeastOneFractionalDigit ? flags : flags | ExceptionFlags.invalidOperation;
7916     else
7917         return atLeastOneDigit ? flags : flags | ExceptionFlags.invalidOperation;
7918 }
7919 
7920 //parses hexadecimals if starts with 0x, otherwise decimals, false on failure
7921 bool parseHexNumberOrNumber(R, T)(ref R range, ref T value, out bool wasHex) 
7922 if (isInputRange!R && isSomeChar!(ElementType!R))
7923 {
7924     if (expect(range, '0'))
7925     {
7926         if (expectInsensitive(range, 'x'))
7927         {
7928             wasHex = true;
7929             return parseHexNumber(range, value);
7930         }
7931         else
7932             return parseNumber(range, value);
7933     }
7934     else
7935         return parseNumber(range, value);
7936 }
7937 
7938 //parses $(B NaN) and optional payload, expect payload as number in optional (), [], {}, <>. invalidOperation on failure
7939 bool parseNaN(R, T)(ref R range, out T payload) 
7940 if (isInputRange!R && isSomeChar!(ElementType!R))
7941 {
7942     if (expectInsensitive(range, "nan"))
7943     {
7944         auto closingBracket = parseBracket(range);  
7945         bool wasHex;
7946         if (!parseHexNumberOrNumber(range, payload, wasHex))
7947         {
7948             if (wasHex)
7949                 return false;
7950         }
7951         if (closingBracket)
7952             return expect(range, closingBracket);
7953         return true;
7954     }
7955     return false;
7956 }
7957 
7958 @safe
7959 ExceptionFlags parseDecimalHex(R, T)(ref R range, out T coefficient, out int exponent)
7960 if (isInputRange!R && isSomeChar!(ElementType!R))
7961 {
7962     if (parseHexNumber(range, coefficient))
7963     {
7964         if (expectInsensitive(range, 'p'))
7965         {
7966             bool signedExponent;
7967             parseSign(range, signedExponent);
7968             uint e;
7969             if (parseNumber(range, e))
7970             {
7971                 if (signedExponent && e > -int.min)
7972                 {
7973                     exponent = int.min;
7974                     return ExceptionFlags.underflow;
7975                 }
7976                 else if (!signedExponent && e > int.max)
7977                 {
7978                     exponent = int.max;
7979                     return ExceptionFlags.overflow;
7980                 }
7981                 exponent = signedExponent ? -e : e;
7982                 return ExceptionFlags.none;
7983             }
7984         }
7985     }
7986     return ExceptionFlags.invalidOperation;
7987 }
7988 
7989 ExceptionFlags parseDecimalFloat(R, T)(ref R range, out T coefficient, out int exponent, const bool zeroPrefix)
7990 if (isInputRange!R && isSomeChar!(ElementType!R))
7991 {
7992     auto flags = parseNumberAndExponent(range, coefficient, exponent, zeroPrefix);
7993     if ((flags & ExceptionFlags.invalidOperation) == 0)
7994     {
7995         if (expectInsensitive(range, 'e'))
7996         {
7997             bool signedExponent;
7998             parseSign(range, signedExponent);
7999             uint ue;
8000             if (!parseNumber(range, ue))
8001                 flags |= ExceptionFlags.invalidOperation;
8002             else
8003             {       
8004                 
8005                 bool overflow;          
8006                 if (!signedExponent)
8007                 {
8008                     if (ue > int.max)
8009                     {
8010                         exponent = int.max;
8011                         flags |= ExceptionFlags.overflow;
8012                     }
8013                     else
8014                         exponent = adds(exponent, cast(int)ue, overflow);
8015                 }
8016                 else
8017                 {
8018                     if (ue > -int.min || overflow)
8019                     {
8020                         exponent = int.min;
8021                         flags |= ExceptionFlags.underflow;
8022                     }
8023                     else
8024                         exponent = adds(exponent, cast(int)(-ue), overflow);
8025                 }
8026                 if (overflow)
8027                     flags |= exponent > 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow;
8028             }
8029         }
8030     }
8031     return flags;
8032 }
8033 
8034 @safe
8035 ExceptionFlags parseDecimal(R, T)(ref R range, out T coefficient, out int exponent, out bool isinf, out bool isnan, 
8036                                   out bool signaling, out bool signed, out bool wasHex)
8037 if (isInputRange!R && isSomeChar!(ElementType!R))
8038 {
8039     while (expect(range, '_')) { }
8040     if (range.empty)
8041         return ExceptionFlags.invalidOperation;
8042     bool hasSign = parseSign(range, signed);
8043     if (range.empty && hasSign)
8044         return ExceptionFlags.invalidOperation;
8045     while (expect(range, '_')) { }
8046     switch (range.front)
8047     {
8048         case 'i':
8049         case 'I':
8050             isinf = true;
8051             return parseInfinity(range) ? ExceptionFlags.none : ExceptionFlags.invalidOperation;
8052         case 'n':
8053         case 'N':
8054             isnan = true;
8055             signaling = false;
8056             return parseNaN(range, coefficient) ? ExceptionFlags.none : ExceptionFlags.invalidOperation;
8057         case 's':
8058         case 'S':
8059             isnan = true;
8060             signaling = true;
8061             range.popFront();
8062             return parseNaN(range, coefficient) ? ExceptionFlags.none : ExceptionFlags.invalidOperation;
8063         case '0':
8064             range.popFront();
8065             if (expectInsensitive(range, 'x'))
8066             {
8067                 wasHex = true;
8068                 return parseDecimalHex(range, coefficient, exponent);
8069             }
8070             else
8071                 return parseDecimalFloat(range, coefficient, exponent, true);
8072         case '1': .. case '9':
8073             return parseDecimalFloat(range, coefficient, exponent, false);
8074         case '.':
8075             return parseDecimalFloat(range, coefficient, exponent, false);
8076         default:
8077             return ExceptionFlags.invalidOperation;
8078     }
8079 }
8080 
8081 ExceptionFlags parse(D, R)(ref R range, out D decimal, const int precision, const RoundingMode mode)
8082 if (isInputRange!R && isSomeChar!(ElementType!R) && isDecimal!D)
8083 {
8084     DataType!D coefficient;
8085     bool isinf, isnan, signaling, signed;
8086     int exponent;
8087     auto flags = parseDecimal(range, coefficient, exponent, isinf, isnan, signaling, isnegative);
8088  
8089     if (flags & ExceptionFlags.invalidOperation)
8090     {   
8091         decimal.data = D.MASK_QNAN;
8092         decimal.data |= coefficient | D.MASK_PAYL;
8093         if (isnegative)
8094             decimal.data |= D.MASK_SGN;
8095         return flags;
8096     }
8097 
8098     if (signaling)
8099         decimal.data = D.MASK_SNAN;
8100     else if (isnan)
8101         decimal.data = D.MASK_QNAN;
8102     else if (isinf)
8103         decimal.data = D.MASK_INF;
8104     else if (coefficient == 0)
8105         decimal.data - D.MASK_ZERO;
8106     else
8107     {
8108         flags |= adjustCoefficient(coefficient, exponent, D.EXP_MIN, D.EXP_MAX, D.COEF_MAX, isnegative, mode);
8109         flags |= adjustPrecision(coefficient, exponent, D.EXP_MIN, D.EXP_MAX, precision, isnegative, mode);
8110         if (flags & ExceptionFlags.overflow)
8111             decimal.data = D.MASK_INF;
8112         else if ((flags & ExceptionFlags.underflow)  || coefficient == 0)
8113             decimal.data = D.MASK_ZERO;
8114         else
8115         {
8116             flags |= decimal.pack(coefficient, exponent, isnegative);
8117             if (flags & ExceptionFlags.overflow)
8118                 decimal.data = D.MASK_INF;
8119             else if ((flags & ExceptionFlags.underflow)  || coefficient == 0)
8120                 decimal.data = D.MASK_ZERO;                
8121         }
8122     }
8123 
8124     if (isNegative)
8125         decimal.data |= D.MASK_SGN;
8126     return flags;
8127 }
8128 
8129 D fromString(D, C)(const(C)[] s)
8130 if (isDecimal!D && isSomeChar!C)
8131 {
8132     Unqual!D result = void;
8133     auto flags = result.packString(s, 
8134                                    __ctfe ? D.PRECISION : DecimalControl.precision,
8135                                    __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
8136     DecimalControl.raiseFlags(flags);
8137     return result;
8138 }
8139 
8140 
8141 /* ****************************************************************************************************************** */
8142 /* DECIMAL TO DECIMAL CONVERSION                                                                                      */
8143 /* ****************************************************************************************************************** */
8144 
8145 ExceptionFlags decimalToDecimal(D1, D2)(auto const ref D1 source, out D2 target, 
8146                                         const int precision, const RoundingMode mode) 
8147 if (isDecimal!(D1, D2))
8148 {
8149     DataType!D1 cx; int ex; bool sx;
8150     final switch(fastDecode(source, cx, ex, sx))
8151     {
8152         case FastClass.finite:
8153             static if (D2.sizeof == D1.sizeof)
8154             {
8155                 target.data = source.data;
8156                 return ExceptionFlags.none;
8157             }
8158             else
8159                 return target.adjustedPack(cx, ex, sx, precision, mode);
8160         case FastClass.zero:
8161             target = sx ? -D2.zero : D2.zero;
8162             return ExceptionFlags.none;
8163         case FastClass.infinite:
8164             target = sx ? -D2.infinity : D2.infinity;
8165             return ExceptionFlags.none;
8166         case FastClass.quietNaN:
8167             target = sx ? -D2.nan : D2.nan;
8168             return ExceptionFlags.none;
8169         case FastClass.signalingNaN:
8170             target = sx ? -D2.nan : D2.nan;
8171             return ExceptionFlags.invalidOperation;
8172     }
8173 }
8174 
8175 ExceptionFlags decimalToUnsigned(D, T)(auto const ref D source, out T target, const RoundingMode mode) 
8176 if (isDecimal!D && isUnsigned!T)
8177 {   
8178     alias U = CommonStorage!(D, T);
8179     U cx; int ex; bool sx;
8180     final switch (fastDecode(source, cx, ex, sx))
8181     {
8182         case FastClass.finite:
8183             auto flags = coefficientAdjust(cx, ex, 0, 0, U(T.max), sx, mode);
8184             if (flags & ExceptionFlags.overflow)
8185             {
8186                 target = T(1) << (T.sizeof * 8 - 1);
8187                 flags = ExceptionFlags.overflow | ExceptionFlags.invalidOperation;
8188             }
8189             else if (flags & ExceptionFlags.underflow)
8190                 target = 0;
8191             else if (sx)
8192             {
8193                 target = T(1) << (T.sizeof * 8 - 1);
8194                 return ExceptionFlags.overflow | ExceptionFlags.invalidOperation;
8195             }
8196             else
8197                 target = cast(T)cx;
8198             return flags;
8199         case FastClass.zero:
8200             target = 0;
8201             return ExceptionFlags.none;
8202         case FastClass.infinite:
8203             target = T(1) << (T.sizeof * 8 - 1);
8204             return ExceptionFlags.overflow | ExceptionFlags.invalidOperation;
8205         case FastClass.quietNaN:
8206         case FastClass.signalingNaN:
8207             target = T(1) << (T.sizeof * 8 - 1);
8208             return ExceptionFlags.invalidOperation;
8209     }
8210 }
8211 
8212 ExceptionFlags decimalToSigned(D, T)(auto const ref D source, out T target, const RoundingMode mode) 
8213 if (isDecimal!D && isSigned!T)
8214 {
8215     alias U = CommonStorage!(D, T);
8216     U cx; int ex; bool sx;
8217     final switch (fastDecode(source, cx, ex, sx))
8218     {
8219         case FastClass.finite:
8220             U max = sx ? unsign!U(T.min) : unsign!U(T.max);
8221             auto flags = coefficientAdjust(cx, ex, 0, 0, max, sx, mode);
8222             if (flags & ExceptionFlags.overflow)
8223             {
8224                 target = T.min;
8225                 flags = ExceptionFlags.overflow | ExceptionFlags.invalidOperation;
8226             }
8227             else if (flags & ExceptionFlags.underflow)
8228                 target = 0;
8229             else
8230                 target = sign!T(cx, sx);
8231             return flags;
8232         case FastClass.zero:
8233             target = 0;
8234             return ExceptionFlags.none;
8235         case FastClass.infinite:
8236             target = T.min;
8237             return ExceptionFlags.overflow | ExceptionFlags.invalidOperation;
8238         case FastClass.quietNaN:
8239         case FastClass.signalingNaN:
8240             target = T.min;
8241             return ExceptionFlags.invalidOperation;
8242     }
8243 }
8244 
8245 ExceptionFlags decimalToFloat(D, T)(auto const ref D source, out T target, const RoundingMode mode)
8246 if (isDecimal!D && isFloatingPoint!T)
8247 {
8248     DataType!D cx; int ex; bool sx;
8249     final switch (fastDecode(source, cx, ex, sx))
8250     {
8251         case FastClass.finite:
8252             ExceptionFlags flags;
8253             static if (is(D: decimal128))
8254                 flags = coefficientAdjust(cx, ex, uint128(ulong.max), sx, mode);
8255             ulong m = cvt!ulong(cx);
8256             final switch (mode)
8257             {
8258                 case RoundingMode.tiesToAway:
8259                     flags |= exp10to2!(RoundingMode.tiesToAway)(m, ex, sx);
8260                     break;
8261                 case RoundingMode.tiesToEven:
8262                     flags |= exp10to2!(RoundingMode.tiesToEven)(m, ex, sx);
8263                     break;
8264                 case RoundingMode.towardNegative:
8265                     flags |= exp10to2!(RoundingMode.towardNegative)(m, ex, sx);
8266                     break;
8267                 case RoundingMode.towardPositive:
8268                     flags |= exp10to2!(RoundingMode.towardPositive)(m, ex, sx);
8269                     break;
8270                 case RoundingMode.towardZero:
8271                     flags |= exp10to2!(RoundingMode.towardZero)(m, ex, sx);
8272                     break;
8273             }
8274             synchronized
8275             {              
8276                 FloatingPointControl fpctrl;
8277                 auto savedExceptions = fpctrl.enabledExceptions;
8278                 fpctrl.disableExceptions(FloatingPointControl.allExceptions);
8279                 auto savedMode = fpctrl.rounding;
8280                 switch (mode)
8281                 {
8282                     case RoundingMode.tiesToAway:
8283                     case RoundingMode.tiesToEven:
8284                         fpctrl.rounding = FloatingPointControl.roundToNearest;
8285                         break;
8286                     case RoundingMode.towardNegative:
8287                         fpctrl.rounding = FloatingPointControl.roundDown;
8288                         break;
8289                     case RoundingMode.towardPositive:
8290                         fpctrl.rounding = FloatingPointControl.roundUp;
8291                         break;
8292                     case RoundingMode.towardZero:
8293                         fpctrl.rounding = FloatingPointControl.roundToZero;
8294                         break;
8295                     default:
8296                         break;
8297                 }
8298                 resetIeeeFlags();
8299                 
8300                 real r = m;
8301                 target = ldexp(r, ex);
8302                 if (sx)
8303                     target = -target;
8304 
8305                 if (ieeeFlags.inexact)
8306                     flags |= ExceptionFlags.inexact;
8307                 if (ieeeFlags.underflow)
8308                     flags |= ExceptionFlags.underflow;
8309                 if (ieeeFlags.overflow)
8310                     flags |= ExceptionFlags.overflow;
8311                 if (ieeeFlags.invalid)
8312                     flags |= ExceptionFlags.invalidOperation;
8313                 if (ieeeFlags.divByZero)
8314                     flags |= ExceptionFlags.divisionByZero;
8315                 fpctrl.enableExceptions(savedExceptions);
8316             }
8317             
8318             return flags;         
8319         case FastClass.zero:
8320             target = sx ? -0.0: 0.0;
8321             return ExceptionFlags.none;
8322         case FastClass.infinite:
8323             target = sx ? -T.infinity : T.infinity;
8324             return ExceptionFlags.none;
8325         case FastClass.quietNaN:
8326         case FastClass.signalingNaN:
8327             target = T.nan;
8328             return ExceptionFlags.none;
8329     }
8330 
8331 
8332 
8333 }
8334 
8335 /* ****************************************************************************************************************** */
8336 /* DECIMAL ARITHMETIC                                                                                      */
8337 /* ****************************************************************************************************************** */
8338 
8339 template CommonStorage(D, T) if (isDecimal!D && isDecimal!T)
8340 {
8341     static if (D.sizeof >= T.sizeof)
8342         alias CommonStorage = DataType!D;
8343     else
8344         alias CommonStorage = DataType!T;
8345 }
8346 
8347 template CommonStorage(D, T) if (isDecimal!D && isIntegral!T)
8348 {
8349     static if (D.sizeof >= T.sizeof)
8350         alias CommonStorage = DataType!D;
8351     else
8352         alias CommonStorage = Unsigned!T;
8353 }
8354 
8355 template CommonStorage(D, T) if (isDecimal!D && isFloatingPoint!T)
8356 {
8357     static if (is(Unqual!T == float))
8358         alias CommonStorage = DataType!D;
8359     else
8360         alias CommonStorage = CommonStorage!(D, ulong);
8361 }
8362 
8363 
8364 @safe pure nothrow @nogc
8365 D canonical(D)(auto const ref D x)
8366 if (isDecimal!D)
8367 {
8368     Unqual!D result = x;
8369     canonicalize(result);
8370     return x;
8371 }
8372 
8373 @safe pure nothrow @nogc
8374 void canonicalize(D)(ref D x)
8375 if (isDecimal!D)
8376 {
8377     if ((x.data & D.MASK_INF) == D.MASK_INF)
8378     {
8379         if ((x.data & D.MASK_QNAN) == D.MASK_QNAN)
8380             x.data &= D.MASK_SNAN | D.MASK_SGN | D.MASK_PAYL;
8381         else
8382             x.data &= D.MASK_INF | D.MASK_SGN;
8383     }
8384     else if ((x.data & D.MASK_EXT) == D.MASK_EXT && 
8385              (((x.data & D.MASK_COE2) | D.MASK_COEX) > D.COEF_MAX))
8386         x.data &= D.MASK_ZERO | D.MASK_SGN;    
8387     else if ((x.data & D.MASK_COE1) == 0U)
8388         x.data &= D.MASK_ZERO | D.MASK_SGN;
8389 }
8390 
8391 @safe pure nothrow @nogc
8392 void unsignalize(D)(ref D x)
8393 if (isDecimal!D)
8394 {
8395     x.data &= ~D.MASK_SNANBIT;
8396 }
8397 
8398 @safe pure nothrow @nogc
8399 DecimalClass decimalDecode(D, T)(auto const ref D x, out T cx, out int ex, out bool sx) 
8400 if (isDecimal!D && is(T: DataType!D))
8401 {
8402     sx = cast(bool)(x.data & D.MASK_SGN);
8403 
8404     if ((x.data & D.MASK_INF) == D.MASK_INF)
8405         if ((x.data & D.MASK_QNAN) == D.MASK_QNAN)
8406             if ((x.data & D.MASK_SNAN) == D.MASK_SNAN)
8407                 return DecimalClass.signalingNaN;
8408             else
8409                 return DecimalClass.quietNaN;
8410         else
8411             return sx ? DecimalClass.negativeInfinity : DecimalClass.positiveInfinity;
8412     else if ((x.data & D.MASK_EXT) == D.MASK_EXT)
8413     {
8414         cx = (x.data & D.MASK_COE2) | D.MASK_COEX;
8415         if (cx > D.COEF_MAX)
8416         {
8417             return sx ? DecimalClass.negativeZero : DecimalClass.positiveZero; 
8418         }
8419         ex = cast(uint)((x.data & D.MASK_EXP2) >>> D.SHIFT_EXP2) - D.EXP_BIAS;
8420     }
8421     else
8422     {
8423         cx = x.data & D.MASK_COE1;
8424         if (cx == 0U || cx > D.COEF_MAX)
8425         {
8426             ex = 0;
8427             return sx ? DecimalClass.negativeZero : DecimalClass.positiveZero; 
8428         }
8429         ex = cast(uint)((x.data & D.MASK_EXP1) >>> D.SHIFT_EXP1) - D.EXP_BIAS;
8430     }
8431 
8432     if (ex + D.EXP_BIAS < D.PRECISION - 1)
8433     {
8434         if (prec(cx) < D.PRECISION - ex + D.EXP_BIAS)
8435             return sx ? DecimalClass.negativeSubnormal : DecimalClass.positiveSubnormal;
8436     }
8437     return sx ? DecimalClass.negativeNormal : DecimalClass.positiveNormal;
8438 }
8439 
8440 enum FastClass
8441 {
8442     signalingNaN,
8443     quietNaN,
8444     infinite,
8445     zero,
8446     finite,
8447 }
8448 
8449 @safe pure nothrow @nogc
8450 FastClass fastDecode(D, T)(auto const ref D x, out T cx, out int ex, out bool sx) 
8451 if ((is(D: decimal32) || is(D: decimal64)) && isAnyUnsigned!T)
8452 {
8453     static assert (T.sizeof >= D.sizeof);
8454 
8455     sx = cast(bool)(x.data & D.MASK_SGN);
8456 
8457     if ((x.data & D.MASK_INF) == D.MASK_INF)
8458         if ((x.data & D.MASK_QNAN) == D.MASK_QNAN)
8459         {
8460             cx = x.data & D.MASK_PAYL;
8461             if (cx > D.PAYL_MAX)
8462                 cx = 0U;
8463             if ((x.data & D.MASK_SNAN) == D.MASK_SNAN)
8464                 return FastClass.signalingNaN;
8465             else
8466                 return FastClass.quietNaN;
8467             
8468         }
8469         else
8470             return FastClass.infinite;
8471     else if ((x.data & D.MASK_EXT) == D.MASK_EXT)
8472     {
8473         cx = (x.data & D.MASK_COE2) | D.MASK_COEX;
8474         if (cx > D.COEF_MAX)
8475             cx = 0U;
8476         ex = cast(uint)((x.data & D.MASK_EXP2) >>> D.SHIFT_EXP2) - D.EXP_BIAS;
8477     }
8478     else
8479     {
8480         cx = x.data & D.MASK_COE1;
8481         ex = cast(uint)((x.data & D.MASK_EXP1) >>> D.SHIFT_EXP1) - D.EXP_BIAS;
8482     }
8483 
8484     return cx == 0U ? FastClass.zero : FastClass.finite;
8485 }
8486 
8487 @safe pure nothrow @nogc
8488 FastClass fastDecode(D, T)(auto const ref D x, out T cx, out int ex, out bool sx) 
8489 if (is(D: decimal128) && isAnyUnsigned!T)
8490 {
8491     static assert (T.sizeof >= D.sizeof);
8492 
8493     sx = cast(bool)(x.data.hi & D.MASK_SGN.hi);
8494 
8495     if ((x.data.hi & D.MASK_INF.hi) == D.MASK_INF.hi)
8496         if ((x.data.hi & D.MASK_QNAN.hi) == D.MASK_QNAN.hi)
8497         {
8498             cx = x.data & D.MASK_PAYL; 
8499             if (cx > D.PAYL_MAX)
8500                 cx = 0U;
8501             if ((x.data.hi & D.MASK_SNAN.hi) == D.MASK_SNAN.hi)
8502                 return FastClass.signalingNaN;
8503             else
8504                 return FastClass.quietNaN;
8505         }
8506         else
8507             return FastClass.infinite;
8508     else if ((x.data.hi & D.MASK_EXT.hi) == D.MASK_EXT.hi)
8509     {
8510         cx = 0U;
8511         ex = cast(uint)((x.data.hi & D.MASK_EXP2.hi) >>> (D.SHIFT_EXP2 - 64)) - D.EXP_BIAS;
8512     }
8513     else
8514     {
8515         cx = x.data & D.MASK_COE1;
8516         if (cx > D.COEF_MAX)
8517             cx = 0U;
8518         ex = cast(uint)((x.data.hi & D.MASK_EXP1.hi) >>> (D.SHIFT_EXP1 - 64)) - D.EXP_BIAS;
8519     }
8520 
8521     return cx == 0U ? FastClass.zero : FastClass.finite;
8522 }
8523 
8524 @safe pure nothrow @nogc
8525 FastClass fastDecode(F, T)(auto const ref F x, out T cx, out int ex, out bool sx, const RoundingMode mode, out ExceptionFlags flags)
8526 if (isFloatingPoint!F && isAnyUnsigned!T)
8527 {
8528     bool nan, inf;
8529     static if (is(Unqual!F == float))
8530     {
8531         uint m;
8532         sx = funpack(x, ex, m, inf, nan);
8533     }
8534     else static if (is(Unqual!F == real) && real.mant_dig == 64)
8535     {
8536         ulong m;
8537         sx = runpack(x, ex, m, inf, nan);
8538     }
8539     else
8540     {
8541         ulong m;
8542         sx = dunpack(cast(double)x, ex, m, inf, nan);
8543     }
8544 
8545     if (x == 0.0)
8546         return FastClass.zero;
8547 
8548     if (inf)
8549         return FastClass.infinite;
8550 
8551     if (nan)
8552     {
8553         cx = cvt!T(m);
8554         return FastClass.quietNaN;
8555     }
8556 
8557     static if (is(F == float) && T.sizeof > uint.sizeof)
8558         alias U = uint;
8559     else static if (is(F == double) && T.sizeof > ulong.sizeof)
8560         alias U = ulong;
8561     else static if (is(F == real) && T.sizeof > uint128.sizeof)
8562         alias U = uint128;
8563     else static if (T.sizeof < typeof(m).sizeof)
8564         alias U = typeof(m);
8565     else
8566         alias U = T;
8567 
8568     U u = m;
8569 
8570     final switch(mode)
8571     {
8572         case RoundingMode.tiesToAway:
8573             flags = exp2to10!(RoundingMode.tiesToAway)(u, ex, sx);
8574             break;
8575         case RoundingMode.tiesToEven:
8576             flags = exp2to10!(RoundingMode.tiesToEven)(u, ex, sx);
8577             break;
8578         case RoundingMode.towardZero:
8579             flags = exp2to10!(RoundingMode.towardZero)(u, ex, sx);
8580             break;
8581         case RoundingMode.towardNegative:
8582             flags = exp2to10!(RoundingMode.towardNegative)(u, ex, sx);
8583             break;
8584         case RoundingMode.towardPositive:
8585             flags = exp2to10!(RoundingMode.towardPositive)(u, ex, sx);
8586             break;
8587     }
8588 
8589     static if (T.sizeof < U.sizeof)
8590     {
8591         flags |= coefficientAdjust(u, ex, cvt!U(T.max), sx, mode);
8592     }
8593 
8594     cx = cvt!T(u);
8595     return cx ? FastClass.finite : FastClass.zero;
8596 
8597 }
8598 
8599 @safe pure nothrow @nogc
8600 ExceptionFlags decimalInc(D)(ref D x, const int precision, const RoundingMode mode)
8601 {
8602 
8603     DataType!D cx; int ex; bool sx;
8604     final switch(fastDecode(x, cx, ex, sx))
8605     {
8606         case FastClass.finite:
8607             auto flags = coefficientAdd(cx, ex, sx, DataType!D(1U), 0, false, RoundingMode.implicit);
8608             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
8609         case FastClass.zero:
8610             x = D.one;
8611             return ExceptionFlags.none;
8612         case FastClass.quietNaN:
8613         case FastClass.infinite:
8614             return ExceptionFlags.none;
8615         case FastClass.signalingNaN:
8616             unsignalize(x);
8617             return ExceptionFlags.invalidOperation;
8618     }
8619 }
8620 
8621 @safe pure nothrow @nogc
8622 ExceptionFlags decimalDec(D)(ref D x, const int precision, const RoundingMode mode)
8623 {
8624     DataType!D cx; int ex; bool sx;
8625     final switch(fastDecode(x, cx, ex, sx))
8626     {
8627         case FastClass.finite:
8628             auto flags = coefficientAdd(cx, ex, sx, DataType!D(1U), 0, true, RoundingMode.implicit);
8629             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
8630         case FastClass.zero:
8631             x = -D.one;
8632             return ExceptionFlags.none;
8633         case FastClass.infinite:
8634         case FastClass.quietNaN:
8635             return ExceptionFlags.none;
8636         case FastClass.signalingNaN:
8637             unsignalize(x);
8638             return ExceptionFlags.invalidOperation;
8639     }
8640 }
8641 
8642 @safe pure nothrow @nogc
8643 ExceptionFlags decimalRound(D)(ref D x, const int precision, const RoundingMode mode)
8644 if (isDecimal!D)
8645 {
8646     DataType!D cx; int ex; bool sx;
8647     final switch(fastDecode(x, cx, ex, sx))
8648     {
8649         case FastClass.finite:
8650             auto flags = coefficientAdjust(cx, ex, 0, D.EXP_MAX, D.COEF_MAX, sx, mode);
8651             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
8652         case FastClass.zero:
8653         case FastClass.infinite:
8654         case FastClass.quietNaN:
8655             return ExceptionFlags.none;
8656         case FastClass.signalingNaN:
8657             unsignalize(x);
8658             return ExceptionFlags.invalidOperation; 
8659     }
8660 }
8661 
8662 @safe pure nothrow @nogc
8663 ExceptionFlags decimalAdjust(D)(ref D x, const int precision, const RoundingMode mode)
8664 {
8665     DataType!D cx; int ex; bool sx;
8666     final switch(fastDecode(x, cx, ex, sx))
8667     {
8668         case FastClass.finite:
8669             return x.adjustedPack(cx, ex, sx, precision, mode, ExceptionFlags.none);
8670         case FastClass.zero:
8671         case FastClass.infinite:
8672         case FastClass.quietNaN:
8673             return ExceptionFlags.none;
8674         case FastClass.signalingNaN:
8675             unsignalize(x);
8676             return ExceptionFlags.invalidOperation; 
8677     }
8678 }
8679 
8680 @safe pure nothrow @nogc
8681 ExceptionFlags decimalNextUp(D)(ref D x)
8682 if (isDecimal!D)
8683 {
8684     DataType!D cx; int ex; bool sx;
8685     final switch(fastDecode(x, cx, ex, sx))
8686     {
8687         case FastClass.finite:
8688             coefficientExpand(cx, ex);
8689             if (sx)
8690                 --cx;
8691             else
8692                 ++cx;
8693             return x.adjustedPack(cx, ex, sx, 0, RoundingMode.towardPositive, ExceptionFlags.none);
8694         case FastClass.zero:
8695             x.pack(DataType!D(1U), D.EXP_MIN, false);
8696             return ExceptionFlags.none;
8697         case FastClass.infinite:
8698             if (sx)
8699                 x = -D.max;
8700             return ExceptionFlags.none;
8701         case FastClass.quietNaN:
8702             return ExceptionFlags.none;
8703         case FastClass.signalingNaN:
8704             unsignalize(x);
8705             return ExceptionFlags.invalidOperation; 
8706     }  
8707 }
8708 
8709 @safe pure nothrow @nogc
8710 ExceptionFlags decimalNextDown(D)(ref D x)
8711 if (isDecimal!D)
8712 {
8713     DataType!D cx; int ex; bool sx;
8714     final switch(fastDecode(x, cx, ex, sx))
8715     {
8716         case FastClass.finite:
8717             coefficientExpand(cx, ex);
8718             if (!sx)
8719                 --cx;
8720             else
8721                 ++cx;
8722             return x.adjustedPack(cx, ex, sx, 0, RoundingMode.towardNegative, ExceptionFlags.none);
8723         case FastClass.zero:
8724             x.pack(DataType!D(1U), D.EXP_MIN, true);
8725             return ExceptionFlags.none;
8726         case FastClass.infinite:
8727             if (!sx)
8728                 x = D.max;
8729             return ExceptionFlags.none;
8730         case FastClass.quietNaN:
8731             return ExceptionFlags.none;
8732         case FastClass.signalingNaN:
8733             unsignalize(x);
8734             return ExceptionFlags.invalidOperation;  
8735     }
8736 }
8737 
8738 ExceptionFlags decimalMin(D1, D2, D)(auto const ref D1 x, auto const ref D2 y, out D z)
8739 if (isDecimal!(D1, D2, D) && is(D: CommonDecimal!(D1, D2)))
8740 {
8741     DataType!D cx, cy; int ex, ey; bool sx, sy;
8742     immutable fx = fastDecode(x, cx, ex, sx);
8743     immutable fy = fastDecode(y, cy, ey, sy);
8744 
8745     if (fx == FastClass.signalingNaN)
8746     {
8747         z = copysign(D.nan, x);
8748         return ExceptionFlags.invalidOperation;
8749     }
8750 
8751     if (fy == FastClass.signalingNaN)
8752     {
8753         if (fx == FastClass.quietNaN)
8754             z = copysign(D.nan, x);
8755         else
8756             z = copysign(D.nan, y);
8757         return ExceptionFlags.invalidOperation;
8758     }
8759 
8760     if (fx == FastClass.quietNaN)
8761     {
8762         if (fy == FastClass.quietNaN)
8763             z = x;
8764         else
8765             z = y;
8766         return ExceptionFlags.none;
8767     }
8768 
8769     if (fy == FastClass.quietNaN)
8770     {
8771         z = x;
8772         return ExceptionFlags.none;
8773     }
8774 
8775     if (fx == FastClass.infinite)
8776     {
8777         if (sx)
8778             z = x;
8779         else
8780             z = y;
8781         return ExceptionFlags.none;
8782     }
8783 
8784     if (fy == FastClass.infinite)
8785     {
8786         if (sy)
8787             z = y;
8788         else
8789             z = x;
8790         return ExceptionFlags.none;
8791     }
8792 
8793     if (fx == FastClass.zero)
8794     {
8795         if (sy)
8796             z = y;
8797         else
8798             z = x;
8799         return ExceptionFlags.none;
8800     }
8801 
8802     if (fy == FastClass.zero)
8803     {
8804         if (sx)
8805             z = x;
8806         else
8807             z = y;
8808         return ExceptionFlags.none;
8809     }
8810 
8811     immutable c = coefficientCmp(cx, ex, sx, cy, ey, sy);
8812     if (c <= 0)
8813         z = x;
8814     else
8815         z = y;
8816     return ExceptionFlags.none;
8817 }
8818 
8819 ExceptionFlags decimalMinAbs(D1, D2, D)(auto const ref D1 x, auto const ref D2 y, out D z)
8820 if (isDecimal!(D1, D2, D) && is(D: CommonDecimal!(D1, D2)))
8821 {
8822     DataType!D cx, cy; int ex, ey; bool sx, sy;
8823     immutable fx = fastDecode(x, cx, ex, sx);
8824     immutable fy = fastDecode(y, cy, ey, sy);
8825 
8826     if (fx == FastClass.signalingNaN)
8827     {
8828         z = copysign(D.nan, x);
8829         return ExceptionFlags.invalidOperation;
8830     }
8831 
8832     if (fy == FastClass.signalingNaN)
8833     {
8834         if (fx == FastClass.quietNaN)
8835             z = copysign(D.nan, x);
8836         else
8837             z = copysign(D.nan, y);
8838         return ExceptionFlags.invalidOperation;
8839     }
8840 
8841     if (fx == FastClass.quietNaN)
8842     {
8843         if (fy == FastClass.quietNaN)
8844             z = x;
8845         else
8846             z = y;
8847         return ExceptionFlags.none;
8848     }
8849 
8850     if (fy == FastClass.quietNaN)
8851     {
8852         z = x;
8853         return ExceptionFlags.none;
8854     }
8855 
8856     if (fx == FastClass.infinite)
8857     {
8858         if (fy == FastClass.infinite && sx)
8859             z = x;
8860         else
8861             z = y;
8862         return ExceptionFlags.none;
8863     }
8864 
8865     if (fy == FastClass.infinite)
8866     {
8867         z = x;
8868         return ExceptionFlags.none;
8869     }
8870 
8871     if (fx == FastClass.zero)
8872     {
8873         z = x;
8874         return ExceptionFlags.none;
8875     }
8876 
8877     if (fy == FastClass.zero)
8878     {
8879         z = y;
8880         return ExceptionFlags.none;
8881     }
8882 
8883     immutable c = coefficientCmp(cx, ex, cy, ey);
8884     if (c < 0)
8885         z = x;
8886     else if (c == 0 && sx)
8887         z = x;
8888     else
8889         z = y;
8890     return ExceptionFlags.none;
8891 }
8892 
8893 ExceptionFlags decimalMax(D1, D2, D)(auto const ref D1 x, auto const ref D2 y, out D z)
8894 if (isDecimal!(D1, D2, D) && is(D: CommonDecimal!(D1, D2)))
8895 {
8896     DataType!D cx, cy; int ex, ey; bool sx, sy;
8897     immutable fx = fastDecode(x, cx, ex, sx);
8898     immutable fy = fastDecode(y, cy, ey, sy);
8899 
8900     if (fx == FastClass.signalingNaN)
8901     {
8902         z = copysign(D.nan, x);
8903         return ExceptionFlags.invalidOperation;
8904     }
8905 
8906     if (fy == FastClass.signalingNaN)
8907     {
8908         if (fx == FastClass.quietNaN)
8909             z = copysign(D.nan, x);
8910         else
8911             z = copysign(D.nan, y);
8912         return ExceptionFlags.invalidOperation;
8913     }
8914 
8915     if (fx == FastClass.quietNaN)
8916     {
8917         if (fy == FastClass.quietNaN)
8918             z = x;
8919         else
8920             z = y;
8921         return ExceptionFlags.none;
8922     }
8923 
8924     if (fy == FastClass.quietNaN)
8925     {
8926         z = x;
8927         return ExceptionFlags.none;
8928     }
8929 
8930     if (fx == FastClass.infinite)
8931     {
8932         if (sx)
8933             z = y;
8934         else
8935             z = x;
8936         return ExceptionFlags.none;
8937     }
8938 
8939     if (fy == FastClass.infinite)
8940     {
8941         if (sy)
8942             z = x;
8943         else
8944             z = y;
8945         return ExceptionFlags.none;
8946     }
8947 
8948     if (fx == FastClass.zero)
8949     {
8950         if (sy)
8951             z = x;
8952         else
8953             z = y;
8954         return ExceptionFlags.none;
8955     }
8956 
8957     if (fy == FastClass.zero)
8958     {
8959         if (sx)
8960             z = y;
8961         else
8962             z = x;
8963         return ExceptionFlags.none;
8964     }
8965 
8966     immutable c = coefficientCmp(cx, ex, sx, cy, ey, sy);
8967     if (c >= 0)
8968         z = x;
8969     else
8970         z = y;
8971     return ExceptionFlags.none;
8972 }
8973 
8974 ExceptionFlags decimalMaxAbs(D1, D2, D)(auto const ref D1 x, auto const ref D2 y, out D z)
8975 if (isDecimal!(D1, D2, D) && is(D: CommonDecimal!(D1, D2)))
8976 {
8977     DataType!D cx, cy; int ex, ey; bool sx, sy;
8978     immutable fx = fastDecode(x, cx, ex, sx);
8979     immutable fy = fastDecode(y, cy, ey, sy);
8980 
8981     if (fx == FastClass.signalingNaN)
8982     {
8983         z = copysign(D.nan, x);
8984         return ExceptionFlags.invalidOperation;
8985     }
8986 
8987     if (fy == FastClass.signalingNaN)
8988     {
8989         if (fx == FastClass.quietNaN)
8990             z = copysign(D.nan, x);
8991         else
8992             z = copysign(D.nan, y);
8993         return ExceptionFlags.invalidOperation;
8994     }
8995 
8996     if (fx == FastClass.quietNaN)
8997     {
8998         if (fy == FastClass.quietNaN)
8999             z = x;
9000         else
9001             z = y;
9002         return ExceptionFlags.none;
9003     }
9004 
9005     if (fy == FastClass.quietNaN)
9006     {
9007         z = x;
9008         return ExceptionFlags.none;
9009     }
9010 
9011     if (fx == FastClass.infinite)
9012     {
9013         if (!sx || fy != FastClass.infinite)
9014             z = x;
9015         else
9016             z = y;
9017         return ExceptionFlags.none;
9018     }
9019 
9020     if (fy == FastClass.infinite)
9021     {
9022         z = y;
9023         return ExceptionFlags.none;
9024     }
9025 
9026     if (fx == FastClass.zero)
9027     {
9028         z = y;
9029         return ExceptionFlags.none;
9030     }
9031 
9032     if (fy == FastClass.zero)
9033     {
9034         z = x;
9035         return ExceptionFlags.none;
9036     }
9037 
9038     immutable c = coefficientCmp(cx, ex, cy, ey);
9039     if (c > 0)
9040         z = x;
9041     else if (c == 0 && !sx)
9042         z = x;
9043     else
9044         z = y;
9045     return ExceptionFlags.none;
9046 }
9047 
9048 @safe pure nothrow @nogc
9049 ExceptionFlags decimalQuantize(D1, D2)(ref D1 x, auto const ref D2 y, const int precision, const RoundingMode mode)
9050 if (isDecimal!(D1, D2))
9051 {
9052     alias U = CommonStorage!(D1, D2);
9053     U cx, cy; int ex, ey; bool sx, sy;
9054     immutable fx = fastDecode(x, cx, ex, sx);
9055     immutable fy = fastDecode(y, cy, ey, sy);
9056 
9057     if (fx == FastClass.signalingNaN)
9058     {
9059         unsignalize(x);
9060         return ExceptionFlags.invalidOperation;
9061     }
9062 
9063     if (fy == FastClass.signalingNaN)
9064     {
9065         x = D1.nan;
9066         return ExceptionFlags.invalidOperation;
9067     }
9068     
9069     if (fx == FastClass.quietNaN)
9070         return ExceptionFlags.none;
9071 
9072     if (fy == FastClass.quietNaN)
9073     {
9074         x = D1.nan;
9075         return ExceptionFlags.none;
9076     }
9077 
9078     if (fx == FastClass.infinite)
9079     {
9080         if (fy == FastClass.infinite)
9081             return ExceptionFlags.none;
9082         x = D1.nan;
9083         return ExceptionFlags.invalidOperation;
9084     }
9085 
9086     if (fy == FastClass.infinite)
9087     {
9088         x = D1.nan;
9089         return ExceptionFlags.invalidOperation;
9090     }
9091     
9092     auto flags = coefficientAdjust(cx, ex, ey, ey, cvt!U(D1.COEF_MAX), sx, mode);
9093     if (flags & ExceptionFlags.overflow)
9094         flags = ExceptionFlags.invalidOperation;
9095     return x.adjustedPack(cx, ex, sx, precision, mode, flags);
9096        
9097 }
9098 
9099 @safe pure nothrow @nogc
9100 ExceptionFlags decimalScale(D)(ref D x, const int n, const int precision, const RoundingMode mode)
9101 if (isDecimal!D)
9102 {
9103     DataType!D cx; int ex; bool sx;
9104     final switch(fastDecode(x, cx, ex, sx))
9105     {
9106         case FastClass.finite:
9107             if (!n)
9108                 return ExceptionFlags.none;
9109             auto remainder = cappedAdd(ex, n) - n;
9110             ExceptionFlags flags;
9111             if (remainder)
9112             {
9113                 if (remainder < 0)
9114                     coefficientShrink(cx, ex);
9115                 else
9116                     coefficientExpand(cx, ex);
9117                 if (cappedAdd(ex, remainder) != remainder)
9118                     flags = ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow;
9119             }                
9120             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
9121         case FastClass.zero:
9122         case FastClass.infinite:
9123         case FastClass.quietNaN:
9124             return ExceptionFlags.none;
9125         case FastClass.signalingNaN:
9126             unsignalize(x);
9127             return ExceptionFlags.invalidOperation;
9128     }   
9129 }
9130 
9131 
9132 @safe pure nothrow @nogc
9133 ExceptionFlags decimalMulPow2(D)(ref D x, const int n, const int precision, const RoundingMode mode)
9134 if (isDecimal!D)
9135 {
9136     DataType!D cx; int ex; bool sx;
9137     final switch(fastDecode(x, cx, ex, sx))
9138     {
9139         case FastClass.finite:
9140             if (!n)
9141                 return ExceptionFlags.none;
9142             DataType!D cy = 1U;
9143             int ey = n;
9144             ExceptionFlags flags;
9145             final switch(mode)
9146             {
9147                 case RoundingMode.tiesToAway:
9148                     flags = exp2to10!(RoundingMode.tiesToAway)(cy, ey, false);
9149                     break;
9150                 case RoundingMode.tiesToEven:
9151                     flags = exp2to10!(RoundingMode.tiesToEven)(cy, ey, false);
9152                     break;
9153                 case RoundingMode.towardZero:
9154                     flags = exp2to10!(RoundingMode.towardZero)(cy, ey, false);
9155                     break;
9156                 case RoundingMode.towardNegative:
9157                     flags = exp2to10!(RoundingMode.towardNegative)(cy, ey, false);
9158                     break;
9159                 case RoundingMode.towardPositive:
9160                     flags = exp2to10!(RoundingMode.towardPositive)(cy, ey, false);
9161                     break;
9162             }
9163             flags |= coefficientMul(cx, ex, sx, cy, ey, false, mode);
9164             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
9165         case FastClass.zero:
9166         case FastClass.infinite:
9167         case FastClass.quietNaN:
9168             return ExceptionFlags.none;
9169         case FastClass.signalingNaN:
9170             unsignalize(x);
9171             return ExceptionFlags.invalidOperation;
9172     }   
9173 }
9174 
9175 @safe pure nothrow @nogc
9176 ExceptionFlags decimalLog(D)(auto const ref D x, out int y)
9177 if (isDecimal!D)
9178 {
9179     DataType!D cx; int ex; bool sx;
9180     final switch(fastDecode(x, cx, ex, sx))
9181     {
9182         case FastClass.finite:
9183             y = prec(cx) + ex - 1;
9184             return ExceptionFlags.none;
9185         case FastClass.zero:
9186             y = int.min;
9187             return ExceptionFlags.invalidOperation;
9188         case FastClass.infinite:
9189             y = int.max;
9190             return ExceptionFlags.invalidOperation;
9191         case FastClass.quietNaN:
9192         case FastClass.signalingNaN:
9193             y = int.min;
9194             return ExceptionFlags.invalidOperation;  
9195     }   
9196 }
9197 
9198 @safe pure nothrow @nogc
9199 ExceptionFlags decimalMul(D1, D2)(ref D1 x, auto const ref D2 y, const int precision, const RoundingMode mode)
9200 if (isDecimal!(D1, D2))
9201 {
9202     alias D = CommonDecimal!(D1, D2);
9203     alias T = DataType!D;
9204     alias T1 = DataType!D1;
9205 
9206     T cx, cy; int ex, ey; bool sx, sy;
9207 
9208     immutable fx = fastDecode(x, cx, ex, sx);
9209     immutable fy = fastDecode(y, cy, ey, sy);
9210 
9211     if (fx == FastClass.signalingNaN || fy == FastClass.signalingNaN)
9212     {
9213         x = sx ^ sy ? -D1.nan : D1.nan;
9214         return ExceptionFlags.invalidOperation;
9215     }
9216 
9217     if (fx == FastClass.quietNaN || fy == FastClass.quietNaN)
9218     {
9219         x = sx ^ sy ? -D1.nan : D1.nan;
9220         return ExceptionFlags.none;
9221     }
9222 
9223     if (fx == FastClass.infinite)
9224     {
9225         if (fy == FastClass.zero)
9226         {
9227             x = sx ^ sy ? -D1.nan : D1.nan;
9228             return ExceptionFlags.invalidOperation;
9229         }
9230         x = sx ^ sy ? -D1.infinity : D1.infinity;
9231         return ExceptionFlags.none;
9232     }
9233 
9234     if (fy == FastClass.infinite)
9235     {
9236         if (fx == FastClass.zero)
9237         {
9238             x = sx ^ sy ? -D1.nan : D1.nan;
9239             return ExceptionFlags.invalidOperation;
9240         }
9241         x = sx ^ sy ? -D1.infinity : D1.infinity;
9242         return ExceptionFlags.none;
9243     }
9244 
9245     if (fx == FastClass.zero || fy == FastClass.zero)
9246     {
9247         x = sx ^ sy ? -D1.zero : D1.zero;
9248         return ExceptionFlags.none;
9249     }
9250 
9251     auto flags = coefficientMul(cx, ex, sx, cy, ey, sy, mode);
9252     return x.adjustedPack(cx, ex, sx, precision, mode, flags);
9253 }
9254 
9255 @safe pure nothrow @nogc
9256 ExceptionFlags decimalMul(D, T)(ref D x, auto const ref T y, const int precision, const RoundingMode mode)
9257 if (isDecimal!D && isIntegral!T)
9258 {
9259     alias U = CommonStorage!(D, T);
9260     alias X = DataType!D;
9261     U cx; int ex; bool sx;
9262     bool sy;
9263     U cy = unsign!U(y, sy);
9264     final switch(fastDecode(x, cx, ex, sx))
9265     {
9266         case FastClass.finite:
9267             if (!y)
9268             {
9269                 x = sx ^ sy ? -D.zero : D.zero;
9270                 return ExceptionFlags.none;
9271             }
9272             auto flags = coefficientMul(cx, ex, sx, cy, 0, sy, RoundingMode.implicit);
9273             flags |= coefficientAdjust(cx, ex, cvt!U(X.max), sx, RoundingMode.implicit);
9274             return x.adjustedPack(cvt!X(cx), ex, sx, precision, mode, flags);
9275         case FastClass.zero:
9276             x = sx ^ sy ? -D.zero : D.zero;
9277             return ExceptionFlags.none;
9278         case FastClass.infinite:
9279             if (!y)
9280             {
9281                 x = sx ^ sy ? -D.nan : D.nan;
9282                 return ExceptionFlags.invalidOperation;
9283             }
9284             return ExceptionFlags.none;
9285         case FastClass.quietNaN:
9286             return ExceptionFlags.none;
9287         case FastClass.signalingNaN:
9288             unsignalize(x);
9289             return ExceptionFlags.invalidOperation;
9290     }
9291 }
9292 
9293 @safe pure nothrow @nogc
9294 ExceptionFlags decimalMul(D, F)(ref D x, auto const ref F y, const int precision, const RoundingMode mode)
9295 if (isDecimal!D && isFloatingPoint!F)
9296 {
9297     alias T = CommonStorage!(D, F);
9298 
9299     T cx, cy; int ex, ey; bool sx, sy;
9300     ExceptionFlags flags;
9301     immutable fx = fastDecode(x, cx, ex, sx);
9302     immutable fy = fastDecode(y, cy, ey, sy, mode, flags);
9303 
9304     if (fx == FastClass.signalingNaN)
9305     {
9306         x = sx ^ sy ? -D.nan : D.nan;
9307         return ExceptionFlags.invalidOperation;
9308     }
9309 
9310     if (fx == FastClass.quietNaN || fy == FastClass.quietNaN)
9311     {
9312         x = sx ^ sy ? -D.nan : D.nan;
9313         return ExceptionFlags.none;
9314     }
9315 
9316     if (fx == FastClass.infinite)
9317     {
9318         if (fy == FastClass.zero)
9319         {
9320             x = sx ^ sy ? -D.nan : D.nan;
9321             return ExceptionFlags.invalidOperation;
9322         }
9323         x = sx ^ sy ? -D.infinity : D.infinity;
9324         return ExceptionFlags.none;
9325     }
9326 
9327     if (fy == FastClass.infinite)
9328     {
9329         if (fx == FastClass.zero)
9330         {
9331             x = sx ^ sy ? -D.nan : D.nan;
9332             return ExceptionFlags.invalidOperation;
9333         }
9334         x = sx ^ sy ? -D.infinity : D.infinity;
9335         return ExceptionFlags.none;
9336     }
9337 
9338     if (fx == FastClass.zero || fy == FastClass.zero)
9339     {
9340         x = sx ^ sy ? -D.zero : D.zero;
9341         return ExceptionFlags.none;
9342     }
9343     flags |= coefficientAdjust(cy, ey, realFloatPrecision!F(0), sy, mode);
9344     flags |= coefficientMul(cx, ex, sx, cy, ey, sy, mode);
9345     return x.adjustedPack(cx, ex, sx, precision, mode, flags);
9346 }
9347 
9348 @safe pure nothrow @nogc
9349 ExceptionFlags decimalMul(T, D)(auto const ref T x, auto const ref D y, out D z, const int precision, const RoundingMode mode)
9350 if (isDecimal!D && isIntegral!T)
9351 {
9352    z = y;
9353    return decimalMul(z, x, precision, mode);
9354 }
9355 
9356 @safe pure nothrow @nogc
9357 ExceptionFlags decimalMul(F, D)(auto const ref F x, auto const ref D y, out D z, const int precision, const RoundingMode mode)
9358 if (isDecimal!D && isFloatingPoint!F)
9359 {
9360     z = y;
9361     return decimalMul(z, x, precision, mode);
9362 }
9363 
9364 @safe pure nothrow @nogc
9365 ExceptionFlags decimalDiv(D1, D2)(ref D1 x, auto const ref D2 y, const int precision, const RoundingMode mode)
9366 if (isDecimal!(D1, D2))
9367 {
9368     alias D = CommonDecimal!(D1, D2);
9369     alias T = DataType!D;
9370     alias T1 = DataType!D1;
9371 
9372     T cx, cy; int ex, ey; bool sx, sy;
9373 
9374     immutable fx = fastDecode(x, cx, ex, sx);
9375     immutable fy = fastDecode(y, cy, ey, sy);
9376 
9377     if (fx == FastClass.signalingNaN || fy == FastClass.signalingNaN)
9378     {
9379         x = sx ^ sy ? -D1.nan : D1.nan;
9380         return ExceptionFlags.invalidOperation;
9381     }
9382 
9383     if (fx == FastClass.quietNaN || fy == FastClass.quietNaN)
9384     {
9385         x = sx ^ sy ? -D1.nan : D1.nan;
9386         return ExceptionFlags.none;
9387     }
9388 
9389     if (fx == FastClass.infinite)
9390     {
9391         if (fy == FastClass.infinite)
9392         {
9393             x = sx ^ sy ? -D1.nan : D1.nan;
9394             return ExceptionFlags.invalidOperation;
9395         }
9396         x = sx ^ sy ? -D1.infinity : D1.infinity;
9397         return ExceptionFlags.none;
9398     }
9399 
9400     
9401 
9402     if (fx == FastClass.zero)
9403     {
9404         if (fy == FastClass.zero)
9405         {
9406             x = sx ^ sy ? -D1.nan : D1.nan;
9407             return ExceptionFlags.invalidOperation;
9408         }
9409 
9410         x = sx ^ sy ? -D1.zero : D1.zero;
9411         return ExceptionFlags.none;
9412     }
9413 
9414     if (fy == FastClass.infinite)
9415     {
9416         x = sx ^ sy ? -D1.zero : D1.zero;
9417         return ExceptionFlags.none;
9418     }
9419 
9420     if (fy == FastClass.zero)
9421     {
9422         x = sx ^ sy ? -D1.infinity : D1.infinity;
9423         return ExceptionFlags.divisionByZero;
9424     }
9425  
9426     auto flags = coefficientDiv(cx, ex, sx, cy, ey, sy, RoundingMode.implicit);
9427     flags |= coefficientAdjust(cx, ex, cvt!T(T1.max), sx, RoundingMode.implicit);
9428     return x.adjustedPack(cvt!T1(cx), ex, sx, precision, mode, flags);
9429 }
9430 
9431 @safe pure nothrow @nogc
9432 ExceptionFlags decimalDiv(D, T)(ref D x, auto const ref T y, const int precision, const RoundingMode mode)
9433 if (isDecimal!D && isIntegral!T)
9434 {
9435     alias U = CommonStorage!(D, T);
9436     U cx; int ex; bool sx;
9437     bool sy;
9438     U cy = unsign!U(y, sy);
9439     final switch (fastDecode(x, cx, ex, sx))
9440     {
9441         case FastClass.finite:
9442             if (!y)
9443             {
9444                 x = sx ^ sy ? -D.infinity : D.infinity;
9445                 return ExceptionFlags.divisionByZero;
9446             }
9447             auto flags = coefficientDiv(cx, ex, sx, cy, 0, sy, mode);
9448             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
9449         case FastClass.zero:
9450             x = sx ^ sy ? -D.zero : D.zero;
9451             return ExceptionFlags.none;
9452         case FastClass.infinite:
9453             if (!y)
9454             {
9455                 x = sx ^ sy ? -D.nan : D.nan;
9456                 return ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero;
9457             }
9458             return ExceptionFlags.none;
9459         case FastClass.quietNaN:
9460             return ExceptionFlags.none;
9461         case FastClass.signalingNaN:
9462             unsignalize(x);
9463             return ExceptionFlags.invalidOperation;
9464     }
9465 }
9466 
9467 @safe pure nothrow @nogc
9468 ExceptionFlags decimalDiv(T, D)(auto const ref T x, auto const ref D y, out D z, const int precision, const RoundingMode mode)
9469 if (isDecimal!D && isIntegral!T)
9470 {
9471     alias U = CommonStorage!(D, T);
9472     U cy; int ey; bool sy;
9473     int ex = 0;
9474     bool sx;
9475     U cx = unsign!U(x, sx);
9476     final switch (fastDecode(y, cy, ey, sy))
9477     {
9478         case FastClass.finite:
9479             auto flags = coefficientDiv(cx, ex, sx, cy, 0, sy, RoundingMode.implicit);
9480             flags |= coefficientAdjust(cx, ex, cvt!U(DataType!D.max), sx, RoundingMode.implicit);
9481             return z.adjustedPack(cvt!(DataType!D)(cx), ex, sx, precision, mode, flags);
9482         case FastClass.zero:
9483             z = sx ^ sy ? -D.infinity : D.infinity;
9484             return ExceptionFlags.divisionByZero;
9485         case FastClass.infinite:
9486             z = y;
9487             return ExceptionFlags.none;
9488         case FastClass.quietNaN:
9489             z = sx ^ sy ? -D.nan : D.nan;
9490             return ExceptionFlags.none;
9491         case FastClass.signalingNaN:
9492             z = sx ^ sy ? -D.nan : D.nan;
9493             return ExceptionFlags.invalidOperation;
9494     }
9495 }
9496 
9497 @safe pure nothrow @nogc
9498 ExceptionFlags decimalDiv(D, F)(ref D x, auto const ref F y, const int precision, const RoundingMode mode)
9499 if (isDecimal!D && isFloatingPoint!F)
9500 {
9501     alias T = CommonStorage!(D, F);
9502    
9503     T cx, cy; int ex, ey; bool sx, sy;
9504 
9505     ExceptionFlags flags;
9506     immutable fx = fastDecode(x, cx, ex, sx);
9507     immutable fy = fastDecode(y, cy, ey, sy, mode, flags);
9508 
9509     if (fx == FastClass.signalingNaN)
9510     {
9511         x = sx ^ sy ? -D.nan : D.nan;
9512         return ExceptionFlags.invalidOperation;
9513     }
9514 
9515     if (fx == FastClass.quietNaN || fy == FastClass.quietNaN)
9516     {
9517         x = sx ^ sy ? -D.nan : D.nan;
9518         return ExceptionFlags.none;
9519     }
9520 
9521     if (fx == FastClass.infinite)
9522     {
9523         if (fy == FastClass.zero)
9524         {
9525             x = sx ^ sy ? -D.nan : D.nan;
9526             return ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero;
9527         }
9528 
9529         if (fy == FastClass.infinite)
9530         {
9531             x = sx ^ sy ? -D.nan : D.nan;
9532             return ExceptionFlags.invalidOperation;
9533         }
9534         x = sx ^ sy ? -D.infinity : D.infinity;
9535         return ExceptionFlags.none;
9536     }
9537 
9538     if (fy == FastClass.infinite)
9539     {
9540         x = sx ^ sy ? -D.infinity : D.infinity;
9541         return ExceptionFlags.none;
9542     }
9543 
9544     if (fx == FastClass.zero)
9545     {
9546         x = sx ^ sy ? -D.zero : D.zero;
9547         return ExceptionFlags.none;
9548     }
9549 
9550     if (fy == FastClass.zero)
9551     {
9552         x = sx ^ sy ? -D.infinity : D.infinity;
9553         return ExceptionFlags.divisionByZero;
9554     }
9555 
9556     flags |= coefficientAdjust(cy, ey, realFloatPrecision!F(0), sy, mode);
9557     flags |= coefficientDiv(cx, ex, sx, cy, ey, sy, mode);
9558     return x.adjustedPack(cx, ex, sx, precision, mode, flags);
9559 }
9560 
9561 @safe pure nothrow @nogc
9562 ExceptionFlags decimalDiv(F, D)(auto const ref F x, auto const ref D y, out D z, const int precision, const RoundingMode mode)
9563 if (isDecimal!D && isFloatingPoint!F)
9564 {
9565     alias T = CommonStorage!(D, F);
9566 
9567     T cx, cy; int ex, ey; bool sx, sy;
9568     ExceptionFlags flags;
9569     immutable fx = fastDecode(x, cx, ex, sx, mode, flags);
9570     immutable fy = fastDecode(y, cy, ey, sy);
9571 
9572     if (fy == FastClass.signalingNaN)
9573     {
9574         z = sx ^ sy ? -D.nan : D.nan;
9575         return ExceptionFlags.invalidOperation;
9576     }
9577 
9578     if (fx == FastClass.quietNaN || fy == FastClass.quietNaN)
9579     {
9580         z = sx ^ sy ? -D.nan : D.nan;
9581         return ExceptionFlags.none;
9582     }
9583 
9584     if (fx == FastClass.infinite)
9585     {
9586         if (fy == FastClass.zero)
9587         {
9588             z = sx ^ sy ? -D.nan : D.nan;
9589             return ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero;
9590         }
9591 
9592         if (fy == FastClass.infinite)
9593         {
9594             z = sx ^ sy ? -D.nan : D.nan;
9595             return ExceptionFlags.invalidOperation;
9596         }
9597         z = sx ^ sy ? -D.infinity : D.infinity;
9598         return ExceptionFlags.none;
9599     }
9600 
9601     if (fy == FastClass.infinite)
9602     {
9603         z = sx ^ sy ? -D.infinity : D.infinity;
9604         return ExceptionFlags.none;
9605     }
9606 
9607     if (fx == FastClass.zero)
9608     {
9609         z = sx ^ sy ? -D.zero : D.zero;
9610         return ExceptionFlags.none;
9611     }
9612 
9613     if (fy == FastClass.zero)
9614     {
9615         z = sx ^ sy ? -D.infinity : D.infinity;
9616         return ExceptionFlags.divisionByZero;
9617     }
9618     flags |= coefficientAdjust(cx, ex, realFloatPrecision!F(0), sx, mode);
9619     flags |= coefficientDiv(cx, ex, sx, cy, ey, sy, mode);
9620     return z.adjustedPack(cx, ex, sx, precision, mode, flags);
9621 }
9622 
9623 @safe pure nothrow @nogc
9624 ExceptionFlags decimalAdd(D1, D2)(ref D1 x, auto const ref D2 y, const int precision, const RoundingMode mode)
9625 if (isDecimal!(D1, D2))
9626 {
9627     alias D = CommonDecimal!(D1, D2);
9628     alias T = DataType!D;
9629     alias T1 = DataType!D1;
9630 
9631     T cx, cy; int ex, ey; bool sx, sy;
9632 
9633     immutable fx = fastDecode(x, cx, ex, sx);
9634     immutable fy = fastDecode(y, cy, ey, sy);
9635 
9636     if (fx == FastClass.signalingNaN)
9637     {
9638         x = sx  ? -D1.nan : D1.nan;
9639         return ExceptionFlags.invalidOperation;
9640     }
9641 
9642     if (fy == FastClass.signalingNaN)
9643     {
9644         x = sy && (fx == FastClass.quietNaN ? sx : true) ? -D1.nan : D1.nan;
9645         return ExceptionFlags.invalidOperation;
9646     }
9647 
9648     if (fx == FastClass.quietNaN)
9649         return ExceptionFlags.none;
9650 
9651     if (fy == FastClass.quietNaN)
9652     {
9653         x = sy ? -D1.nan : D1.nan;
9654         return ExceptionFlags.none;
9655     }
9656 
9657     if (fx == FastClass.infinite)
9658     {
9659         if (fy == FastClass.infinite && sx != sy)
9660         {
9661             x = D1.nan;
9662             return ExceptionFlags.invalidOperation;
9663         }
9664         return ExceptionFlags.none;  
9665     }
9666 
9667     if (fy == FastClass.infinite)
9668     {
9669         x = sy ? -D1.infinity : D1.infinity;
9670         return ExceptionFlags.none;   
9671     }
9672 
9673     if (fx == FastClass.zero)
9674     {
9675         if (fy == FastClass.zero)
9676         {
9677             x = (mode == RoundingMode.towardNegative && sx != sy)  || (sx && sy) ? -D1.zero : D1.zero;
9678             return ExceptionFlags.none; 
9679         }
9680         return decimalToDecimal(y, x, precision, mode);
9681     }
9682 
9683     if (fy == FastClass.zero)
9684         return ExceptionFlags.none;
9685 
9686     ExceptionFlags flags = coefficientAdd(cx, ex, sx, cy, ey, sy, mode);
9687     flags = x.adjustedPack(cx, ex, sx, precision, mode, flags);
9688     if (isZero(x))
9689         x = (mode == RoundingMode.towardNegative && sx != sy)  || (sx && sy) ? -D1.zero : D1.zero;
9690     return flags;
9691 }
9692 
9693 @safe pure nothrow @nogc
9694 ExceptionFlags decimalAdd(D, T)(ref D x, auto const ref T y, const int precision, const RoundingMode mode)
9695 if (isDecimal!D && isIntegral!T)
9696 {
9697     alias U = CommonStorage!(D, T);
9698     alias X = DataType!D;
9699     U cx; int ex; bool sx; 
9700     final switch(fastDecode(x, cx, ex, sx))
9701     {
9702         case FastClass.finite:
9703             if (!y)
9704                 return ExceptionFlags.none;
9705             bool sy;
9706             U cy = unsign!U(y, sy);
9707             auto flags = coefficientAdd(cx, ex, sx, cy, 0, sy, RoundingMode.implicit);
9708             flags |= coefficientAdjust(cx, ex, cvt!U(X.max), sx, RoundingMode.implicit);
9709             return x.adjustedPack(cvt!X(cx), ex, sx, precision, mode, flags);
9710         case FastClass.zero:
9711             return x.packIntegral(y, precision, mode);
9712         case FastClass.infinite:
9713         case FastClass.quietNaN:
9714             return ExceptionFlags.none;
9715         case FastClass.signalingNaN:
9716             unsignalize(x);
9717             return ExceptionFlags.invalidOperation;
9718     }
9719 }
9720 
9721 int realFloatPrecision(F)(const int precision)
9722 {
9723     static if (is(F == float))
9724         return precision == 0 ? 9 : (precision > 9 ? 9 : precision);
9725     else static if (is(F == float))
9726         return precision == 0 ? 17 : (precision > 17 ? 17 : precision);
9727     else
9728         return precision == 0 ? 21 : (precision > 21 ? 21 : precision);
9729 }
9730 
9731 @safe pure nothrow @nogc
9732 ExceptionFlags decimalAdd(D, F)(ref D x, auto const ref F y, const int precision, const RoundingMode mode)
9733 if (isDecimal!D && isFloatingPoint!F)
9734 {
9735     alias T = CommonStorage!(D, F);
9736     alias X = DataType!D;
9737 
9738     T cx, cy; int ex, ey; bool sx, sy;
9739     ExceptionFlags flags;
9740     immutable fx = fastDecode(x, cx, ex, sx);
9741     immutable fy = fastDecode(y, cy, ey, sy, mode, flags);
9742 
9743     if (fx == FastClass.signalingNaN)
9744     {
9745         x = sy ? -D.nan : D.nan;
9746         return ExceptionFlags.invalidOperation;
9747     }
9748 
9749     if (fx == FastClass.quietNaN)
9750         return ExceptionFlags.none;
9751 
9752     if (fy == FastClass.quietNaN)
9753     {
9754         x = sy ? -D.nan : D.nan;
9755         return ExceptionFlags.invalidOperation;
9756     }
9757 
9758     if (fx == FastClass.infinite)
9759     {
9760         if (fy == FastClass.infinite && sx != sy)
9761         {
9762             x = sx ? -D.nan : D.nan;
9763             return ExceptionFlags.invalidOperation;
9764         }
9765         return ExceptionFlags.none;  
9766     }
9767 
9768     if (fy == FastClass.infinite)
9769     {
9770         x = sy ? -D.infinity : D.infinity;
9771         return ExceptionFlags.none;   
9772     }
9773 
9774     if (fx == FastClass.zero)
9775         return x.adjustedPack(cy, ey, sy, realFloatPrecision!F(precision), mode, flags);
9776 
9777     if (fy == FastClass.zero)
9778         return x.adjustedPack(cx, ex, sx, precision, mode, flags);
9779 
9780     flags |= coefficientAdjust(cy, ey, realFloatPrecision!F(0), sy, mode);
9781     flags |= coefficientAdd(cx, ex, sx, cy, ey, sy, mode);
9782     return x.adjustedPack(cx, ex, sx, precision, mode, flags);
9783 }
9784 
9785 @safe pure nothrow @nogc
9786 ExceptionFlags decimalAdd(T, D)(auto const ref T x, auto const ref D y, out D z, const int precision, const RoundingMode mode)
9787 if (isDecimal!D && isIntegral!T)
9788 {
9789     z = y;
9790     return decimalAdd(z, x, precision, mode);
9791 }
9792 
9793 @safe pure nothrow @nogc
9794 ExceptionFlags decimalAdd(F, D)(auto const ref F x, auto const ref D y, out D z, const int precision, const RoundingMode mode)
9795 if (isDecimal!D && isFloatingPoint!F)
9796 {
9797     z = y;
9798     return decimalAdd(z, x, precision, mode);
9799 }
9800 
9801 @safe pure nothrow @nogc
9802 ExceptionFlags decimalSub(D1, D2)(ref D1 x, auto const ref D2 y, const int precision, const RoundingMode mode)
9803 if (isDecimal!(D1, D2))
9804 {
9805    return decimalAdd(x, -y, precision, mode);
9806 }
9807 
9808 @safe pure nothrow @nogc
9809 ExceptionFlags decimalSub(D, T)(ref D x, auto const ref T y, const int precision, const RoundingMode mode)
9810 if (isDecimal!D && isIntegral!T)
9811 {
9812     alias U = CommonStorage!(D, T);
9813     alias X = DataType!D;
9814     U cx; int ex; bool sx;
9815     final switch(fastDecode(x, cx, ex, sx))
9816     {
9817         case FastClass.finite:
9818             if (!y)
9819                 return x.adjustedPack(cvt!X(cx), ex, sx, precision, mode, ExceptionFlags.none);
9820             bool sy;
9821             U cy = unsign!U(y, sy);
9822             auto flags = coefficientAdd(cx, ex, sx, cy, 0, !sy, RoundingMode.implicit);
9823             flags |= coefficientAdjust(cx, ex, cvt!U(X.max), sx, RoundingMode.implicit);
9824             return x.adjustedPack(cvt!X(cx), ex, sx, precision, mode, flags);
9825         case FastClass.zero:
9826             auto flags = x.packIntegral(y, precision, mode);
9827             x = -x;
9828             return flags;
9829         case FastClass.infinite:
9830         case FastClass.quietNaN:
9831             return ExceptionFlags.none;
9832         case FastClass.signalingNaN:
9833             unsignalize(x);
9834             return ExceptionFlags.invalidOperation;
9835     }
9836 }
9837 
9838 @safe pure nothrow @nogc
9839 ExceptionFlags decimalSub(D, F)(ref D x, auto const ref F y, const int precision, const RoundingMode mode)
9840 if (isDecimal!D && isFloatingPoint!F)
9841 {
9842     return decimalAdd(x, -y, precision, mode);
9843 }
9844 
9845 @safe pure nothrow @nogc
9846 ExceptionFlags decimalSub(T, D)(auto const ref T x, auto const ref D y, out D z, const int precision, const RoundingMode mode)
9847 if (isDecimal!D && isIntegral!T)
9848 {
9849     z = -y;
9850     return decimalAdd(z, x, precision, mode);
9851 }
9852 
9853 @safe pure nothrow @nogc
9854 ExceptionFlags decimalSub(F, D)(auto const ref F x, auto const ref D y, out D z, const int precision, const RoundingMode mode)
9855 if (isDecimal!D && isFloatingPoint!F)
9856 {
9857     z = -y;
9858     return decimalAdd(z, x, precision, mode);
9859 }
9860 
9861 @safe pure nothrow @nogc
9862 ExceptionFlags decimalMod(D1, D2)(ref D1 x, auto const ref D2 y, const int precision, const RoundingMode mode)
9863 if (isDecimal!(D1, D2))
9864 {
9865 
9866     alias D = CommonDecimal!(D1, D2);
9867     alias T = DataType!D;
9868     alias T1 = DataType!D1;
9869 
9870     T cx, cy; int ex, ey; bool sx, sy;
9871 
9872     immutable fx = fastDecode(x, cx, ex, sx);
9873     immutable fy = fastDecode(y, cy, ey, sy);
9874     immutable sxx = sx;
9875 
9876     if (fx == FastClass.signalingNaN)
9877     {
9878         unsignalize(x);
9879         return ExceptionFlags.invalidOperation;
9880     }
9881 
9882     if (fy == FastClass.signalingNaN)
9883     {
9884         x = sy ? -D1.nan : D1.nan;
9885         return ExceptionFlags.invalidOperation;
9886     }
9887     
9888     if (fx == FastClass.quietNaN)
9889         return ExceptionFlags.none;
9890 
9891     if (fy == FastClass.quietNaN)
9892     {
9893         x = sy ? -D1.nan : D1.nan;
9894         return ExceptionFlags.none;
9895     }
9896 
9897     if (fx == FastClass.infinite)
9898     {
9899         x = sx ? -D1.nan : D1.nan;
9900         return ExceptionFlags.invalidOperation;
9901     }
9902 
9903     if (fy == FastClass.zero)
9904     {
9905         x = sx ? -D1.nan : D1.nan;
9906         return ExceptionFlags.invalidOperation;
9907     }
9908 
9909     if (fx == FastClass.zero)
9910         return ExceptionFlags.none;
9911 
9912     
9913 
9914     if (fy == FastClass.infinite)
9915         return ExceptionFlags.none;
9916 
9917     ////coefficientShrink(cx, ex);
9918     //coefficientShrink(cy, ey);
9919     //
9920     //if (cy == 1U && ey == 0)
9921     //{
9922     //    //if (cx == 1U && ex == 0)
9923     //        x = sx ? -D1.zero : D1.zero;
9924     //    return ExceptionFlags.none;
9925     //}
9926     
9927     
9928      
9929     ExceptionFlags flags = coefficientMod(cx, ex, sx, cy, ey, sy, mode);
9930     flags = x.adjustedPack(cx, ex, sx, precision, mode, flags);
9931 
9932     if (isZero(x))
9933         x = sxx ? -D1.zero : D1.zero; 
9934     return flags;
9935 }
9936 
9937 @safe pure nothrow @nogc
9938 ExceptionFlags decimalMod(D, T)(ref D x, auto const ref T y, const int precision, const RoundingMode mode)
9939 if (isDecimal!D && isIntegral!T)
9940 {
9941     alias U = CommonStorage!(D, T);
9942     alias X = DataType!D;
9943 
9944     U cx; int ex; bool sx;
9945     bool sy;
9946     U cy = unsign!U(y, sy);
9947 
9948     if (!y)
9949     {
9950         x = sx ^ sy ? -D.nan : D.nan;
9951         return ExceptionFlags.invalidOperation;
9952     }
9953 
9954     final switch (fastDecode(x, cx, ex, sx))
9955     {
9956         case FastClass.finite:
9957             auto flags = coefficientMod(cx, ex, sx, cy, 0, sy, mode);
9958             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
9959         case FastClass.zero:
9960             return ExceptionFlags.none;
9961         case FastClass.infinite:
9962             x = sx ? -D.nan : D.nan;
9963             return ExceptionFlags.invalidOperation;
9964         case FastClass.quietNaN:
9965             return ExceptionFlags.none;
9966         case FastClass.signalingNaN:
9967             unsignalize(x);
9968             return ExceptionFlags.invalidOperation;
9969     }
9970 }
9971 
9972 @safe pure nothrow @nogc
9973 ExceptionFlags decimalMod(T, D)(auto const ref T x, auto const ref D y, out D z, const int precision, const RoundingMode mode)
9974 if (isDecimal!D && isIntegral!T)
9975 {
9976 
9977     alias U = CommonStorage!(D, T);
9978     alias X = DataType!D;
9979     U cy; int ey; bool sy;
9980     int ex = 0;
9981     bool sx;
9982     U cx = unsign!U(x, sx);
9983     final switch (fastDecode(y, cy, ey, sy))
9984     {
9985         case FastClass.finite:
9986             if (x == 0)
9987             {
9988                 z = D.zero;
9989                 return ExceptionFlags.none;
9990             }
9991             auto flags = coefficientMod(cx, ex, sx, cy, 0, sy, mode);
9992             flags |= coefficientAdjust(cx, ex, cvt!U(X.max), sx, RoundingMode.implicit);
9993             return z.adjustedPack(cvt!X(cx), ex, sx, precision, mode, flags);
9994         case FastClass.zero:
9995             z = sy ? -D.nan : D.nan;
9996             return ExceptionFlags.invalidOperation;
9997         case FastClass.infinite:
9998             return z.packIntegral(x, precision, mode);
9999         case FastClass.quietNaN:
10000             z = sy ? -D.nan : D.nan;
10001             return ExceptionFlags.none;
10002         case FastClass.signalingNaN:
10003             z = sy ? -D.nan : D.nan;
10004             return ExceptionFlags.invalidOperation;
10005     }
10006 
10007 }
10008 
10009 @safe pure nothrow @nogc
10010 ExceptionFlags decimalMod(D, F)(ref D x, auto const ref F y, const int precision, const RoundingMode mode)
10011 if (isDecimal!D && isFloatingPoint!F)
10012 {
10013     alias T = CommonStorage!(D, F);
10014 
10015     T cx, cy; int ex, ey; bool sx, sy;
10016     ExceptionFlags flags;
10017     immutable fx = fastDecode(x, cx, ex, sx);
10018     immutable fy = fastDecode(y, cy, ey, sy, mode, flags);
10019 
10020     if (fx == FastClass.signalingNaN)
10021     {
10022         unsignalize(x);
10023         return ExceptionFlags.invalidOperation;
10024     }
10025 
10026     if (fx == FastClass.quietNaN)
10027         return ExceptionFlags.none;
10028 
10029     if (fy == FastClass.quietNaN)
10030     {
10031         x = sy ? -D.nan : D.nan;
10032         return ExceptionFlags.none;
10033     }
10034 
10035     if (fx == FastClass.infinite || fy == FastClass.zero)
10036     {
10037         x = sx ? -D.nan : D.nan;
10038         return ExceptionFlags.invalidOperation;
10039     }
10040 
10041     if (fx == FastClass.zero)
10042         return ExceptionFlags.none;
10043 
10044     if (fy == FastClass.infinite)
10045         return ExceptionFlags.none;
10046 
10047     flags |= coefficientAdjust(cy, ey, realFloatPrecision!F(0), sy, mode);
10048     flags |= coefficientMod(cx, ex, sx, cy, ey, sy, mode);
10049     return x.adjustedPack(cx, ex, sx, precision, mode, flags);
10050 }
10051 
10052 @safe pure nothrow @nogc
10053 ExceptionFlags decimalMod(F, D)(auto const ref F x, auto const ref D y, out D z, const int precision, const RoundingMode mode)
10054 if (isDecimal!D && isFloatingPoint!F)
10055 {
10056     alias T = CommonStorage!(D, F);
10057     alias X = DataType!D;
10058 
10059     T cx, cy; int ex, ey; bool sx, sy;
10060     ExceptionFlags flags;
10061     immutable fx = fastDecode(x, cx, ex, sx, mode, flags);
10062     immutable fy = fastDecode(y, cy, ey, sy);
10063 
10064     if (fy == FastClass.signalingNaN)
10065     {
10066         z = sy ? -D.nan : D.nan;
10067         return ExceptionFlags.invalidOperation;
10068     }
10069 
10070     if (fx == FastClass.quietNaN)
10071     {
10072         z = sx ? -D.nan : D.nan;
10073         return ExceptionFlags.none;
10074     }
10075 
10076     if (fy == FastClass.quietNaN)
10077     {
10078         z = sy ? -D.nan : D.nan;
10079         return ExceptionFlags.none;
10080     }
10081 
10082     if (fx == FastClass.infinite || fy == FastClass.zero)
10083     {
10084         z = sx ? -D.nan : D.nan;
10085         return ExceptionFlags.invalidOperation;
10086     }
10087 
10088     if (fy == FastClass.infinite)
10089         return ExceptionFlags.none;
10090 
10091     flags |= coefficientAdjust(cx, ex, realFloatPrecision!F(0), sx, mode);
10092     flags |= coefficientMod(cx, ex, sx, cy, ey, sy, mode);
10093     return z.adjustedPack(cx, ex, sx, precision, mode, flags);
10094 
10095 }
10096 
10097 @safe pure nothrow @nogc
10098 int decimalCmp(D1, D2)(auto const ref D1 x, auto const ref D2 y)
10099 if (isDecimal!(D1, D2))
10100 {
10101     //-3 signan
10102     //-2 nan
10103     alias D = CommonDecimal!(D1, D2);
10104     DataType!D cx, cy; int ex, ey; bool sx, sy;
10105     immutable fx = fastDecode(x, cx, ex, sx);
10106     immutable fy = fastDecode(y, cy, ey, sy);
10107     final switch(fx) 
10108     {
10109         case FastClass.finite:
10110             if (fy == FastClass.finite)
10111                 return coefficientCmp(cx, ex, sx, cy, ey, sy);
10112             if (fy == FastClass.zero)
10113                 return sx ? -1: 1;
10114             if (fy == FastClass.infinite)
10115                 return sy ? 1 : -1;
10116             return fy == FastClass.signalingNaN ? -3 : -2;
10117         case FastClass.zero:
10118             if (fy == FastClass.finite || fy == FastClass.infinite)
10119                 return sy ? 1 : -1;
10120             if (fy == FastClass.zero)
10121                 return 0;
10122             return fy == FastClass.signalingNaN ? -3 : -2;
10123         case FastClass.infinite:
10124             if (fy == FastClass.finite || fy == FastClass.zero)
10125                 return sx ? -1 : 1;
10126             if (fy == FastClass.infinite)
10127                 return sx == sy ? 0 : (sx ? -1 : 1);
10128             return fy == FastClass.signalingNaN ? -3 : -2;
10129         case FastClass.quietNaN:
10130             return fy == FastClass.signalingNaN ? -3 : -2;
10131         case FastClass.signalingNaN:
10132             return -3;
10133 
10134     }
10135 }
10136 
10137 @safe pure nothrow @nogc
10138 int decimalCmp(D, T)(auto const ref D x, auto const ref T y)
10139 if (isDecimal!D && isIntegral!T)
10140 {
10141     alias U = CommonStorage!(D, T);
10142     U cx; int ex; bool sx;
10143     final switch(fastDecode(x, cx, ex, sx))
10144     {
10145         case FastClass.finite:
10146             bool sy;
10147             U cy = unsign!U(y, sy);   
10148             return coefficientCmp(cx, ex, sx, cy, 0, sy);
10149         case FastClass.zero:
10150             static if (isUnsigned!T)
10151                 return y == 0 ? 0 : -1;
10152             else
10153                 return y == 0 ? 0 : (y < 0 ? 1 : -1);
10154         case FastClass.infinite:
10155             return sx ? -1 : 1;
10156         case FastClass.quietNaN:
10157         case FastClass.signalingNaN:
10158             return -2;
10159     }
10160 }
10161 
10162 @safe pure nothrow @nogc
10163 int decimalCmp(D, F)(auto const ref D x, auto const  ref F y)
10164 if (isDecimal!D && isFloatingPoint!F)
10165 {
10166     if (isSignaling(x))
10167         return -3;
10168     if (isNaN(x) || isNaN(y))
10169         return -2;
10170 
10171     bool sx = cast(bool)signbit(x);
10172     bool sy = cast(bool)signbit(y);
10173 
10174     if (isZero(x))
10175     {
10176         if (y == 0.0)
10177             return 0;
10178         return sy ? 1 : -1;
10179     }
10180 
10181     if (y == 0.0)
10182         return sx ? -1 : 1;
10183 
10184     if (sx != sy)
10185         return sx ? -1 : 1;
10186 
10187     if (isInfinity(x))
10188     {
10189         if (isInfinity(y))
10190             return 0;
10191         return sx ? -1 : 1;
10192     }
10193 
10194     if (isInfinity(y))
10195         return sx ? 1 : -1;
10196 
10197     Unqual!D v = void;
10198 
10199     auto flags = v.packFloatingPoint(y, 0, RoundingMode.towardZero);
10200 
10201     if (flags & ExceptionFlags.overflow)
10202     {
10203         //floating point is too big
10204         return sx ? 1 : -1;
10205     }
10206     else if (flags & ExceptionFlags.underflow)
10207     {
10208         //floating point is too small
10209         return sx ? -1 : 1;
10210     }
10211 
10212     auto result = decimalCmp(x, v);
10213 
10214     if (result == 0 && (flags & ExceptionFlags.inexact))
10215     {
10216         //seems equal, but float was truncated toward zero, so it's smaller
10217         return sx ? -1 : 1;
10218     }
10219 
10220     return result;
10221 }
10222 
10223 @safe pure nothrow @nogc
10224 int decimalEqu(D1, D2)(auto const ref D1 x, auto const ref D2 y)
10225 if (isDecimal!(D1, D2))
10226 {
10227     alias D = CommonDecimal!(D1, D2);
10228     DataType!D cx, cy; int ex, ey; bool sx, sy;
10229     immutable fx = fastDecode(x, cx, ex, sx);
10230     immutable fy = fastDecode(y, cy, ey, sy);
10231 
10232     final switch(fx) 
10233     {
10234         case FastClass.finite:
10235                 if (fy == FastClass.finite  && coefficientEqu(cx, ex, sx, cy, ey, sy))
10236                     return 1;
10237                 if (fy == FastClass.zero || fy == FastClass.infinite)
10238                     return 0;
10239                 return fy == FastClass.signalingNaN ? -3 : -2;
10240         case FastClass.zero:
10241             if (fy == FastClass.zero)
10242                 return 1;
10243             if (fy == FastClass.finite || fy == FastClass.infinite)
10244                 return 0;
10245             return fy == FastClass.signalingNaN ? -3 : -2;
10246         case FastClass.infinite:
10247             if (fy == FastClass.infinite)
10248                 return sx == sy ? 1 : 0;
10249             if (fy == FastClass.finite || fy == FastClass.zero)
10250                 return 0;
10251             return fy == FastClass.signalingNaN ? -3 : -2;
10252         case FastClass.quietNaN:
10253             return fy == FastClass.signalingNaN ? -3 : -2;
10254         case FastClass.signalingNaN:
10255             return -3;
10256     }
10257 }
10258 
10259 @safe pure nothrow @nogc
10260 int decimalEqu(D, T)(auto const ref D x, auto const ref T y)
10261 if (isDecimal!D && isIntegral!T)
10262 {
10263     alias U = CommonStorage!(D, T);
10264     U cx; int ex; bool sx;
10265     final switch(fastDecode(x, cx, ex, sx))
10266     {
10267         case FastClass.finite:
10268             bool sy;
10269             U cy = unsign!U(y, sy);   
10270             return coefficientEqu(cx, ex, sx, cy, 0, sy) ? 1 : 0;
10271         case FastClass.zero:
10272             return y == 0 ? 1 : 0;
10273         case FastClass.infinite:
10274             return 0;
10275         case FastClass.quietNaN:
10276             return -2;
10277         case FastClass.signalingNaN:
10278             return -3;
10279     }
10280     return ExceptionFlags.none;
10281 }
10282 
10283 @safe pure nothrow @nogc
10284 int decimalEqu(D, F)(auto const ref D x, auto const ref F y)
10285 if (isDecimal!D && isFloatingPoint!F)
10286 {
10287     if (isSignaling(x))
10288         return -3;
10289     if (isNaN(x) || isNaN(y))
10290         return -2;
10291     if (isZero(x))
10292         return y == 0.0 ? 1 : 0;
10293     if (y == 0.0)
10294         return 0;
10295 
10296     bool sx = cast(bool)signbit(x);
10297     bool sy = cast(bool)signbit(y);
10298 
10299     if (sx != sy)
10300         return 0;
10301     if (isInfinity(x))
10302         return isInfinity(y) ? 1 : 0;
10303     if (isInfinity(y))
10304         return 0;
10305     Unqual!D v = void;
10306     auto flags = v.packFloatingPoint(y, D.PRECISION, RoundingMode.towardZero);
10307     if (flags)
10308         return 0;
10309     else
10310         return decimalEqu(x, v);
10311 
10312 }
10313 
10314 @safe pure nothrow @nogc
10315 ExceptionFlags decimalSqrt(D)(ref D x, const int precision, const RoundingMode mode)
10316 if (isDecimal!D)
10317 {
10318     DataType!D cx; int ex; bool sx;
10319     final switch(fastDecode(x, cx, ex, sx))
10320     {
10321         case FastClass.finite:
10322             if (sx)
10323             {
10324                 x = -D.nan;
10325                 return ExceptionFlags.invalidOperation;
10326             }
10327             auto flags = coefficientSqrt(cx, ex);
10328             return x.adjustedPack(cx, ex, false, precision, mode, flags);
10329         case FastClass.zero:
10330             return ExceptionFlags.none;
10331         case FastClass.infinite:
10332             if (sx)
10333             {
10334                 x = -D.nan;
10335                 return ExceptionFlags.invalidOperation;
10336             }
10337             return ExceptionFlags.none;
10338         case FastClass.quietNaN:
10339             return ExceptionFlags.none;
10340         case FastClass.signalingNaN:
10341             unsignalize(x);
10342             return ExceptionFlags.invalidOperation;
10343     }
10344 
10345  }
10346 
10347 @safe pure nothrow @nogc
10348 ExceptionFlags decimalRSqrt(D)(ref D x, const int precision, const RoundingMode mode)
10349 if (isDecimal!D)
10350 {
10351     DataType!D cx; int ex; bool sx;
10352     final switch(fastDecode(x, cx, ex, sx))
10353     {
10354         case FastClass.finite:
10355             if (sx)
10356             {
10357                 x = -D.nan;
10358                 return ExceptionFlags.invalidOperation;
10359             }
10360             auto flags = coefficientRSqrt(cx, ex);
10361             return x.adjustedPack(cx, ex, false, precision, mode, flags);
10362         case FastClass.zero:
10363             x = D.infinity;
10364             return ExceptionFlags.divisionByZero;
10365         case FastClass.infinite:
10366             if (sx)
10367             {
10368                 x = -D.nan;
10369                 return ExceptionFlags.invalidOperation;
10370             }
10371             x = D.zero;
10372             return ExceptionFlags.none;
10373         case FastClass.quietNaN:
10374             return ExceptionFlags.none;
10375         case FastClass.signalingNaN:
10376             unsignalize(x);
10377             return ExceptionFlags.invalidOperation;
10378     }
10379 }
10380 
10381 @safe pure nothrow @nogc
10382 ExceptionFlags decimalSqr(D)(ref D x, const int precision, const RoundingMode mode)
10383 if (isDecimal!D)
10384 {
10385     DataType!D cx; int ex; bool sx;
10386     final switch(fastDecode(x, cx, ex, sx))
10387     {
10388         case FastClass.finite:
10389             auto flags = coefficientSqr(cx, ex, RoundingMode.implicit);
10390             return x.adjustedPack(cx, ex, false, precision, mode, flags);
10391         case FastClass.zero:
10392             x = D.zero;
10393             return ExceptionFlags.none;
10394         case FastClass.infinite:
10395             x = D.infinity;
10396             return ExceptionFlags.none;
10397         case FastClass.quietNaN:
10398             return ExceptionFlags.none;
10399         case FastClass.signalingNaN:
10400             unsignalize(x);
10401             return ExceptionFlags.invalidOperation;
10402     }
10403 }
10404 
10405 @safe pure nothrow @nogc
10406 ExceptionFlags decimalCbrt(D)(ref D x, const int precision, const RoundingMode mode)
10407 if (isDecimal!D)
10408 {
10409     DataType!D cx; int ex; bool sx;
10410     final switch(fastDecode(x, cx, ex, sx))
10411     {
10412         case FastClass.finite:
10413             auto flags = coefficientCbrt(cx, ex);
10414             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
10415         case FastClass.zero:
10416         case FastClass.infinite:
10417         case FastClass.quietNaN:
10418             return ExceptionFlags.none;
10419         case FastClass.signalingNaN:
10420             unsignalize(x);
10421             return ExceptionFlags.invalidOperation;
10422     }
10423 }
10424 
10425 @safe pure nothrow @nogc
10426 ExceptionFlags decimalHypot(D1, D2, D)(auto const ref D1 x, auto const ref D2 y, out D z,
10427                                     const int precision, const RoundingMode mode)
10428 if (isDecimal!(D1, D2) && is(D: CommonDecimal!(D1, D2)))
10429 {
10430     alias U = DataType!D;
10431 
10432     U cx, cy; int ex, ey; bool sx, sy;
10433 
10434     immutable fx = fastDecode(x, cx, ex, sx);
10435     immutable fy = fastDecode(y, cy, ey, sy);
10436 
10437     if (fx == FastClass.signalingNaN || fy == FastClass.signalingNaN)
10438     {
10439         z = D.nan;
10440         return ExceptionFlags.invalidOperation;
10441     }
10442 
10443     if (fx == FastClass.quietNaN || fy == FastClass.quietNaN)
10444     {
10445         z = D.nan;
10446         return ExceptionFlags.none;
10447     }
10448 
10449     if (fx == FastClass.infinite || fy == FastClass.infinite)
10450     {
10451         z = D.infinity;
10452         return ExceptionFlags.none;
10453     }
10454 
10455     if (fx == FastClass.zero)
10456         return z.adjustedPack(cy, ey, false, precision, mode, ExceptionFlags.none);
10457 
10458     if (fy == FastClass.zero)
10459         return z.adjustedPack(cx, ex, false, precision, mode, ExceptionFlags.none);
10460 
10461     auto flags = coefficientHypot(cx, ex, cy, ey);
10462     return z.adjustedPack(cx, ex, false, precision, mode, flags);
10463 }
10464 
10465 
10466 @safe pure nothrow @nogc
10467 ExceptionFlags decimalFMA(D1, D2, D3, D)(auto const ref D1 x, auto const ref D2 y, auto const ref D3 z, 
10468                                       out D result, 
10469                                       const int precision, const RoundingMode mode)
10470 if (isDecimal!(D1, D2, D3) && is(D : CommonDecimal!(D1, D2, D3))) 
10471 {
10472     alias U = DataType!D;
10473 
10474     U cx, cy, cz; int ex, ey, ez; bool sx, sy, sz;
10475 
10476     immutable fx = fastDecode(x, cx, ex, sx);
10477     immutable fy = fastDecode(y, cy, ey, sy);
10478     immutable fz = fastDecode(z, cz, ez, sz);
10479 
10480     if (fx == FastClass.signalingNaN || fy == FastClass.signalingNaN || fz == FastClass.signalingNaN)
10481     {
10482         result = D.nan;
10483         return ExceptionFlags.invalidOperation;
10484     }
10485 
10486     if (fx == FastClass.quietNaN || fy == FastClass.quietNaN || fz == FastClass.quietNaN)
10487     {
10488         result = D.nan;
10489         return ExceptionFlags.none;
10490     }
10491 
10492     if (fx == FastClass.infinite)
10493     {
10494         if (fy == FastClass.zero)
10495         {
10496             result = D.nan;
10497             return ExceptionFlags.invalidOperation;
10498         }
10499 
10500         if (fz == FastClass.infinite)
10501         {
10502             if ((sx ^ sy) != sz)
10503             {
10504                 result = D.nan;
10505                 return ExceptionFlags.invalidOperation;
10506             }
10507         }
10508         result = sx ^ sy ? -D.infinity : D.infinity;
10509         return ExceptionFlags.none;
10510     }
10511 
10512     if (fy == FastClass.infinite)
10513     {
10514         if (fx == FastClass.zero)
10515         {
10516             result = D.nan;
10517             return ExceptionFlags.invalidOperation;
10518         }
10519 
10520         if (fz == FastClass.infinite)
10521         {
10522             if ((sx ^ sy) != sz)
10523             {
10524                 result = D.nan;
10525                 return ExceptionFlags.invalidOperation;
10526             }
10527         }
10528         result = sx ^ sy ? -D.infinity : D.infinity;
10529         return ExceptionFlags.none;
10530     }
10531 
10532     if (fx == FastClass.zero || fy == FastClass.zero)
10533         return result.adjustedPack(cx, ex, sx, precision, mode, ExceptionFlags.none);
10534 
10535     if (fz == FastClass.zero)
10536     {
10537         auto flags = coefficientMul(cx, ex, sx, cy, ey, sy, RoundingMode.implicit);
10538         return result.adjustedPack(cx, ex, sx, precision, mode, flags);
10539     }
10540 
10541     auto flags = coefficientFMA(cx, ex, sx, cy, ey, sy, cz, ez, sz, mode);
10542     return result.adjustedPack(cx, ex, sx, precision, mode, flags);
10543 }
10544 
10545 ExceptionFlags decimalPow(D, T)(ref D x, const T n, const int precision, const RoundingMode mode)
10546 if (isDecimal!D & isIntegral!T)
10547 {
10548     DataType!D cx; int ex; bool sx;
10549 
10550     final switch (fastDecode(x, cx, ex, sx))
10551     {
10552         case FastClass.finite:
10553             if (!n)
10554             {
10555                 x = D.one;
10556                 return ExceptionFlags.none;
10557             }
10558 
10559             DataType!D cv; int ev; bool sv;
10560             ExceptionFlags flags;
10561             static if (isSigned!T)
10562             {
10563                 auto m = unsign!(Unsigned!T)(n);
10564                 if (n < 0)
10565                 {
10566                     cv = 1U;
10567                     ev = 0;
10568                     sv = false;
10569                     flags = coefficientDiv(cv, ev, sv, cx, ex, sx, RoundingMode.implicit);
10570                 }
10571                 else
10572                 {
10573                     cv = cx;
10574                     ev = ex;
10575                     sv = sx;
10576                 }
10577             }
10578             else
10579             {
10580                 Unqual!T m = n;
10581                 cv = cx;
10582                 ev = ex;
10583                 sv = sx;
10584             }
10585 
10586             cx = 1U;
10587             ex = 0;
10588             sx = false;
10589 
10590             ExceptionFlags sqrFlags;
10591             while (m)
10592             {
10593                 if (m & 1)
10594                 {
10595                     flags |= sqrFlags | coefficientMul(cx, ex, sx, cv, ev, sv, RoundingMode.implicit);
10596                     sqrFlags = ExceptionFlags.none;
10597                     if (flags & (ExceptionFlags.overflow | ExceptionFlags.underflow))
10598                         break;
10599                 }
10600                 m >>>= 1;
10601                 sqrFlags |= coefficientSqr(cv, ev, RoundingMode.implicit);
10602                 sv = false;
10603             }
10604 
10605             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
10606         case FastClass.zero:
10607             if (!n)
10608                 x = D.one;
10609             else
10610             {
10611                 if (n & 1) //odd
10612                     return n < 0 ? ExceptionFlags.divisionByZero : ExceptionFlags.none;
10613                 else //even
10614                 {
10615                     if (n < 0)
10616                         return ExceptionFlags.divisionByZero;
10617                     else
10618                     {
10619                         x = D.zero;
10620                         return ExceptionFlags.none;
10621                     }
10622                 }
10623             }
10624             return ExceptionFlags.none;
10625         case FastClass.infinite:
10626             if (!n)
10627                 x = D.one;
10628             else
10629                 x = !sx || (n & 1) ? D.infinity : -D.infinity;
10630             return ExceptionFlags.none;
10631         case FastClass.quietNaN:
10632             if (!n)
10633                 x = D.one;
10634             return ExceptionFlags.none;
10635         case FastClass.signalingNaN:
10636             unsignalize(x);
10637             return ExceptionFlags.invalidOperation;
10638     }
10639 
10640  
10641 }
10642 
10643 ExceptionFlags decimalPow(D1, D2)(ref D1 x, auto const ref D2 y, const int precision, const RoundingMode mode)
10644 if (isDecimal!(D1, D2))
10645 {
10646     long ip;
10647     auto flags = decimalToSigned(y, ip, mode);
10648     if (flags == ExceptionFlags.none)
10649         return decimalPow(x, ip, precision, mode);
10650 
10651     flags = decimalLog(x, 0, mode);
10652     flags |= decimalMul(x, y, 0, mode);
10653     return flags | decimalExp(x, precision, mode);
10654 }
10655 
10656 ExceptionFlags decimalPow(D, F)(ref D x, auto const ref F y, const int precision, const RoundingMode mode)
10657 if (isDecimal!D && isFloatingPoint!F)
10658 {
10659     Unqual!D z;
10660     auto flags = z.packFloatingPoint(y, 0, mode);
10661     return flags | decimalPow(x, z, precision, mode);
10662 }
10663 
10664 ExceptionFlags decimalPow(T, D)(auto const ref T x, auto const ref D y, out D result, const int precision, const RoundingMode mode)
10665 if (isDecimal!D && isIntegral!T)
10666 {
10667     decimal128 r = x;
10668     auto flags = decimalPow(r, y, precision, mode);
10669     return flags | decimalToDecimal(r, result, precision, mode);
10670 }
10671 
10672 ExceptionFlags decimalPow(F, D)(auto const ref F x, auto const ref D y, out D result, const int precision, const RoundingMode mode)
10673 if (isDecimal!D && isFloatingPoint!F)
10674 {
10675     decimal128 r = x;
10676     auto flags = decimalPow(r, y, precision, mode);
10677     return flags | decimalToDecimal(r, result, precision, mode);
10678 }
10679 
10680 ExceptionFlags decimalExp(D)(ref D x, const int precision, const RoundingMode mode)
10681 if (isDecimal!D)
10682 {
10683     if (isSignaling(x))
10684     {
10685         x = D.nan;
10686         return ExceptionFlags.invalidOperation;
10687     }
10688 
10689     if (isZero(x))
10690     {
10691         x = D.one;
10692         return ExceptionFlags.none;
10693     }
10694 
10695     if (isNaN(x))
10696         return ExceptionFlags.none;
10697 
10698     if (isInfinity(x))
10699     {
10700         x = signbit(x) ? D.zero : D.infinity;
10701         return ExceptionFlags.none;
10702     }
10703  
10704     long n;
10705     auto flags = decimalToSigned(x, n, mode);
10706     if (flags == ExceptionFlags.none)
10707     {
10708         x = D.E;
10709         return decimalPow(x, n, precision, mode);
10710     }
10711 
10712     static if (is(D : decimal32))
10713     {
10714         enum lnmax = decimal32("+223.3507");
10715         enum lnmin = decimal32("-232.5610");
10716     }
10717     else static if (is(D: decimal64))
10718     {
10719         enum lnmax = decimal64("+886.4952608027075");
10720         enum lnmin = decimal64("-916.4288670116301");
10721     }
10722     else
10723     {
10724         enum lnmax = decimal128("+14149.38539644841072829055748903541");
10725         enum lnmin = decimal128("-14220.76553433122614449511522413063");
10726     }   
10727 
10728     if (isLess(x, lnmin))
10729     {
10730         x = D.zero;
10731         return ExceptionFlags.underflow | ExceptionFlags.inexact;
10732     }
10733 
10734     if (isGreater(x, lnmax))
10735     {
10736         x = D.infinity;
10737         return ExceptionFlags.overflow | ExceptionFlags.inexact;
10738     }
10739     
10740     DataType!D cx;
10741     int ex;
10742 
10743     bool sx = x.unpack(cx, ex);
10744     flags = coefficientExp(cx, ex, sx);
10745     return x.adjustedPack(cx, ex, sx, precision, mode, flags);
10746 }
10747 
10748 ExceptionFlags decimalLog(D)(ref D x, const int precision, const RoundingMode mode)
10749 if (isDecimal!D)
10750 {
10751     if (isSignaling(x))
10752     {
10753         x = D.nan;
10754         return ExceptionFlags.invalidOperation;
10755     }
10756 
10757     if (isNaN(x))
10758         return ExceptionFlags.none;
10759 
10760     if (signbit(x))
10761     {
10762         x = D.nan;
10763         return ExceptionFlags.invalidOperation;
10764     }
10765 
10766     if (isInfinity(x))
10767     {
10768         x = D.infinity;
10769         return ExceptionFlags.none;
10770     }
10771 
10772     if (isZero(x))
10773     {
10774         x = -D.infinity;
10775         return ExceptionFlags.divisionByZero;
10776     }
10777 
10778     DataType!D cx;
10779     int ex;
10780     bool sx = x.unpack(cx, ex);
10781     auto flags = coefficientLog(cx, ex, sx);
10782     return x.adjustedPack(cx, ex, sx, precision, mode, flags);
10783 }
10784 
10785 ExceptionFlags decimalExp10(D)(out D x, int n, const int precision, const RoundingMode mode)
10786 if (isDecimal!D)
10787 { 
10788     if (n == 0)
10789     {
10790         x = D.one;
10791         return ExceptionFlags.none;
10792     }
10793     alias T = DataType!D;
10794     return x.adjustedPack(T(1U), n, false, precision, mode, ExceptionFlags.none);
10795 }
10796 
10797 ExceptionFlags decimalExp10(D)(ref D x, const int precision, const RoundingMode mode)
10798 if (isDecimal!D)
10799 { 
10800     if (isSignaling(x))
10801     {
10802         x = D.nan;
10803         return ExceptionFlags.invalidOperation;
10804     }
10805 
10806     if (isZero(x))
10807     {
10808         x = D.one;
10809         return ExceptionFlags.none;
10810     }
10811 
10812     if (isNaN(x))
10813         return ExceptionFlags.none;
10814 
10815     if (isInfinity(x))
10816     {
10817         x = signbit(x) ? D.zero : D.infinity;
10818         return ExceptionFlags.none;
10819     }
10820    
10821     int n;
10822     auto flags = decimalToSigned(x, n, RoundingMode.implicit);
10823     if (flags == ExceptionFlags.none)
10824         return decimalExp10(x, n, precision, mode);
10825 
10826     flags = decimalMul(x, D.LN10, 0, mode);
10827     return flags | decimalExp(x, precision, mode);
10828 }
10829 
10830 ExceptionFlags decimalExp10m1(D)(ref D x, const int precision, const RoundingMode mode)
10831 if (isDecimal!D)
10832 { 
10833     if (isSignaling(x))
10834     {
10835         x = D.nan;
10836         return ExceptionFlags.invalidOperation;
10837     }
10838 
10839     if (isZero(x))
10840         return ExceptionFlags.none;
10841 
10842     if (isNaN(x))
10843         return ExceptionFlags.none;
10844 
10845     if (isInfinity(x))
10846     {
10847         x = signbit(x) ? -D.one : D.infinity;
10848         return ExceptionFlags.none;
10849     }
10850 
10851     auto flags = decimalExp10(x, 0, mode);
10852     return flags | decimalAdd(x, -1, precision, mode);
10853 }
10854 
10855 
10856 ExceptionFlags decimalExpm1(D)(ref D x, const int precision, const RoundingMode mode)
10857 if (isDecimal!D)
10858 {
10859     if (isSignaling(x))
10860     {
10861         x = D.nan;
10862         return ExceptionFlags.invalidOperation;
10863     }
10864 
10865     if (isZero(x))
10866         return ExceptionFlags.none;
10867 
10868     if (isNaN(x))
10869         return ExceptionFlags.none;
10870 
10871     if (isInfinity(x))
10872     {
10873         x = signbit(x) ? -D.one : D.infinity;
10874         return ExceptionFlags.none;
10875     }
10876 
10877     auto flags = decimalExp(x, 0, mode);
10878     return flags | decimalAdd(x, -1, precision, mode);
10879 }
10880 
10881 ExceptionFlags decimalExp2(D)(ref D x, const int precision, const RoundingMode mode)
10882 if (isDecimal!D)
10883 {
10884     if (isSignaling(x))
10885     {
10886         x = D.nan;
10887         return ExceptionFlags.invalidOperation;
10888     }
10889 
10890     if (isZero(x))
10891     {
10892         x = D.one;
10893         return ExceptionFlags.none;
10894     }
10895 
10896     if (isNaN(x))
10897         return ExceptionFlags.none;
10898 
10899     if (isInfinity(x))
10900     {
10901         x = signbit(x) ? D.zero : D.infinity;
10902         return ExceptionFlags.none;
10903     }
10904 
10905     int n;
10906     auto flags = decimalToSigned(x, n, RoundingMode.implicit);
10907     if (flags == ExceptionFlags.none)
10908     {
10909         x = D.two;
10910         return decimalPow(x, n, precision, mode);
10911     }
10912 
10913     flags = decimalMul(x, D.LN2, 0, mode);
10914     return flags | decimalExp(x, precision, mode);
10915 }
10916 
10917 ExceptionFlags decimalExp2m1(D)(ref D x, const int precision, const RoundingMode mode)
10918 if (isDecimal!D)
10919 {
10920     if (isSignaling(x))
10921     {
10922         x = D.nan;
10923         return ExceptionFlags.invalidOperation;
10924     }
10925 
10926     if (isZero(x))
10927         return ExceptionFlags.none;
10928 
10929     if (isNaN(x))
10930         return ExceptionFlags.none;
10931 
10932     if (isInfinity(x))
10933     {
10934         x = signbit(x) ? -D.one : D.infinity;
10935         return ExceptionFlags.none;
10936     }
10937 
10938     auto flags = decimalExp2(x, 0, mode);
10939     return flags |= decimalAdd(x, -1, precision, mode);
10940 }
10941 
10942 ExceptionFlags decimalLog2(D)(ref D x, const int precision, const RoundingMode mode)
10943 if (isDecimal!D)
10944 {
10945     auto flags = decimalLog(x, 0, mode);
10946     return flags | decimalDiv(x, D.LN2, precision, mode);
10947 }
10948 
10949 ExceptionFlags decimalLog10(D)(ref D x, const int precision, const RoundingMode mode)
10950 if (isDecimal!D)
10951 {
10952     if (isSignaling(x))
10953     {
10954         x = D.nan;
10955         return ExceptionFlags.invalidOperation;
10956     }
10957 
10958     if (isNaN(x))
10959         return ExceptionFlags.none;
10960 
10961     if (signbit(x))
10962     {
10963         x = D.nan;
10964         return ExceptionFlags.invalidOperation;
10965     }
10966 
10967     if (isInfinity(x))
10968     {
10969         x = D.infinity;
10970         return ExceptionFlags.none;
10971     }
10972 
10973     if (isZero(x))
10974     {
10975         x = -D.infinity;
10976         return ExceptionFlags.divisionByZero;
10977     }
10978 
10979     DataType!D c;
10980     int e;
10981     x.unpack(c, e);
10982     coefficientShrink(c, e);
10983 
10984     Unqual!D y = e;
10985     auto flags = decimalMul(y, D.LN10, 0, RoundingMode.implicit);
10986     x = c;
10987     flags |= decimalLog(x, 0, mode);
10988     return flags | decimalAdd(x, y, precision, mode);
10989 }
10990 
10991 ExceptionFlags decimalLogp1(D)(ref D x, const int precision, const RoundingMode mode)
10992 if (isDecimal!D)
10993 {
10994     auto flags = decimalAdd(x, 1U, 0, mode);
10995     return flags | decimalLog(x);
10996 }
10997 
10998 ExceptionFlags decimalLog2p1(D)(ref D x, const int precision, const RoundingMode mode)
10999 if (isDecimal!D)
11000 {
11001     auto flags = decimalAdd(x, 1U, 0, mode);
11002     return flags | decimalLog2(x, precision, mode);
11003 }
11004 
11005 ExceptionFlags decimalLog10p1(D)(ref D x, const int precision, const RoundingMode mode)
11006 if (isDecimal!D)
11007 {
11008     auto flags = decimalAdd(x, 1U, 0, mode);
11009     return flags | decimalLog10(x, precision, mode);
11010 }
11011 
11012 ExceptionFlags decimalCompound(D)(ref D x, const int n, const int precision, const RoundingMode mode)
11013 if (isDecimal!D)
11014 {
11015     if (isSignaling(x))
11016     {
11017         x = D.nan;
11018         return ExceptionFlags.invalidOperation;
11019     }
11020 
11021     if (isLess(x, -D.one))
11022     {
11023         x = D.nan;
11024         return ExceptionFlags.invalidOperation;
11025     }
11026 
11027     if (n == 0)
11028     {
11029         x = D.one;
11030         return ExceptionFlags.none;
11031     }
11032 
11033     if (x == -1 && n < 0)
11034     {
11035         x = D.infinity;
11036         return ExceptionFlags.divisionByZero;
11037     }
11038 
11039     if (x == -1)
11040     {
11041         x = D.zero;
11042         return ExceptionFlags.none;
11043     }
11044 
11045     if (isNaN(x))
11046         return ExceptionFlags.none;
11047 
11048     if (isInfinity(x))
11049     {
11050         if (signbit(x))
11051             x = n & 1 ? -D.infinity : D.infinity;
11052         else
11053             x = D.infinity;
11054         return ExceptionFlags.none;
11055     }
11056     
11057     Unqual!D y = x;
11058     auto flags = decimalAdd(x, 1U, 0, mode);
11059     if ((flags & ExceptionFlags.overflow) && n < 0)
11060     {
11061         x = y;
11062         flags &= ~ExceptionFlags.overflow;
11063     }
11064 
11065     if (flags & ExceptionFlags.overflow)
11066         return flags;
11067 
11068     return flags | decimalPow(x, n, precision, mode);
11069 }
11070 
11071 ExceptionFlags decimalRoot(D, T)(ref D x, const T n, const int precision, const RoundingMode mode)
11072 if (isDecimal!D && isIntegral!T)
11073 {
11074     if (isSignaling(x))
11075     {
11076         x = D.nan;
11077         return ExceptionFlags.invalidOperation;
11078     }
11079 
11080     if (!n)
11081     {
11082         x = D.nan;
11083         return ExceptionFlags.invalidOperation;
11084     }
11085 
11086     if (n == -1)
11087     {
11088         return ExceptionFlags.overflow | ExceptionFlags.underflow;
11089     }
11090 
11091     if (isNaN(x))
11092         return ExceptionFlags.none;
11093 
11094     if (isInfinity(x))
11095     {
11096         x = !signbit(x) || (n & 1) ? D.infinity : -D.infinity;
11097     }
11098 
11099     if (isZero(x))
11100     {
11101         if (n & 1) //odd
11102         {
11103             if (n < 0)
11104             {
11105                 x = signbit(x) ? -D.infinity : D.infinity;
11106                 return ExceptionFlags.divisionByZero;
11107             }
11108             else
11109                 return ExceptionFlags.none;
11110         }
11111         else //even
11112         {
11113             if (n < 0)
11114             {
11115                 x = D.infinity;
11116                 return ExceptionFlags.divisionByZero;
11117             }
11118             else
11119             {
11120                 x = D.zero;
11121                 return ExceptionFlags.none;
11122             }
11123         }
11124     }
11125 
11126     if (n == 1)
11127         return ExceptionFlags.none;
11128     Unqual!D y = 1U;
11129     auto flags = decimalDiv(y, n, 0, mode);
11130     return flags | decimalPow(x, y, precision, mode);
11131 }
11132 
11133 ExceptionFlags decimalSin(D)(ref D x, const int precision, const RoundingMode mode)
11134 if (isDecimal!D)
11135 {
11136     DataType!D cx; int ex; bool sx;
11137     switch(fastDecode(x, cx, ex, sx))
11138     {
11139         case FastClass.signalingNaN:
11140             unsignalize(x);
11141             return ExceptionFlags.invalidOperation;
11142         case FastClass.infinite:
11143             x = sx ? -D.nan : D.nan;
11144             return ExceptionFlags.invalidOperation;
11145         case FastClass.quietNaN:
11146         case FastClass.zero:
11147             return ExceptionFlags.none;
11148         default:
11149             int quadrant;
11150             auto flags = coefficientCapAngle(cx, ex, sx, quadrant);
11151             switch (quadrant)
11152             {
11153                 case 1:
11154                     flags |= coefficientSinQ(cx, ex, sx);
11155                     break;
11156                 case 2:
11157                     flags |= coefficientCosQ(cx, ex, sx);
11158                     break;
11159                 case 3:
11160                     flags |= coefficientSinQ(cx, ex, sx);
11161                     sx = !sx;
11162                     break;
11163                 case 4:
11164                     flags |= coefficientCosQ(cx, ex, sx);
11165                     sx = !sx;
11166                     break;
11167                 default:
11168                     assert(0);
11169             }
11170             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
11171     }
11172 }
11173 
11174 ExceptionFlags decimalCos(D)(ref D x, const int precision, const RoundingMode mode)
11175 if (isDecimal!D)
11176 {
11177     DataType!D cx; int ex; bool sx;
11178     switch(fastDecode(x, cx, ex, sx))
11179     {
11180         case FastClass.signalingNaN:
11181             return ExceptionFlags.invalidOperation;
11182         case FastClass.infinite:
11183             x = sx ? -D.nan : D.nan;
11184             return ExceptionFlags.invalidOperation;
11185         case FastClass.quietNaN:
11186             return ExceptionFlags.none;
11187         case FastClass.zero:
11188             x = D.one;
11189             return ExceptionFlags.none;
11190         default:
11191             int quadrant;
11192             auto flags = coefficientCapAngle(cx, ex, sx, quadrant);
11193             switch (quadrant)
11194             {
11195                 case 1:
11196                     flags |= coefficientCosQ(cx, ex, sx);
11197                     break;
11198                 case 2:
11199                     flags |= coefficientSinQ(cx, ex, sx);
11200                     sx = !sx;
11201                     break;
11202                 case 3:
11203                     flags |= coefficientCosQ(cx, ex, sx);
11204                     sx = !sx;
11205                     break;
11206                 case 4:
11207                     flags |= coefficientSinQ(cx, ex, sx);
11208                     break;
11209                 default:
11210                     assert(0);
11211             }
11212             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
11213     }
11214 }
11215 
11216 ExceptionFlags decimalTan(D)(ref D x, const int precision, const RoundingMode mode)
11217 if (isDecimal!D)
11218 {
11219 
11220     DataType!D cx; int ex; bool sx;
11221     switch(fastDecode(x, cx, ex, sx))
11222     {
11223         case FastClass.signalingNaN:
11224             return ExceptionFlags.invalidOperation;
11225         case FastClass.infinite:
11226             x = sx ? -D.nan : D.nan;
11227             return ExceptionFlags.invalidOperation;
11228         case FastClass.quietNaN:
11229         case FastClass.zero:
11230             return ExceptionFlags.none;
11231         default:
11232             int quadrant;
11233             auto flags = coefficientCapAngle(cx, ex, sx, quadrant);
11234             DataType!D csin, ccos; int esin, ecos; bool ssin, scos;
11235             flags |= coefficientSinCosQ(cx, ex, sx, csin, esin, ssin, ccos, ecos, scos);
11236             switch (quadrant)
11237             {
11238                 case 1:
11239                     //sin/cos, -sin/-cos
11240                 case 3:
11241                     cx = csin; ex = esin; sx = ssin;
11242                     flags |= coefficientDiv(cx, ex, sx, ccos, ecos, scos, RoundingMode.implicit);
11243                     break;
11244                 case 2:
11245                     //cos/-sin
11246                     cx = ccos; ex = ecos; sx = scos;
11247                     flags |= coefficientDiv(cx, ex, sx, csin, esin, !ssin, RoundingMode.implicit);
11248                     break;
11249                 case 4://-cos/sin
11250                     cx = ccos; ex = ecos; sx = !scos;
11251                     flags |= coefficientDiv(cx, ex, sx, csin, esin, ssin, RoundingMode.implicit);
11252                     break;
11253                 default:
11254                     assert(0);
11255             }
11256             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
11257     }
11258 }
11259 
11260 ExceptionFlags decimalAtan(D)(ref D x, const int precision, const RoundingMode mode)
11261 if (isDecimal!D)
11262 {
11263     DataType!D cx; int ex; bool sx;
11264     switch (fastDecode(x, cx, ex, sx))
11265     {
11266         case FastClass.signalingNaN:
11267             return ExceptionFlags.invalidOperation;
11268         case FastClass.quietNaN:
11269         case FastClass.zero:
11270             return ExceptionFlags.none;
11271         case FastClass.infinite:
11272             x = signbit(x) ? -D.PI_2 : D.PI_2;
11273             return decimalAdjust(x, precision, mode);
11274         default:
11275             DataType!D reductions;
11276             coefficientCapAtan(cx, ex, sx, reductions);
11277             auto flags = coefficientAtan(cx, ex, sx);
11278             if (reductions)
11279             {
11280                 flags |= coefficientMul(cx, ex, sx, reductions, 0, false, RoundingMode.implicit);
11281                 flags |= coefficientMul(cx, ex, sx, DataType!D(2U), 0, false, RoundingMode.implicit);
11282             }
11283             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
11284     }
11285 }
11286 
11287 ExceptionFlags decimalSinPi(D)(ref D x, const int precision, const RoundingMode mode)
11288 if (isDecimal!D)
11289 {
11290     if (isSignaling(x) || isInfinity(x))
11291     {
11292         x = D.nan;
11293         return ExceptionFlags.invalidOperation;
11294     }
11295 
11296     if (isNaN(x))
11297         return ExceptionFlags.none;
11298 
11299     decimalReduceAngle(x);
11300 
11301     auto flags = decimalMul(x, D.PI, 0, mode);
11302     return flags | decimalSin(x, precision, mode);
11303 }
11304 
11305 ExceptionFlags decimalCosPi(D)(ref D x, const int precision, const RoundingMode mode)
11306 if (isDecimal!D)
11307 {
11308     if (isSignaling(x) || isInfinity(x))
11309     {
11310         x = D.nan;
11311         return ExceptionFlags.invalidOperation;
11312     }
11313 
11314     if (isNaN(x))
11315         return ExceptionFlags.none;
11316 
11317     decimalReduceAngle(x);
11318 
11319     auto flags = decimalMul(x, D.PI, 0, mode);
11320     return flags | decimalCos(x, precision, mode);
11321 }
11322 
11323 ExceptionFlags decimalAtanPi(D)(ref D x, const int precision, const RoundingMode mode)
11324 if (isDecimal!D)
11325 {
11326 
11327     if (isSignaling(x))
11328     {
11329         x = D.nan;
11330         return ExceptionFlags.invalidOperation;
11331     }
11332 
11333     if (isNaN(x) || isZero(x))
11334         return ExceptionFlags.none;
11335 
11336     if (isInfinity(x))
11337     {
11338         x = signbit(x) ? -D.half : D.half;
11339         return ExceptionFlags.none;
11340     }
11341 
11342     bool sx = cast(bool)signbit(x);
11343     x = fabs(x);
11344 
11345     //if (decimalEqu(x, D.SQRT3))
11346     //{
11347     //    x = sx ? -D.onethird : D.onethird;
11348     //    return ExceptionFlags.none;
11349     //}
11350     //
11351     //if (decimalEqu(x, D.one))
11352     //{
11353     //    x = sx ? -D.quarter : D.quarter;
11354     //    return ExceptionFlags.none;
11355     //}
11356     //
11357     //if (decimalEqu(x, D.M_SQRT3))
11358     //{
11359     //    x = sx ? -D._1_6 : D._1_6;
11360     //    return ExceptionFlags.none;
11361     //}
11362 
11363 
11364     auto flags = decimalAtan(x, 0, mode);
11365     return flags | decimalDiv(x, D.PI, precision, mode);
11366 }
11367 
11368 ExceptionFlags decimalAtan2(D1, D2, D3)(auto const ref D1 y, auto const ref D2 x, out D3 z, 
11369                                     const int precision, const RoundingMode mode)
11370 {
11371     alias D = CommonDecimal!(D1, D2);
11372 
11373     if (isSignaling(x) || isSignaling(y))
11374     {
11375         z = D.nan;
11376         return ExceptionFlags.invalidOperation;
11377     }
11378 
11379     if (isNaN(x) || isNaN(y))
11380     {
11381         z = D.nan;
11382         return ExceptionFlags.none;
11383     }
11384     
11385     if (isZero(y))
11386     {
11387         if (signbit(x))
11388             z = signbit(y) ? -D.PI : D.PI;
11389         else
11390             z = signbit(y) ? -D.zero : D.zero;
11391         return ExceptionFlags.inexact;
11392     }
11393 
11394     if (isZero(x))
11395     {
11396         z = signbit(y) ? -D.PI_2 : D.PI_2;
11397         return ExceptionFlags.inexact;
11398     }
11399 
11400     if (isInfinity(y))
11401     {
11402         if (isInfinity(x))
11403         {
11404             if (signbit(x))
11405                 z = signbit(y) ? -D._3PI_4 : D._3PI_4;
11406             else
11407                 z = signbit(y) ? -D.PI_4 : D.PI_4;
11408         }
11409         else
11410             z = signbit(y) ? -D.PI_2 : D.PI_2;
11411         return ExceptionFlags.inexact;
11412     }
11413 
11414     if (isInfinity(x))
11415     {
11416         if (signbit(x))
11417             z = signbit(y) ? -D.PI : D.PI;
11418         else
11419             z = signbit(y) ? -D.zero : D.zero;
11420         return ExceptionFlags.inexact; 
11421     }
11422 
11423     z = y;
11424     D xx = x;
11425     auto flags = decimalDiv(z, xx, 0, mode);
11426     z = fabs(z);
11427     flags |= decimalAtan(z, 0, mode);
11428     
11429     if (signbit(x))
11430     {
11431         z = -z;
11432         return (flags | decimalAdd(z, D.PI, precision, mode)) & ExceptionFlags.inexact;
11433     }
11434     else
11435         return (flags | decimalAdjust(z, precision, mode)) & (ExceptionFlags.inexact | ExceptionFlags.underflow);
11436 }
11437 
11438 ExceptionFlags decimalAtan2Pi(D1, D2, D3)(auto const ref D1 y, auto const ref D2 x, out D3 z, const int precision, const RoundingMode mode)
11439 if (isDecimal!(D1, D2, D3))
11440 {
11441     alias D = CommonDecimal!(D1, D2);
11442 
11443     if (isSignaling(x) || isSignaling(y))
11444     {
11445         z = D.nan;
11446         return ExceptionFlags.invalidOperation;
11447     }
11448 
11449     if (isNaN(x) || isNaN(y))
11450     {
11451         z = D.nan;
11452         return ExceptionFlags.none;
11453     }
11454 
11455     if (isZero(y))
11456     {
11457         if (signbit(x))
11458             z = signbit(y) ? -D.one : D.one;
11459         else
11460             z = signbit(y) ? -D.zero : D.zero;
11461         return ExceptionFlags.inexact;
11462     }
11463 
11464     if (isZero(x))
11465     {
11466         z = signbit(y) ? -D.half : D.half;
11467         return ExceptionFlags.inexact;
11468     }
11469 
11470     if (isInfinity(y))
11471     {
11472         if (isInfinity(x))
11473         {
11474             if (signbit(x))
11475                 z = signbit(y) ? -D.threequarters : D.threequarters;
11476             else
11477                 z = signbit(y) ? -D.quarter : D.quarter;
11478         }
11479         else
11480             z = signbit(y) ? -D.half : D.half;
11481         return ExceptionFlags.inexact;
11482     }
11483 
11484     if (isInfinity(x))
11485     {
11486         if (signbit(x))
11487             z = signbit(y) ? -D.one : D.one;
11488         else
11489             z = signbit(y) ? -D.zero : D.zero;
11490         return ExceptionFlags.inexact; 
11491     }
11492     auto flags = decimalAtan2(y, x, z, 0, mode);
11493     return flags | decimalDiv(z, D.PI, precision, mode);
11494 }
11495 
11496 ExceptionFlags decimalAsin(D)(ref D x, const int precision, const RoundingMode mode)
11497 {
11498     if (isSignaling(x))
11499     {
11500         x = D.nan;
11501         return ExceptionFlags.invalidOperation;
11502     }
11503 
11504     if (isNaN(x))
11505         return ExceptionFlags.none;
11506 
11507     if (isLess(x, -D.one) || isGreater(x, D.one))
11508     {
11509         x = D.nan;
11510         return ExceptionFlags.invalidOperation;
11511     }
11512 
11513     if (isZero(x))
11514         return ExceptionFlags.none;
11515     
11516 
11517     if (x == -D.one)
11518     {
11519         x = -D.PI_2;
11520         return decimalAdjust(x, precision, mode);
11521     }
11522 
11523     if (x == D.one)
11524     {
11525         x = D.PI_2;
11526         return ExceptionFlags.none;
11527     }
11528 
11529 
11530 
11531     if (x == -D.SQRT3_2)
11532     {
11533         x = -D.PI_3;
11534         return ExceptionFlags.none;
11535     }
11536 
11537     if (x == -D.SQRT2_2)
11538     {
11539         x = -D.PI_4;
11540         return ExceptionFlags.none;
11541     }
11542 
11543     if (x == -D.half)
11544     {
11545         x  = -D.PI_6;
11546         return ExceptionFlags.none;
11547     }
11548 
11549     if (x == D.half)
11550     {
11551         x  = D.PI_6;
11552         return ExceptionFlags.none;
11553     }
11554 
11555     if (x == D.SQRT2_2)
11556     {
11557         x = D.PI_4;
11558         return ExceptionFlags.none;
11559     }
11560 
11561     if (x == D.SQRT3_2)
11562     {
11563         x = D.PI_6;
11564         return ExceptionFlags.none;
11565     }
11566 
11567     //asin(x) = 2 * atan(x / ( 1 + sqrt(1 - x* x))
11568     Unqual!D x2 = x;
11569     auto flags = decimalSqr(x2, 0, mode);
11570     x2 = -x2;
11571     flags |= decimalAdd(x2, 1U, 0, mode);
11572     flags |= decimalSqrt(x2, 0, mode);
11573     flags |= decimalAdd(x2, 1U, 0, mode);
11574     flags |= decimalDiv(x, x2, 0, mode);
11575     flags |= decimalAtan(x, 0, mode);
11576     return flags | decimalMul(x, 2U, precision, mode);
11577 }
11578 
11579 ExceptionFlags decimalAcos(D)(ref D x, const int precision, const RoundingMode mode)
11580 {
11581     if (isSignaling(x))
11582     {
11583         x = D.nan;
11584         return ExceptionFlags.invalidOperation;
11585     }
11586 
11587     if (isNaN(x))
11588         return ExceptionFlags.none;
11589 
11590     if (isLess(x, -D.one) || isGreater(x, D.one))
11591     {
11592         x = D.nan;
11593         return ExceptionFlags.invalidOperation;
11594     }
11595 
11596     if (isZero(x))
11597     {
11598         x = D.PI_2;
11599         return decimalAdjust(x, precision, mode);
11600     }
11601 
11602     if (x == -D.one)
11603     {
11604         x = D.PI;
11605         return decimalAdjust(x, precision, mode);
11606     }
11607 
11608     if (x == D.one)
11609     {
11610         x = D.zero;
11611         return ExceptionFlags.none;
11612     }
11613 
11614     
11615 
11616     if (x == -D.SQRT3_2)
11617     {
11618         x = D._5PI_6;
11619         return ExceptionFlags.none;
11620     }
11621 
11622     if (x == -D.SQRT2_2)
11623     {
11624         x = D._3PI_4;
11625         return ExceptionFlags.none;
11626     }
11627 
11628     if (x == -D.half)
11629     {
11630         x  = D._2PI_3;
11631         return ExceptionFlags.none;
11632     }
11633 
11634     if (x == D.half)
11635     {
11636         x  = D.PI_2;
11637         return ExceptionFlags.none;
11638     }
11639 
11640     if (x == D.SQRT2_2)
11641     {
11642         x = D.PI_4;
11643         return ExceptionFlags.none;
11644     }
11645 
11646     if (x == D.SQRT3_2)
11647     {
11648         x = D.PI_6;
11649         return ExceptionFlags.none;
11650     }
11651 
11652     
11653 
11654     Unqual!D x2 = x;
11655     auto flags = decimalSqr(x2, 0, mode);
11656     x2 = -x2;
11657     flags |= decimalAdd(x2, 1U, 0, mode);
11658     flags |= decimalSqrt(x2, 0, mode);
11659     flags |= decimalAdd(x, 1U, 0, mode);
11660     flags |= decimalDiv(x2, x, 0, mode);
11661     x = x2;
11662     flags |= decimalAtan(x, 0, mode);
11663     return flags | decimalMul(x, 2U, precision, mode);
11664 }
11665 
11666 ExceptionFlags decimalSinh(D)(ref D x, const int precision, const RoundingMode mode)
11667 {
11668     if (isSignaling(x))
11669     {
11670         x = D.nan;
11671         return ExceptionFlags.invalidOperation;
11672     }
11673 
11674     if (isNaN(x))
11675         return ExceptionFlags.none;
11676 
11677     if (isInfinity(x))
11678     {
11679         x = D.infinity;
11680         return ExceptionFlags.none;
11681     }
11682 
11683     if (isZero(x))
11684         return ExceptionFlags.none;
11685 
11686     Unqual!D x1 = x;
11687     Unqual!D x2 = -x;
11688 
11689     
11690     auto flags = decimalExp(x1, 0, mode);
11691     flags |= decimalExp(x2, 0, mode);
11692     flags |= decimalSub(x1, x2, 0, mode);
11693     x = x1;
11694     return flags | decimalMul(x, 2U, precision, mode);
11695 }
11696 
11697 ExceptionFlags decimalCosh(D)(ref D x, const int precision, const RoundingMode mode)
11698 {
11699     if (isSignaling(x))
11700     {
11701         x = D.nan;
11702         return ExceptionFlags.invalidOperation;
11703     }
11704 
11705     if (isNaN(x))
11706         return ExceptionFlags.none;
11707 
11708     if (isInfinity(x))
11709     {
11710         x = D.infinity;
11711         return ExceptionFlags.none;
11712     }
11713 
11714     if (isZero(x))
11715     {
11716         x = D.one;
11717         return ExceptionFlags.none;
11718     }
11719 
11720     Unqual!D x1 = x;
11721     Unqual!D x2 = -x;
11722     auto flags = decimalExp(x1, 0, mode);
11723     flags |= decimalExp(x2, 0, mode);
11724     flags |= decimalAdd(x1, x2, 0, mode);
11725     x = x1;
11726     return flags | decimalMul(x, D.half, precision, mode);
11727 }
11728 
11729 ExceptionFlags decimalTanh(D)(ref D x, const int precision, const RoundingMode mode)
11730 {
11731 
11732     if (isSignaling(x))
11733     {
11734         x = D.nan;
11735         return ExceptionFlags.invalidOperation;
11736     }
11737 
11738     if (isNaN(x))
11739         return ExceptionFlags.none;
11740 
11741     if (isInfinity(x))
11742     {
11743         x = signbit(x) ? -D.one : D.one;
11744         return ExceptionFlags.none;
11745     }
11746 
11747     if (isZero(x))
11748         return ExceptionFlags.none;
11749 
11750     Unqual!D x1 = x;
11751     Unqual!D x2 = -x;
11752     auto flags = decimalSinh(x1, 0, mode);
11753     flags |= decimalCosh(x2, 0, mode);
11754     x = x1;
11755     return flags | decimalDiv(x, x2, precision, mode);
11756 }
11757 
11758 ExceptionFlags decimalAsinh(D)(ref D x, const int precision, const RoundingMode mode)
11759 {
11760     if (isSignaling(x))
11761     {
11762         x = D.nan;
11763         return ExceptionFlags.invalidOperation;
11764     }
11765 
11766     if (isNaN(x) || isZero(x) || isInfinity(x))
11767         return ExceptionFlags.none;
11768 
11769     //+- ln(|x| + sqrt(x*x + 1))
11770     //+-[ln(2) + ln(|x|)] for very big x,
11771 
11772     //sqrt(D.max)/2
11773     static if (is(D: decimal32))
11774     {
11775         enum asinhmax = decimal32("1.581138e51");
11776     }
11777     else static if (is(D: decimal64))
11778     {
11779         enum asinhmax = decimal64("1.581138830084189e192");
11780     }
11781     else
11782     {
11783         enum asinhmax = decimal128("1.581138830084189665999446772216359e3072");
11784     }
11785 
11786     bool sx = cast(bool)signbit(x);
11787     x = fabs(x);
11788 
11789     ExceptionFlags flags;
11790     if (isGreater(x, asinhmax))
11791     {
11792         flags = decimalLog(x, 0, mode) | ExceptionFlags.inexact;
11793         flags |= decimalAdd(x, D.LN2, 0, mode);
11794         
11795     }
11796     else
11797     {
11798         Unqual!D x1 = x;
11799         flags = decimalSqr(x1, 0, mode);
11800         flags |= decimalAdd(x1, 1U, 0, mode);
11801         flags |= decimalSqrt(x1, 0, mode);
11802         flags |= decimalAdd(x, x1, 0, mode);
11803         flags |= decimalLog(x, 0, mode);
11804     }
11805 
11806     if (sx)
11807         x = -x;
11808     return flags | decimalAdjust(x, precision, mode);
11809     
11810     
11811 }
11812 
11813 ExceptionFlags decimalAcosh(D)(ref D x, const int precision, const RoundingMode mode)
11814 {
11815     if (isSignaling(x))
11816     {
11817         x = D.nan;
11818         return ExceptionFlags.invalidOperation;
11819     }
11820 
11821     if (isNaN(x))
11822         return ExceptionFlags.none;
11823 
11824     if (isLess(x, D.one))
11825     {
11826         x = D.nan;
11827         return ExceptionFlags.invalidOperation;
11828     }
11829 
11830     if (x == D.one)
11831     {
11832         x = D.zero;
11833         return ExceptionFlags.none;
11834     }
11835 
11836     if (isInfinity(x))
11837         return ExceptionFlags.none;
11838 
11839     ExceptionFlags flags;
11840 
11841     /*
11842         ln(x+sqrt(x*x - 1))
11843         for very big x: (ln(x + x) = ln(2) + ln(x), otherwise will overflow
11844     */
11845 
11846     //sqrt(D.max)/2
11847     static if (is(D: decimal32))
11848     {
11849         enum acoshmax = decimal32("1.581138e51");
11850     }
11851     else static if (is(D: decimal64))
11852     {
11853         enum acoshmax = decimal64("1.581138830084189e192");
11854     }
11855     else
11856     {
11857         enum acoshmax = decimal128("1.581138830084189665999446772216359e3072");
11858     }
11859 
11860     if (isGreater(x, acoshmax))
11861     {
11862         flags = decimalLog(x, 0, mode) | ExceptionFlags.inexact;
11863         return flags |= decimalAdd(x, D.LN2, precision, mode);
11864     }
11865     else
11866     {
11867         Unqual!D x1 = x;
11868         flags = decimalSqr(x1, 0, mode);
11869         flags |= decimalSub(x1, 1U, 0, mode);
11870         flags |= decimalSqrt(x1, 0, mode);
11871         flags |= decimalAdd(x, x1, 0, mode);
11872         return flags | decimalLog(x, precision, mode);
11873     }
11874 }
11875 
11876 ExceptionFlags decimalAtanh(D)(ref D x, const int precision, const RoundingMode mode)
11877 {
11878     if (isSignaling(x))
11879     {
11880         x = D.nan;
11881         return ExceptionFlags.invalidOperation;
11882     }
11883 
11884     if (isNaN(x) || isZero(x))
11885         return ExceptionFlags.none;
11886 
11887     alias T = DataType!D;
11888     T cx;
11889     int ex;
11890     bool sx = x.unpack(cx, ex);
11891 
11892     auto cmp = coefficientCmp(cx, ex, false, T(1U), 0, false);
11893 
11894     if (cmp > 0)
11895     {
11896         x = signbit(x) ? -D.nan : D.nan;
11897         return ExceptionFlags.none;
11898     }
11899 
11900     if (cmp == 0)
11901     {
11902         x = signbit(x) ? -D.infinity : D.infinity;
11903         return ExceptionFlags.none;
11904     }
11905     
11906     auto flags = coefficientAtanh(cx, ex, sx);
11907     return x.adjustedPack(cx, ex, sx, precision, mode, flags);
11908 
11909 }
11910 
11911 ExceptionFlags decimalSum(D)(const(D)[] x, out D result, const int precision, const RoundingMode mode)
11912 if (isDecimal!D)
11913 {
11914     ExceptionFlags flags;
11915     alias T = MakeUnsigned!(D.sizeof * 16);
11916     DataType!D cx;
11917     T cxx, cr;
11918     int ex, er;
11919     bool sx, sr;
11920 
11921     result = 0;
11922     bool hasPositiveInfinity, hasNegativeInfinity;
11923     size_t i = 0;
11924     while (i < x.length)
11925     {
11926         if (isSignaling(x[i]))
11927         {
11928             result = D.nan;
11929             return ExceptionFlags.invalidOperation;
11930         }
11931 
11932         if (isNaN(x[i]))
11933         {
11934             result = D.nan;
11935             return ExceptionFlags.none;
11936         }
11937 
11938         if (isInfinity(x[i]))
11939         {
11940             if (signbit(x[i]))
11941                 hasNegativeInfinity = true;
11942             else
11943                 hasPositiveInfinity = true;
11944             ++i;
11945             break;
11946         }
11947 
11948         if (isZero(x[i]))
11949         {
11950             ++i;
11951             continue;
11952         }
11953         
11954         sx = x.unpack(cx, ex);
11955         cxx = cx;
11956         flags |= coefficientAdd(cr, er, sr, cxx, ex, sx, mode);
11957         ++i;
11958 
11959         if (flags & ExceptionFlags.overflow)
11960             break;
11961     }
11962 
11963     while (i < x.length)
11964     {
11965         //infinity or overflow detected
11966         if (isSignaling(x[i]))
11967         {
11968             result = D.nan;
11969             return ExceptionFlags.invalidOperation;
11970         }
11971 
11972         if (isNaN(x[i]))
11973         {
11974             result = D.nan;
11975             return ExceptionFlags.none;
11976         }
11977 
11978         if (isInfinity(x[i]))
11979         {
11980             if (signbit(x[i]))
11981                 hasNegativeInfinity = true;
11982             else
11983                 hasPositiveInfinity = true;
11984         }
11985         ++i;
11986     }
11987 
11988     if (hasPositiveInfinity)
11989     {
11990         if (hasNegativeInfinity)
11991         {
11992             result = D.nan;
11993             return ExceptionFlags.invalidOperation;
11994         }
11995         result = D.infinity;
11996         return ExceptionFlags.none;
11997     }
11998 
11999     if (hasNegativeInfinity)
12000     {
12001         result = -D.infinity;
12002         return ExceptionFlags.none;
12003     }
12004 
12005     flags |= coefficientAdjust(cr, er, cvt!T(DataType!D.max), sr, mode);
12006     return result.adjustedPack(cvt!(DataType!D)(cr), er, sr, precision, mode, flags);
12007 }
12008 
12009 ExceptionFlags decimalSumSquare(D)(const(D)[] x, out D result, const int precision, const RoundingMode mode)
12010 if (isDecimal!D)
12011 {
12012     ExceptionFlags flags;
12013     alias T = MakeUnsigned!(D.sizeof * 16);
12014     DataType!D cx;
12015     T cxx, cr;
12016     int ex, er;
12017     bool sr;
12018     result = 0;
12019     bool hasInfinity;
12020     size_t i = 0;
12021     while (i < x.length)
12022     {
12023         if (isSignaling(x[i]))
12024         {
12025             result = D.nan;
12026             return ExceptionFlags.invalidOperation;
12027         }
12028 
12029         if (isNaN(x[i]))
12030         {
12031             result = D.nan;
12032             return ExceptionFlags.none;
12033         }
12034 
12035         if (isInfinity(x[i]))
12036         {
12037             hasInfinity = true;
12038             ++i;
12039             break;
12040         }
12041 
12042         if (isZero(x[i]))
12043         {
12044             ++i;
12045             continue;
12046         }
12047 
12048         x.unpack(cx, ex);
12049         cxx = cx;
12050         flags |= coefficientSqr(cxx, ex);
12051         flags |= coefficientAdd(cr, er, sr, cxx, ex, false, mode);
12052         ++i;
12053 
12054         if (flags & ExceptionFlags.overflow)
12055             break;
12056     }
12057 
12058     while (i < x.length)
12059     {
12060         //infinity or overflow detected
12061         if (isSignaling(x[i]))
12062         {
12063             result = D.nan;
12064             return ExceptionFlags.invalidOperation;
12065         }
12066 
12067         if (isNaN(x[i]))
12068         {
12069             result = D.nan;
12070             return ExceptionFlags.none;
12071         }
12072 
12073         if (isInfinity(x[i]))
12074             hasInfinity = true;
12075         ++i;
12076     }
12077 
12078     if (hasInfinity)
12079     {
12080         result = D.infinity;
12081         return ExceptionFlags.none;
12082     }
12083 
12084     flags |= coefficientAdjust(cr, er, cvt!T(DataType!D.max), sr, mode);
12085     return result.adjustedPack(cvt!(DataType!D)(cr), er, sr, precision, mode, flags);
12086 
12087 }
12088 
12089 ExceptionFlags decimalSumAbs(D)(const(D)[] x, out D result, const int precision, const RoundingMode mode)
12090 if (isDecimal!D)
12091 {
12092     ExceptionFlags flags;
12093     alias T = MakeUnsigned!(D.sizeof * 16);
12094     DataType!D cx;
12095     T cxx, cr;
12096     int ex, er;
12097     bool sr;
12098 
12099     result = 0;
12100     bool hasInfinity;
12101     size_t i = 0;
12102     while (i < x.length)
12103     {
12104         if (isSignaling(x[i]))
12105         {
12106             result = D.nan;
12107             return ExceptionFlags.invalidOperation;
12108         }
12109 
12110         if (isNaN(x[i]))
12111         {
12112             result = D.nan;
12113             return ExceptionFlags.none;
12114         }
12115 
12116         if (isInfinity(x[i]))
12117         {
12118             hasInfinity = true;
12119             ++i;
12120             break;
12121         }
12122 
12123         if (isZero(x[i]))
12124         {
12125             ++i;
12126             continue;
12127         }
12128 
12129         x.unpack(cx, ex);
12130         cxx = cx;
12131         flags |= coefficientAdd(cr, er, sr, cxx, ex, false, mode);
12132         ++i;
12133 
12134         if (flags & ExceptionFlags.overflow)
12135             break;
12136     }
12137 
12138     while (i < x.length)
12139     {
12140         //infinity or overflow detected
12141         if (isSignaling(x[i]))
12142         {
12143             result = D.nan;
12144             return ExceptionFlags.invalidOperation;
12145         }
12146 
12147         if (isNaN(x[i]))
12148         {
12149             result = D.nan;
12150             return ExceptionFlags.none;
12151         }
12152 
12153         if (isInfinity(x[i]))
12154             hasInfinity = true;
12155         ++i;
12156     }
12157 
12158 
12159 
12160     if (hasInfinity)
12161     {
12162         result = D.infinity;
12163         return ExceptionFlags.none;
12164     }
12165 
12166     flags |= coefficientAdjust(cr, er, cvt!T(DataType!D.max), sr, mode);
12167     return result.adjustedPack(cvt!(DataType!D)(cr), er, sr, precision, mode, flags);
12168 }
12169 
12170 ExceptionFlags decimalDot(D)(const(D)[] x, const(D)[] y, out D result, const int precision, const RoundingMode mode)
12171 if (isDecimal!D)
12172 {
12173     size_t len = x.length;
12174     if (len > y.length)
12175         len = y.length;
12176 
12177     bool hasPositiveInfinity, hasNegativeInfinity;
12178 
12179     alias T = MakeUnsigned!(D.sizeof * 16);
12180     DataType!D cx, cy;
12181     T cxx, cyy, cr;
12182     int ex, ey, er;
12183     bool sx, sy, sr;
12184 
12185     size_t i = 0;
12186     while (i < len)
12187     {
12188         if (isSignaling(x[i]) || isSignaling(y[i]))
12189         {
12190             result = D.nan;
12191             return ExceptionFlags.invalidOperation;
12192         }
12193 
12194         if (isNaN(x[i]) || isNaN(y[i]))
12195         {
12196             result = D.nan;
12197             return ExceptionFlags.none;
12198         }
12199 
12200         if (isInfinity(x[i]))
12201         {
12202             if (isZero(y[i]))
12203             {
12204                 result = D.nan;
12205                 return ExceptionFlags.invalidOperation;
12206             }
12207 
12208             if (isInfinity(y[i]))
12209             {
12210                 if (signbit(x[i]) ^ signbit(y[i]))
12211                     hasNegativeInfinity = true;
12212                 else
12213                     hasPositiveInfinity = true;
12214                 
12215             }
12216             else
12217             {
12218                 if (signbit(x[i]))
12219                     hasNegativeInfinity = true;
12220                 else
12221                     hasPositiveInfinity = true;
12222             }
12223             ++i;
12224             break;
12225         }
12226 
12227         if (isInfinity(y[i]))
12228         {
12229             if (isZero(x[i]))
12230             {
12231                 result = D.nan;
12232                 return ExceptionFlags.invalidOperation;
12233             }
12234 
12235           
12236             if (signbit(y[i]))
12237                 hasNegativeInfinity = true;
12238             else
12239                 hasPositiveInfinity = true;
12240             
12241             ++i;
12242             break;
12243         }
12244 
12245         if (isZero(x[i]) || isZero(y[i]))
12246         {
12247             ++i;
12248             continue;
12249         }
12250 
12251         sx = x[i].unpack(cx, ex);
12252         sy = y[i].unpack(cy, ey);
12253         cxx = cx; cyy = cy;
12254         flags |= coefficientMul(cx, ex, sx, cy, ey, sy, mode);
12255         flags |= coefficientAdd(cr, er, sr, cx, ex, sx, mode);
12256         ++i;
12257         if (flags & ExceptionFlags.overflow)
12258             break;
12259     }
12260 
12261     while (i < len)
12262     {
12263         if (isSignaling(x[i]) || isSignaling(y[i]))
12264         {
12265             result = D.nan;
12266             return ExceptionFlags.invalidOperation;
12267         }
12268 
12269         if (isNaN(x[i]) || isNaN(y[i]))
12270         {
12271             result = D.nan;
12272             return ExceptionFlags.none;
12273         }
12274 
12275         if (isInfinity(x[i]))
12276         {
12277             if (isZero(y[i]))
12278             {
12279                 result = D.nan;
12280                 return ExceptionFlags.invalidOperation;
12281             }
12282 
12283             if (isInfinity(y[i]))
12284             {
12285                 if (signbit(x[i]) ^ signbit(y[i]))
12286                     hasNegativeInfinity = true;
12287                 else
12288                     hasPositiveInfinity = true;
12289 
12290             }
12291             else
12292             {
12293                 if (signbit(x[i]))
12294                     hasNegativeInfinity = true;
12295                 else
12296                     hasPositiveInfinity = true;
12297             }
12298         }
12299 
12300         if (isInfinity(y[i]))
12301         {
12302             if (isZero(x[i]))
12303             {
12304                 result = D.nan;
12305                 return ExceptionFlags.invalidOperation;
12306             }
12307 
12308 
12309             if (signbit(y[i]))
12310                 hasNegativeInfinity = true;
12311             else
12312                 hasPositiveInfinity = true;
12313         }
12314 
12315         ++i;
12316     }
12317 
12318     if (hasPositiveInfinity)
12319     {
12320         if (hasNegativeInfinity)
12321         {
12322             result = D.nan;
12323             return ExceptionFlags.invalidOperation;
12324         }
12325         result = D.infinity;
12326         return ExceptionFlags.none;
12327     }
12328 
12329     if (hasNegativeInfinity)
12330     {
12331         result = -D.infinity;
12332         return ExceptionFlags.none;
12333     }
12334 
12335     flags |= coefficientAdjust(cr, er, cvt!T(DataType!D.max), sr, mode);
12336     return result.adjustedPack(cvt!(DataType!D)(cr), er, sr, precision, mode, flags);
12337 }
12338 
12339 ExceptionFlags decimalProd(D)(const(D)[] x, out D result, out int scale, const int precision, const RoundingMode mode)
12340 if (isDecimal!D)
12341 {
12342     ExceptionFlags flags;
12343     alias T = MakeUnsigned!(D.sizeof * 16);
12344     DataType!D cx;
12345     T cxx, cr;
12346     int ex, er;
12347     bool sx, sr;
12348 
12349     result = 0;
12350     scale = 0;
12351     bool hasInfinity;
12352     bool hasZero;
12353     bool infinitySign;
12354     bool zeroSign;
12355     size_t i = 0;
12356     while (i < x.length)
12357     {
12358         if (isSignaling(x[i]))
12359         {
12360             result = D.nan;
12361             return ExceptionFlags.invalidOperation;
12362         }
12363 
12364         if (isNaN(x[i]))
12365         {
12366             result = D.nan;
12367             return ExceptionFlags.none;
12368         }
12369 
12370         if (isInfinity(x[i]))
12371         {
12372             hasInfinity = true;
12373             infinitySign = cast(bool)(signbit(x[i]));
12374             ++i;
12375             break;
12376         }
12377 
12378         if (isZero(x[i]))
12379         {
12380             hasZero = true;
12381             zeroSign = cast(bool)(signbit(x[i]));
12382             ++i;
12383             break;
12384         }
12385 
12386         sx = x.unpack(cx, ex);
12387         cxx = cx;
12388         flags |= coefficientMul(cr, er, sr, cxx, ex, sx, mode);
12389         er -= cappedAdd(scale, er);
12390         ++i;
12391 
12392         if (flags & ExceptionFlags.overflow)
12393             break;
12394     }
12395 
12396     while (i < x.length)
12397     {
12398         //infinity or overflow detected
12399         if (isSignaling(x[i]))
12400         {
12401             result = D.nan;
12402             return ExceptionFlags.invalidOperation;
12403         }
12404 
12405         if (isNaN(x[i]))
12406         {
12407             result = D.nan;
12408             return ExceptionFlags.none;
12409         }
12410 
12411         if (isInfinity(x[i]))
12412         {
12413             hasInfinity = true;
12414             infinitySign ^= cast(bool)(signbit(x[i]));
12415         }
12416         else if (isZero(x[i]))
12417         {
12418             hasZero = true;
12419             zeroSign ^= cast(bool)(signbit(x[i]));
12420         }
12421         else
12422         {
12423             zeroSign ^= cast(bool)(signbit(x[i]));
12424         }
12425 
12426 
12427         ++i;
12428     }
12429 
12430     if (hasInfinity & hasZero)
12431     {
12432         result = D.nan;
12433         return ExceptionFlags.invalidOperation;
12434     }
12435 
12436     if (hasInfinity)
12437     {
12438         result = infinitySign ? -D.infinity : D.infinity;
12439         return ExceptionFlags.none;
12440     }
12441 
12442     if (hasZero)
12443     {
12444         result = zeroSign ? -D.zero : D.zero;
12445         return ExceptionFlags.none;
12446     }
12447 
12448     flags |= coefficientAdjust(cr, er, cvt!T(DataType!D.max), sr, mode);
12449     return result.adjustedPack(cvt!(DataType!D)(cr), er, sr, precision, mode, flags);
12450 }
12451 
12452 ExceptionFlags decimalProdSum(D)(const(D)[] x, const(D)[] y, out D result, out int scale, const int precision, const RoundingMode mode)
12453 if (isDecimal!D)
12454 {
12455     size_t len = x.length;
12456     if (len > y.length)
12457         len = y.length;
12458 
12459     bool hasInfinity;
12460     bool hasZero;
12461 
12462     bool infinitySign;
12463 
12464     bool invalidSum;
12465 
12466     alias T = MakeUnsigned!(D.sizeof * 16);
12467     DataType!D cx, cy;
12468     T cxx, cyy, cr;
12469     int ex, ey, er;
12470     bool sx, sy, sr;
12471 
12472     size_t i = 0;
12473     while (i < len)
12474     {
12475         if (isSignaling(x[i]) || isSignaling(y[i]))
12476         {
12477             result = D.nan;
12478             return ExceptionFlags.invalidOperation;
12479         }
12480 
12481         if (isNaN(x[i]) || isNaN(y[i]))
12482         {
12483             result = D.nan;
12484             return ExceptionFlags.none;
12485         }
12486 
12487         if (isInfinity(x[i]))
12488         {
12489             if (isInfinity(y[i]) && signbit(x) != signbit(y))
12490             {
12491                 invalidSum = true;
12492                 ++i;
12493                 break;
12494             }
12495 
12496             hasInfinity = true;
12497             infinitySign = cast(bool)signbit(x[i]);
12498             ++i;
12499             break;
12500         }
12501 
12502         if (isInfinity(y[i]))
12503         {
12504             hasInfinity = true;
12505             infinitySign = cast(bool)signbit(x[i]);
12506             ++i;
12507             break;
12508         }
12509 
12510         if (x[i] == -y[i])
12511         {
12512             hasZero = true;
12513             ++i;
12514             break;
12515         }
12516         sx = x[i].unpack(cx, ex);
12517         sy = y[i].unpack(cy, ey);
12518         cxx = cx; cyy = cy;
12519         flags |= coefficientAdd(cx, ex, sx, cy, ey, sy, mode);
12520         flags |= coefficientMul(cr, er, sr, cx, ex, sx, mode);
12521         er -= cappedAdd(scale, er);
12522         ++i;
12523         if (flags & ExceptionFlags.overflow)
12524             break;
12525         if (flags & ExceptionFlags.underflow)
12526             break;
12527         
12528     }
12529 
12530     while (i < len)
12531     {
12532         //inf, zero or overflow, underflow, invalidSum;
12533         if (isSignaling(x[i]) || isSignaling(y[i]))
12534         {
12535             result = D.nan;
12536             return ExceptionFlags.invalidOperation;
12537         }
12538 
12539         if (isNaN(x[i]) || isNaN(y[i]))
12540         {
12541             result = D.nan;
12542             return ExceptionFlags.none;
12543         }
12544 
12545         if (isInfinity(x[i]))
12546         {
12547             if (isInfinity(y[i]) && signbit(x) != signbit(y))
12548                 invalidSum = true;
12549             else
12550             {
12551                 hasInfinity = true;
12552                 infinitySign ^= cast(bool)signbit(x[i]);
12553             }
12554         }
12555         else if (isInfinity(y[i]))
12556         {
12557             hasInfinity = true;
12558             infinitySign ^= cast(bool)signbit(y[i]);
12559         }
12560         else if (x[i] == -y[i])
12561             hasZero = true;
12562         ++i;
12563     }
12564 
12565     if (invalidSum)
12566     {
12567         result = D.nan;
12568         return ExceptionFlags.invalidOperation;
12569     }
12570 
12571     if (hasInfinity & hasZero)
12572     {
12573         result = D.nan;
12574         return ExceptionFlags.invalidOperation;
12575     }
12576 
12577     if (hasInfinity)
12578     {
12579         result = infinitySign ? -D.infinity : D.infinity;
12580         return ExceptionFlags.none;
12581     }
12582 
12583     if (hasZero)
12584     {
12585         result = D.zero;
12586         return ExceptionFlags.none;
12587     }
12588 
12589     flags |= coefficientAdjust(cr, er, cvt!T(DataType!D.max), sr, mode);
12590     return result.adjustedPack(cvt!(DataType!D)(cr), er, sr, precision, mode, flags);
12591 }
12592 
12593 ExceptionFlags decimalProdDiff(D)(const(D)[] x, const(D)[] y, out D result, out int scale, const int precision, const RoundingMode mode)
12594 if (isDecimal!D)
12595 {
12596     size_t len = x.length;
12597     if (len > y.length)
12598         len = y.length;
12599 
12600     bool hasInfinity;
12601     bool hasZero;
12602 
12603     bool infinitySign;
12604 
12605     bool invalidSum;
12606 
12607     alias T = MakeUnsigned!(D.sizeof * 16);
12608     DataType!D cx, cy;
12609     T cxx, cyy, cr;
12610     int ex, ey, er;
12611     bool sx, sy, sr;
12612 
12613     size_t i = 0;
12614     while (i < len)
12615     {
12616         if (isSignaling(x[i]) || isSignaling(y[i]))
12617         {
12618             result = D.nan;
12619             return ExceptionFlags.invalidOperation;
12620         }
12621 
12622         if (isNaN(x[i]) || isNaN(y[i]))
12623         {
12624             result = D.nan;
12625             return ExceptionFlags.none;
12626         }
12627 
12628         if (isInfinity(x[i]))
12629         {
12630             if (isInfinity(y[i]) && signbit(x) != signbit(y))
12631             {
12632                 invalidSum = true;
12633                 ++i;
12634                 break;
12635             }
12636 
12637             hasInfinity = true;
12638             infinitySign = cast(bool)signbit(x[i]);
12639             ++i;
12640             break;
12641         }
12642 
12643         if (isInfinity(y[i]))
12644         {
12645             hasInfinity = true;
12646             infinitySign = cast(bool)signbit(x[i]);
12647             ++i;
12648             break;
12649         }
12650 
12651         if (x[i] == y[i])
12652         {
12653             hasZero = true;
12654             ++i;
12655             break;
12656         }
12657         sx = x[i].unpack(cx, ex);
12658         sy = y[i].unpack(cy, ey);
12659         cxx = cx; cyy = cy;
12660         flags |= coefficientSub(cx, ex, sx, cy, ey, sy, mode);
12661         flags |= coefficientMul(cr, er, sr, cx, ex, sx, mode);
12662         er -= cappedAdd(scale, er);
12663         ++i;
12664         if (flags & ExceptionFlags.overflow)
12665             break;
12666         if (flags & ExceptionFlags.underflow)
12667             break;
12668 
12669     }
12670 
12671     while (i < len)
12672     {
12673         //inf, zero or overflow, underflow, invalidSum;
12674         if (isSignaling(x[i]) || isSignaling(y[i]))
12675         {
12676             result = D.nan;
12677             return ExceptionFlags.invalidOperation;
12678         }
12679 
12680         if (isNaN(x[i]) || isNaN(y[i]))
12681         {
12682             result = D.nan;
12683             return ExceptionFlags.none;
12684         }
12685 
12686         if (isInfinity(x[i]))
12687         {
12688             if (isInfinity(y[i]) && signbit(x) != signbit(y))
12689                 invalidSum = true;
12690             else
12691             {
12692                 hasInfinity = true;
12693                 infinitySign ^= cast(bool)signbit(x[i]);
12694             }
12695         }
12696         else if (isInfinity(y[i]))
12697         {
12698             hasInfinity = true;
12699             infinitySign ^= cast(bool)signbit(y[i]);
12700         }
12701         else if (x[i] == y[i])
12702             hasZero = true;
12703         ++i;
12704     }
12705 
12706     if (invalidSum)
12707     {
12708         result = D.nan;
12709         return ExceptionFlags.invalidOperation;
12710     }
12711 
12712     if (hasInfinity & hasZero)
12713     {
12714         result = D.nan;
12715         return ExceptionFlags.invalidOperation;
12716     }
12717 
12718     if (hasInfinity)
12719     {
12720         result = infinitySign ? -D.infinity : D.infinity;
12721         return ExceptionFlags.none;
12722     }
12723 
12724     if (hasZero)
12725     {
12726         result = D.zero;
12727         return ExceptionFlags.none;
12728     }
12729 
12730     flags |= coefficientAdjust(cr, er, cvt!T(DataType!D.max), sr, mode);
12731     return result.adjustedPack(cvt!(DataType!D)(cr), er, sr, precision, mode, flags);
12732 }
12733 
12734 ExceptionFlags decimalPoly(D1, D2, D)(auto const ref D1 x, const(D2)[] a, out D result)
12735 if (isDecimal!(D1, D2) && is(D: CommonDecimal!(D1, D2)))
12736 {
12737     if (!a.length)
12738     {
12739         result = 0;
12740         return ExceptionFlags.none;
12741     }
12742     ptrdiff_t i = a.length - 1;
12743     D result = a[i];
12744     ExceptionFlags flags;
12745     while (--i >= 0)
12746     {
12747         flags |= decimalMul(result, x);
12748         flags |= decimalAdd(result, a[i]);
12749     }
12750     return flags;    
12751 }
12752 
12753 /* ****************************************************************************************************************** */
12754 /* COEFFICIENT ARITHMETIC                                                                                            */       
12755 /* ****************************************************************************************************************** */
12756 //divPow10          - inexact
12757 //mulPow10          - overflow
12758 //coefficientAdjust - inexact, overflow, underflow
12759 //coefficientExpand - none
12760 //coefficientShrink - inexact
12761 //coefficientAdd    - inexact, overflow
12762 //coefficientMul    - inexact, overflow, underflow
12763 //coefficientDiv    - inexact, overflow, underflow, div0
12764 //coefficientMod    - inexact, overflow, underflow, invalid
12765 //coefficientFMA    - inexact, overflow, underflow
12766 //coefficientCmp    - none
12767 //coefficientEqu    - none
12768 //coefficientSqr    - inexact, overflow, underflow
12769 
12770 
12771 
12772 
12773 ExceptionFlags exp2to10(RoundingMode mode = RoundingMode.implicit, U)(ref U coefficient, ref int exponent, const bool isNegative)
12774 {
12775     enum maxMultiplicable = U.max / 5U;
12776 
12777     enum hibit = U(1U) << (U.sizeof * 8 - 1);
12778     ExceptionFlags flags;
12779     auto e5 = -exponent;
12780 
12781     if (e5 > 0)
12782     {
12783         auto tz = ctz(coefficient);
12784         if (tz)
12785         {
12786             auto shift = e5 > tz ? tz : e5;
12787             e5 -= shift;
12788             exponent += shift;
12789             coefficient >>= shift;
12790         }
12791 
12792         while (e5 > 0)
12793         {
12794             --e5;
12795             if (coefficient < maxMultiplicable)
12796                 coefficient *= 5U;
12797             else
12798             {
12799                 ++exponent;
12800                 bool mustRound = cast(bool)(coefficient & 1U);
12801                 coefficient >>= 1;
12802                 if (mustRound)
12803                 {
12804                     flags = ExceptionFlags.inexact;
12805                     static if (mode == RoundingMode.tiesToAway)
12806                     {
12807                         ++coefficient;
12808                     }
12809                     else static if (mode == RoundingMode.tiesToEven)
12810                     {
12811                         if ((coefficient & 1U))
12812                             ++coefficient;
12813                     }
12814                     else static if (mode == RoundingMode.towardNegative)
12815                     {
12816                         if (isNegative)
12817                             ++coefficient;
12818                     }
12819                     else static if (mode == RoundingMode.towardPositive)
12820                     {
12821                         if (!isNegative)
12822                             ++coefficient;
12823                     }
12824                 }           
12825             }
12826         }
12827     }
12828 
12829     if (e5 < 0)
12830     {
12831         auto lz = clz(coefficient);
12832         if (lz)
12833         {
12834             auto shift = -e5 > lz ? lz : -e5;
12835             exponent -= shift;
12836             e5 += shift;
12837             coefficient <<= shift;
12838         }
12839 
12840         while (e5 < 0)
12841         {
12842             ++e5;
12843             if (coefficient & hibit)
12844             {
12845                 auto r = divrem(coefficient, 5U);
12846                 if (r)
12847                 {
12848                     flags = ExceptionFlags.inexact;
12849                     static if (mode == RoundingMode.towardNegative)
12850                     {
12851                         if (isNegative)
12852                             ++coefficient;
12853                     }
12854                     else static if (mode == RoundingMode.towardPositive)
12855                     {
12856                         if (!isNegative)
12857                             ++coefficient;
12858                     }
12859                     else static if (mode == RoundingMode.tiesToAway || mode == RoundingMode.tiesToEven)
12860                     {
12861                         if (r >= 3U)
12862                             ++coefficient;
12863                     }
12864                 }
12865             }
12866             else
12867             {
12868                 coefficient <<= 1;
12869                 --exponent;
12870             }
12871         }
12872  
12873     }
12874 
12875     return flags;
12876 }
12877 
12878 ExceptionFlags exp10to2(RoundingMode mode = RoundingMode.implicit, U)(ref U coefficient, ref int exponent, const bool isNegative)
12879 {
12880     enum maxMultiplicable = U.max / 5U;
12881 
12882     enum hibit = U(1U) << (U.sizeof * 8 - 1);
12883     ExceptionFlags flags;
12884     auto e5 = exponent;
12885 
12886     if (e5 > 0)
12887     {
12888         while (e5 > 0)
12889         {
12890             
12891             if (coefficient < maxMultiplicable)
12892             {
12893                 --e5;
12894                 coefficient *= 5U;
12895             }
12896             else
12897             {
12898                 ++exponent;
12899                 bool mustRound = cast(bool)(coefficient & 1U);
12900                 coefficient >>= 1;
12901                 if (mustRound)
12902                 {
12903                     flags = ExceptionFlags.inexact;
12904                     static if (mode == RoundingMode.tiesToAway)
12905                     {
12906                         ++coefficient;
12907                     }
12908                     else static if (mode == RoundingMode.tiesToEven)
12909                     {
12910                         if ((coefficient & 1U))
12911                             ++coefficient;
12912                     }
12913                     else static if (mode == RoundingMode.towardNegative)
12914                     {
12915                         if (isNegative)
12916                             ++coefficient;
12917                     }
12918                     else static if (mode == RoundingMode.towardPositive)
12919                     {
12920                         if (!isNegative)
12921                             ++coefficient;
12922                     }
12923                 }           
12924             }
12925         }
12926     }
12927 
12928     if (e5 < 0)
12929     {
12930         while (e5 < 0)
12931         {
12932             
12933             if (coefficient & hibit)
12934             {          
12935                 ++e5;
12936                 auto r = divrem(coefficient, 5U);
12937                 if (r)
12938                 {
12939                     flags = ExceptionFlags.inexact;
12940                     static if (mode == RoundingMode.towardNegative)
12941                     {
12942                         if (isNegative)
12943                             ++coefficient;
12944                     }
12945                     else static if (mode == RoundingMode.towardPositive)
12946                     {
12947                         if (!isNegative)
12948                             ++coefficient;
12949                     }
12950                     else static if (mode == RoundingMode.tiesToAway || mode == RoundingMode.tiesToEven)
12951                     {
12952                         if (r >= 3U)
12953                             ++coefficient;
12954                     }
12955                 }
12956             }
12957             else
12958             {
12959                 coefficient <<= 1;
12960                 --exponent;
12961             }
12962         }
12963 
12964     }
12965 
12966     return flags;
12967 }
12968 
12969 unittest
12970 {
12971     uint cx = 3402823;
12972     int ex = 32;
12973 
12974    
12975     exp10to2!(RoundingMode.towardZero)(cx, ex, false);
12976 }
12977 
12978 //divides coefficient by 10^power
12979 //inexact
12980 @safe pure nothrow @nogc
12981 ExceptionFlags divpow10(T)(ref T coefficient, const int power, const bool isNegative, const RoundingMode mode)
12982 if (isAnyUnsigned!T)
12983 in
12984 {
12985     assert (power >= 0);
12986 }
12987 body
12988 {
12989     Unqual!T remainder;
12990 
12991     if (coefficient == 0U)
12992         return ExceptionFlags.none;
12993 
12994     if (power == 0)
12995         return ExceptionFlags.none;
12996 
12997     if (power >= pow10!T.length)
12998     {
12999         remainder = coefficient;
13000         coefficient = 0U;
13001     }
13002     else
13003         remainder = divrem(coefficient, pow10!T[power]);
13004 
13005     if (remainder == 0U)
13006         return ExceptionFlags.none;
13007 
13008     immutable half = power >= pow10!T.length ? T.max : pow10!T[power] >>> 1;
13009     final switch (mode)
13010     {
13011         case RoundingMode.tiesToEven:
13012             if (remainder > half)
13013                 ++coefficient;
13014             else if ((remainder == half) && ((coefficient & 1U) != 0U))
13015                 ++coefficient;
13016             break;
13017         case RoundingMode.tiesToAway:
13018             if (remainder >= half)
13019                 ++coefficient;
13020             break;
13021         case RoundingMode.towardNegative:
13022             if (isNegative)
13023                 ++coefficient;
13024             break;
13025         case RoundingMode.towardPositive:
13026             if (!isNegative)
13027                 ++coefficient;
13028             break;
13029         case RoundingMode.towardZero:
13030             break;
13031     } 
13032 
13033     return ExceptionFlags.inexact;
13034 }
13035 
13036 unittest
13037 {
13038     struct S {uint c; int p; bool n; RoundingMode r; uint outc; bool inexact; }
13039 
13040     S[] test = 
13041     [
13042         S (0, 0, false, RoundingMode.tiesToAway, 0, false),
13043         S (0, 0, false, RoundingMode.tiesToEven, 0, false),
13044         S (0, 0, false, RoundingMode.towardNegative, 0, false),
13045         S (0, 0, false, RoundingMode.towardPositive, 0, false),
13046         S (0, 0, false, RoundingMode.towardZero, 0, false),
13047 
13048         S (10, 1, false, RoundingMode.tiesToAway, 1, false),
13049         S (10, 1, false, RoundingMode.tiesToEven, 1, false),
13050         S (10, 1, false, RoundingMode.towardNegative, 1, false),
13051         S (10, 1, false, RoundingMode.towardPositive, 1, false),
13052         S (10, 1, false, RoundingMode.towardZero, 1, false),
13053 
13054         S (13, 1, false, RoundingMode.tiesToAway, 1, true),
13055         S (13, 1, false, RoundingMode.tiesToEven, 1, true),
13056         S (13, 1, false, RoundingMode.towardNegative, 1, true),
13057         S (13, 1, false, RoundingMode.towardPositive, 2, true),
13058         S (13, 1, false, RoundingMode.towardZero, 1, true),
13059 
13060         S (13, 1, true, RoundingMode.tiesToAway, 1, true),
13061         S (13, 1, true, RoundingMode.tiesToEven, 1, true),
13062         S (13, 1, true, RoundingMode.towardNegative, 2, true),
13063         S (13, 1, true, RoundingMode.towardPositive, 1, true),
13064         S (13, 1, true, RoundingMode.towardZero, 1, true),
13065 
13066 
13067         S (15, 1, false, RoundingMode.tiesToAway, 2, true),
13068         S (15, 1, false, RoundingMode.tiesToEven, 2, true),
13069         S (15, 1, false, RoundingMode.towardNegative, 1, true),
13070         S (15, 1, false, RoundingMode.towardPositive, 2, true),
13071         S (15, 1, false, RoundingMode.towardZero, 1, true),
13072 
13073         S (15, 1, true, RoundingMode.tiesToAway, 2, true),
13074         S (15, 1, true, RoundingMode.tiesToEven, 2, true),
13075         S (15, 1, true, RoundingMode.towardNegative, 2, true),
13076         S (15, 1, true, RoundingMode.towardPositive, 1, true),
13077         S (15, 1, true, RoundingMode.towardZero, 1, true),
13078 
13079 
13080         S (18, 1, false, RoundingMode.tiesToAway, 2, true),
13081         S (18, 1, false, RoundingMode.tiesToEven, 2, true),
13082         S (18, 1, false, RoundingMode.towardNegative, 1, true),
13083         S (18, 1, false, RoundingMode.towardPositive, 2, true),
13084         S (18, 1, false, RoundingMode.towardZero, 1, true),
13085 
13086         S (18, 1, true, RoundingMode.tiesToAway, 2, true),
13087         S (18, 1, true, RoundingMode.tiesToEven, 2, true),
13088         S (18, 1, true, RoundingMode.towardNegative, 2, true),
13089         S (18, 1, true, RoundingMode.towardPositive, 1, true),
13090         S (18, 1, true, RoundingMode.towardZero, 1, true),
13091 
13092         S (25, 1, false, RoundingMode.tiesToAway, 3, true),
13093         S (25, 1, false, RoundingMode.tiesToEven, 2, true),
13094         S (25, 1, false, RoundingMode.towardNegative, 2, true),
13095         S (25, 1, false, RoundingMode.towardPositive, 3, true),
13096         S (25, 1, false, RoundingMode.towardZero, 2, true),
13097 
13098         S (25, 1, true, RoundingMode.tiesToAway, 3, true),
13099         S (25, 1, true, RoundingMode.tiesToEven, 2, true),
13100         S (25, 1, true, RoundingMode.towardNegative, 3, true),
13101         S (25, 1, true, RoundingMode.towardPositive, 2, true),
13102         S (25, 1, true, RoundingMode.towardZero, 2, true),
13103     ];
13104 
13105     foreach (ref s; test)
13106     {
13107         auto flags = divpow10(s.c, s.p, s.n, s.r);
13108         assert (s.c == s.outc);
13109         assert (flags == ExceptionFlags.inexact ? s.inexact : !s.inexact);
13110 
13111     }
13112 
13113 }
13114 
13115 //multiplies coefficient by 10^^power, returns possible overflow
13116 //overflow
13117 @safe pure nothrow @nogc
13118 ExceptionFlags mulpow10(T)(ref T coefficient, const int power)
13119 if (isAnyUnsigned!T)
13120 in 
13121 {
13122     assert (power >= 0);
13123 }
13124 body
13125 {
13126     if (coefficient == 0U || power == 0)
13127         return ExceptionFlags.none;   
13128     if (power >= pow10!T.length || coefficient > maxmul10!T[power])
13129         return ExceptionFlags.overflow;
13130     coefficient *= pow10!T[power];
13131     return ExceptionFlags.none;   
13132 }
13133 
13134 
13135 //adjusts coefficient to fit minExponent <= exponent <= maxExponent and coefficient <= maxCoefficient
13136 //inexact, overflow, underflow
13137 @safe pure nothrow @nogc
13138 ExceptionFlags coefficientAdjust(T)(ref T coefficient, ref int exponent, const int minExponent, const int maxExponent, 
13139                                     const T maxCoefficient, const bool isNegative, const RoundingMode mode)
13140 if (isAnyUnsigned!T)
13141 in
13142 {
13143     assert (minExponent <= maxExponent);
13144     assert (maxCoefficient >= 1U);
13145 }
13146 body
13147 {
13148     bool overflow;
13149     ExceptionFlags flags;
13150 
13151     if (coefficient == 0U)
13152     {
13153         if (exponent < minExponent)
13154             exponent = minExponent;      
13155         if (exponent > maxExponent)
13156             exponent = maxExponent;
13157         return ExceptionFlags.none;
13158     }
13159 
13160     if (exponent < minExponent)
13161     {
13162         //increase exponent, divide coefficient 
13163         immutable dif = minExponent - exponent;
13164         flags = divpow10(coefficient, dif, isNegative, mode);
13165         if (coefficient == 0U)
13166             flags |= ExceptionFlags.underflow | ExceptionFlags.inexact;
13167         exponent += dif;
13168     }
13169     else if (exponent > maxExponent)
13170     {
13171         //decrease exponent, multiply coefficient
13172         immutable dif = exponent - maxExponent;
13173         flags = mulpow10(coefficient, dif);
13174         if (flags & ExceptionFlags.overflow)
13175             return flags | ExceptionFlags.inexact;
13176         else
13177             exponent -= dif;
13178     }
13179 
13180     if (coefficient > maxCoefficient)
13181     {
13182         //increase exponent, divide coefficient
13183         auto dif = prec(coefficient) - prec(maxCoefficient);
13184         if (!dif) 
13185             dif = 1;
13186         flags |= divpow10(coefficient, dif, isNegative, mode);
13187         if (coefficient > maxCoefficient)
13188         {
13189             //same precision but greater
13190             flags |= divpow10(coefficient, 1, isNegative, mode);         
13191             ++dif;
13192         }
13193         if (cappedAdd(exponent, dif) != dif)
13194         {
13195             if (coefficient != 0U)
13196                 return flags | ExceptionFlags.overflow | ExceptionFlags.inexact;
13197         }
13198     }
13199 
13200 
13201     //coefficient became 0, dont' bother with exponents;
13202     if (coefficient == 0U)
13203     {
13204         exponent = 0;
13205         if (exponent < minExponent)
13206             exponent = minExponent;      
13207         if (exponent > maxExponent)
13208             exponent = maxExponent;
13209         return flags;
13210     }
13211 
13212     if (exponent < minExponent)
13213         return flags | ExceptionFlags.underflow | ExceptionFlags.inexact;
13214     
13215     if (exponent > maxExponent)
13216         return flags | ExceptionFlags.overflow | ExceptionFlags.inexact;
13217 
13218 
13219     return flags;
13220 
13221 }
13222 
13223 
13224 //adjusts coefficient to fit minExponent <= exponent <= maxExponent
13225 //inexact, overflow, underflow
13226 @safe pure nothrow @nogc
13227 ExceptionFlags coefficientAdjust(T)(ref T coefficient, ref int exponent, const int minExponent, const int maxExponent, 
13228                                     const bool isNegative, const RoundingMode mode)
13229 if (isAnyUnsigned!T)
13230 in
13231 {
13232     assert (minExponent <= maxExponent);
13233 }
13234 body
13235 {
13236     return coefficientAdjust(coefficient, exponent, minExponent, maxExponent, T.max, isNegative, mode);
13237 }
13238 
13239 //adjusts coefficient to fit coefficient in maxCoefficient
13240 //inexact, overflow, underflow
13241 @safe pure nothrow @nogc
13242 ExceptionFlags coefficientAdjust(T)(ref T coefficient, ref int exponent, const T maxCoefficient, 
13243                                     const bool isNegative, const RoundingMode mode)
13244 if (isAnyUnsigned!T)
13245 in
13246 {
13247     assert (maxCoefficient >= 1U);
13248 }
13249 body
13250 {
13251     return coefficientAdjust(coefficient, exponent, int.min, int.max, maxCoefficient, isNegative, mode);
13252 }
13253 
13254 
13255 //adjusts coefficient to fit minExponent <= exponent <= maxExponent and to fit precision
13256 //inexact, overflow, underflow
13257 @safe pure nothrow @nogc
13258 ExceptionFlags coefficientAdjust(T)(ref T coefficient, ref int exponent, const int minExponent, const int maxExponent, 
13259                                   const int precision, const bool isNegative, const RoundingMode mode)
13260 if (isAnyUnsigned!T)
13261 in
13262 {
13263     assert (precision >= 1);
13264     assert (minExponent <= maxExponent);
13265 }
13266 body
13267 {
13268     immutable maxCoefficient = precision >= pow10!T.length ? T.max : pow10!T[precision] - 1U;
13269     auto flags = coefficientAdjust(coefficient, exponent, minExponent, maxExponent, maxCoefficient, isNegative, mode);
13270     if (flags & (ExceptionFlags.overflow | ExceptionFlags.underflow))
13271         return flags;
13272 
13273     immutable p = prec(coefficient);
13274     if (p > precision)
13275     {
13276         flags |= divpow10(coefficient, 1, isNegative, mode);
13277         if (coefficient == 0U)
13278         {
13279             exponent = 0;
13280             if (exponent < minExponent)
13281                 exponent = minExponent;      
13282             if (exponent > maxExponent)
13283                 exponent = maxExponent;
13284             return flags;
13285         }
13286         else
13287         {
13288             if (cappedAdd(exponent, 1) != 1)
13289                 return flags | ExceptionFlags.overflow;
13290             if (exponent > maxExponent)
13291                 return flags | ExceptionFlags.overflow;
13292         }
13293     }
13294     return flags;
13295 }
13296 
13297 //adjusts coefficient to fit precision
13298 //inexact, overflow, underflow
13299 @safe pure nothrow @nogc
13300 ExceptionFlags coefficientAdjust(T)(ref T coefficient, ref int exponent, 
13301                                     const int precision, const bool isNegative, const RoundingMode mode)
13302 if (isAnyUnsigned!T)
13303 in
13304 {
13305     assert (precision >= 1);
13306 }
13307 body
13308 {
13309     return coefficientAdjust(coefficient, exponent, int.min, int.max, precision, isNegative, mode);
13310 }
13311 
13312 //shrinks coefficient by cutting out terminating zeros and increasing exponent
13313 @safe pure nothrow @nogc
13314 void coefficientShrink(T)(ref T coefficient, ref int exponent)
13315 {
13316     if (coefficient > 9U && (coefficient & 1U) == 0U && exponent < int.max)
13317     {
13318         Unqual!T c = coefficient;
13319         Unqual!T r = divrem(c, 10U);
13320         int e = exponent + 1;
13321         while (r == 0U)
13322         {
13323             coefficient = c;
13324             exponent = e;
13325             if ((c & 1U) || e == int.max)
13326                 break;
13327             r = divrem(c, 10U);
13328             ++e;
13329         }
13330     }
13331 }
13332 
13333 //expands cx with 10^^target if possible
13334 @safe pure nothrow @nogc
13335 void coefficientExpand(T)(ref T cx, ref int ex, ref int target)
13336 in
13337 {
13338     assert (cx);
13339     assert (target > 0);
13340 }
13341 body
13342 {
13343     int px = prec(cx);
13344     int maxPow10 = cast(int)pow10!T.length - px;
13345     auto maxCoefficient = maxmul10!T[$ - px];
13346     if (cx > maxCoefficient)
13347         --maxPow10;
13348     auto pow = target > maxPow10 ? maxPow10 : target;    
13349     pow = cappedSub(ex, pow);
13350     if (pow)
13351     {
13352         cx *= pow10!T[pow];
13353         target -= pow;
13354     }
13355 }
13356 
13357 //expands cx to maximum available digits
13358 @safe pure nothrow @nogc
13359 void coefficientExpand(T)(ref T cx, ref int ex)
13360 {
13361     if (cx)
13362     {
13363         int px = prec(cx);
13364         int pow = cast(int)pow10!T.length - px;
13365         auto maxCoefficient = maxmul10!T[$ - px];
13366         if (cx > maxCoefficient)
13367             --pow;
13368         pow = cappedSub(ex, pow);
13369         if (pow)
13370         {
13371             cx *= pow10!T[pow];
13372         }
13373     }
13374 }
13375 
13376 unittest
13377 {
13378     struct S {uint x1; int ex1; int target1; uint x2; int ex2; int target2; }
13379     S[] tests =
13380     [
13381         S(1, 0, 4, 10000, -4, 0),
13382         S(429496729, 0, 1, 4294967290, -1, 0),
13383         S(429496739, 0, 1, 429496739, 0, 1),
13384         S(429496729, 0, 2, 4294967290, -1, 1),
13385         S(42949672, 0, 1, 429496720, -1, 0),
13386         S(42949672, 0, 2, 4294967200, -2, 0),
13387         S(42949672, 0, 3, 4294967200, -2, 1),
13388     ];
13389 
13390     foreach( s; tests)
13391     {
13392         coefficientExpand(s.x1, s.ex1, s.target1);
13393         assert (s.x1 == s.x2);
13394         assert (s.ex1 == s.ex2);
13395         assert (s.target1 == s.target2);
13396     }
13397 }
13398 
13399 //shrinks cx with 10^^target
13400 //inexact
13401 @safe pure nothrow @nogc
13402 ExceptionFlags coefficientShrink(T)(ref T cx, ref int ex, const bool sx, ref int target, const RoundingMode mode)
13403 in
13404 {
13405     assert (cx);
13406     assert (target > 0);
13407 }
13408 body
13409 {
13410     auto pow = cappedAdd(ex, target);
13411     if (pow)
13412     {
13413         auto flags = divpow10(cx, pow, sx, mode);
13414         target -= pow;
13415         return flags;
13416     }
13417     else
13418         return ExceptionFlags.none;
13419 }
13420 
13421 //inexact
13422 @safe pure nothrow @nogc
13423 ExceptionFlags exponentAlign(T)(ref T cx, ref int ex, const bool sx, ref T cy, ref int ey, const bool sy, const RoundingMode mode)
13424 out
13425 {
13426     assert (ex == ey);
13427 }
13428 body
13429 {
13430     if (ex == ey)
13431         return ExceptionFlags.none;
13432 
13433     if (!cx)
13434     {
13435         ex = ey;
13436         return ExceptionFlags.none;
13437     }
13438     
13439     if (!cy)
13440     {
13441         ey = ex;
13442         return ExceptionFlags.none;
13443     }
13444 
13445     ExceptionFlags flags;
13446     int dif = ex - ey;
13447     if (dif > 0) //ex > ey
13448     {
13449         coefficientExpand(cx, ex, dif);
13450         if (dif)
13451             flags = coefficientShrink(cy, ey, sy, dif, mode);
13452         assert(!dif);
13453     }
13454     else //ex < ey
13455     {
13456         dif = -dif;
13457         coefficientExpand(cy, ey, dif);
13458         if (dif)
13459             flags = coefficientShrink(cx, ex, sx, dif, mode);
13460         assert(!dif);
13461     }
13462     return flags;
13463 }
13464 
13465 //inexact, overflow, underflow
13466 @safe pure nothrow @nogc
13467 ExceptionFlags coefficientAdd(T)(ref T cx, ref int ex, ref bool sx, const T cy, const int ey, const bool sy, const RoundingMode mode)
13468 {
13469     if (!cy)
13470         return ExceptionFlags.none;
13471     
13472     if (!cx)
13473     {
13474         cx = cy;
13475         ex = ey;
13476         sx = sy;
13477         return ExceptionFlags.none;
13478     }
13479 
13480     Unqual!T cyy = cy;
13481     int eyy = ey;
13482 
13483     //if cx or cy underflowed, don't propagate
13484     auto flags = exponentAlign(cx, ex, sx, cyy, eyy, sy, mode) & ~ExceptionFlags.underflow;
13485 
13486     if (!cyy)
13487     {
13488         //cx is very big
13489         switch (mode)
13490         {
13491             case RoundingMode.towardPositive:
13492                 if (!sx && !sy)
13493                     ++cx;
13494                 else if (sx && !sy)
13495                     --cx;
13496                 break;
13497             case RoundingMode.towardNegative:
13498                 if (sx && sy)
13499                     ++cx;
13500                 else if (!sx && sy)
13501                     --cx;
13502                 break;
13503             case RoundingMode.towardZero:
13504                 if (sx != sy)
13505                     --cx;
13506                 break;
13507             default:
13508                 break;
13509         }
13510 
13511 
13512         //if (sx == sy)
13513         //{
13514         //    //cx + 0.0.....001 => cx0000.0....001
13515         //    if (sx && mode == RoundingMode.towardNegative)
13516         //        ++cx;
13517         //    else if (!sx && mode == RoundingMode.towardPositive)
13518         //        ++cx;
13519         //}
13520         //else
13521         //{
13522         //    //cx - 0.0.....001 => (cx-1)9999.9...999
13523         //    if (sx && mode == RoundingMode.towardZero)
13524         //        --cx;
13525         //    else if (!sx && mode == RoundingMode.towardNegative)
13526         //        --cx;
13527         //}
13528     }
13529     
13530     if (!cx)
13531     {
13532         //cy is very big, cx is tiny 
13533         switch (mode)
13534         {
13535             case RoundingMode.towardPositive:
13536                 if (!sx && !sy)
13537                     ++cyy;
13538                 else if (!sx && sy)
13539                     --cyy;
13540                 break;
13541             case RoundingMode.towardNegative:
13542                 if (sx && sy)
13543                     ++cyy;
13544                 else if (sx && !sy)
13545                     --cyy;
13546                 break;
13547             case RoundingMode.towardZero:
13548                 if (sx != sy)
13549                     --cyy;
13550                 break;
13551             default:
13552                 break;
13553         }
13554 
13555 
13556         //if (sx == sy)
13557         //{
13558         //    //0.0.....001 + cyy => cyy0000.0....001
13559         //    if (sy && mode == RoundingMode.towardNegative)
13560         //        ++cyy;
13561         //    else if (!sy && mode == RoundingMode.towardPositive)
13562         //        ++cyy;
13563         //}
13564         //else
13565         //{
13566         //    //0.0.....001 - cyy => -(cyy + 0.0.....001)
13567         //    if (sy && mode == RoundingMode.towardZero)
13568         //        --cyy;
13569         //    else if (!sy && mode == RoundingMode.towardNegative)
13570         //        --cyy;
13571         //}
13572     }
13573 
13574     if (sx == sy)
13575     {
13576         Unqual!T savecx = cx;
13577         auto carry = xadd(cx, cyy);
13578         if (carry)
13579         {
13580             if (!cappedAdd(ex, 1))
13581                 return flags | ExceptionFlags.overflow;
13582             flags |= divpow10(savecx, 1, sx, mode);
13583             flags |= divpow10(cyy, 1, sy, mode);
13584             cx = savecx + cyy;
13585         }
13586         return flags;
13587     }
13588     else
13589     {
13590         if (cx == cyy)
13591         {
13592             cx = T(0U);
13593             ex = 0;
13594             sx = false;
13595             return flags;
13596         }
13597 
13598         if (cx > cyy)
13599             cx -= cyy;
13600         else
13601         {
13602             cx = cyy - cx;
13603             sx = sy;
13604         }
13605         return flags;
13606     }
13607 }
13608 
13609 unittest
13610 {
13611     int x = 0;
13612 }
13613 
13614 //inexact, overflow, underflow
13615 @safe pure nothrow @nogc
13616 ExceptionFlags coefficientMul(T)(ref T cx, ref int ex, ref bool sx, const T cy, const int ey, const bool sy, const RoundingMode mode)
13617 {
13618     if (!cy || !cy)
13619     {
13620         cx = T(0U);
13621         sx ^= sy;
13622         return ExceptionFlags.none;
13623     }
13624 
13625     auto r = xmul(cx, cy);
13626     
13627     if (cappedAdd(ex, ey) != ey)
13628         return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow;
13629 
13630     sx ^= sy;
13631 
13632     if (r > T.max)
13633     {
13634         auto px = prec(r);
13635         auto pm = prec(T.max) - 1;
13636         auto flags = divpow10(r, px - pm, sx, mode);
13637         if (cappedAdd(ex, px - pm) != px - pm)
13638             return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow;
13639         cx = cvt!T(r);
13640         return flags;
13641     }
13642     else
13643     {
13644         cx = cvt!T(r);
13645         return ExceptionFlags.none;
13646     }
13647 }
13648 
13649 //div0, overflow, underflow
13650 @safe pure nothrow @nogc
13651 ExceptionFlags coefficientDiv(T)(ref T cx, ref int ex, ref bool sx, const T cy, const int ey, const bool sy, const RoundingMode mode)
13652 {
13653     if (!cy)
13654     {
13655         sx ^= sy;
13656         return ExceptionFlags.divisionByZero;
13657     }
13658 
13659     if (!cx)
13660     {
13661         ex = 0;
13662         sx ^= sy;
13663         return ExceptionFlags.none;
13664     }
13665 
13666     if (cy == 1U)
13667     {
13668         if (cappedSub(ex, ey) != ey)
13669             return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow;
13670         sx ^= sy;
13671         return ExceptionFlags.none;
13672     }
13673 
13674     Unqual!T savecx = cx;
13675     sx ^= sy;
13676     auto r = divrem(cx, cy);
13677     if (!r)
13678     {
13679         if (cappedSub(ex, ey) != ey)
13680            return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow; 
13681         return ExceptionFlags.none;
13682     }
13683 
13684     alias U = MakeUnsigned!(T.sizeof * 16);
13685     U cxx = savecx;
13686     auto px = prec(savecx);
13687     auto pm = prec(U.max) - 1;
13688     mulpow10(cxx, pm - px);
13689     auto scale = pm - px - cappedSub(ex, pm - px);
13690     auto s = divrem(cxx, cy);
13691     ExceptionFlags flags;
13692     if (s)
13693     {
13694         immutable half = cy >>> 1;
13695         final switch (mode)
13696         {
13697             case RoundingMode.tiesToEven:
13698                 if (s > half)
13699                     ++cxx;
13700                 else if ((s == half) && ((cxx & 1U) == 0U))
13701                     ++cxx;
13702                 break;
13703             case RoundingMode.tiesToAway:
13704                 if (s >= half)
13705                     ++cxx;
13706                 break;
13707             case RoundingMode.towardNegative:
13708                 if (sx)
13709                     ++cxx;
13710                 break;
13711             case RoundingMode.towardPositive:
13712                 if (!sx)
13713                     ++cxx;
13714                 break;
13715             case RoundingMode.towardZero:
13716                 break;
13717         }
13718         flags = ExceptionFlags.inexact;
13719     }
13720 
13721     flags |= coefficientAdjust(cxx, ex, U(T.max), sx, mode);
13722 
13723     if (flags & ExceptionFlags.underflow)
13724     {
13725         cx = 0U;
13726         ex = 0U;
13727         return flags;
13728     }
13729 
13730     if (flags & ExceptionFlags.overflow)
13731         return flags;
13732 
13733     
13734     cx = cast(T)cxx;
13735     if (cappedSub(ex, ey) != ey)
13736         flags |= ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow; 
13737     if (cappedSub(ex, scale) != scale)
13738         flags |= ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow; 
13739 
13740     return flags;
13741 }
13742 
13743 //inexact, overflow, underflow
13744 @safe pure nothrow @nogc
13745 ExceptionFlags coefficientFMA(T)(ref T cx, ref int ex, ref bool sx, const T cy, const int ey, const bool sy, const T cz, const int ez, const bool sz, const RoundingMode mode)
13746 {
13747     if (!cx || !cy)
13748     {
13749         cx = cz;
13750         ex = ez;
13751         sx = sz;
13752         return ExceptionFlags.none;
13753     }
13754 
13755     if (!cz)
13756         return coefficientMul(cx, ex, sx, cy, ey, sy, mode);
13757 
13758     
13759     if (cappedAdd(ex, ey) != ey)
13760         return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow;
13761     auto m = xmul(cx, cy);
13762     sx ^= sy;
13763 
13764     typeof(m) czz = cz;
13765     auto flags = coefficientAdd(m, ex, sx, czz, ez, sz, mode);
13766     auto pm = prec(m);
13767     auto pmax = prec(T.max) - 1;
13768     if (pm > pmax)
13769     {
13770         flags |= divpow10(m, pm - pmax, sx, mode);
13771         if (cappedAdd(ex, pm - pmax) != pm - pmax)
13772             return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow;
13773     }
13774     cx = cast(Unqual!T)m;
13775     return flags;
13776 }
13777 
13778 //inexact
13779 @safe pure nothrow @nogc
13780 ExceptionFlags coefficientRound(T)(ref T cx, ref int ex, const bool sx, const RoundingMode mode)
13781 {
13782     if (ex < 0)
13783     {
13784         auto flags = divpow10(cx, -ex, sx, mode);
13785         ex = 0;
13786         return flags;
13787     }
13788     return ExceptionFlags.none;
13789 }
13790 
13791 //inexact, overflow, underflow
13792 @safe pure nothrow @nogc
13793 ExceptionFlags coefficientMod(T)(ref T cx, ref int ex, ref bool sx, const T cy, const int ey, const bool sy, const RoundingMode mode)
13794 {
13795     if (!cy)
13796         return ExceptionFlags.invalidOperation;
13797     Unqual!T rcx = cx;
13798     int rex = ex;
13799     bool rsx = sx;
13800     coefficientDiv(rcx, rex, rsx, cy, ey, sy, mode);   //16
13801     coefficientRound(rcx, rex, rsx, mode);             //00
13802     coefficientMul(rcx, rex, rsx, cy, ey, sy, mode);   //16
13803     return coefficientAdd(cx, ex, sx, rcx, rex, !rsx, mode);  //0
13804 }
13805 
13806 unittest
13807 {
13808 
13809 }
13810 
13811 @safe pure nothrow @nogc
13812 int coefficientCmp(T)(const T cx, const int ex, const bool sx, const T cy, const int ey, const bool sy)
13813 {
13814     if (!cx)
13815         return cy ? (sy ? 1 : -1) : 0;
13816     if (!cy)
13817         return sx ? -1 : 1;
13818     
13819     if (sx && !sy)
13820         return -1;
13821     else if (!sx && sy)
13822         return 1;
13823     else
13824         return sx ? -coefficientCmp(cx, ex, cy, ey) : coefficientCmp(cx, ex, cy, ey);
13825 }
13826 
13827 @safe pure nothrow @nogc
13828 int coefficientCmp(T)(const T cx, const int ex, const T cy, const int ey)
13829 {
13830     if (!cx)
13831         return cy ? -1 : 0;
13832     if (!cy)
13833         return 1;
13834 
13835     int px = prec(cx);
13836     int py = prec(cy);
13837 
13838     if (px > py)
13839     {
13840         int eyy = ey - (px - py);
13841         if (ex > eyy)
13842             return 1;
13843         if (ex < eyy)
13844             return -1;
13845         Unqual!T cyy = cy;
13846         mulpow10(cyy, px - py);
13847         if (cx > cyy)
13848             return 1;
13849         if (cx < cyy)
13850             return -1;
13851         return 0;
13852     }
13853 
13854     if (px < py)
13855     {
13856         int exx = ex - (py - px);
13857         if (exx > ey)
13858             return 1;
13859         if (exx < ey)
13860             return -1;
13861         Unqual!T cxx = cx;
13862         mulpow10(cxx, py - px);       
13863         if (cxx > cy)
13864             return 1;
13865         if (cxx < cy)
13866             return -1;
13867         return 0;
13868     }
13869 
13870     if (ex > ey)
13871         return 1;
13872     if (ex < ey)
13873         return -1;
13874 
13875     if (cx > cy)
13876         return 1;
13877     else if (cx < cy)
13878         return -1;
13879     return 0;
13880     
13881 }
13882 
13883 @safe pure nothrow @nogc
13884 bool coefficientEqu(T)(const T cx, const int ex, const bool sx, const T cy, const int ey, const bool sy)
13885 {
13886     if (!cx)
13887         return cy == 0U;
13888 
13889     if (sx != sy)
13890         return false;
13891     else
13892     {
13893         int px = prec(cx);
13894         int py = prec(cy);
13895 
13896         if (px > py)
13897         {     
13898             int eyy = ey - (px - py);
13899             if (ex != eyy)
13900                 return false;
13901             Unqual!T cyy = cy;
13902             mulpow10(cyy, px - py);
13903             return cx == cyy;
13904         }
13905 
13906         if (px < py)
13907         {
13908             int exx = ex - (py - px);
13909             if (exx != ey)
13910                 return false;
13911             Unqual!T cxx = cx;
13912             mulpow10(cxx, py - px);       
13913             return cxx == cy;
13914         }
13915 
13916         return cx == cy && ex == ey;
13917     }
13918 }
13919 
13920 @safe pure nothrow @nogc
13921 bool coefficientApproxEqu(T)(const T cx, const int ex, const bool sx, const T cy, const int ey, const bool sy)
13922 {
13923     //same as coefficientEqu, but we ignore the last digit if coefficient > 10^max
13924     //this is useful in convergence loops to not become infinite
13925     if (!cx)
13926         return cy == 0U;
13927 
13928     if (sx != sy)
13929         return false;
13930     else
13931     {
13932         int px = prec(cx);
13933         int py = prec(cy);
13934 
13935         if (px > py)
13936         {     
13937             int eyy = ey - (px - py);
13938             if (ex != eyy)
13939                 return false;
13940             Unqual!T cyy = cy;
13941             mulpow10(cyy, px - py);
13942             if (cx > pow10!T[$ - 2])
13943                 return cx >= cy ? cx - cy < 10U : cy - cx < 10U;
13944             return cx == cy;
13945         }
13946 
13947         if (px < py)
13948         {
13949             int exx = ex - (py - px);
13950             if (exx != ey)
13951                 return false;
13952             Unqual!T cxx = cx;
13953             mulpow10(cxx, py - px);  
13954             if (cxx > pow10!T[$ - 2])
13955                 return cxx >= cy ? cxx - cy < 10U : cy - cxx < 10U;
13956             return cx == cy;
13957         }
13958 
13959         if (cx > pow10!T[$ - 2])
13960             return cx >= cy ? cx - cy < 10U : cy - cx < 10U;
13961 
13962         return cx == cy;
13963     }
13964 }
13965 
13966 //inexact, overflow, underflow
13967 @safe pure nothrow @nogc
13968 ExceptionFlags coefficientSqr(T)(ref T cx, ref int ex, const RoundingMode mode)
13969 {
13970     if (!cx)
13971     {
13972         cx = T(0U);
13973         ex = 0;
13974         return ExceptionFlags.none;
13975     }
13976 
13977     auto r = xsqr(cx);
13978 
13979     int ey = ex;
13980     if (cappedAdd(ex, ey) != ey)
13981         return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow;
13982 
13983 
13984     if (r > T.max)
13985     {
13986         auto px = prec(r);
13987         auto pm = prec(T.max) - 1;
13988         auto flags = divpow10(r, px - pm, false, mode);
13989         if (cappedAdd(ex, px - pm) != px - pm)
13990             return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow;
13991         cx = cvt!T(r);
13992         return flags;
13993     }
13994     else
13995     {
13996         cx = cvt!T(r);
13997         return ExceptionFlags.none;
13998     }
13999 }
14000 
14001 //inexact, underflow
14002 @safe pure nothrow @nogc
14003 ExceptionFlags coefficientSqrt(T)(ref T cx, ref int ex)
14004 {
14005     // Newton-Raphson: x = (x + n/x) / 2;
14006     if (!cx)
14007     {
14008         cx = 0U;
14009         ex = 0;
14010         return ExceptionFlags.none;
14011     }
14012 
14013     alias U = MakeUnsigned!(T.sizeof * 16);
14014 
14015     U cxx = cx;
14016     ExceptionFlags flags;
14017 
14018     //we need full precision
14019     coefficientExpand(cxx, ex);
14020 
14021     if (ex & 1)
14022     {
14023         //exponent is odd, make it even
14024         flags = divpow10(cxx, 1, false, RoundingMode.implicit);
14025         ++ex;
14026     }
14027 
14028     ex /= 2;
14029     bool inexact = decimal.integrals.sqrt(cxx);
14030     flags |= coefficientAdjust(cxx, ex, cvt!U(T.max), false, RoundingMode.implicit);
14031     cx = cast(T)cxx;
14032     return inexact ? flags | ExceptionFlags.inexact : flags;
14033 }
14034 
14035 //inexact, underflow
14036 @safe pure nothrow @nogc
14037 ExceptionFlags coefficientRSqrt(T)(ref T cx, ref int ex)
14038 {
14039     bool sx = false;
14040     if (!cx)
14041         return ExceptionFlags.divisionByZero;
14042     Unqual!T cy = cx; int ey = ex;
14043     auto flags = coefficientSqrt(cy, ey);
14044     if (flags & ExceptionFlags.underflow)
14045         return ExceptionFlags.overflow;
14046     cx = 1U;
14047     ex = 0;
14048     return flags | coefficientDiv(cx, ex, sx, cy, ey, false, RoundingMode.implicit);
14049 }
14050 
14051 @safe pure nothrow @nogc
14052 ExceptionFlags coefficientCbrt(T)(ref T cx, ref int ex)
14053 {
14054     // Newton-Raphson: x = (2x + N/x2)/3
14055 
14056     if (!cx)
14057     {
14058         cx = 0U;
14059         ex = 0;
14060         return ExceptionFlags.none;
14061     }
14062 
14063     alias U = MakeUnsigned!(T.sizeof * 16);
14064 
14065     U cxx = cx;
14066     ExceptionFlags flags;
14067 
14068     //we need full precision
14069     coefficientExpand(cxx, ex);
14070 
14071     auto r = ex % 3;
14072     if (r)
14073     {
14074         //exponent is not divisible by 3, make it
14075         flags = divpow10(cxx, 3 - r, false, RoundingMode.implicit);
14076         ex += 3 - r;
14077     }
14078 
14079     ex /= 3;
14080     bool inexact = decimal.integrals.cbrt(cxx);
14081     flags |= coefficientAdjust(cxx, ex, cvt!U(T.max), false, RoundingMode.implicit);
14082     cx = cast(T)cxx;
14083     return inexact ? flags | ExceptionFlags.inexact : flags; 
14084 }
14085 
14086 @safe pure nothrow @nogc
14087 ExceptionFlags coefficientHypot(T)(ref T cx, ref int ex, auto const ref T cy, const int ey)
14088 {
14089     Unqual!T cyy = cy;
14090     int eyy = ey;
14091     bool sx;
14092     auto flags = coefficientSqr(cx, ex, RoundingMode.implicit);
14093     flags |= coefficientSqr(cyy, eyy, RoundingMode.implicit);
14094     flags |= coefficientAdd(cx, ex, sx, cyy, eyy, false, RoundingMode.implicit);
14095     return flags | coefficientSqrt(cx, ex);
14096 }
14097 
14098 @safe pure nothrow @nogc
14099 ExceptionFlags coefficientExp(T)(ref T cx, ref int ex, ref bool sx)
14100 {
14101     //e^x = 1 + x + x2/2! + x3/3! + x4/4! ...
14102     //to avoid overflow and underflow:
14103     //x^n/n! = (x^(n-1)/(n-1)! * x/n
14104     
14105     ExceptionFlags flags;
14106 
14107     //save x for repeated multiplication
14108     immutable Unqual!T cxx = cx;
14109     immutable exx = ex;
14110     immutable sxx = sx;
14111 
14112     //shadow value
14113     Unqual!T cy;
14114     int ey = 0;
14115     bool sy = false;
14116 
14117     Unqual!T cf = cx;
14118     int ef = ex;
14119     bool sf = sx;
14120 
14121     if (coefficientAdd(cx, ex, sx, T(1U), 0, false, RoundingMode.implicit) & ExceptionFlags.overflow)
14122         return ExceptionFlags.overflow;
14123     
14124     
14125     Unqual!T n = 1U;
14126 
14127     do
14128     {
14129         cy = cx;
14130         ey = ex;
14131         sy = sx;
14132 
14133         Unqual!T cp = cxx;
14134         int ep = exx;
14135         bool sp = sxx;
14136 
14137         coefficientDiv(cp, ep, sp, ++n, 0, false, RoundingMode.implicit);
14138         coefficientMul(cf, ef, sf, cp, ep, sp, RoundingMode.implicit);
14139         coefficientAdd(cx, ex, sx, cf, ef, sf, RoundingMode.implicit);
14140 
14141     } 
14142     while (!coefficientApproxEqu(cx, ex, sx, cy, ey, sy));
14143 
14144     return ExceptionFlags.inexact;
14145     
14146 }
14147 
14148 @safe pure nothrow @nogc
14149 ExceptionFlags coefficientLog(T)(ref T cx, ref int ex, ref bool sx)
14150 {
14151     
14152     assert(!sx); //only positive
14153     assert(cx);
14154 
14155     //ln(coefficient * 10^exponent) = ln(coefficient) + exponent * ln(10);
14156 
14157     static if (is(T:uint))
14158     {
14159         immutable uint ce = 2718281828U;
14160         immutable int ee = -9;
14161         immutable uint cl = 2302585093U;
14162         immutable int el = -9;
14163 
14164     }
14165     else static if (is(T:ulong))
14166     {
14167         immutable ulong ce = 2718281828459045235UL;
14168         immutable int ee = -18;
14169         immutable ulong cl = 2302585092994045684UL;
14170         immutable int el = -18;
14171     }
14172     else static if (is(T:uint128))
14173     {
14174         immutable uint128 ce = uint128("271828182845904523536028747135266249776");
14175         immutable int ee = -38;
14176         immutable uint128 cl = uint128("230258509299404568401799145468436420760");
14177         immutable int el = -38;
14178     }
14179     else
14180         static assert(0);
14181 
14182     //ln(x) = ln(n*e) = ln(n) + ln(e);
14183     //we divide x by e to find out how many times (n) we must add ln(e) = 1
14184     //ln(x + 1) taylor series works in the interval (-1 .. 1]
14185     //so our taylor series is valid for x in (0 .. 2]
14186 
14187     //save exponent for later
14188     int exponent = ex;
14189     ex = 0;
14190     
14191     enum one = T(1U);
14192     enum two = T(2U);
14193 
14194     Unqual!T n = 0U;
14195     bool ss = false;
14196 
14197     immutable aaa = cx;
14198 
14199     while (coefficientCmp(cx, ex, false, two, 0, false) >= 0)
14200     {
14201         coefficientDiv(cx, ex, sx, ce, ee, false, RoundingMode.implicit);
14202         ++n;
14203     }
14204 
14205     coefficientDiv(cx, ex, sx, ce, ee, false, RoundingMode.implicit);
14206     ++n;
14207 
14208     //ln(x) = (x - 1) - [(x - 1)^2]/2 + [(x - 1)^3]/3 - ....
14209 
14210     //initialize our result to x - 1;
14211     coefficientAdd(cx, ex, sx, one, 0, true, RoundingMode.implicit);
14212      
14213     //store cx in cxm1, this will be used for repeated multiplication
14214     //we negate the sign to alternate between +/-
14215     Unqual!T cxm1 = cx;
14216     int exm1 = ex;
14217     bool sxm1 = !sx;
14218 
14219     //shadow
14220     Unqual!T cy;
14221     int ey;
14222     bool sy;
14223 
14224     Unqual!T cd = cxm1;
14225     int ed = exm1;
14226     bool sd = !sxm1;
14227 
14228     Unqual!T i = 2U;
14229 
14230     do
14231     {
14232         cy = cx;
14233         ey = ex;
14234         sy = sx;
14235 
14236         coefficientMul(cd, ed, sd, cxm1, exm1, sxm1, RoundingMode.implicit);
14237         
14238         Unqual!T cf = cd;
14239         int ef = ed;
14240         bool sf = sd;
14241 
14242         coefficientDiv(cf, ef, sf, i++, 0, false, RoundingMode.implicit);
14243         coefficientAdd(cx, ex, sx, cf, ef, sf, RoundingMode.implicit);
14244 
14245         //writefln("%10d %10d %10d %10d %10d %10d", cx, ex, cy, ey, cx - cy, i);
14246     }
14247     while (!coefficientApproxEqu(cx, ex, sx, cy, ey, sy));
14248    
14249 
14250 
14251     coefficientAdd(cx, ex, sx, n, 0, false, RoundingMode.implicit);
14252     
14253     if (exponent != 0)
14254     {
14255         sy = exponent < 0;
14256         cy = sy ? cast(uint)(-exponent) : cast(uint)(exponent);
14257         ey = 0;
14258         coefficientMul(cy, ey, sy, cl, el, false, RoundingMode.implicit);
14259         coefficientAdd(cx, ex, sx, cy, ey, sy, RoundingMode.implicit);
14260     }
14261 
14262     //iterations 
14263     //decimal32 min:         15, max:         48 avg:      30.03
14264     //decimal64 min:         30, max:        234 avg:     149.25    
14265 
14266 
14267     return ExceptionFlags.inexact;
14268 }
14269 
14270 @safe pure nothrow @nogc
14271 ExceptionFlags coefficientAtanh(T)(ref T cx, ref int ex, ref bool sx)
14272 {
14273     //1/2*ln[(1 + x)/(1 - x)]
14274 
14275     assert (coefficientCmp(cx, ex, sx, T(1U), 0, true) > 0);
14276     assert (coefficientCmp(cx, ex, sx, T(1U), 0, false) < 0);
14277 
14278     //1/2*ln[(1 + x)/(1 - x)]
14279 
14280     Unqual!T cm1 = cx;
14281     int em1 = ex;
14282     bool sm1 = !sx;
14283     coefficientAdd(cm1, em1, sm1, T(1U), 0, false, RoundingMode.implicit);
14284     coefficientAdd(cx, ex, sx, T(1U), 0, false, RoundingMode.implicit);
14285     coefficientDiv(cx, ex, sx, cm1, em1, sm1, RoundingMode.implicit);
14286     coefficientLog(cx, ex, sx);
14287     coefficientMul(cx, ex, sx, T(5U), -1, false, RoundingMode.implicit);
14288     return ExceptionFlags.inexact;
14289 }
14290 
14291 //caps angle to -2π ... +2π
14292 @safe pure nothrow @nogc
14293 ExceptionFlags coefficientCapAngle(T)(ref T cx, ref int ex, ref bool sx)
14294 {
14295     if (coefficientCmp(cx, ex, Constants!T.c2π, Constants!T.e2π) > 0)
14296     {
14297         Unqual!T cy = cx;
14298         int ey = ex;
14299         bool sy = sx;
14300         coefficientMul(cy, ey, sy, Constants!T.c1_2π, Constants!T.e1_2π, false, RoundingMode.towardZero);
14301         coefficientRound(cy, ey, sy, RoundingMode.towardZero);
14302         coefficientMul(cy, ey, sy, Constants!T.c2π, Constants!T.e2π, false, RoundingMode.towardZero);
14303         coefficientAdd(cx, ex, sx, cy, ey, !sy, RoundingMode.towardZero);
14304         return ExceptionFlags.inexact;
14305     }
14306     return ExceptionFlags.none;
14307 }
14308 
14309 //caps angle to -π/2  .. +π/2 
14310 @safe pure nothrow @nogc
14311 ExceptionFlags coefficientCapAngle(T)(ref T cx, ref int ex, ref bool sx, out int quadrant)
14312 {
14313     quadrant = 1;
14314     auto flags = coefficientCapAngle(cx, ex, sx);
14315     if (coefficientCmp(cx, ex, Constants!T.c2π, Constants!T.e2π) > 0)
14316     {
14317         Unqual!T cy = cx;
14318         int ey = ex;
14319         bool sy = sx;
14320         coefficientMul(cy, ey, sy, Constants!T.c2_π, Constants!T.e2_π, false, RoundingMode.towardZero);
14321         coefficientRound(cy, ey, sy, RoundingMode.towardZero);
14322         quadrant = cast(uint)(cy % 4U) + 1;
14323         coefficientMul(cy, ey, sy, Constants!T.cπ_2, Constants!T.eπ_2, false, RoundingMode.towardZero);
14324         coefficientAdd(cx, ex, sx, cy, ey, !sy, RoundingMode.towardZero);
14325         flags |= ExceptionFlags.inexact;
14326     }
14327     return flags;
14328 }
14329 
14330 @safe pure nothrow @nogc
14331 ExceptionFlags coefficientSinQ(T)(ref T cx, ref int ex, ref bool sx)
14332 {
14333     //taylor series: sin(x) = x - x^3/3! + x^5/5! - x^7/7! ...
14334     
14335     Unqual!T cx2 = cx; int ex2 = ex; bool sx2 = true;
14336     coefficientSqr(cx2, ex2, RoundingMode.implicit);
14337 
14338     Unqual!T cy; int ey; bool sy;
14339     Unqual!T cf = cx; int ef = ex; bool sf = sx;
14340 
14341     Unqual!T n = 2U;
14342 
14343     do
14344     {
14345         cy = cx;
14346         ey = ex;
14347         sy = sx;
14348         
14349         coefficientMul(cf, ef, sf, cx2, ex2, sx2, RoundingMode.implicit);
14350         coefficientDiv(cf, ef, sf, n++, 0, false, RoundingMode.implicit);
14351         coefficientDiv(cf, ef, sf, n++, 0, false, RoundingMode.implicit);
14352         coefficientAdd(cx, ex, sx, cf, ef, sf, RoundingMode.implicit);
14353         //writefln("%10d %10d %10d %10d", cx, ex, cy, ey);
14354        // writefln("%016x%016x %10d %016x%016x %10d", cx.hi, cx.lo, ex, cy.hi, cy.lo, ey);
14355     }
14356     while (!coefficientApproxEqu(cx, ex, sx, cy, ey, sy));
14357     return ExceptionFlags.inexact;
14358 }
14359 
14360 unittest
14361 {
14362     ulong cx = 11000000000000000855UL;
14363     int ex = -19;
14364     bool sx;
14365 
14366     coefficientSinQ(cx, ex, sx);
14367 
14368     //writefln("%35.34f", sin(decimal128("1.1000000000000000855000000000000000")));
14369     //writefln("%35.34f", decimal128(1.1));
14370 }
14371 
14372 @safe pure nothrow @nogc
14373 ExceptionFlags coefficientCosQ(T)(ref T cx, ref int ex, ref bool sx)
14374 {
14375     //taylor series: cos(x) = 1 - x^2/2! + x^4/4! - x^6/6! ...
14376 
14377     Unqual!T cx2 = cx; int ex2 = ex; bool sx2 = true;
14378     coefficientSqr(cx2, ex2, RoundingMode.implicit);
14379 
14380     cx = 1U;
14381     ex = 0;
14382     sx = false;
14383     Unqual!T cy; int ey; bool sy;
14384     Unqual!T cf = cx; int ef = ex; bool sf = sx;
14385 
14386     Unqual!T n = 1U;
14387 
14388     do
14389     {
14390         cy = cx;
14391         ey = ex;
14392         sy = sx;
14393 
14394         coefficientMul(cf, ef, sf, cx2, ex2, sx2, RoundingMode.implicit);
14395         coefficientDiv(cf, ef, sf, n++, 0, false, RoundingMode.implicit);
14396         coefficientDiv(cf, ef, sf, n++, 0, false, RoundingMode.implicit);
14397         coefficientAdd(cx, ex, sx, cf, ef, sf, RoundingMode.implicit);
14398         //writefln("%10d %10d %10d %10d", cx, ex, cy, ey);
14399     }
14400     while (!coefficientApproxEqu(cx, ex, sx, cy, ey, sy));
14401     return ExceptionFlags.inexact;
14402 }
14403 
14404 @safe pure nothrow @nogc
14405 ExceptionFlags coefficientSinCosQ(T)(const T cx, const int ex, const bool sx,
14406                                      out T csin, out int esin, out bool ssin,
14407                                      out T ccos, out int ecos, out bool scos)
14408 {
14409     csin = cx; esin = ex; ssin = sx;
14410     ccos = 1U; ecos = 0; scos = false;
14411     Unqual!T cs, cc; int es, ec; bool ss, sc;
14412 
14413     Unqual!T cf = cx; int ef = ex; bool sf = sx;
14414     Unqual!T n = 2U;
14415     do
14416     {
14417         cs = csin; es = esin; ss = ssin;
14418         cc = ccos; ec = ecos; sc = scos;
14419         coefficientMul(cf, ef, sf, cx, ex, !sx, RoundingMode.implicit);
14420         coefficientDiv(cf, ef, sf, n++, 0, false, RoundingMode.implicit);
14421         coefficientAdd(ccos, ecos, scos, cf, ef, sf, RoundingMode.implicit);
14422         coefficientMul(cf, ef, sf, cx, ex, sx, RoundingMode.implicit);
14423         coefficientDiv(cf, ef, sf, n++, 0, false, RoundingMode.implicit);
14424         coefficientAdd(csin, esin, ssin, cf, ef, sf, RoundingMode.implicit);
14425         //writefln("%10d %10d %10d %10d %10d %10d %10d %10d", csin, esin, cs, es, ccos, ecos, cc, ec);
14426     }
14427     while(!coefficientApproxEqu(csin, esin, ssin, cs, es, ss) &&
14428           !coefficientApproxEqu(ccos, ecos, scos, cc, ec, sc));
14429 
14430     return ExceptionFlags.inexact;
14431 }
14432 
14433 @safe pure nothrow @nogc
14434 ExceptionFlags coefficientCapAtan(T)(ref T cx, ref int ex, ref bool sx, out T reductions)
14435 {
14436     //half angle formula: atan(x/2) = 2 * atan(x/(1 + sqrt(1 +x^^2))))
14437     //reduce x = x / (sqrt(x * x + 1) + 1);
14438 
14439     reductions = 0U;
14440     while (coefficientCmp(cx, ex, T(1U), 0) >= 0)
14441     {
14442         Unqual!T cy = cx; int ey = ex; bool sy = false;
14443         coefficientSqr(cy, ey, RoundingMode.implicit);
14444         coefficientAdd(cy, ey, sy, T(1U), 0, false, RoundingMode.implicit);
14445         coefficientSqrt(cy, ey);
14446         coefficientAdd(cy, ey, sy, T(1U), 0, false, RoundingMode.implicit);
14447         coefficientDiv(cx, ex, sx, cy, ey, false, RoundingMode.implicit);
14448         ++reductions;
14449     }
14450 
14451     return ExceptionFlags.inexact;
14452 }
14453 
14454 @safe pure nothrow @nogc
14455 ExceptionFlags coefficientAtan(T)(ref T cx, ref int ex, bool sx)
14456 {
14457     //taylor series:
14458     //atan(x) = x - x^3/3 + x^5/5 - x^7/7 ...
14459 
14460     Unqual!T cx2 = cx; int ex2 = ex;
14461     coefficientSqr(cx2, ex2, RoundingMode.implicit);
14462 
14463     Unqual!T cy; int ey; bool sy;
14464 
14465     Unqual!T cxx = cx; int exx = ex; bool sxx = sx;
14466 
14467     Unqual!T n = 3U;
14468 
14469     do
14470     {
14471         cy = cx;
14472         ey = ex;
14473         sy = sx;
14474 
14475         coefficientMul(cxx, exx, sxx, cx2, ex2, true, RoundingMode.implicit);
14476         
14477         Unqual!T cf = cxx;
14478         int ef = exx;
14479         bool sf = sxx;
14480 
14481         coefficientDiv(cf, ef, sf, n, 0, false, RoundingMode.implicit);
14482         coefficientAdd(cx, ex, sx, cf, ef, sf, RoundingMode.implicit);
14483         n += 2U;
14484 
14485     }
14486     while (!coefficientApproxEqu(cx, ex, sx, cy, ey, sy));
14487     return ExceptionFlags.inexact;
14488 }
14489 
14490 
14491 struct Constants(T)
14492 {
14493     static if (is(T:uint))
14494     {
14495         enum uint       c1_2π       = 1591549431U;
14496         enum int        e1_2π       = -10;
14497         enum uint       c2π         = 628318531U;
14498         enum int        e2π         = -8;
14499         enum uint       c2_π        = 636619772U;
14500         enum int        e2_π        = -9;
14501         enum uint       cπ_2        = 1570796327U;
14502         enum int        eπ_2        = -9;
14503         enum uint       chalf       = 5;
14504         enum int        ehalf       = -1;
14505         enum uint       cthird      = 3333333333;
14506         enum int        ethird      = -10;
14507         enum uint       ce          = 2718281828U;
14508         enum int        ee          = -9;
14509         enum uint       cln10       = 2302585093U;
14510         enum int        eln10       = -9;
14511     }
14512     else static if (is(T:ulong))
14513     {
14514         enum ulong      c1_2π       = 15915494309189533577UL;
14515         enum int        e1_2π       = -20;
14516         enum ulong      c2π         = 6283185307179586477UL;
14517         enum int        e2π         = -18;
14518         enum ulong      c2_π        = 6366197723675813431UL;
14519         enum int        e2_π        = -19;
14520         enum ulong      cπ_2        = 15707963267948966192UL;
14521         enum int        eπ_2        = -19;
14522         enum ulong      chalf       = 5;
14523         enum int        ehalf       = -1;
14524         enum ulong      cthird      = 3333333333333333333UL;
14525         enum int        ethird      = -19;
14526         enum ulong      ce          = 2718281828459045235UL;
14527         enum int        ee          = -18;
14528         enum ulong      cln10       = 2302585092994045684UL;
14529         enum int        eln10       = -18;
14530     }
14531     else static if (is(T:uint128))
14532     {
14533         enum uint128    c1_2π       = uint128("159154943091895335768883763372514362034");
14534         enum int        e1_2π       = -39;
14535         enum uint128    c2π         = uint128("62831853071795864769252867665590057684");
14536         enum int        e2π         = -37;
14537         enum uint128    c2_π        = uint128("63661977236758134307553505349005744814");
14538         enum int        e2_π        = -38;
14539         enum uint128    cπ_2        = uint128("157079632679489661923132169163975144210");
14540         enum int        eπ_2        = -38;
14541         enum uint128    chalf       = 5U;
14542         enum int        ehalf       = -1;
14543         enum uint128    cthird      = uint128("333333333333333333333333333333333333333");
14544         enum int        ethird      = -39;
14545         enum uint128    ce          = uint128("271828182845904523536028747135266249776");
14546         enum int        ee          = -38;
14547         enum uint128    cln10       = uint128("230258509299404568401799145468436420760");
14548         enum int        eln10       = -38;
14549     }
14550     else
14551         static assert(0);
14552 }
14553 
14554 enum
14555 {
14556     s_e             = "2.7182818284590452353602874713526625",
14557     s_pi            = "3.1415926535897932384626433832795029",
14558     s_pi_2          = "1.5707963267948966192313216916397514",
14559     s_pi_4          = "0.7853981633974483096156608458198757",
14560     s_m_1_pi        = "0.3183098861837906715377675267450287",
14561     s_m_2_pi        = "0.6366197723675813430755350534900574",
14562     s_m_2_sqrtpi    = "1.1283791670955125738961589031215452",
14563     s_sqrt2         = "1.4142135623730950488016887242096981",
14564     s_sqrt1_2       = "0.7071067811865475244008443621048490",
14565     s_ln10          = "2.3025850929940456840179914546843642",
14566     s_log2t         = "3.3219280948873623478703194294893902",
14567     s_log2e         = "1.4426950408889634073599246810018921",
14568     s_log2          = "0.3010299956639811952137388947244930",
14569     s_log10e        = "0.4342944819032518276511289189166051",
14570     s_ln2           = "0.6931471805599453094172321214581766",
14571 
14572     s_sqrt3         = "1.7320508075688772935274463415058723",
14573     s_m_sqrt3       = "0.5773502691896257645091487805019574",
14574     s_pi_3          = "1.0471975511965977461542144610931676",
14575     s_pi_6          = "0.5235987755982988730771072305465838",
14576 
14577     s_sqrt2_2       = "0.7071067811865475244008443621048490",
14578     s_sqrt3_2       = "0.8660254037844386467637231707529361",
14579     s_5pi_6         = "2.6179938779914943653855361527329190",
14580     s_3pi_4         = "2.3561944901923449288469825374596271",
14581     s_2pi_3         = "2.0943951023931954923084289221863352",
14582     s_onethird      = "0.3333333333333333333333333333333333",
14583     s_twothirds     = "0.6666666666666666666666666666666667",
14584     s_5_6           = "0.8333333333333333333333333333333333",
14585     s_1_6           = "0.1666666666666666666666666666666667",
14586     s_m_1_2pi       = "0.1591549430918953357688837633725144",
14587     s_pi2           = "6.2831853071795864769252867665590058",
14588 }
14589 
14590 struct IEEECompliant
14591 {
14592     string name;
14593     int page;
14594 }
14595 
14596 D parse(D, R)(ref R range)
14597 if (isInputRange!R && isSomeChar!(ElementType!R) && isDecimal!D)
14598 {
14599     Unqual!D result;
14600     auto flags = parse(range, result, D.realPrecision(DecimalControl.precision), DecimalControl.rounding);
14601     if (flags)
14602         DecimalControl.raiseFlags(flags);
14603 }
14604 
14605 //10 bit encoding
14606 @safe pure nothrow @nogc
14607 private uint packDPD(const uint d1, const uint d2, const uint d3)
14608 {
14609     uint x = ((d1 & 8) >>> 1) | ((d2 & 8) >>> 2) | ((d3 & 8) >>> 3);
14610 
14611     switch(x)
14612     {
14613         case 0: 
14614             return (d1 << 7) | (d2 << 4) | d3;
14615         case 1:
14616             return (d1 << 7) | (d2 << 4) | (d3 & 1) | 8;
14617         case 2:
14618             return (d1 << 7) | ((d3 & 6) << 4) | ((d2 & 1) << 4) | (d3 & 1) | 10;
14619         case 3:
14620             return (d1 << 7) | ((d2 & 1) << 4) | (d3 & 1) | 78;
14621         case 4:
14622             return ((d3 & 6) << 7) | ((d1 & 1) << 7) | (d2 << 4) | (d3 & 1) | 12;
14623         case 5:
14624             return ((d2 & 6) << 7) | ((d1 & 1) << 7) | ((d2 & 1) << 4) | (d3 & 1) | 46;
14625         case 6:
14626             return ((d3 & 6) << 7) | ((d1 & 1) << 7) | ((d2 & 1) << 4) | (d3 & 1) | 14;
14627         case 7:
14628             return ((d1 & 1) << 7) | ((d2 & 1) << 4) | (d3 & 1) | 110;
14629         default:
14630             assert(0);
14631     }
14632 }
14633 
14634 //10 bit decoding
14635 @safe pure nothrow @nogc
14636 private void unpackDPD(const uint declet, out uint d1, out uint d2, out uint d3)
14637 {
14638     uint x = declet & 14;
14639     uint decoded;
14640     switch (x)
14641     {
14642         case 0:
14643             decoded = ((declet & 896) << 1) | (declet & 119);
14644             break;
14645         case 1:
14646             decoded = ((declet & 128) << 1) | (declet & 113) | ((declet & 768) >> 7) | 2048;
14647             break;
14648         case 2: 
14649             decoded = ((declet & 896) << 1) | (declet & 17) | ((declet & 96) >> 4) | 128;
14650             break;
14651         case 3:
14652             decoded = ((declet & 896) << 1) | (declet & 113) | 8;
14653             break;
14654         case 4: 
14655             decoded = ((declet & 128) << 1) | (declet & 17) | ((declet & 768) >> 7) | 2176;
14656             break;
14657         case 5:
14658             decoded = ((declet & 128) << 1) | (declet & 17) | ((declet & 768) >> 3) | 2056;
14659             break;
14660         case 6:
14661             decoded = ((declet & 896) << 1) | (declet & 17) | 136;
14662             break;
14663         case 7: 
14664             decoded = ((declet & 128) << 1) | (declet & 17) | 2184;
14665             break;
14666         default:
14667             assert(0);
14668     }
14669 
14670     d1 = (decoded & 3840) >> 8;
14671     d2 = (decoded & 240) >> 4;
14672     d3 = (decoded & 15);
14673 }