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, fabs;
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     @nogc nothrow pure @safe
579     ExceptionFlags infinityPack(const bool isNegative)
580     {      
581         
582         data = MASK_INF;
583         if (isNegative)
584             data |= D.MASK_SGN;
585         return ExceptionFlags.none;
586     }
587 
588     //packs zero or min, depending on the rounding mode
589     @nogc nothrow pure @safe
590     ExceptionFlags underflowPack(const bool isNegative, const RoundingMode mode)
591     {      
592         switch (mode)
593         {
594             case RoundingMode.towardPositive:
595                 if (!isNegative)
596                     return minPack(false);
597                 goto default;
598             case RoundingMode.towardNegative:
599                 if (isNegative)
600                     return minPack(true);
601                 goto default;
602             default:
603                 data = MASK_ZERO;
604                 if (isNegative)
605                     data |= D.MASK_SGN;
606         }
607         return ExceptionFlags.underflow;
608     }
609 
610     //packs $(B NaN)
611     @nogc nothrow pure @safe
612     ExceptionFlags invalidPack(const bool isNegative, const U payload)
613     {
614         data = MASK_QNAN;
615         data |= (payload & MASK_PAYL);
616         if (isNegative)
617             data |= MASK_SGN;
618         return ExceptionFlags.invalidOperation;
619     }
620 
621     //packs infinity
622     @nogc nothrow pure @safe
623     ExceptionFlags div0Pack(const bool isNegative)
624     {
625         data = MASK_INF;
626         if (isNegative)
627             data |= MASK_SGN;
628         return ExceptionFlags.divisionByZero;
629     }
630 
631 
632     @nogc nothrow pure @safe
633     ExceptionFlags adjustedPack(T)(const T coefficient, const int exponent, const bool isNegative, 
634                                     const int precision, const RoundingMode mode, 
635                                     const ExceptionFlags previousFlags = ExceptionFlags.none)
636     {
637         if (!errorPack(isNegative, previousFlags, precision, mode, cvt!U(coefficient)))
638         {
639             bool stickyUnderflow = coefficient && (exponent < int.max - EXP_BIAS && exponent + EXP_BIAS < PRECISION - 1 && prec(coefficient) < PRECISION - (exponent + EXP_BIAS));
640             static if (T.sizeof <= U.sizeof)
641                 U cx = coefficient;
642             else
643                 Unqual!T cx = coefficient;
644             int ex = exponent; 
645             ExceptionFlags flags = coefficientAdjust(cx, ex, EXP_MIN, EXP_MAX, realPrecision(precision), isNegative, mode) | previousFlags; 
646             if (stickyUnderflow)
647                 flags |= ExceptionFlags.underflow;
648             return checkedPack(cvt!U(cx), ex, isNegative, precision, mode, false) | flags;
649         }
650         return previousFlags;
651     }
652 
653     @nogc nothrow pure @safe
654     bool unpack(out U coefficient, out int exponent) const
655     out
656     {
657         assert (exponent >= EXP_MIN && exponent <= EXP_MAX);
658         assert (coefficient <= (MASK_COE2 | MASK_COEX));
659     }
660     body
661     {
662         uint e;
663         bool isNegative = unpackRaw(coefficient, e);
664         exponent = cast(int)(e - EXP_BIAS);
665         return isNegative;
666     }
667 
668     @nogc nothrow pure @safe
669     bool unpackRaw(out U coefficient, out uint exponent) const
670     {
671         if ((data & MASK_EXT) == MASK_EXT)
672         {
673             coefficient = data & MASK_COE2 | MASK_COEX;
674             exponent = cast(uint)((data & MASK_EXP2) >>> SHIFT_EXP2);
675         }
676         else
677         {
678             coefficient = data & MASK_COE1;
679             exponent = cast(uint)((data & MASK_EXP1) >>> SHIFT_EXP1);
680         }
681         return (data & MASK_SGN) != 0U;
682     }
683 
684     @nogc nothrow pure @safe
685     static int realPrecision(const int precision)
686     {
687         if (precision <= 0 || precision > PRECISION)
688             return PRECISION;
689         else
690             return precision;
691     }
692 
693     ExceptionFlags packIntegral(T)(const T value, const int precision, const RoundingMode mode)
694     if (isIntegral!T)
695     {
696         alias V = CommonStorage!(D, T);
697         if (!value)
698         {
699             this.data = MASK_ZERO;
700             return ExceptionFlags.none;
701         }
702         else
703         {
704             static if (isSigned!T)
705             {
706                 bool isNegative = void;
707                 V coefficient = unsign!V(value, isNegative);
708             }
709             else
710             {
711                 enum isNegative = false;
712                 V coefficient = value;
713             }
714             int exponent = 0;
715             auto flags = coefficientAdjust(coefficient, exponent, cvt!V(COEF_MAX), isNegative, mode);
716             return adjustedPack(cvt!U(coefficient), exponent, isNegative, precision, mode, flags);
717         }
718     }
719 
720     ExceptionFlags packFloatingPoint(T)(const T value, const int precision, const RoundingMode mode) 
721     if (isFloatingPoint!T)
722     {
723         ExceptionFlags flags;
724         DataType!D cx; int ex; bool sx;
725         switch (fastDecode(value, cx, ex, sx, mode, flags))
726         {
727             case FastClass.quietNaN:
728                 data = MASK_QNAN;
729                 if (sx)
730                     data |= MASK_SGN;
731                 data |= cx & MASK_PAYL;
732                 return ExceptionFlags.none;
733             case FastClass.infinite:
734                 data = MASK_INF;
735                 if (sx)
736                     data |= MASK_SGN;
737                 return ExceptionFlags.none;
738             case FastClass.zero:
739                 data = MASK_ZERO;
740                 if (sx)
741                     data |= MASK_SGN;
742                 return ExceptionFlags.none;
743             case FastClass.finite:
744 
745                 auto targetPrecision = realPrecision(precision);
746                 static if (is(T == float))
747                 {
748                     if (targetPrecision > 9)
749                         targetPrecision = 9;
750                 }
751                 else static if (is(T == double))
752                 {
753                     if (targetPrecision > 17)
754                         targetPrecision = 17;
755                 }
756                 else
757                 {
758                     if (targetPrecision > 21)
759                         targetPrecision = 21;
760                 }
761                 flags |= coefficientAdjust(cx, ex, targetPrecision, sx, mode);
762                 return adjustedPack(cx, ex, sx, precision, mode, flags);                
763             default:
764                 assert(0);
765         }
766     }
767 
768 
769     ExceptionFlags packString(C)(const(C)[] value, const int precision, const RoundingMode mode)
770     if (isSomeChar!C)
771     {
772             U coefficient;
773             bool isinf, isnan, issnan, isnegative, wasHex;
774             int exponent;
775             const(C)[] ss = value;
776             auto flags = parseDecimal(ss, coefficient, exponent, isinf, isnan, issnan, isnegative, wasHex);
777 
778             if (!ss.empty)
779                 return invalidPack(isnegative, coefficient) | flags;
780 
781             if (flags & ExceptionFlags.invalidOperation)
782                 return invalidPack(isnegative, coefficient) | flags;
783 
784             if (issnan)
785                 data = MASK_SNAN | (coefficient & MASK_PAYL);
786             else if (isnan)
787                 data = MASK_QNAN | (coefficient & MASK_PAYL);
788             else if (isinf)
789                 data = MASK_INF;
790             else
791             {   
792                 if (!wasHex)
793                     return adjustedPack(coefficient, exponent, isnegative, precision, mode, flags);
794                 else
795                     return flags | checkedPack(coefficient, exponent, isnegative, precision, mode, true);
796             }
797 
798             if (isnegative)
799                 data |= MASK_SGN;
800 
801             return flags;
802     }
803 
804     ExceptionFlags packRange(R)(ref R range, const int precision, const RoundingMode mode)
805     if (isInputRange!R && isSomeChar!(ElementType!R) && !isSomeString!range)
806     {
807             U coefficient;
808             bool isinf, isnan, issnan, isnegative, wasHex;
809             int exponent;
810             auto flags = parseDecimal(range, coefficient, exponent, isinf, isnan, issnan, isnegative, wasHex);
811 
812             if (!ss.empty)
813                 flags |= ExceptionFlags.invalidOperation;
814 
815             if (flags & ExceptionFlags.invalidOperation)
816             {
817                 packErrors(isnegative, flags, coefficient);
818                 return flags;
819             }
820 
821             if (issnan)
822                 data = MASK_SNAN | (coefficient & MASK_PAYL);
823             else if (isnan)
824                 data = MASK_QNAN | (coefficient & MASK_PAYL);
825             else if (isinf)
826                 data = MASK_INF;
827             if (flags & ExceptionFlags.underflow)
828                 data = MASK_ZERO;
829             else if (flags & ExceptionFlags.overflow)
830                 data = MASK_INF;
831             else 
832             {
833                 flags |= adjustCoefficient(coefficient, exponent, EXP_MIN, EXP_MAX, COEF_MAX, isnegative, mode);
834                 flags |= adjustPrecision(coefficient, exponent, EXP_MIN, EXP_MAX, precision, isnegative, mode);
835             }
836             
837             if (flags & ExceptionFlags.underflow)
838                 data = MASK_ZERO;
839             else if (flags & ExceptionFlags.overflow)
840                 data = MASK_INF;
841 
842             if (isnegative)
843                 data |= MASK_SGN;
844 
845             return flags;
846     }
847      
848 
849     enum zero           = D(U(0U), 0, false);
850     enum minusZero      = D(U(0U), 0, true);
851     enum one            = D(U(1U), 0, false);
852     enum two            = D(U(2U), 0, false);
853     enum three          = D(U(3U), 0, false);
854     enum minusOne       = D(U(1U), 0, true);
855     enum minusInfinity  = -infinity;
856     enum ten            = D(U(10U), 0, false);
857     enum minusTen       = D(U(10U), 0, true);
858     enum qnan           = nan;
859     enum snan           = D(MASK_NONE, MASK_NONE, MASK_SNAN);
860     enum subn           = D(U(1U), EXP_MIN, false);
861     enum minusSubn      = D(U(1U), EXP_MIN, true);
862     enum min            = D(COEF_MAX, EXP_MAX, true);
863     enum half           = D(U(5U), -1, false);
864     enum threequarters  = D(U(75U), -2, false);
865     enum quarter        = D(U(25U), -2, false);
866 
867     static if (bits == 128)
868     {
869         enum maxFloat       = D(s_max_float);
870         enum maxDouble      = D(s_max_double);
871         enum maxReal        = D(s_max_real);
872         enum minFloat       = D(s_min_float);
873         enum minDouble      = D(s_min_double);
874         enum minReal        = D(s_min_real);
875     }
876 
877 
878 
879     enum SQRT3          = fromString!D(s_sqrt3);
880     enum M_SQRT3        = fromString!D(s_m_sqrt3);
881     enum PI_3           = fromString!D(s_pi_3);
882     enum PI_6           = fromString!D(s_pi_6);
883     enum _5PI_6         = fromString!D(s_5pi_6);
884     enum _3PI_4         = fromString!D(s_3pi_4);
885     enum _2PI_3         = fromString!D(s_2pi_3);
886     enum SQRT3_2        = fromString!D(s_sqrt3_2);
887     enum SQRT2_2        = fromString!D(s_sqrt2_2);
888     enum onethird       = fromString!D(s_onethird);
889     enum twothirds      = fromString!D(s_twothirds);
890     enum _5_6           = fromString!D(s_5_6);
891     enum _1_6           = fromString!D(s_1_6);
892     enum M_1_2PI        = fromString!D(s_m_1_2pi);
893     enum PI2            = fromString!D(s_pi2);
894 public:
895 
896     
897     enum dig            = PRECISION;
898     enum epsilon        = D(U(1U), -PRECISION + 1, false);
899     enum infinity       = D(MASK_NONE, MASK_NONE, MASK_INF);
900     enum max            = D(COEF_MAX, EXP_MAX, false);
901     enum max_10_exp     = EMAX;
902     enum max_exp        = cast(int)(max_10_exp / LOG10_2);
903     enum mant_dig       = trailingBits;
904     enum min_10_exp     = -(max_10_exp - 1);
905     enum min_exp        = cast(int)(min_10_exp / LOG10_2);
906     enum min_normal     = D(U(1U), min_10_exp, false);    
907     enum nan            = D(MASK_NONE, MASK_NONE, MASK_QNAN);
908     
909 
910     enum E              = fromString!D(s_e);
911     enum PI             = fromString!D(s_pi);
912     enum PI_2           = fromString!D(s_pi_2);
913     enum PI_4           = fromString!D(s_pi_4);
914     enum M_1_PI         = fromString!D(s_m_1_pi);
915     enum M_2_PI         = fromString!D(s_m_2_pi);
916     enum M_2_SQRTPI     = fromString!D(s_m_2_sqrtpi);
917     enum SQRT2          = fromString!D(s_sqrt2);
918     enum SQRT1_2        = fromString!D(s_sqrt1_2);
919     enum LN10           = fromString!D(s_ln10);
920     enum LOG2T          = fromString!D(s_log2t);
921     enum LOG2E          = fromString!D(s_log2e);
922     enum LOG2           = fromString!D(s_log2);
923     enum LOG10E         = fromString!D(s_log10e);
924     enum LN2            = fromString!D(s_ln2);
925 
926     ///always 10 for _decimal data types
927     @IEEECompliant("radix", 25)
928     enum radix          = 10;
929 
930     /**
931     Constructs a Decimal data type using the specified _value
932     Params:
933         value = any integral, char, bool, floating point, decimal, string or character range _value
934     Exceptions: 
935         $(BOOKTABLE,
936             $(TR $(TH Data type) $(TH Invalid) $(TH Overflow) $(TH Underflow) $(TH Inexact))
937             $(TR $(TD integral)  $(TD        ) $(TD         ) $(TD          ) $(TD ✓     ))
938             $(TR $(TD char    )  $(TD        ) $(TD         ) $(TD          ) $(TD ✓     ))
939             $(TR $(TD float   )  $(TD        ) $(TD ✓      ) $(TD ✓       ) $(TD ✓     ))
940             $(TR $(TD bool    )  $(TD        ) $(TD         ) $(TD          ) $(TD        ))
941             $(TR $(TD decimal )  $(TD        ) $(TD ✓      ) $(TD ✓       ) $(TD ✓     ))
942             $(TR $(TD string  )  $(TD ✓     ) $(TD ✓      ) $(TD ✓       ) $(TD ✓     ))
943             $(TR $(TD range   )  $(TD ✓     ) $(TD ✓      ) $(TD ✓       ) $(TD ✓     ))
944         )
945     Using_integral_values:
946         ---
947         auto a = decimal32(112);       //represented as 112 x 10^^0;
948         auto b = decimal32(123456789); //inexact, represented as 1234568 * x 10^^2
949         ---
950     Using_floating_point_values:
951         ---
952         auto a = decimal32(1.23);
953         //inexact, represented as 123 x 10^^-2, 
954         //because floating point data cannot exactly represent 1.23 
955         //in fact 1.23 as float is 1.230000019073486328125
956         auto b = decimal64(float.nan); 
957         ---
958     Using_other_decimal_values:
959         ---
960         auto a = decimal32(decimal64(10)); 
961         auto b = decimal64(a);
962         auto c = decimal64(decimal128.nan);
963         ---
964     Using_strings_or_ranges:
965         A _decimal value can be defined based on _decimal, scientific or hexadecimal representation:
966         $(UL
967             $(LI values are rounded away from zero in case of precision overflow;)
968             ---
969             auto d = decimal32("2.3456789")
970             //internal representation will be 2.345679
971             //because decimal32 has a 7-digit precision
972             ---
973             $(LI the exponent in hexadecimal notation is 10-based;)
974             ---
975             auto d1 = decimal64("0x00003p+21");
976             auto d2 = decimal64("3e+21");
977             assert (d1 == d2);
978             ---
979             $(LI the hexadecimal notation doesn't have any _decimal point, 
980                 because there is no leading 1 as for binary floating point values;)
981             $(LI there is no octal notation, any leading zero before the decimal point is ignored;)
982             $(LI digits can be grouped using underscores;)
983             $(LI case insensitive special values are accepted: $(B nan, qnan, snan, inf, infinity);)
984             $(LI there is no digit count limit for _decimal representation, very large values are rounded and adjusted by 
985                 increasing the 10-exponent;)
986             ---
987             auto d1 = decimal32("123_456_789_123_456_789_123_456_789_123"); //30 digits
988             //internal representation will be 1.234568 x 10^^30
989             ---
990             $(LI $(B NaN) payloads can be defined betwen optional brackets ([], (), {}, <>). 
991             The payload is unsigned and is accepted in decimal or hexadecimal format;)
992         )   
993             ---
994             auto d = decimal32("10");              //integral
995             auto e = decimal64("125.43")           //floating point
996             auto f = decimal128("123.456E-32");    //scientific
997             auto g = decimal32("0xABCDEp+21");     //hexadecimal 0xABCD * 10^^21
998             auto h = decimal64("NaN1234");         //$(B NaN) with 1234 payload
999             auto i = decimal128("sNaN<0xABCD>")    //signaling $(B NaN) with a 0xABCD payload
1000             auto j = decimal32("inf");             //infinity
1001             ---
1002     Using_char_or_bool_values:
1003         These constructors are provided only from convenience, and to 
1004         offer support for conversion function $(PHOBOS conv, to, to).
1005         Char values are cast to unsigned int.
1006         Bool values are converted to 0.0 (false) or 1.0 (true)
1007         ---
1008         auto a = decimal32(true); //1.0
1009         auto b = decimal32('a');  //'a' ascii code (97)
1010 
1011         auto c = to!decimal32(false); //phobos to!(bool, decimal32)
1012         auto d = to!decimal128('Z');  //phobos to!(char, decimal128)
1013         ---
1014     */
1015     @IEEECompliant("convertFormat", 22)
1016     @IEEECompliant("convertFromDecimalCharacter", 22)
1017     @IEEECompliant("convertFromHexCharacter", 22)
1018     @IEEECompliant("convertFromInt", 21)
1019     @IEEECompliant("decodeBinary", 23)
1020     this(T)(auto const ref T value)
1021     {
1022         static if (isIntegral!T)
1023         {
1024             auto flags = packIntegral(value, 
1025                                  __ctfe ? 0 : DecimalControl.precision, 
1026                                  __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1027             DecimalControl.raiseFlags(flags);
1028         }
1029         else static if (isSomeChar!T)
1030         {
1031             auto flags = packIntegral(cast(uint)value, 
1032                                  __ctfe ? 0 : DecimalControl.precision, 
1033                                  __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1034             DecimalControl.raiseFlags(flags);
1035         }
1036         else static if (isFloatingPoint!T)
1037         {
1038             auto flags = packFloatingPoint(value, 
1039                                  __ctfe ? 0 : DecimalControl.precision, 
1040                                  __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1041             DecimalControl.raiseFlags(flags);
1042         }
1043         else static if (isSomeString!T)
1044         {
1045             auto flags = packString(value, 
1046                                  __ctfe ? 0 : DecimalControl.precision, 
1047                                  __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1048             DecimalControl.raiseFlags(flags);
1049         }
1050         else static if (isInputRange!T && isSomeChar!(ElementType!T) && !isSomeString!T)
1051         {
1052             auto flags = packRange(value, 
1053                                  __ctfe ? 0 : DecimalControl.precision, 
1054                                  __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1055             DecimalControl.raiseFlags(flags);
1056         }
1057         else static if (is(T: D))
1058             this.data = value.data;
1059         else static if (is(T: bool))
1060         {
1061             this.data = value ? one.data : zero.data;
1062         }
1063         else static if (isDecimal!T)
1064         {
1065             auto flags = decimalToDecimal(value, this, 
1066                                  __ctfe ? 0 : DecimalControl.precision, 
1067                                  __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1068             DecimalControl.raiseFlags(flags);
1069         }
1070         else
1071             static assert (0, "Cannot convert expression of type '" ~ 
1072                            Unqual!T.stringof ~ "' to '" ~
1073                            Unqual!D.stringof ~ "'");
1074     }  
1075 
1076 
1077 
1078     /**
1079     Implementation of assignnment operator. It supports the same semantics as the constructor.
1080     */
1081     @IEEECompliant("copy", 23)
1082     auto ref opAssign(T)(auto const ref T value)
1083     {
1084         auto result = Unqual!D(value);
1085         this.data = result.data;
1086     }
1087 
1088     /**
1089     Implementation of cast operator. Supported casts: integral, floating point, _decimal, char, bool
1090     Exceptions: 
1091         $(BOOKTABLE,
1092             $(TR $(TH Data type) $(TH Invalid) $(TH Overflow) $(TH Underflow) $(TH Inexact))
1093             $(TR $(TD integral)  $(TD      ✓) $(TD ✓      ) $(TD ✓       ) $(TD ✓     ))
1094             $(TR $(TD char    )  $(TD      ✓) $(TD ✓      ) $(TD ✓       ) $(TD ✓     ))
1095             $(TR $(TD float   )  $(TD        ) $(TD ✓      ) $(TD ✓       ) $(TD ✓     ))
1096             $(TR $(TD bool    )  $(TD        ) $(TD         ) $(TD          ) $(TD        ))
1097             $(TR $(TD decimal )  $(TD        ) $(TD ✓      ) $(TD ✓       ) $(TD ✓     ))
1098         )
1099     */
1100     @IEEECompliant("convertFormat", 22)
1101     @IEEECompliant("encodeBinary", 23)
1102     T opCast(T)() const
1103     {
1104         Unqual!T result;
1105         static if (isUnsigned!T)
1106         {
1107             auto flags = decimalToUnsigned(this, result, 
1108                                       __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1109             DecimalControl.raiseFlags(flags);
1110         }
1111         else static if (isIntegral!T)
1112         {
1113             auto flags = decimalToSigned(this, result, 
1114                                     __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1115             DecimalControl.raiseFlags(flags);
1116         }
1117         else static if (is(T: D))
1118             result = this;
1119         else static if (is(D: decimal32) && (is(T: decimal64) || is(T: decimal128)))
1120             decimalToDecimal(this, result, 0, RoundingMode.implicit);
1121         else static if (is(D: decimal64) && is(T: decimal128))
1122             decimalToDecimal(this, result, 0, RoundingMode.implicit);
1123         else static if (isDecimal!T)
1124         {
1125             auto flags = decimalToDecimal(this, result, 
1126                                           __ctfe ? 0 : DecimalControl.precision,
1127                                           __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1128             DecimalControl.raiseFlags(flags);
1129         }
1130         else static if (isFloatingPoint!T)
1131         {
1132             auto flags = decimalToFloat(this, result, 
1133                                         __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1134             DecimalControl.raiseFlags(flags);
1135         }
1136         else static if (isSomeChar!T)
1137         {
1138             uint r;
1139             auto flags = decimalToUnsigned(this, r, 
1140                                            __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1141             result = cast(Unqual!T)r;
1142             DecimalControl.raiseFlags(flags);
1143         }
1144         else static if (is(T: bool))
1145             result = !isZero(this);
1146         else
1147             static assert(0, "Cannot cast a value of type '" ~ 
1148                           Unqual!D.stringof ~ "' to '" ~ 
1149                           Unqual!T.stringof ~ "'");
1150         
1151         return result;
1152     }
1153     
1154 
1155     /**
1156     Implementation of +/- unary operators. These operations are silent, no exceptions are thrown
1157     */
1158     @safe pure nothrow @nogc
1159     auto opUnary(string op: "+")() const
1160     {
1161         return this;
1162     }
1163 
1164     ///ditto
1165     @IEEECompliant("negate", 23)
1166     @safe pure nothrow @nogc
1167     auto opUnary(string op: "-")() const
1168     {
1169         D result = this;
1170         static if (is(D: decimal128))
1171             result.data.hi ^= D.MASK_SGN.hi;
1172         else
1173             result.data ^= D.MASK_SGN;
1174         return result;
1175     }
1176 
1177     /**
1178     Implementation of ++/-- unary operators.
1179     Exceptions: 
1180         $(BOOKTABLE,
1181             $(TR $(TH Value) $(TH ++/-- ) $(TH Invalid) $(TH Overflow) $(TH Inexact))
1182             $(TR $(TD $(B NaN)  ) $(TD $(B NaN)   ) $(TD ✓     ) $(TD         ) $(TD        ))
1183             $(TR $(TD ±∞   ) $(TD ±∞    ) $(TD        ) $(TD         ) $(TD        ))
1184             $(TR $(TD any  ) $(TD any   ) $(TD        ) $(TD ✓      ) $(TD ✓     ))
1185         )
1186     */
1187     @safe
1188     auto ref opUnary(string op: "++")()
1189     {
1190         auto flags = decimalInc(this,
1191                                 __ctfe ? 0 : DecimalControl.precision, 
1192                                 __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1193         DecimalControl.raiseFlags(flags);
1194         return this;
1195     }
1196 
1197     ///ditto
1198     @safe
1199     auto ref opUnary(string op: "--")()
1200     {
1201         auto flags = decimalDec(this,
1202                                 __ctfe ? 0 : DecimalControl.precision, 
1203                                 __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1204         DecimalControl.raiseFlags(flags);
1205         return this;
1206     }
1207 
1208 
1209     /**
1210     Implementation of == operator. This operation is silent, no exceptions are thrown.
1211     Supported types : _decimal, floating point, integral, char    
1212     */
1213     @IEEECompliant("compareQuietEqual", 24)
1214     @IEEECompliant("compareQuietNotEqual", 24)
1215     bool opEquals(T)(auto const ref T value) const
1216     {
1217         static if (isDecimal!T || isIntegral!T || isFloatingPoint!T)
1218         {
1219             int result = decimalEqu(this, value);
1220             if (result < -2)
1221             {
1222                 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
1223                 return false;
1224             }
1225             return result == 1;
1226         }
1227         else static if (isSomeChar!T)
1228             return opEquals(cast(uint)value);
1229         else
1230             static assert (0, "Cannot compare values of type '" ~ 
1231                 Unqual!D.stringof ~ "' and '" ~ 
1232                 Unqual!T.stringof ~ "'");
1233     }
1234 
1235     /**
1236     Implementation of comparison operator. 
1237     Supported types : _decimal, floating point, integral, char   
1238     $(BOOKTABLE,
1239             $(TR $(TH this) $(TH Value) $(TH Result)    $(TH Invalid)) 
1240             $(TR $(TD $(B NaN) ) $(TD any  ) $(TD $(B NaN)   )    $(TD ✓     ))
1241             $(TR $(TD any ) $(TD $(B NaN)  ) $(TD $(B NaN)   )    $(TD ✓     )) 
1242             $(TR $(TD any ) $(TD any  ) $(TD ±1.0, 0.0) $(TD        )) 
1243         )
1244     */
1245     @IEEECompliant("compareSignalingGreater", 24)
1246     @IEEECompliant("compareSignalingGreaterEqual", 24)
1247     @IEEECompliant("compareSignalingGreaterUnordered", 24)
1248     @IEEECompliant("compareSignalingLess", 24)
1249     @IEEECompliant("compareSignalingLessEqual", 24)
1250     @IEEECompliant("compareSignalingLessUnordered", 24)
1251     @IEEECompliant("compareSignalingNotGreater", 24)
1252     @IEEECompliant("compareSignalingNotLess", 24)
1253     float opCmp(T)(auto const ref T value) const
1254     {
1255         static if (isDecimal!T || isIntegral!T || isFloatingPoint!T)
1256         {
1257             int result = decimalCmp(this, value);
1258             if (result < -1)
1259             {
1260                 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
1261                 return float.nan;
1262             }
1263             else
1264                 return cast(float)(result);
1265         }
1266         else static if (isSomeChar!T)
1267         {
1268             int result = decimalCmp(this, cast(uint)value);
1269             if (result < -1)
1270             {
1271                 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
1272                 return float.nan;
1273             }
1274             else
1275                 return cast(float)(result);
1276         }
1277         else
1278             static assert (0, "Cannot compare values of type '" ~ 
1279                            Unqual!D.stringof ~ "' and '" ~ 
1280                            Unqual!T.stringof ~ "'");
1281     }
1282 
1283     
1284     /**
1285     Implementation of binary and assignment operators (+, -, *, /, %, ^^). 
1286     Returns:
1287         the widest _decimal value as result of the operation
1288     Supported_types:
1289         _decimal, floating point, integral, char   
1290     Exceptions:
1291     $(BOOKTABLE,
1292         $(TR $(TH Left) $(TH Op) $(TH Right) $(TH Result) $(TH Invalid) $(TH Div0) $(TH Overflow) $(TH Underflow) $(TH Inexact))
1293         $(TR $(TD $(B NaN)) $(TD any) $(TD any) $(TD $(B NaN))      $(TD ✓     ) $(TD     ) $(TD         ) $(TD         )  $(TD        ))
1294         $(TR $(TD any) $(TD any) $(TD $(B NaN)) $(TD $(B NaN))      $(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 -∞) $(TD +) $(TD +∞) $(TD $(B NaN))          $(TD ✓     ) $(TD     ) $(TD         ) $(TD         )  $(TD        ))
1299         $(TR $(TD -∞) $(TD +) $(TD any) $(TD -∞)          $(TD        ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1300         $(TR $(TD any) $(TD +) $(TD -∞) $(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 +∞) $(TD -) $(TD any) $(TD +∞)          $(TD        ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1304         $(TR $(TD any) $(TD -) $(TD +∞) $(TD -∞)          $(TD        ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1305         $(TR $(TD -∞) $(TD -) $(TD -∞) $(TD $(B NaN))          $(TD ✓     ) $(TD     ) $(TD         ) $(TD         )  $(TD        ))  
1306         $(TR $(TD -∞) $(TD -) $(TD any) $(TD -∞)          $(TD        ) $(TD     ) $(TD         ) $(TD         )  $(TD        ))  
1307         $(TR $(TD any) $(TD -) $(TD -∞) $(TD -∞)          $(TD        ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1308         $(TR $(TD any) $(TD -) $(TD any) $(TD any)        $(TD        ) $(TD     ) $(TD ✓      ) $(TD ✓      )  $(TD ✓     )) 
1309         $(TR $(TD ±∞) $(TD *) $(TD 0.0) $(TD $(B NaN))         $(TD ✓     ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1310         $(TR $(TD ±∞) $(TD *) $(TD any) $(TD ±∞)          $(TD        ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1311         $(TR $(TD any) $(TD *) $(TD any) $(TD any)        $(TD        ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1312         $(TR $(TD ±∞) $(TD /) $(TD ±∞) $(TD $(B NaN))          $(TD ✓     ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1313         $(TR $(TD 0.0) $(TD /) $(TD 0.0) $(TD $(B NaN))        $(TD ✓     ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1314         $(TR $(TD ±∞) $(TD /) $(TD any) $(TD ±∞)          $(TD        ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1315         $(TR $(TD any) $(TD /) $(TD 0.0) $(TD ±∞)         $(TD        ) $(TD ✓  ) $(TD         ) $(TD         )  $(TD        )) 
1316         $(TR $(TD any) $(TD /) $(TD any) $(TD any)        $(TD        ) $(TD     ) $(TD ✓      ) $(TD ✓      )  $(TD ✓     ))  
1317         $(TR $(TD ±∞) $(TD %) $(TD any) $(TD $(B NaN))         $(TD ✓     ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1318         $(TR $(TD any) $(TD %) $(TD ±∞) $(TD $(B NaN))         $(TD ✓     ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1319         $(TR $(TD any) $(TD %) $(TD 0.0) $(TD $(B NaN))        $(TD ✓     ) $(TD     ) $(TD         ) $(TD         )  $(TD        )) 
1320         $(TR $(TD any) $(TD %) $(TD any) $(TD any)        $(TD        ) $(TD     ) $(TD ✓      ) $(TD ✓      )  $(TD ✓     )) 
1321     )
1322     */
1323     @IEEECompliant("addition", 21)
1324     @IEEECompliant("division", 21)
1325     @IEEECompliant("multiplication", 21)
1326     @IEEECompliant("pow", 42)
1327     @IEEECompliant("pown", 42)
1328     @IEEECompliant("powr", 42)
1329     @IEEECompliant("remainder", 25)
1330     @IEEECompliant("substraction", 21)
1331     auto opBinary(string op, T)(auto const ref T value) const
1332     if (op == "+" || op == "-" || op == "*" || op == "/" || op == "%" || op == "^^")
1333     {
1334         static if (isDecimal!T)
1335             CommonDecimal!(D, T) result = this;
1336         else
1337             Unqual!D result = this;
1338 
1339         static if (op == "+")
1340             alias decimalOp = decimalAdd;
1341         else static if (op == "-")
1342             alias decimalOp = decimalSub;
1343         else static if (op == "*")
1344             alias decimalOp = decimalMul;
1345         else static if (op == "/")
1346             alias decimalOp = decimalDiv;
1347         else static if (op == "%")
1348             alias decimalOp = decimalMod;
1349         else static if (op == "^^")
1350             alias decimalOp = decimalPow;
1351         else 
1352             static assert(0);
1353 
1354         static if (isIntegral!T || isFloatingPoint!T || isDecimal!T)
1355             auto flags = decimalOp(result, value, 
1356                                    __ctfe ? 0 : DecimalControl.precision, 
1357                                    __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1358         else static if (isSomeChar!T)
1359             auto flags = decimalOp(result, cast(uint)value, 
1360                                    __ctfe ? 0 : DecimalControl.precision, 
1361                                    __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1362         else
1363             static assert (0, "Cannot perform binary operation: '" ~ 
1364                             Unqual!D.stringof ~ "' " ~ op ~" '" ~ 
1365                             Unqual!T.stringof ~ "'");
1366 
1367         DecimalControl.raiseFlags(flags);
1368         return result;
1369     }
1370 
1371     ///ditto
1372     auto opBinaryRight(string op, T)(auto const ref T value) const
1373     if (op == "+" || op == "-" || op == "*" || op == "/" || op == "%" || op == "^^")
1374     {
1375         static if (isDecimal!T)
1376             CommonDecimal!(D, T) result = value;
1377         else
1378             Unqual!D result;
1379         static if (op == "+")
1380             alias decimalOp = decimalAdd;
1381         else static if (op == "-")
1382             alias decimalOp = decimalSub;
1383         else static if (op == "*")
1384             alias decimalOp = decimalMul;
1385         else static if (op == "/")
1386             alias decimalOp = decimalDiv;
1387         else static if (op == "%")
1388             alias decimalOp = decimalMod;
1389         else static if (op == "^^")
1390             alias decimalOp = decimalPow;
1391         else 
1392             static assert(0);
1393 
1394         static if (isDecimal!T)
1395         {
1396             
1397             auto flags = decimalOp(result, this, 
1398                                    __ctfe ? 0 : DecimalControl.precision, 
1399                                    __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1400         }
1401         else static if (isIntegral!T || isFloatingPoint!T)
1402             auto flags = decimalOp(value, this, result,
1403                                    __ctfe ? 0 : DecimalControl.precision, 
1404                                    __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1405         else static if (isSomeChar!T)
1406             auto flags = decimalOp(cast(uint)value, this, result,
1407                                    __ctfe ? 0 : DecimalControl.precision, 
1408                                    __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1409         else
1410             static assert (0, "Cannot perform binary operation: '" ~ 
1411                             Unqual!T.stringof ~ "' " ~ op ~" '" ~ 
1412                             Unqual!D.stringof ~ "'");
1413 
1414         DecimalControl.raiseFlags(flags);
1415         return result;
1416     }
1417 
1418     ///ditto
1419     auto opOpAssign(string op, T)(auto const ref T value)
1420     if (op == "+" || op == "-" || op == "*" || op == "/" || op == "%" || op == "^^")
1421     {
1422         static if (op == "+")
1423             alias decimalOp = decimalAdd;
1424         else static if (op == "-")
1425             alias decimalOp = decimalSub;
1426         else static if (op == "*")
1427             alias decimalOp = decimalMul;
1428         else static if (op == "/")
1429             alias decimalOp = decimalDiv;
1430         else static if (op == "%")
1431             alias decimalOp = decimalMod;
1432         else static if (op == "^^")
1433             alias decimalOp = decimalPow;
1434         else 
1435             static assert(0);
1436 
1437 
1438 
1439         static if (isIntegral!T || isFloatingPoint!T || isDecimal!T)
1440             auto flags = decimalOp(this, value, 
1441                                    __ctfe ? 0 : DecimalControl.precision, 
1442                                    __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1443         else static if (isSomeChar!T)
1444             auto flags = decimalOp(this, cast(uint)value, 
1445                                    __ctfe ? 0 : DecimalControl.precision, 
1446                                    __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1447         else
1448             static assert (0, "Cannot perform assignment operation: '" ~ 
1449                             Unqual!D.stringof ~ "' " ~ op ~"= '" ~ 
1450                             Unqual!T.stringof ~ "'");
1451 
1452         DecimalControl.raiseFlags(flags);
1453         return this;
1454     }
1455     
1456     version (D_BetterC) {}
1457     else {   
1458    
1459     /**
1460     Converts current value to string, passing it to the given sink using
1461     the specified format.
1462     Params:
1463       sink = a delegate used to sink character arrays;
1464       fmt  = a format specification;
1465     Notes:
1466       This function is not intended to be used directly, it is used by the format, output or conversion
1467       family of functions from Phobos. All standard format options are supported, except digit grouping. 
1468     Supported_formats:
1469       $(UL
1470         $(LI $(B f, F) - floating point notation)
1471         $(LI $(B e, E) - scientific notation)
1472         $(LI $(B a, A) - hexadecimal floating point notation)
1473         $(LI $(B g, G) - shortest representation between floating point and scientific notation)
1474         $(LI $(B s, S) - same as $(B g, G))
1475       )
1476     Throws:
1477       $(PHOBOS format, FormatException, FormatException) if the format specifier is not supported
1478     See_Also:
1479        $(PHOBOS format, FormatSpec, FormatSpec)
1480        $(PHOBOS format, format, format)
1481        $(PHOBOS conv, to, to)
1482        $(PHOBOS stdio, writef, writef)
1483        $(PHOBOS stdio, writefln, writefln)
1484     */
1485     @IEEECompliant("convertToDecimalCharacter", 22)
1486     @IEEECompliant("convertToHexCharacter", 22)
1487     void toString(C)(scope void delegate(const(C)[]) sink, FormatSpec!C fmt) const
1488     if (isSomeChar!C)
1489     {
1490         if (__ctfe)
1491             sinkDecimal(fmt, sink, this, RoundingMode.tiesToAway);
1492         else
1493             sinkDecimal(fmt, sink, this, DecimalControl.rounding);
1494     }
1495 
1496     ///ditto
1497     @IEEECompliant("convertToDecimalCharacter", 22)
1498     void toString(C)(scope void delegate(const(C)[]) sink) const
1499     if (isSomeChar!C)
1500     {
1501         sinkDecimal(singleSpec("%g"), sink, this, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1502     }
1503 
1504     ///Converts current value to string in floating point or scientific notation,
1505     ///which one is shorter.
1506     @IEEECompliant("convertToDecimalCharacter", 22)
1507     string toString() const
1508     {
1509         return decimalToString!char(this, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1510     }
1511 
1512     ///Converts current value to string according to the 
1513     ///format specification
1514     @IEEECompliant("convertToDecimalCharacter", 22)
1515     @IEEECompliant("convertToHexCharacter", 22)
1516     string toString(C)(FormatSpec!C fmt) const
1517     {
1518         return decimalToString!C(fmt, this, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1519     }
1520 
1521     ///ditto
1522     @IEEECompliant("convertToDecimalCharacter", 22)
1523     @IEEECompliant("convertToHexCharacter", 22)
1524     string toString(C)(const(C)[] fmt) const
1525     {
1526         FormatSpec!C spec = singleSpec(fmt);
1527         return decimalToString!C(spec, this, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
1528     }
1529 
1530     } //!D_BetterC
1531 
1532     /**
1533     Returns a unique hash of the _decimal value suitable for use in a hash table.
1534     Notes:
1535        This function is not intended for direct use, it's provided as support for associative arrays.
1536     */
1537     @safe pure nothrow @nogc
1538     size_t toHash()
1539     {
1540         static if (bits == 32)
1541             return data;
1542         else static if (bits == 64)
1543         {
1544             static if (size_t.sizeof == uint.sizeof)
1545                 return cast(uint)data ^ cast(uint)(data >>> 32);
1546             else
1547                 return data;
1548         }
1549         else
1550         {
1551             static if (size_t.sizeof == uint.sizeof)
1552                 return cast(uint)data.hi ^ cast(uint)(data.hi >>> 32) ^
1553                        cast(uint)data.lo ^ cast(uint)(data.lo >>> 32);
1554             else
1555                 return data.hi ^ data.lo;
1556         }
1557     }
1558 }
1559 
1560 @("Compilation tests")
1561 unittest
1562 {
1563     struct DumbRange(C)
1564     {
1565         bool empty;
1566         C front;
1567         void popFront() {}
1568     }
1569 
1570     alias DecimalTypes = TypeTuple!(decimal32, decimal64, decimal128);
1571     alias IntegralTypes = TypeTuple!(byte, short, int, long, ubyte, ushort, uint, ulong);
1572     alias FloatTypes = TypeTuple!(float, double, real);
1573     alias CharTypes = TypeTuple!(char, wchar, dchar);
1574     alias StringTypes = TypeTuple!(string, wstring, dstring);
1575     alias RangeTypes = TypeTuple!(DumbRange!char, DumbRange!wchar, DumbRange!dchar);
1576 
1577     auto x = decimal32(double.nan);
1578 
1579     //constructors
1580     foreach (D; DecimalTypes)
1581     {
1582         foreach (T; DecimalTypes)
1583             static assert (is(typeof(D(T.init)) == D));
1584         foreach (T; IntegralTypes)
1585             static assert (is(typeof(D(T.init)) == D));
1586         foreach (T; FloatTypes)
1587             static assert (is(typeof(D(T.init)) == D));
1588         foreach (T; CharTypes)
1589             static assert (is(typeof(D(T.init)) == D));
1590         foreach (T; StringTypes)
1591             static assert (is(typeof(D(T.init)) == D));
1592         static assert (is(typeof(D(true)) == D));
1593     }
1594 
1595     //assignment
1596     foreach (D; DecimalTypes)
1597     {
1598         foreach (T; DecimalTypes)
1599             static assert (__traits(compiles, { D d = T.init; }));
1600         foreach (T; IntegralTypes)
1601             static assert (__traits(compiles, { D d = T.init; }));
1602         foreach (T; FloatTypes)
1603             static assert (__traits(compiles, { D d = T.init; }));
1604         foreach (T; CharTypes)
1605             static assert (__traits(compiles, { D d = T.init; }));
1606         foreach (T; StringTypes)
1607             static assert (__traits(compiles, { D d = T.init; }));
1608         static assert (__traits(compiles, { D d = true; }));
1609     }
1610 
1611     auto b = cast(float)decimal32();
1612     //cast
1613     foreach (D; DecimalTypes)
1614     {
1615         foreach (T; DecimalTypes)
1616             static assert (is(typeof(cast(T)(D.init)) == T));
1617         foreach (T; IntegralTypes)
1618             static assert (is(typeof(cast(T)(D.init)) == T));
1619         foreach (T; FloatTypes)
1620             static assert (is(typeof(cast(T)(D.init)) == T));
1621         foreach (T; CharTypes)
1622             static assert (is(typeof(cast(T)(D.init)) == T));
1623         static assert (is(typeof(cast(bool)(D.init)) == bool));
1624     }
1625 
1626 
1627     //unary ops
1628     foreach (D; DecimalTypes)
1629     {
1630         static assert(is(typeof(+D.init) == const D));
1631         static assert(is(typeof(-D.init) == D));
1632         static assert(is(typeof(++D.init) == D));
1633         static assert(is(typeof(--D.init) == D));
1634     }
1635 
1636 
1637     //equality
1638     foreach (D; DecimalTypes)
1639     {
1640         foreach (T; DecimalTypes)
1641             static assert (is(typeof(D.init == T.init) == bool));
1642         foreach (T; IntegralTypes)
1643             static assert (is(typeof(D.init == T.init) == bool));
1644         foreach (T; FloatTypes)
1645             static assert (is(typeof(D.init == T.init) == bool));
1646         foreach (T; CharTypes)
1647             static assert (is(typeof(D.init == T.init) == bool));
1648     }
1649 
1650     auto c = decimal128() > 0.0;
1651   
1652     //comparison
1653     foreach (D; DecimalTypes)
1654     {
1655         foreach (T; DecimalTypes)
1656             static assert (is(typeof(D.init > T.init) == bool));
1657         foreach (T; IntegralTypes)
1658             static assert (is(typeof(D.init > T.init) == bool));
1659         foreach (T; FloatTypes)
1660             static assert (is(typeof(D.init > T.init) == bool));
1661         foreach (T; CharTypes)
1662             static assert (is(typeof(D.init > T.init) == bool));
1663     }
1664 
1665     //binary left
1666     foreach (D; DecimalTypes)
1667     {
1668         foreach (T; DecimalTypes)
1669         {
1670             static assert (is(typeof(D.init + T.init) == CommonDecimal!(D, T)));
1671             static assert (is(typeof(D.init - T.init) == CommonDecimal!(D, T)));
1672             static assert (is(typeof(D.init * T.init) == CommonDecimal!(D, T)));
1673             static assert (is(typeof(D.init / T.init) == CommonDecimal!(D, T)));
1674             static assert (is(typeof(D.init % T.init) == CommonDecimal!(D, T)));
1675             static assert (is(typeof(D.init ^^ T.init) == CommonDecimal!(D, T)));
1676         }
1677 
1678         foreach (T; IntegralTypes)
1679         {
1680             static assert (is(typeof(D.init + T.init) == D));
1681             static assert (is(typeof(D.init - T.init) == D));
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         }
1687 
1688         auto z = decimal32.nan + float.nan;
1689 
1690         foreach (T; FloatTypes)
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         foreach (T; CharTypes)
1701         {
1702             static assert (is(typeof(D.init + T.init) == D));
1703             static assert (is(typeof(D.init - T.init) == D));
1704             static assert (is(typeof(D.init * T.init) == D));
1705             static assert (is(typeof(D.init / T.init) == D));
1706             static assert (is(typeof(D.init % T.init) == D));
1707             static assert (is(typeof(D.init ^^ T.init) == D));
1708         }
1709     }
1710 
1711     //binary right
1712     foreach (D; DecimalTypes)
1713     {
1714         foreach (T; DecimalTypes)
1715         {
1716             static assert (is(typeof(T.init + D.init) == CommonDecimal!(D, T)));
1717             static assert (is(typeof(T.init - D.init) == CommonDecimal!(D, T)));
1718             static assert (is(typeof(T.init * D.init) == CommonDecimal!(D, T)));
1719             static assert (is(typeof(T.init / D.init) == CommonDecimal!(D, T)));
1720             static assert (is(typeof(T.init % D.init) == CommonDecimal!(D, T)));
1721             static assert (is(typeof(T.init ^^ D.init) == CommonDecimal!(D, T)));
1722         }
1723 
1724 
1725         foreach (T; IntegralTypes)
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; FloatTypes)
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         foreach (T; CharTypes)
1746         {
1747             static assert (is(typeof(T.init + D.init) == D));
1748             static assert (is(typeof(T.init - D.init) == D));
1749             static assert (is(typeof(T.init * D.init) == D));
1750             static assert (is(typeof(T.init / D.init) == D));
1751             static assert (is(typeof(T.init % D.init) == D));
1752             static assert (is(typeof(T.init ^^ D.init) == D));
1753         }
1754     }
1755 
1756     //op assignment
1757     foreach (D; DecimalTypes)
1758     {
1759         foreach (T; DecimalTypes)
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; IntegralTypes)
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; FloatTypes)
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         foreach (T; CharTypes)
1790         {
1791             static assert (is(typeof(D.init += T.init) == D));
1792             static assert (is(typeof(D.init -= T.init) == D));
1793             static assert (is(typeof(D.init *= T.init) == D));
1794             static assert (is(typeof(D.init /= T.init) == D));
1795             static assert (is(typeof(D.init %= T.init) == D));
1796             static assert (is(typeof(D.init ^^= T.init) == D));
1797         }
1798     }
1799 
1800     //expected constants
1801     foreach (D; DecimalTypes)
1802     {
1803         static assert (is(typeof(D.init) == D));
1804         static assert (is(typeof(D.nan) == D));
1805         static assert (is(typeof(D.infinity) == D));
1806         static assert (is(typeof(D.max) == D));
1807         static assert (is(typeof(D.min_normal) == D));
1808         static assert (is(typeof(D.epsilon) == D));
1809         static assert (is(typeof(D.dig) == int));
1810         static assert (is(typeof(D.mant_dig) == int));
1811         static assert (is(typeof(D.min_10_exp) == int));
1812         static assert (is(typeof(D.max_10_exp) == int));
1813         static assert (is(typeof(D.min_exp) == int));
1814         static assert (is(typeof(D.max_exp) == int));
1815 
1816         static assert (is(typeof(D.E) == D));
1817         static assert (is(typeof(D.PI) == D));
1818         static assert (is(typeof(D.PI_2) == D));
1819         static assert (is(typeof(D.PI_4) == D));
1820         static assert (is(typeof(D.M_1_PI) == D));
1821         static assert (is(typeof(D.M_2_PI) == D));
1822         static assert (is(typeof(D.M_2_SQRTPI) == D));
1823         static assert (is(typeof(D.LN10) == D));
1824         static assert (is(typeof(D.LN2) == D));
1825         static assert (is(typeof(D.LOG2) == D));
1826         static assert (is(typeof(D.LOG2E) == D));
1827         static assert (is(typeof(D.LOG2T) == D));
1828         static assert (is(typeof(D.LOG10E) == D));
1829         static assert (is(typeof(D.SQRT2) == D));
1830         static assert (is(typeof(D.SQRT1_2) == D));
1831     }
1832 
1833     //expected members
1834     foreach (D; DecimalTypes)
1835     {
1836         static assert (is(typeof(D.init.toHash()) == size_t));
1837         static assert (is(typeof(D.init.toString()) == string));
1838     }
1839 }
1840 
1841 
1842 
1843 @("Decimal should support decimal + float")
1844 unittest
1845 {
1846     immutable expected = decimal128("2");
1847 
1848     auto sut = decimal128("1");
1849     auto result = sut + 1.0f;
1850 
1851     assert(expected == result);
1852 }
1853 
1854 @("Decimal should support decimal - float")
1855 unittest
1856 {
1857     immutable expected = decimal128("5");
1858 
1859     auto sut = decimal128("9");
1860     auto result = sut - 4.0f;
1861 
1862     assert(expected == result);
1863 }
1864 
1865 @("Decimal should support decimal * float")
1866 unittest
1867 {
1868     immutable expected = decimal128("13.3");
1869 
1870     auto sut = decimal128("1.33");
1871     auto result = sut * 10.0f;
1872 
1873     assert(expected == result);
1874 }
1875 
1876 @("Decimal should support decimal / float")
1877 unittest
1878 {
1879     immutable expected = decimal128("0.5");
1880 
1881     auto sut = decimal128("1");
1882     auto result = sut / 2.0f;
1883 
1884     assert(expected == result);
1885 }
1886 
1887 @("Decimal should support decimal % float")
1888 unittest
1889 {
1890     immutable expected = decimal128("1");
1891 
1892     auto sut = decimal128("10");
1893     auto result = sut % 3.0f;
1894 
1895     assert(expected == result);
1896 }
1897 
1898 
1899 @("Decimal should support decimal + integral")
1900 unittest
1901 {
1902     immutable expected = decimal128("3");
1903 
1904     auto sut = decimal128("2");
1905     auto result = sut + 1;
1906 
1907     assert(expected == result);
1908 }
1909 
1910 @("Decimal should support decimal - integral")
1911 unittest
1912 {
1913     immutable expected = decimal128("1");
1914 
1915     auto sut = decimal128("3");
1916     auto result = sut - 2;
1917 
1918     assert(expected == result);
1919 }
1920 
1921 @("Decimal should support decimal * integral")
1922 unittest
1923 {
1924     immutable expected = decimal128("123.4");
1925 
1926     auto sut = decimal128("12.34");
1927     auto result = sut * 10;
1928 
1929     assert(expected == result);
1930 }
1931 
1932 @("Decimal should support decimal / integral")
1933 unittest
1934 {
1935     immutable expected = decimal128("0.5");
1936 
1937     auto sut = decimal128("1");
1938     auto result = sut / 2;
1939 
1940     assert(expected == result);
1941 }
1942 
1943 @("Decimal should support decimal % integral")
1944 unittest
1945 {
1946     immutable expected = decimal128("1");
1947 
1948     auto sut = decimal128("10");
1949     auto result = sut % 3;
1950 
1951     assert(expected == result);
1952 }
1953 
1954 @("Decimal should support decimal % unsigned integral")
1955 unittest
1956 {
1957     immutable expected = decimal128("1");
1958 
1959     auto sut = decimal128("10");
1960     auto result = sut % 3u;
1961 
1962     assert(expected == result);
1963 }
1964 
1965 ///Shorthand notations for $(MYREF Decimal) types
1966 alias decimal32 = Decimal!32;
1967 ///ditto
1968 alias decimal64 = Decimal!64;
1969 ///ditto
1970 alias decimal128 = Decimal!128;
1971 
1972 
1973 ///Returns true if all specified types are _decimal types.
1974 template isDecimal(D...)
1975 {
1976     static if (D.length == 0)
1977         enum isDecimal = false;
1978     static if (D.length == 1)
1979         enum isDecimal = is(D[0] == decimal32) || is(D[0] == decimal64) || is(D[0] == decimal128);
1980     else
1981         enum isDecimal = isDecimal!(D[0]) && isDecimal!(D[1 .. $]);
1982 }
1983 
1984 ///
1985 unittest
1986 {
1987     static assert(isDecimal!decimal32);
1988     static assert(isDecimal!(decimal32, decimal64));
1989     static assert(!isDecimal!int);
1990     static assert(!isDecimal!(decimal128, byte));
1991 }
1992 
1993 ///Returns the most wide _decimal type among the specified types
1994 template CommonDecimal(T...) if (isDecimal!T)
1995 {
1996     static if (T.length == 1)
1997         alias CommonDecimal = T[0];
1998     else static if (is(T[0] == decimal128) || is(T[1] == decimal128))
1999         alias CommonDecimal = decimal128;
2000     else static if (T.length == 2)
2001     {
2002         static if (is(T[0] == decimal32))
2003             alias CommonDecimal = T[1];
2004         else static if (is(T[1] == decimal32))
2005             alias CommonDecimal = T[0];
2006         else static if (is(T[0] == decimal64) && is(T[1] == decimal128))
2007             alias CommonDecimal = decimal128;
2008         else static if (is(T[1] == decimal64) && is(T[0] == decimal128))
2009             alias CommonDecimal = decimal128;
2010         else static if (is(T[1] == T[0]))
2011             alias CommonDecimal = T[0];
2012         else
2013             static assert(false, "Never happen");
2014     }
2015     else
2016         alias CommonDecimal = CommonDecimal!(CommonDecimal!(T[0 .. 1], CommonDecimal!(T[2 .. $])));
2017 }
2018 
2019 ///
2020 unittest
2021 {
2022     static assert(is(CommonDecimal!(decimal32, decimal64) == decimal64));
2023     static assert(is(CommonDecimal!(decimal32, decimal128) == decimal128));
2024     static assert(is(CommonDecimal!(decimal64, decimal128) == decimal128));
2025 }
2026 
2027 version(D_BetterC) 
2028 {
2029 
2030 }
2031 else 
2032 {
2033 
2034     ///Root object for all _decimal exceptions
2035     abstract class DecimalException : Exception
2036     {
2037         mixin ExceptionConstructors;
2038     }
2039 
2040     ///Thrown if any operand of a _decimal operation is not a number or si not finite
2041     class InvalidOperationException : DecimalException
2042     {
2043 	    mixin ExceptionConstructors;
2044     }
2045 
2046     ///Thrown if the denominator of a _decimal division operation is zero. 
2047     class DivisionByZeroException : DecimalException
2048     {
2049 	    mixin ExceptionConstructors;
2050     }
2051 
2052     ///Thrown if the result of a _decimal operation exceeds the largest finite number of the destination format. 
2053     class OverflowException : DecimalException
2054     {
2055 	    mixin ExceptionConstructors;
2056     }
2057 
2058     ///Thrown if the result of a _decimal operation is smaller the smallest finite number of the destination format. 
2059     class UnderflowException : DecimalException
2060     {
2061 	    mixin ExceptionConstructors;
2062     }
2063 
2064     ///Thrown if the result of a _decimal operation was rounded to fit in the destination format. 
2065     class InexactException : DecimalException
2066     {
2067 	    mixin ExceptionConstructors;
2068     }
2069 } 
2070 /**
2071 These flags indicate that an error has occurred. They indicate that a 0, $(B NaN) or an infinity value has been generated, 
2072 that a result is inexact, or that a signalling $(B NaN) has been encountered. 
2073 If the corresponding traps are set using $(MYREF DecimalControl), 
2074 an exception will be thrown after setting these error flags.
2075 
2076 By default the context will have all error flags lowered and exceptions are thrown only for severe errors.
2077 */
2078 enum ExceptionFlags : uint
2079 {
2080     ///no error
2081     none             = 0U,
2082     ///$(MYREF InvalidOperationException) is thrown if trap is set
2083 	invalidOperation = 1U << 0,
2084     ///$(MYREF DivisionByZeroException) is thrown if trap is set
2085 	divisionByZero   = 1U << 1,
2086     ///$(MYREF OverflowException) is thrown if trap is set
2087 	overflow         = 1U << 2,
2088     ///$(MYREF UnderflowException) is thrown if trap is set
2089 	underflow        = 1U << 3,
2090     ///$(MYREF InexactException) is thrown if trap is set
2091 	inexact          = 1U << 4,
2092     ///group of errors considered severe: invalidOperation, divisionByZero, overflow
2093 	severe           = invalidOperation | divisionByZero | overflow,
2094     ///all errors
2095 	all              = severe | underflow | inexact
2096 }
2097 
2098 /**
2099 * Rounding modes. To better understand how rounding is performed, consult the table below. 
2100 *
2101 * $(BOOKTABLE,
2102 *  $(TR $(TH Value) $(TH tiesToEven) $(TH tiesToAway) $(TH towardPositive) $(TH towardNegative) $(TH towardZero)) 
2103 *  $(TR $(TD +1.3)  $(TD +1)         $(TD +1)         $(TD +2)             $(TD +1)             $(TD +1))
2104 *  $(TR $(TD +1.5)  $(TD +2)         $(TD +2)         $(TD +2)             $(TD +1)             $(TD +1))
2105 *  $(TR $(TD +1.8)  $(TD +2)         $(TD +2)         $(TD +2)             $(TD +1)             $(TD +1))
2106 *  $(TR $(TD -1.3)  $(TD -1)         $(TD -1)         $(TD -1)             $(TD -2)             $(TD -1)) 
2107 *  $(TR $(TD -1.5)  $(TD -2)         $(TD -2)         $(TD -1)             $(TD -2)             $(TD -1)) 
2108 *  $(TR $(TD -1.8)  $(TD -2)         $(TD -2)         $(TD -1)             $(TD -2)             $(TD -1)) 
2109 *  $(TR $(TD +2.3)  $(TD +2)         $(TD +2)         $(TD +3)             $(TD +2)             $(TD +2)) 
2110 *  $(TR $(TD +2.5)  $(TD +2)         $(TD +3)         $(TD +3)             $(TD +2)             $(TD +2)) 
2111 *  $(TR $(TD +2.8)  $(TD +3)         $(TD +3)         $(TD +3)             $(TD +2)             $(TD +2)) 
2112 *  $(TR $(TD -2.3)  $(TD -2)         $(TD -2)         $(TD -2)             $(TD -3)             $(TD -2)) 
2113 *  $(TR $(TD -2.5)  $(TD -2)         $(TD -3)         $(TD -2)             $(TD -3)             $(TD -2)) 
2114 *  $(TR $(TD -2.8)  $(TD -3)         $(TD -3)         $(TD -2)             $(TD -3)             $(TD -2)) 
2115 * )  
2116 */
2117 enum RoundingMode
2118 {
2119     ///rounded away from zero; halfs are rounded to the nearest even number
2120 	tiesToEven,
2121     ///rounded away from zero
2122 	tiesToAway,
2123     ///truncated toward positive infinity
2124 	towardPositive,
2125     ///truncated toward negative infinity
2126 	towardNegative,
2127     ///truncated toward zero
2128 	towardZero,
2129 
2130     implicit = tiesToEven,
2131 }
2132 
2133 /**
2134 _Precision used to round _decimal operation results. Every result will be adjusted
2135 to fit the specified precision. Use $(MYREF DecimalControl) to query or set the 
2136 context precision
2137 */
2138 alias Precision = uint;
2139 ///ditto
2140 enum : Precision
2141 {
2142     ///use the default precision of the current type 
2143     ///(7 digits for decimal32, 16 digits for decimal64 or 34 digits for decimal128)
2144 	precisionDefault = 0,
2145     ///use 32 bits precision (7 digits)
2146 	precision32 = Decimal!32.PRECISION,
2147     ///use 64 bits precision (16 digits)
2148 	precision64 = Decimal!64.PRECISION,
2149     ////use 128 bits precision (34 digits)
2150     precision128 = Decimal!128.PRECISION,
2151 }
2152 
2153 /**
2154     Container for _decimal context control, provides methods to alter exception handling,
2155     manually edit error flags, adjust arithmetic precision and rounding mode
2156 */
2157 struct DecimalControl
2158 {
2159 private:
2160 	static ExceptionFlags flags;
2161 	static ExceptionFlags traps;
2162 
2163     @safe
2164     static void checkFlags(const ExceptionFlags group, const ExceptionFlags traps)
2165     {
2166         version(D_BetterC) 
2167         {
2168             if (__ctfe)
2169             {
2170                 if ((group & ExceptionFlags.invalidOperation) && (traps & ExceptionFlags.invalidOperation))
2171                     assert(0, "Invalid operation");
2172                 if ((group & ExceptionFlags.divisionByZero) && (traps & ExceptionFlags.divisionByZero))
2173                     assert(0, "Division by zero");
2174                 if ((group & ExceptionFlags.overflow) && (traps & ExceptionFlags.overflow))
2175                     assert(0, "Overflow");
2176             }
2177         }
2178         else 
2179         {
2180             if ((group & ExceptionFlags.invalidOperation) && (traps & ExceptionFlags.invalidOperation))
2181                 throw new InvalidOperationException("Invalid operation");
2182             if ((group & ExceptionFlags.divisionByZero) && (traps & ExceptionFlags.divisionByZero))
2183                 throw new DivisionByZeroException("Division by zero");
2184             if ((group & ExceptionFlags.overflow) && (traps & ExceptionFlags.overflow))
2185                 throw new OverflowException("Overflow");
2186             if ((group & ExceptionFlags.underflow) && (traps & ExceptionFlags.underflow))
2187                 throw new UnderflowException("Underflow");
2188             if ((group & ExceptionFlags.inexact) && (traps & ExceptionFlags.inexact))
2189                 throw new InexactException("Inexact");
2190         }
2191 
2192     }
2193 
2194 public:
2195 
2196     /**
2197     Gets or sets the rounding mode used when the result of an operation exceeds the _decimal precision.
2198     See $(MYREF RoundingMode) for details.
2199     ---
2200     DecimalControl.rounding = RoundingMode.tiesToEven;
2201     decimal32 d1 = 123456789;
2202     assert(d1 == 123456800);
2203 
2204     DecimalControl.rounding = RoundingMode.towardNegative;
2205     decimal32 d2 = 123456789;
2206     assert(d2 == 123456700);
2207     ---
2208     */
2209     @IEEECompliant("defaultModes", 46)
2210     @IEEECompliant("getDecimalRoundingDirection", 46)
2211     @IEEECompliant("restoreModes", 46)
2212     @IEEECompliant("saveModes", 46)
2213     @IEEECompliant("setDecimalRoundingDirection", 46)
2214     static RoundingMode rounding;
2215 
2216     /**
2217     Gets or sets the precision applied to peration results.
2218     See $(MYREF Precision) for details.
2219     ---
2220     DecimalControl.precision = precisionDefault;
2221     decimal32 d1 = 12345;
2222     assert(d1 == 12345);
2223     
2224     DecimalControl.precision = 4;
2225     decimal32 d2 = 12345;
2226     assert(d2 == 12350);
2227     ---
2228     */
2229     static Precision precision;
2230 
2231     /**
2232     Sets specified error flags. Multiple errors may be ORed together.
2233     ---
2234     DecimalControl.raiseFlags(ExceptionFlags.overflow | ExceptionFlags.underflow);
2235     assert (DecimalControl.overflow);
2236     assert (DecimalControl.underflow);
2237     ---
2238 	*/
2239     @IEEECompliant("raiseFlags", 26)
2240 	@safe
2241 	static void raiseFlags(const ExceptionFlags group)
2242 	{
2243         if (__ctfe)
2244             checkFlags(group, ExceptionFlags.severe);
2245         else
2246         {
2247             ExceptionFlags newFlags = flags ^ (group & ExceptionFlags.all);
2248             flags |= group & ExceptionFlags.all;
2249 		    checkFlags(newFlags, traps);
2250         }
2251 	}
2252 
2253     /**
2254     Unsets specified error flags. Multiple errors may be ORed together.
2255     ---
2256     DecimalControl.resetFlags(ExceptionFlags.inexact);
2257     assert(!DecimalControl.inexact);
2258     ---
2259 	*/
2260     @IEEECompliant("lowerFlags", 26)
2261     @nogc @safe nothrow
2262 	static void resetFlags(const ExceptionFlags group)
2263 	{
2264 		flags &= ~(group & ExceptionFlags.all);
2265 	}
2266 
2267     ///ditto
2268     @IEEECompliant("lowerFlags", 26)
2269     @nogc @safe nothrow
2270 	static void resetFlags()
2271 	{
2272 		flags = ExceptionFlags.none;
2273 	}
2274 
2275     /**
2276     Enables specified error flags (group) without throwing corresponding exceptions.
2277     ---
2278     DecimalControl.restoreFlags(ExceptionFlags.underflow | ExceptionsFlags.inexact);
2279     assert (DecimalControl.testFlags(ExceptionFlags.underflow | ExceptionFlags.inexact));
2280     ---
2281 	*/
2282     @IEEECompliant("restoreFlags", 26)
2283 	@nogc @safe nothrow
2284 	static void restoreFlags(const ExceptionFlags group)
2285 	{
2286 		flags |= group & ExceptionFlags.all;
2287 	}
2288 
2289     /**
2290     Checks if the specified error flags are set. Multiple exceptions may be ORed together.
2291     ---
2292     DecimalControl.raiseFlags(ExceptionFlags.overflow | ExceptionFlags.underflow | ExceptionFlags.inexact);
2293     assert (DecimalControl.hasFlags(ExceptionFlags.overflow | ExceptionFlags.inexact));
2294     ---
2295 	*/
2296     @IEEECompliant("testFlags", 26)
2297     @IEEECompliant("testSavedFlags", 26)
2298 	@nogc @safe nothrow
2299 	static bool hasFlags(const ExceptionFlags group)
2300 	{
2301 		return (flags & (group & ExceptionFlags.all)) != 0;
2302 	}
2303 
2304 
2305      /**
2306     Returns the current set flags.
2307     ---
2308     DecimalControl.restoreFlags(ExceptionFlags.inexact);
2309     assert (DecimalControl.saveFlags() & ExceptionFlags.inexact);
2310     ---
2311 	*/
2312     @IEEECompliant("saveAllFlags", 26)
2313 	@nogc @safe nothrow
2314 	static ExceptionFlags saveFlags()
2315 	{
2316 		return flags;
2317 	}
2318 
2319     /**
2320     Disables specified exceptions. Multiple exceptions may be ORed together.
2321     ---
2322     DecimalControl.disableExceptions(ExceptionFlags.overflow);
2323     auto d = decimal64.max * decimal64.max;
2324     assert (DecimalControl.overflow);
2325     assert (isInfinity(d));
2326     ---
2327 	*/
2328 	@nogc @safe nothrow
2329 	static void disableExceptions(const ExceptionFlags group)
2330 	{
2331 		traps &= ~(group & ExceptionFlags.all);
2332 	}
2333 
2334     ///ditto
2335     @nogc @safe nothrow
2336 	static void disableExceptions()
2337 	{
2338 		traps = ExceptionFlags.none;
2339 	}
2340 
2341     
2342 
2343     /**
2344     Enables specified exceptions. Multiple exceptions may be ORed together.
2345     ---
2346     DecimalControl.enableExceptions(ExceptionFlags.overflow);
2347     try
2348     {
2349         auto d = decimal64.max * 2;
2350     }
2351     catch (OverflowException)
2352     {
2353         writeln("Overflow error")
2354     }
2355     ---
2356 	*/
2357 	@nogc @safe nothrow
2358 	static void enableExceptions(const ExceptionFlags group)
2359 	{
2360 		traps |= group & ExceptionFlags.all;
2361 	}  
2362 
2363     /**
2364     Extracts current enabled exceptions.
2365     ---
2366     auto saved = DecimalControl.enabledExceptions;
2367     DecimalControl.disableExceptions(ExceptionFlags.all);
2368     DecimalControl.enableExceptions(saved);
2369     ---
2370 	*/
2371 	@nogc @safe nothrow
2372 	static @property ExceptionFlags enabledExceptions()
2373 	{
2374 		return traps;
2375 	}
2376 
2377     /**
2378     IEEE _decimal context errors. By default, no error is set.
2379     ---
2380     DecimalControl.disableExceptions(ExceptionFlags.all);
2381     decimal32 uninitialized;
2382     decimal64 d = decimal64.max * 2;
2383     decimal32 e = uninitialized + 5.0;
2384     assert(DecimalControl.overflow);
2385     assert(DecimalControl.invalidOperation);
2386     ---
2387     */
2388 	@nogc @safe nothrow
2389 	static @property bool invalidOperation()
2390 	{
2391 		return (flags & ExceptionFlags.invalidOperation) != 0;
2392 	}
2393 
2394     ///ditto
2395 	@nogc @safe nothrow
2396 	static @property bool divisionByZero()
2397 	{
2398 		return (flags & ExceptionFlags.divisionByZero) != 0;
2399 	}
2400 
2401     ///ditto
2402 	@nogc @safe nothrow
2403 	static @property bool overflow()
2404 	{
2405 		return (flags & ExceptionFlags.overflow) != 0;
2406 	}
2407 
2408     ///ditto
2409 	@nogc @safe nothrow
2410 	static @property bool underflow()
2411 	{
2412 		return (flags & ExceptionFlags.underflow) != 0;
2413 	}
2414 
2415     ///ditto
2416 	@nogc @safe nothrow
2417 	static @property bool inexact()
2418 	{
2419 		return (flags & ExceptionFlags.inexact) != 0;
2420 	}
2421 
2422     ///true if this programming environment conforms to IEEE 754-1985
2423     @IEEECompliant("is754version1985", 24)
2424     enum is754version1985 = true;
2425 
2426     ///true if this programming environment conforms to IEEE 754-2008
2427     @IEEECompliant("is754version2008", 24)
2428     enum is754version2008 = true;
2429 }
2430 
2431 
2432 /**
2433 Calculates the arc cosine of x, returning a value ranging from 0 to π.
2434 Exceptions:
2435 $(BOOKTABLE,
2436     $(TR $(TD $(MYREF InvalidOperationException)) 
2437          $(TD x is signaling $(B NaN) or |x| > 1.0))
2438     $(TR $(TD $(MYREF InexactException)) 
2439          $(TD the result is inexact))
2440 )
2441 Special_values:
2442 $(BOOKTABLE,
2443     $(TR $(TH x) $(TH acos(x)))
2444     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
2445     $(TR $(TD -1.0) $(TD π))
2446     $(TR $(TD +1.0) $(TD +0.0))
2447     $(TR $(TD < -1.0) $(TD $(B NaN)))
2448     $(TR $(TD > +1.0) $(TD $(B NaN)))
2449 )
2450 */
2451 @IEEECompliant("acos", 43)
2452 D acos(D)(auto const ref D x)
2453 if (isDecimal!D)
2454 {
2455     Unqual!D result = x;
2456     auto flags = decimalAcos(result, 
2457                              __ctfe ? D.PRECISION : DecimalControl.precision, 
2458                              __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
2459     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation);
2460     DecimalControl.raiseFlags(flags);
2461     return result;
2462 }
2463 
2464 ///
2465 unittest
2466 {
2467     decimal32 x = 0;
2468     assert(acos(x) == decimal32.PI_2);
2469 }
2470 
2471 unittest
2472 {
2473     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
2474     {
2475         assert (acos(-T.one) == T.PI);
2476         assert (acos(T.one) == 0);
2477         assert (acos(T.zero) == T.PI_2);
2478         assert (isNaN(acos(T.nan)));
2479     }
2480 }
2481 
2482 /**
2483 Calculates the inverse hyperbolic cosine of x
2484 Exceptions:
2485 $(BOOKTABLE,
2486     $(TR $(TD $(MYREF InvalidOperationException)) 
2487          $(TD x is signaling $(B NaN) or x < 1.0))
2488     $(TR $(TD $(MYREF InexactException)) 
2489          $(TD the result is inexact))
2490 )
2491 Special_values:
2492 $(BOOKTABLE,
2493     $(TR $(TH x) $(TH acosh(x)))
2494     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
2495     $(TR $(TD +1.0) $(TD +0.0))
2496     $(TR $(TD +∞) $(TD +∞))
2497     $(TR $(TD < 1.0) $(TD $(B NaN)))
2498 )
2499 */
2500 @IEEECompliant("acosh", 43)
2501 D acosh(D)(auto const ref D x)
2502 if (isDecimal!D)
2503 {
2504     Unqual!D result = x;
2505     auto flags = decimalAcosh(result, 
2506                              __ctfe ? D.PRECISION : DecimalControl.precision, 
2507                              __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
2508     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation);
2509     DecimalControl.raiseFlags(flags);
2510     return result;
2511 }
2512 
2513 ///
2514 unittest
2515 {
2516     decimal32 x = 1;
2517     assert (acosh(x) == 0);
2518 }
2519 
2520 unittest
2521 {
2522     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
2523     {
2524         assert (acosh(T.one) == T.zero);
2525         assert (acosh(T.infinity) == T.infinity);
2526         assert (isNaN(acosh(T.nan)));
2527     }
2528 }
2529 
2530 
2531 /**
2532 Computes whether two values are approximately equal, admitting a maximum relative difference, 
2533 or a maximum absolute difference.
2534 Params:
2535     x = First item to compare
2536     y = Second item to compare
2537     maxRelDiff = Maximum allowable relative difference (defaults to 1e-5)
2538     maxAbsDiff = Maximum allowable absolute difference (defaults to 1e-2)
2539 Returns:
2540     true if the two items are approximately equal under either criterium.
2541 Notes:
2542     This operation is silent, does not throw any exceptions and it doesn't set any error flags.
2543 */
2544 bool approxEqual(D1, D2, D3, D4)(auto const ref D1 x, auto const ref D2 y,
2545                                  auto const ref D3 maxRelDiff, 
2546                                  auto const ref D4 maxAbsDiff)
2547 if (isDecimal!(D1, D2, D3, D4))
2548 {
2549     if (isInfinity(x) && isInfinity(y))
2550         return signbit(x) == signbit(y);
2551     else
2552     {
2553         alias D = CommonDecimal!(D1, D2, D3, D4);
2554         D d;
2555         decimalToDecimal(x, d, D.PRECISION, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
2556         decimalSub(d, y, D.PRECISION, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
2557         d = fabs(d);
2558         if (decimalCmp(maxAbsDiff, d) >= 0)
2559             return true;
2560         decimalDiv(d, y, D.PRECISION, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
2561         if (decimalCmp(maxRelDiff, d) >= 0)
2562             return true;
2563     }
2564     return false;
2565 }
2566 
2567 ///ditto
2568 bool approxEqual(D1, D2, D3)(auto const ref D1 x, auto const ref D2 y,
2569                                  auto const ref D3 maxRelDiff)
2570 if (isDecimal!(D1, D2, D3))
2571 {
2572     enum maxAbsDiff = CommonDecimal!(D1, D2, D3)("1e-5");
2573     return approxEqual(x, y, maxRelDiff, maxAbsDiff);
2574 }
2575 
2576 ///ditto
2577 bool approxEqual(D1, D2)(auto const ref D1 x, auto const ref D2 y)
2578 if (isDecimal!(D1, D2))
2579 {
2580     enum maxAbsDiff = CommonDecimal!(D1, D2)("1e-5");
2581     enum maxRelDiff = CommonDecimal!(D1, D2)("1e-2");
2582     return approxEqual(x, y, maxRelDiff, maxAbsDiff);
2583 }
2584 
2585 
2586 
2587 /**
2588 Calculates the arc sine of x, returning a value ranging from -π/2 to +π/2.
2589 Exceptions:
2590 $(BOOKTABLE,
2591     $(TR $(TD $(MYREF InvalidOperationException)) 
2592          $(TD x is signaling $(B NaN) or |x| > 1.0))
2593     $(TR $(TD $(MYREF InexactException)) 
2594          $(TD the result is inexact))
2595 )
2596 Special_values:
2597 $(BOOKTABLE,
2598     $(TR $(TH x) $(TH asin(x)))
2599     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
2600     $(TR $(TD -1.0) $(TD -π/2))
2601     $(TR $(TD +1.0) $(TD +π/2))
2602     $(TR $(TD < -1.0) $(TD $(B NaN)))
2603     $(TR $(TD > +1.0) $(TD $(B NaN)))
2604 )
2605 */
2606 @IEEECompliant("asin", 43)
2607 D asin(D)(auto const ref D x)
2608 if (isDecimal!D)
2609 {
2610     Unqual!D result = x;
2611     auto flags = decimalAsin(result, 
2612                               __ctfe ? D.PRECISION : DecimalControl.precision, 
2613                               __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
2614     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation);
2615     DecimalControl.raiseFlags(flags);
2616     return result;
2617 }
2618 
2619 ///
2620 unittest
2621 {
2622     decimal32 x = 1;
2623     assert(asin(x) == decimal32.PI_2);
2624     assert(asin(-x) == -decimal32.PI_2);
2625 }
2626 
2627 unittest
2628 {
2629     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
2630     {
2631         assert (asin(-T.one) == -T.PI_2);
2632         assert (asin(T.zero) == 0);
2633         assert (asin(T.one) == T.PI_2);
2634         assert (isNaN(asin(T.nan)));
2635     }
2636 }
2637 
2638 
2639 /**
2640 Calculates the inverse hyperbolic sine of x
2641 Exceptions:
2642 $(BOOKTABLE,
2643     $(TR $(TD $(MYREF InvalidOperationException)) 
2644          $(TD x is signaling $(B NaN)))
2645     $(TR $(TD $(MYREF UnderflowException)) 
2646          $(TD the result is too small to be represented))
2647     $(TR $(TD $(MYREF InexactException)) 
2648          $(TD the result is inexact))
2649 )
2650 Special_values:
2651 $(BOOKTABLE,
2652     $(TR $(TH x) $(TH asinh(x)))
2653     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
2654     $(TR $(TD ±0.0) $(TD ±0.0))
2655     $(TR $(TD ±∞) $(TD ±∞))
2656 )
2657 */
2658 @IEEECompliant("asinh", 43)
2659 D asinh(D)(auto const ref D x)
2660 if (isDecimal!D)
2661 {
2662     Unqual!D result = x;
2663     auto flags = decimalAsinh(result, 
2664                              __ctfe ? D.PRECISION : DecimalControl.precision, 
2665                              __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
2666     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.underflow);
2667     DecimalControl.raiseFlags(flags);
2668     return result;
2669 }
2670 
2671 ///
2672 unittest
2673 {
2674     decimal32 x = 0;
2675     assert (asinh(x) == 0);
2676 }
2677 
2678 unittest
2679 {
2680     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
2681     {
2682         assert (asinh(T.zero) == T.zero);
2683         assert (asinh(T.infinity) == T.infinity);
2684         assert (isNaN(asinh(T.nan)));
2685     }
2686 }
2687 
2688 
2689 
2690 /**
2691 Calculates the arc tangent of x, returning a value ranging from -π/2 to π/2.
2692 Exceptions:
2693 $(BOOKTABLE,
2694     $(TR $(TD $(MYREF InvalidOperationException)) 
2695          $(TD x is signaling $(B NaN)))
2696     $(TR $(TD $(MYREF InexactException)) 
2697          $(TD the result is inexact))
2698     $(TR $(TD $(MYREF UnderflowException)) 
2699          $(TD the result is too small to be represented))
2700 )
2701 Special_values:
2702 $(BOOKTABLE,
2703     $(TR $(TH x) $(TH atan(x)))
2704     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
2705     $(TR $(TD ±0.0) $(TD ±0.0))
2706     $(TR $(TD ±∞) $(TD ±π/2))
2707 )
2708 */
2709 @IEEECompliant("atan", 43)
2710 D atan(D)(auto const ref D x)
2711 if (isDecimal!D)
2712 {
2713     Unqual!D result = x;
2714     auto flags = decimalAtan(result, 
2715                              __ctfe ? D.PRECISION : DecimalControl.precision, 
2716                              __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
2717     flags &= ExceptionFlags.invalidOperation | ExceptionFlags.underflow | ExceptionFlags.inexact;
2718     DecimalControl.raiseFlags(flags);
2719     return result;
2720 }
2721 
2722 ///
2723 unittest
2724 {
2725     decimal32 radians = 1;
2726     assert(atan(radians) == decimal32.PI_4);
2727 }
2728 
2729 
2730 unittest
2731 {
2732     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
2733     {
2734         assert (isIdentical(atan(T.zero), T.zero));
2735         assert (isIdentical(atan(-T.zero), -T.zero));
2736         assert (isIdentical(atan(T.infinity), T.PI_2));
2737         assert (isIdentical(atan(-T.infinity), -T.PI_2));
2738         assert (isNaN(atan(T.nan)));
2739     }
2740 }
2741 
2742 /**
2743 Calculates the arc tangent of y / x, returning a value ranging from -π to π.
2744 Exceptions:
2745 $(BOOKTABLE,
2746     $(TR $(TD $(MYREF InvalidOperationException)) 
2747          $(TD x or y is signaling $(B NaN)))
2748     $(TR $(TD $(MYREF InexactException)) 
2749          $(TD the result is inexact))
2750     $(TR $(TD $(MYREF UnderflowException)) 
2751          $(TD the result is too small to be represented))
2752 )
2753 Special_values:
2754 $(BOOKTABLE,
2755     $(TR $(TH y) $(TH x) $(TH atan2(y, x)))
2756     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
2757     $(TR $(TD any) $(TD $(B NaN)) $(TD $(B NaN)))
2758     $(TR $(TD ±0.0) $(TD -0.0) $(TD ±π))
2759     $(TR $(TD ±0.0) $(TD +0.0) $(TD ±0.0))
2760     $(TR $(TD ±0.0) $(TD <0.0) $(TD ±π))
2761     $(TR $(TD ±0.0) $(TD >0.0) $(TD ±0.0))
2762     $(TR $(TD ±∞) $(TD -∞) $(TD ±3π/4))
2763     $(TR $(TD ±∞) $(TD +∞) $(TD ±π/4))
2764     $(TR $(TD ±∞) $(TD any) $(TD ±π/2))
2765     $(TR $(TD any) $(TD -∞) $(TD ±π))
2766     $(TR $(TD any) $(TD +∞) $(TD ±0.0))
2767 )
2768 */
2769 @IEEECompliant("atan2", 43)
2770 auto atan2(D1, D2)(auto const ref D1 y, auto const ref D2 x)
2771 if (isDecimal!(D1, D2))
2772 {
2773     alias D = CommonDecimal!(D1, D2);
2774     D result;
2775     auto flags = decimalAtan2(y, x, result, 
2776                              __ctfe ? D.PRECISION : DecimalControl.precision, 
2777                              __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
2778     flags &= ExceptionFlags.invalidOperation | ExceptionFlags.underflow | ExceptionFlags.inexact;
2779     DecimalControl.raiseFlags(flags);
2780     return result;
2781 }
2782 
2783 ///
2784 unittest
2785 {
2786     decimal32 y = 10;
2787     decimal32 x = 0;
2788     assert (atan2(y, x) == decimal32.PI_2);
2789 }
2790 
2791 unittest
2792 {
2793 
2794     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
2795     {
2796         assert (isNaN(atan2(T.nan, T.zero)));
2797         assert (isNaN(atan2(T.one, T.nan)));
2798         assert (atan2(T.zero, -T.zero) == T.PI); 
2799         assert (atan2(-T.zero, -T.zero) == -T.PI); 
2800         assert (atan2(T.zero, T.zero) == T.zero);
2801         assert (atan2(-T.zero, T.zero) == -T.zero); 
2802         assert (atan2(T.zero, -T.one) == T.PI);
2803         assert (atan2(-T.zero, -T.one) == -T.PI);
2804         assert (atan2(T.zero, T.one) == T.zero);
2805         assert (atan2(-T.zero, T.one) == -T.zero);
2806         assert (atan2(-T.one, T.zero) == -T.PI_2);
2807         assert (atan2(T.one, T.zero) == T.PI_2);
2808         assert (atan2(T.one, -T.infinity) == T.PI);
2809         assert (atan2(-T.one, -T.infinity) == -T.PI);
2810         assert (atan2(T.one, T.infinity) == T.zero);
2811         assert (atan2(-T.one, T.infinity) == -T.zero);
2812         assert (atan2(-T.infinity, T.one) == -T.PI_2);
2813         assert (atan2(T.infinity, T.one) == T.PI_2);
2814         assert (atan2(-T.infinity, -T.infinity) == -T._3PI_4);
2815         assert (atan2(T.infinity, -T.infinity) == T._3PI_4);
2816         assert (atan2(-T.infinity, T.infinity) == -T.PI_4);
2817         assert (atan2(T.infinity, T.infinity) == T.PI_4);
2818     }
2819 }
2820 
2821 /**
2822 Calculates the arc tangent of y / x divided by π, returning a value ranging from -1 to 1.
2823 Exceptions:
2824 $(BOOKTABLE,
2825     $(TR $(TD $(MYREF InvalidOperationException)) 
2826          $(TD x or y is signaling $(B NaN)))
2827     $(TR $(TD $(MYREF InexactException)) 
2828          $(TD the result is inexact))
2829     $(TR $(TD $(MYREF UnderflowException)) 
2830          $(TD the result is too small to be represented))
2831 )
2832 Special_values:
2833 $(BOOKTABLE,
2834     $(TR $(TH y) $(TH x) $(TH atan2pi(y, x)))
2835     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
2836     $(TR $(TD any) $(TD $(B NaN)) $(TD $(B NaN)))
2837     $(TR $(TD ±0.0) $(TD -0.0) $(TD ±1.0))
2838     $(TR $(TD ±0.0) $(TD +0.0) $(TD ±0.0))
2839     $(TR $(TD ±0.0) $(TD <0.0) $(TD ±1.0))
2840     $(TR $(TD ±0.0) $(TD >0.0) $(TD ±0.0))
2841     $(TR $(TD ±∞) $(TD -∞) $(TD ±3/4))
2842     $(TR $(TD ±∞) $(TD +∞) $(TD ±1/4))
2843     $(TR $(TD ±∞) $(TD any) $(TD ±1/2))
2844     $(TR $(TD any) $(TD -∞) $(TD ±1.0))
2845     $(TR $(TD any) $(TD +∞) $(TD ±0.0))
2846 )
2847 */
2848 @IEEECompliant("atan2Pi", 43)
2849 auto atan2pi(D1, D2)(auto const ref D1 y, auto const ref D2 x)
2850 if (isDecimal!(D1, D2))
2851 {
2852     alias D = CommonDecimal!(D1, D2);
2853     D result;
2854     auto flags = decimalAtan2Pi(y, x, result, 
2855                               __ctfe ? D.PRECISION : DecimalControl.precision, 
2856                               __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
2857     flags &= ExceptionFlags.invalidOperation | ExceptionFlags.underflow | ExceptionFlags.inexact;
2858     DecimalControl.raiseFlags(flags);
2859     return result;
2860 }
2861 
2862 ///
2863 unittest
2864 {
2865     decimal32 y = 10;
2866     decimal32 x = 0;
2867     assert (atan2pi(y, x) == decimal32("0.5"));
2868 }
2869 
2870 unittest
2871 {
2872 
2873     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
2874     {
2875         assert (isNaN(atan2(T.nan, T.zero)));
2876         assert (isNaN(atan2(T.one, T.nan)));
2877         assert (atan2pi(T.zero, -T.zero) == T.one); 
2878         assert (atan2pi(-T.zero, -T.zero) == -T.one); 
2879         assert (atan2pi(T.zero, T.zero) == T.zero);
2880         assert (atan2pi(-T.zero, T.zero) == -T.zero); 
2881         assert (atan2pi(T.zero, -T.one) == T.one);
2882         assert (atan2pi(-T.zero, -T.one) == -T.one);
2883         assert (atan2pi(T.zero, T.one) == T.zero);
2884         assert (atan2pi(-T.zero, T.one) == -T.zero);
2885         assert (atan2pi(-T.one, T.zero) == -T.half);
2886         assert (atan2pi(T.one, T.zero) == T.half);
2887         assert (atan2pi(T.one, -T.infinity) == T.one);
2888         assert (atan2pi(-T.one, -T.infinity) == -T.one);
2889         assert (atan2pi(T.one, T.infinity) == T.zero);
2890         assert (atan2pi(-T.one, T.infinity) == -T.zero);
2891         assert (atan2pi(-T.infinity, T.one) == -T.half);
2892         assert (atan2pi(T.infinity, T.one) == T.half);
2893         assert (atan2pi(-T.infinity, -T.infinity) == -T.threequarters);
2894         assert (atan2pi(T.infinity, -T.infinity) == T.threequarters);
2895         assert (atan2pi(-T.infinity, T.infinity) == -T.quarter);
2896         assert (atan2pi(T.infinity, T.infinity) == T.quarter);
2897     }
2898 }
2899 
2900 /**
2901 Calculates the inverse hyperbolic tangent of x
2902 Exceptions:
2903 $(BOOKTABLE,
2904     $(TR $(TD $(MYREF InvalidOperationException)) 
2905          $(TD x is signaling $(B NaN) or |x| > 1.0))
2906     $(TR $(TD $(MYREF DivisionByZeroException)) 
2907          $(TD |x| = 1.0))
2908     $(TR $(TD $(MYREF UnderflowException)) 
2909          $(TD the result is too small to be represented))
2910     $(TR $(TD $(MYREF InexactException)) 
2911          $(TD the result is inexact))
2912 )
2913 Special_values:
2914 $(BOOKTABLE,
2915     $(TR $(TH x) $(TH atanh(x)))
2916     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
2917     $(TR $(TD ±0.0) $(TD ±0.0))
2918     $(TR $(TD ±1.0) $(TD ±∞))
2919     $(TR $(TD >1.0) $(TD $(B NaN)))
2920     $(TR $(TD <1.0) $(TD $(B NaN)))
2921 )
2922 */
2923 @IEEECompliant("atanh", 43)
2924 D atanh(D)(auto const ref D x)
2925 if (isDecimal!D)
2926 {
2927     Unqual!D result = x;
2928     auto flags = decimalAtanh(result, 
2929                              __ctfe ? D.PRECISION : DecimalControl.precision, 
2930                              __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
2931     flags &= ExceptionFlags.invalidOperation | ExceptionFlags.underflow | 
2932              ExceptionFlags.inexact | ExceptionFlags.divisionByZero;
2933     DecimalControl.raiseFlags(flags);
2934     return result;
2935 }
2936 
2937 ///
2938 unittest
2939 {
2940     decimal32 x = 0;
2941     assert (atanh(x) == 0);
2942 }
2943 
2944 /**
2945 Calculates the arc tangent of x divided by π, returning a value ranging from -1/2 to 1/2.
2946 Exceptions:
2947 $(BOOKTABLE,
2948     $(TR $(TD $(MYREF InvalidOperationException)) 
2949          $(TD x is signaling $(B NaN)))
2950     $(TR $(TD $(MYREF InexactException)) 
2951          $(TD the result is inexact))
2952     $(TR $(TD $(MYREF UnderflowException)) 
2953          $(TD the result is too small to be represented))
2954 )
2955 Special_values:
2956 $(BOOKTABLE,
2957     $(TR $(TH x) $(TH atan(x)))
2958     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
2959     $(TR $(TD ±0.0) $(TD ±0.0))
2960     $(TR $(TD ±∞) $(TD ±1/2))
2961 )
2962 */
2963 @IEEECompliant("atanPi", 43)
2964 D atanpi(D)(auto const ref D x)
2965 if (isDecimal!D)
2966 {
2967     Unqual!D result = x;
2968     auto flags = decimalAtanPi(result, 
2969                               __ctfe ? D.PRECISION : DecimalControl.precision, 
2970                               __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
2971     flags &= ExceptionFlags.invalidOperation | ExceptionFlags.underflow | ExceptionFlags.inexact;
2972     DecimalControl.raiseFlags(flags);
2973     return result;
2974 }
2975 
2976 ///
2977 unittest
2978 {
2979     decimal32 radians = 1;
2980     assert (atanpi(radians) == decimal32("0.25"));
2981 }
2982 
2983 
2984 unittest
2985 {
2986     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
2987     {
2988         assert (isIdentical(atanpi(T.zero), T.zero));
2989         assert (isIdentical(atanpi(-T.zero), -T.zero));
2990         assert (isIdentical(atanpi(T.infinity), T.half));
2991         assert (isIdentical(atanpi(-T.infinity), -T.half));
2992         assert (isNaN(atanpi(T.nan)));
2993     }
2994 }
2995 
2996 /**
2997 Computes the cubic root of x
2998 Throws:
2999 $(BOOKTABLE,
3000     $(TR $(TD $(MYREF InvalidOperationException)) 
3001          $(TD x is signaling $(B NaN)))
3002     $(TR $(TD $(MYREF UnderflowException)) 
3003          $(TD cubic root of x is too small to be represented))
3004     $(TR $(TD $(MYREF InexactException)) 
3005          $(TD the result is inexact))
3006 )
3007 Special_values:
3008 $(BOOKTABLE,
3009     $(TR $(TH x) $(TH cbrt(x)))
3010     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3011     $(TR $(TD ±0.0) $(TD ±0.0))
3012     $(TR $(TD ±∞) $(TD ±∞))
3013 )
3014 */
3015 D cbrt(D)(auto const ref D x)
3016 if (isDecimal!D)
3017 {
3018     Unqual!D result = x;
3019     auto flags = decimalCbrt(result, 
3020                             __ctfe ? D.PRECISION : DecimalControl.precision, 
3021                             __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3022     DecimalControl.raiseFlags(flags);
3023     return result;
3024 }
3025 
3026 ///
3027 unittest
3028 {
3029     decimal32 x = 27;
3030     assert (cbrt(x) == 3);
3031 }
3032 
3033 /**
3034 Returns the value of x rounded upward to the next integer (toward positive infinity).
3035 This operation is silent, doesn't throw any exception.
3036 Special_values:
3037 $(BOOKTABLE,
3038     $(TR $(TH x) $(TH ceil(x)))
3039     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3040     $(TR $(TD ±0.0) $(TD ±0.0))
3041     $(TR $(TD ±∞) $(TD ±∞))
3042 )
3043 */
3044 D ceil(D)(auto const ref D x)
3045 if (isDecimal!D)
3046 {
3047     Unqual!D result = x;
3048     decimalRound(result, 0, RoundingMode.towardPositive);
3049     return result;
3050 }
3051 
3052 ///
3053 unittest
3054 {
3055     assert (ceil(decimal32("123.456")) == 124);
3056     assert (ceil(decimal32("-123.456")) == -123);
3057 }
3058 
3059 /**
3060 Defines a total order on all _decimal values.
3061 Params:
3062     x = a _decimal value
3063     y = a _decimal value
3064 Returns:
3065     -1 if x precedes y, 0 if x is equal to y, +1 if x follows y
3066 Notes:
3067     The total order is defined as:<br/>
3068     - -sNaN < -$(B NaN) < -infinity < -finite < -0.0 < +0.0 < +finite < +infinity < +$(B NaN) < +sNaN<br/>
3069     - for two $(B NaN) values the total order is defined based on the payload 
3070 */
3071 int cmp(D1, D2)(auto const ref D1 x, auto const ref D2 y)
3072 if (isDecimal!(D1, D2))
3073 {
3074     static if (is(D1 : D2))
3075     {
3076         if (x.data == y.data)
3077             return 0;
3078     }
3079     alias U = CommonStorage!(D1, D2);
3080     U cx, cy; int ex, ey; bool sx, sy;
3081     auto fx = fastDecode(x, cx, ex, sx);
3082     auto fy = fastDecode(y, cy, ey, sy);
3083     
3084     if (sx != sy)
3085         return sx ? -1 : 1;
3086     
3087     if (fx == FastClass.quietNaN)
3088     {
3089         if (fy == FastClass.quietNaN)
3090         {
3091             if (cx > cy)
3092                 return sx ? -1 : 1;
3093             else if (cx < cy)
3094                 return sx ? 1 : -1;
3095             return 0;
3096         }
3097         return sx ? -1 : 1;
3098     }
3099 
3100     if (fy == FastClass.quietNaN)
3101         return sx ? 1 : -1;
3102 
3103     if (fx == FastClass.signalingNaN)
3104     {
3105         if (fy == FastClass.signalingNaN)
3106         {
3107             if (cx > cy)
3108                 return sx ? -1 : 1;
3109             else if (cx < cy)
3110                 return sx ? 1 : -1;
3111             return 0;
3112         }
3113         return sx ? -1 : 1;
3114     }
3115 
3116     if (fy == FastClass.signalingNaN)
3117         return sx ? 1 : -1;
3118 
3119     
3120 
3121     if (fx == FastClass.infinite)
3122     {
3123         if (fy == FastClass.infinite)
3124             return 0;
3125         return sx ? -1 : 1;
3126     }
3127 
3128     if (fy == FastClass.infinite)
3129         return sx ? 1 : -1;
3130 
3131     //if (fx == FastClass.zero)
3132     //{
3133     //    if (fy == FastClass.zero)
3134     //        return 0;
3135     //    return sx ? 1 : -1;
3136     //}
3137     //
3138     //if (fy == FastClass.zero)
3139     //    return sx ? -1 : 1;
3140 
3141     int c = coefficientCmp(cx, ex, cy, ey);
3142 
3143     if (c == 0)
3144     {
3145         if (ex > ey)
3146             c = sx ? -1 : 1;
3147         else if (ex < ey)
3148             c = sx ? 1 : -1;
3149     }
3150     else if (sx)
3151         c = -c;
3152 
3153     return c;
3154 
3155 }
3156 
3157 ///
3158 unittest
3159 {
3160     assert (cmp(-decimal32.nan, decimal64.max) == -1);
3161     assert (cmp(decimal32.max, decimal128.min_normal) == 1);
3162     assert (cmp(decimal64(0), -decimal64(0)) == 1);
3163 }
3164 /**
3165 Computes (1 + x)$(SUPERSCRIPT n) where n is an integer
3166 Throws:
3167 $(BOOKTABLE,
3168     $(TR $(TD $(MYREF InvalidOperationException)) 
3169          $(TD x is signaling $(B NaN) or x < -1.0))
3170     $(TR $(TD $(MYREF DivisionByZeroException)) 
3171          $(TD x = -1.0 and n < 0))
3172     $(TR $(TD $(MYREF OverflowException)) 
3173          $(TD result is too big to be represented))
3174     $(TR $(TD $(MYREF UnderflowException)) 
3175          $(TD result is too small to be represented))
3176     $(TR $(TD $(MYREF InexactException)) 
3177          $(TD the result is inexact))
3178 )
3179 Special_values:
3180 $(BOOKTABLE,
3181     $(TR $(TH x) $(TH n) $(TH compound(x, n)))
3182     $(TR $(TD sNaN) $(TD any) $(TD $(B NaN)))
3183     $(TR $(TD any) $(TD 0) $(TD +1.0))
3184     $(TR $(TD -1.0) $(TD <0) $(TD +∞))
3185     $(TR $(TD -1.0) $(TD >0) $(TD +0.0))
3186     $(TR $(TD +∞) $(TD any) $(TD +∞))
3187 )
3188 */
3189 @IEEECompliant("compound", 42)
3190 auto compound(D)(auto const ref D x, const int n)
3191 if (isDecimal!D)
3192 {
3193     Unqual!D result = x;
3194     auto flags = decimalCompound(result, n,
3195                                __ctfe ? D.PRECISION : DecimalControl.precision, 
3196                                __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3197     DecimalControl.raiseFlags(flags);
3198     return result;
3199 }
3200 
3201 unittest
3202 {
3203     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
3204     {
3205         assert (compound(T.ten, 0) == 1);
3206         assert (compound(T.infinity, 0) == 1);
3207         assert (compound(-T.one, 0) == 1);
3208         assert (compound(T.zero, 0) == 1);
3209         assert (compound(-T.one, 5) == 0);
3210         assert (compound(T.infinity, 5) == T.infinity);
3211     }
3212 }
3213 
3214 ///
3215 unittest
3216 {
3217     decimal32 x = "0.2";
3218     assert (compound(x, 2) == decimal32("1.44"));
3219 }
3220 
3221 /**
3222 Copies the sign of a _decimal value _to another.
3223 This operation is silent, no error flags are set and no exceptions are thrown.
3224 Params:
3225     to = a _decimal value to copy
3226     from = a _decimal value from which the sign is copied
3227 Returns: 
3228     to with the sign of from
3229 */
3230 @IEEECompliant("copySign", 23)
3231 D1 copysign(D1, D2)(auto const ref D1 to, auto const ref D2 from)
3232 if (isDecimal!(D1, D2))
3233 {
3234     Unqual!D1 result = to;
3235     bool sx = cast(bool)((from.data & D2.MASK_SGN) == D2.MASK_SGN);
3236 
3237     static if (is(D1: decimal32) || is(D1: decimal64))
3238     {
3239         if (sx)
3240             result.data |= D1.MASK_SGN;
3241         else
3242             result.data &= ~D1.MASK_SGN;
3243     }
3244     else
3245     {
3246         if (sx)
3247             result.data.hi |= D1.MASK_SGN.hi;
3248         else
3249             result.data.hi &= ~D1.MASK_SGN.hi;
3250     }
3251 
3252     return result;
3253 }
3254 
3255 ///
3256 unittest
3257 {
3258     decimal32 negative = -decimal32.min_normal;
3259     decimal64 test = decimal64.max;
3260     assert(copysign(test, negative) == -decimal64.max);
3261 
3262 }
3263 
3264 /**
3265 Returns cosine of x.
3266 Throws:
3267 $(BOOKTABLE,
3268     $(TR $(TD $(MYREF InvalidOperationException)) 
3269          $(TD x is signaling $(B NaN) or ±∞))
3270     $(TR $(TD $(MYREF UnderflowException)) 
3271          $(TD result is too small to be represented))
3272     $(TR $(TD $(MYREF InexactException)) 
3273          $(TD the result is inexact))
3274 )
3275 Special_values:
3276 $(BOOKTABLE,
3277     $(TR $(TH x) $(TH cos(x)))
3278     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3279     $(TR $(TD ±∞) $(TD $(B NaN)))
3280     $(TR $(TD ±0.0) $(TD +1.0))
3281     $(TR $(TD π/6) $(TD +√3/2))
3282     $(TR $(TD π/4) $(TD +√2/2))
3283     $(TR $(TD π/3) $(TD +0.5))
3284     $(TR $(TD π/2) $(TD +0.0))
3285     $(TR $(TD 2π/3) $(TD -0.5))
3286     $(TR $(TD 3π/4) $(TD -√2/2))
3287     $(TR $(TD 5π/6) $(TD -√3/2))
3288     $(TR $(TD π) $(TD -1.0))
3289 )
3290 */
3291 @IEEECompliant("cos", 42)
3292 D cos(D)(auto const ref D x)
3293 if (isDecimal!D)
3294 {
3295     Unqual!D result = x;
3296     auto flags = decimalCos(result, 
3297                              __ctfe ? D.PRECISION : DecimalControl.precision, 
3298                              __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3299     DecimalControl.raiseFlags(flags);
3300     return result;
3301 }
3302 
3303 
3304 /**
3305 Calculates the hyperbolic cosine of x.
3306 Throws:
3307 $(BOOKTABLE,
3308     $(TR $(TD $(MYREF InvalidOperationException)) 
3309          $(TD x is signaling $(B NaN)))
3310     $(TR $(TD $(MYREF OverflowException)) 
3311          $(TD result is too big to be represented))
3312     $(TR $(TD $(MYREF InexactException)) 
3313          $(TD the result is inexact))
3314 )
3315 Special_values:
3316 $(BOOKTABLE,
3317     $(TR $(TH x) $(TH cosh(x)))
3318     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3319     $(TR $(TD ±∞) $(TD +∞))
3320     $(TR $(TD ±0.0) $(TD +1.0))
3321 )
3322 */
3323 @IEEECompliant("cosh", 42)
3324 D cosh(D)(auto const ref D x)
3325 if (isDecimal!D)
3326 {
3327     Unqual!D result = x;
3328     auto flags = decimalCosh(result, 
3329                             __ctfe ? D.PRECISION : DecimalControl.precision, 
3330                             __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3331     DecimalControl.raiseFlags(flags);
3332     return result;
3333 }
3334 
3335 //unittest
3336 //{
3337 //    import std.stdio;
3338 //    import std.math;
3339 //    for(int i = 1; i < 10; ++i)
3340 //    {
3341 //        writefln("+%3.2f %35.34f %35.34f", i/10.0, cosh(decimal128(i)/10), std.math.cosh(i/10.0));
3342 //    }
3343 //}
3344 
3345 /**
3346 Returns cosine of xπ.
3347 Throws:
3348 $(BOOKTABLE,
3349     $(TR $(TD $(MYREF InvalidOperationException)) 
3350          $(TD x is signaling $(B NaN) or ±∞))
3351     $(TR $(TD $(MYREF UnderflowException)) 
3352          $(TD result is too small to be represented))
3353     $(TR $(TD $(MYREF InexactException)) 
3354          $(TD the result is inexact))
3355 )
3356 Special_values:
3357 $(BOOKTABLE,
3358     $(TR $(TH x) $(TH cospi(x)))
3359     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3360     $(TR $(TD ±∞) $(TD $(B NaN)))
3361     $(TR $(TD ±0.0) $(TD +1.0))
3362     $(TR $(TD 1/6) $(TD +√3/2))
3363     $(TR $(TD 1/4) $(TD +√2/2))
3364     $(TR $(TD 1/3) $(TD +0.5))
3365     $(TR $(TD 1/2) $(TD +0.0))
3366     $(TR $(TD 2/3) $(TD -0.5))
3367     $(TR $(TD 3/4) $(TD -√2/2))
3368     $(TR $(TD 5/6) $(TD -√3/2))
3369     $(TR $(TD 1.0) $(TD -1.0))
3370 )
3371 */
3372 @IEEECompliant("cosPi", 42)
3373 D cospi(D)(auto const ref D x)
3374 if (isDecimal!D)
3375 {
3376     Unqual!D result = x;
3377     auto flags = decimalCosPi(result, 
3378                              __ctfe ? D.PRECISION : DecimalControl.precision, 
3379                              __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3380     DecimalControl.raiseFlags(flags);
3381     return result;
3382 }
3383 
3384 ///IEEE-754-2008 floating point categories
3385 enum DecimalClass
3386 {
3387     ///a signalling $(B NaN) represents most of the time an uninitialized variable; 
3388     ///a quiet $(B NaN) represents the result of an invalid operation
3389     signalingNaN,
3390     ///ditto
3391     quietNaN,
3392     ///value represents infinity
3393     negativeInfinity,
3394     ///ditto
3395     positiveInfinity,
3396     ///value represents a normalized _decimal value
3397     negativeNormal,
3398     ///ditto
3399     positiveNormal,
3400     ///value represents a subnormal _decimal value
3401     negativeSubnormal,
3402     ///ditto
3403     positiveSubnormal,
3404     ///value is 0
3405     negativeZero,
3406     ///ditto
3407     positiveZero,
3408 }
3409 
3410 /**
3411 Returns the decimal class where x falls into.
3412 This operation is silent, no exception flags are set and no exceptions are thrown.
3413 Params:
3414     x = a _decimal value
3415 Returns: 
3416     One of the members of $(MYREF DecimalClass) enumeration
3417 */
3418 @IEEECompliant("class", 25)
3419 DecimalClass decimalClass(D)(auto const ref D x) 
3420 if (isDecimal!D)
3421 {
3422     DataType!D coefficient;
3423     uint exponent;
3424 
3425     static if (is(D: decimal32) || is(D: decimal64))
3426     {
3427         if ((x.data & D.MASK_INF) == D.MASK_INF)
3428             if ((x.data & D.MASK_QNAN) == D.MASK_QNAN)
3429                 if ((x.data & D.MASK_SNAN) == D.MASK_SNAN)
3430                     return DecimalClass.signalingNaN;
3431                 else
3432                     return DecimalClass.quietNaN;
3433             else
3434                 return x.data & D.MASK_SGN ? DecimalClass.negativeInfinity : DecimalClass.positiveInfinity;
3435         else if ((x.data & D.MASK_EXT) == D.MASK_EXT)
3436         {
3437             coefficient = (x.data & D.MASK_COE2) | D.MASK_COEX;
3438             if (coefficient > D.COEF_MAX)
3439                 return x.data & D.MASK_SGN ? DecimalClass.negativeZero : DecimalClass.positiveZero; 
3440             exponent = cast(uint)((x.data & D.MASK_EXP2) >>> D.SHIFT_EXP2);
3441         }
3442         else
3443         {
3444             coefficient = x.data & D.MASK_COE1;
3445             if (coefficient == 0U)
3446                 return (x.data & D.MASK_SGN) == D.MASK_SGN ? DecimalClass.negativeZero : DecimalClass.positiveZero; 
3447             exponent = cast(uint)((x.data & D.MASK_EXP1) >>> D.SHIFT_EXP1);
3448         }
3449         bool sx = (x.data & D.MASK_SGN) == D.MASK_SGN;
3450     }
3451     else
3452     {
3453         if ((x.data.hi & D.MASK_INF.hi) == D.MASK_INF.hi)
3454             if ((x.data.hi & D.MASK_QNAN.hi) == D.MASK_QNAN.hi)
3455                 if ((x.data.hi & D.MASK_SNAN.hi) == D.MASK_SNAN.hi)
3456                     return DecimalClass.signalingNaN;
3457                 else
3458                     return DecimalClass.quietNaN;
3459             else
3460                 return x.data.hi & D.MASK_SGN.hi ? DecimalClass.negativeInfinity : DecimalClass.positiveInfinity;
3461         else if ((x.data.hi & D.MASK_EXT.hi) == D.MASK_EXT.hi)
3462             return (x.data.hi & D.MASK_SGN.hi) == D.MASK_SGN.hi ? DecimalClass.negativeZero : DecimalClass.positiveZero; 
3463         else
3464         {
3465             coefficient = x.data & D.MASK_COE1;
3466             if (coefficient == 0U || coefficient > D.COEF_MAX)
3467                 return (x.data.hi & D.MASK_SGN.hi) == D.MASK_SGN.hi ? DecimalClass.negativeZero : DecimalClass.positiveZero; 
3468             exponent = cast(uint)((x.data & D.MASK_EXP1) >>> D.SHIFT_EXP1);
3469         }
3470         bool sx = (x.data.hi & D.MASK_SGN.hi) == D.MASK_SGN.hi;
3471     }
3472 
3473     if (exponent < D.PRECISION - 1)
3474     {
3475         if (prec(coefficient) < D.PRECISION - exponent)
3476             return sx ? DecimalClass.negativeSubnormal : DecimalClass.positiveSubnormal;
3477     }
3478     return sx ? DecimalClass.negativeNormal : DecimalClass.positiveNormal;
3479 }
3480 
3481 ///
3482 unittest
3483 {
3484     assert(decimalClass(decimal32.nan) == DecimalClass.quietNaN);
3485     assert(decimalClass(decimal64.infinity) == DecimalClass.positiveInfinity);
3486     assert(decimalClass(decimal128.max) == DecimalClass.positiveNormal);
3487     assert(decimalClass(-decimal32.max) == DecimalClass.negativeNormal);
3488     assert(decimalClass(decimal128.epsilon) == DecimalClass.positiveNormal);
3489 }
3490 
3491 unittest
3492 {
3493     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
3494     {
3495         assert(decimalClass(T.snan) == DecimalClass.signalingNaN);
3496         assert(decimalClass(T.qnan) == DecimalClass.quietNaN);
3497         assert(decimalClass(T.minusInfinity) == DecimalClass.negativeInfinity);
3498         assert(decimalClass(T.infinity) == DecimalClass.positiveInfinity);
3499         assert(decimalClass(T.zero) == DecimalClass.positiveZero);
3500         assert(decimalClass(T.minusZero) == DecimalClass.negativeZero);
3501         assert(decimalClass(T.subn) == DecimalClass.positiveSubnormal);
3502         assert(decimalClass(T.minusSubn) == DecimalClass.negativeSubnormal);
3503         assert(decimalClass(T.ten) == DecimalClass.positiveNormal);
3504         assert(decimalClass(T.minusTen) == DecimalClass.negativeNormal);
3505         assert(decimalClass(T.max) == DecimalClass.positiveNormal);
3506         assert(decimalClass(-T.max) == DecimalClass.negativeNormal);
3507         assert(decimalClass(T.min_normal) == DecimalClass.positiveNormal);
3508         assert(decimalClass(T.epsilon) == DecimalClass.positiveNormal);
3509     }
3510 }
3511 
3512 
3513 
3514 /**
3515 Sums x$(SUBSCRIPT i) * y$(SUBSCRIPT i) using a higher precision, rounding only once at the end.
3516 Returns:
3517     x$(SUBSCRIPT 0) * y$(SUBSCRIPT 0) + x$(SUBSCRIPT 1) * y$(SUBSCRIPT 1) + ... + x$(SUBSCRIPT n) * y$(SUBSCRIPT n)
3518 Notes:
3519     If x and y arrays are not of the same length, operation is performed for min(x.length, y.length);
3520 Throws:
3521 $(BOOKTABLE,
3522     $(TR $(TD $(MYREF InvalidOperationException)) 
3523          $(TD any x is signaling $(B NaN)))
3524     $(TR $(TD $(MYREF InvalidOperationException)) 
3525          $(TD any combination of elements is (±∞, ±0.0) or (±0.0, ±∞)))
3526     $(TR $(TD $(MYREF InvalidOperationException)) 
3527          $(TD there are two products resulting in infinities of different sign))
3528     $(TR $(TD $(MYREF OverflowException)) 
3529          $(TD result is too big to be represented))
3530     $(TR $(TD $(MYREF UnderflowException)) 
3531          $(TD result is too small to be represented))
3532     $(TR $(TD $(MYREF InexactException)) 
3533          $(TD result is inexact))
3534 )
3535 */
3536 @IEEECompliant("dot", 47)
3537 D dot(D)(const(D)[] x, const(D)[] y)
3538 if (isDecimal!D)
3539 {
3540     Unqual!D result = x;
3541     auto flags = decimalDot(x, y, result, 
3542                             __ctfe ? D.PRECISION : DecimalControl.precision, 
3543                             __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3544     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.overflow | ExceptionFlags.underflow);
3545     DecimalControl.raiseFlags(flags);
3546     return result;
3547 }
3548 
3549 /**
3550 Calculates e$(SUPERSCRIPT x)
3551 Throws:
3552 $(BOOKTABLE,
3553     $(TR $(TD $(MYREF InvalidOperationException)) 
3554          $(TD x is signaling $(B NaN)))
3555     $(TR $(TD $(MYREF UnderflowException)) 
3556          $(TD e$(SUPERSCRIPT x) is too small to be represented))
3557     $(TR $(TD $(MYREF OverflowException)) 
3558          $(TD e$(SUPERSCRIPT x) is too big to be represented))
3559     $(TR $(TD $(MYREF InexactException)) 
3560          $(TD the result is inexact))
3561 )
3562 Special_values:
3563 $(BOOKTABLE,
3564     $(TR $(TH x) $(TH exp(x)))
3565     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3566     $(TR $(TD ±0.0) $(TD +1.0))
3567     $(TR $(TD -∞) $(TD 0))
3568     $(TR $(TD +∞) $(TD +∞))
3569 )
3570 */
3571 @IEEECompliant("exp", 42)
3572 D exp(D)(auto const ref D x)
3573 if (isDecimal!D)
3574 {
3575     Unqual!D result = x;
3576     auto flags = decimalExp(result, 
3577                             __ctfe ? D.PRECISION : DecimalControl.precision, 
3578                             __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3579     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.overflow | ExceptionFlags.underflow);
3580     DecimalControl.raiseFlags(flags);
3581     return result;
3582 }
3583 
3584 ///
3585 unittest
3586 {
3587     decimal32 power = 1;
3588     assert (exp(power) == decimal32.E);
3589 }
3590 
3591 unittest
3592 {
3593     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
3594     {
3595         assert (exp(T.zero) == T.one);
3596         assert (exp(-T.infinity) == T.zero);
3597         assert (exp(T.infinity) == T.infinity);
3598         assert (isNaN(exp(T.nan)));
3599     }
3600 }
3601 
3602 /**
3603 Calculates 10$(SUPERSCRIPT x)
3604 Throws:
3605 $(BOOKTABLE,
3606     $(TR $(TD $(MYREF InvalidOperationException)) 
3607          $(TD x is signaling $(B NaN)))
3608     $(TR $(TD $(MYREF UnderflowException)) 
3609          $(TD 10$(SUPERSCRIPT x) is too small to be represented))
3610     $(TR $(TD $(MYREF OverflowException)) 
3611          $(TD 10$(SUPERSCRIPT x) is too big to be represented))
3612     $(TR $(TD $(MYREF InexactException)) 
3613          $(TD the result is inexact))
3614 )
3615 Special_values:
3616 $(BOOKTABLE,
3617     $(TR $(TH x) $(TH exp10(x)))
3618     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3619     $(TR $(TD ±0.0) $(TD +1.0))
3620     $(TR $(TD -∞) $(TD +0.0))
3621     $(TR $(TD +∞) $(TD +∞))
3622 )
3623 */
3624 @IEEECompliant("exp10", 42)
3625 D exp10(D)(auto const ref D x)
3626 if (isDecimal!D)
3627 {
3628     Unqual!D result = x;
3629     auto flags = decimalExp10(result, 
3630                             __ctfe ? D.PRECISION : DecimalControl.precision, 
3631                             __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3632     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.overflow | ExceptionFlags.underflow);
3633     DecimalControl.raiseFlags(flags);
3634     return result;
3635 }
3636 
3637 ///
3638 unittest
3639 {
3640     decimal32 x = 3;
3641     assert(exp10(x) == 1000);
3642 }
3643 
3644 
3645 /**
3646 Calculates 10$(SUPERSCRIPT x) - 1
3647 Throws:
3648 $(BOOKTABLE,
3649     $(TR $(TD $(MYREF InvalidOperationException)) 
3650          $(TD x is signaling $(B NaN)))
3651     $(TR $(TD $(MYREF UnderflowException)) 
3652          $(TD 10$(SUPERSCRIPT x) - 1 is too small to be represented))
3653     $(TR $(TD $(MYREF OverflowException)) 
3654          $(TD 10$(SUPERSCRIPT x) - 1 is too big to be represented))
3655     $(TR $(TD $(MYREF InexactException)) 
3656          $(TD the result is inexact))
3657 )
3658 Special_values:
3659 $(BOOKTABLE,
3660     $(TR $(TH x) $(TH exp10m1(x)))
3661     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3662     $(TR $(TD ±0.0) $(TD ±0.0))
3663     $(TR $(TD -∞) $(TD -1.0))
3664     $(TR $(TD +∞) $(TD +∞))
3665 )
3666 */
3667 @IEEECompliant("exp10m1", 42)
3668 D exp10m1(D)(auto const ref D x)
3669 if (isDecimal!D)
3670 {
3671     Unqual!D result = x;
3672     auto flags = decimalExp10m1(result, 
3673                               __ctfe ? D.PRECISION : DecimalControl.precision, 
3674                               __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3675     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.overflow | ExceptionFlags.underflow);
3676     DecimalControl.raiseFlags(flags);
3677     return result;
3678 }
3679 
3680 ///
3681 unittest
3682 {
3683     decimal32 x = 3;
3684     assert(exp10m1(x) == 999);
3685 }
3686 
3687 /**
3688 Calculates 2$(SUPERSCRIPT x)
3689 Throws:
3690 $(BOOKTABLE,
3691     $(TR $(TD $(MYREF InvalidOperationException)) 
3692          $(TD x is signaling $(B NaN)))
3693     $(TR $(TD $(MYREF UnderflowException)) 
3694          $(TD 2$(SUPERSCRIPT x) is too small to be represented))
3695     $(TR $(TD $(MYREF OverflowException)) 
3696          $(TD 2$(SUPERSCRIPT x) is too big to be represented))
3697     $(TR $(TD $(MYREF InexactException)) 
3698          $(TD the result is inexact))
3699 )
3700 Special_values:
3701 $(BOOKTABLE,
3702     $(TR $(TH x) $(TH exp2(x)))
3703     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3704     $(TR $(TD ±0.0) $(TD +1.0))
3705     $(TR $(TD -∞) $(TD +0.0))
3706     $(TR $(TD +∞) $(TD +∞))
3707 )
3708 */
3709 @IEEECompliant("exp2", 42)
3710 D exp2(D)(auto const ref D x)
3711 if (isDecimal!D)
3712 {
3713     Unqual!D result = x;
3714     auto flags = decimalExp2(result, 
3715                               __ctfe ? D.PRECISION : DecimalControl.precision, 
3716                               __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3717     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.overflow | ExceptionFlags.underflow);
3718     DecimalControl.raiseFlags(flags);
3719     return result;
3720 }
3721 
3722 ///
3723 unittest
3724 {
3725     decimal32 x = 3;
3726     assert(exp2(x) == 8);
3727 }
3728 
3729 /**
3730 Calculates 2$(SUPERSCRIPT x) - 1
3731 Throws:
3732 $(BOOKTABLE,
3733     $(TR $(TD $(MYREF InvalidOperationException)) 
3734          $(TD x is signaling $(B NaN)))
3735     $(TR $(TD $(MYREF UnderflowException)) 
3736          $(TD 2$(SUPERSCRIPT x) - 1 is too small to be represented))
3737     $(TR $(TD $(MYREF OverflowException)) 
3738          $(TD 2$(SUPERSCRIPT x) - 1 is too big to be represented))
3739     $(TR $(TD $(MYREF InexactException)) 
3740          $(TD the result is inexact))
3741 )
3742 Special_values:
3743 $(BOOKTABLE,
3744     $(TR $(TH x) $(TH exp2m1(x)))
3745     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3746     $(TR $(TD ±0.0) $(TD ±0.0))
3747     $(TR $(TD -∞) $(TD -1.0))
3748     $(TR $(TD +∞) $(TD +∞))
3749 )
3750 */
3751 @IEEECompliant("exp2m1", 42)
3752 D exp2m1(D)(auto const ref D x)
3753 if (isDecimal!D)
3754 {
3755     Unqual!D result = x;
3756     auto flags = decimalExp2m1(result, 
3757                              __ctfe ? D.PRECISION : DecimalControl.precision, 
3758                              __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3759     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.overflow | ExceptionFlags.underflow);
3760     DecimalControl.raiseFlags(flags);
3761     return result;
3762 }
3763 
3764 ///
3765 unittest
3766 {
3767     decimal32 x = 3;
3768     assert(exp2m1(x) == 7);
3769 }
3770 
3771 /**
3772 Calculates e$(SUPERSCRIPT x) - 1
3773 Throws:
3774 $(BOOKTABLE,
3775     $(TR $(TD $(MYREF InvalidOperationException)) 
3776          $(TD x is signaling $(B NaN)))
3777     $(TR $(TD $(MYREF UnderflowException)) 
3778          $(TD e$(SUPERSCRIPT x) - 1 is too small to be represented))
3779     $(TR $(TD $(MYREF OverflowException)) 
3780          $(TD e$(SUPERSCRIPT x) - 1 is too big to be represented))
3781     $(TR $(TD $(MYREF InexactException)) 
3782          $(TD the result is inexact))
3783 )
3784 Special_values:
3785 $(BOOKTABLE,
3786     $(TR $(TH x) $(TH expm1(x)))
3787     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3788     $(TR $(TD ±0.0) $(TD ±0.0))
3789     $(TR $(TD -∞) $(TD -1.0))
3790     $(TR $(TD +∞) $(TD +∞))
3791 )
3792 */
3793 @IEEECompliant("expm1", 42)
3794 D expm1(D)(auto const ref D x)
3795 if (isDecimal!D)
3796 {
3797     Unqual!D result = x;
3798     auto flags = decimalExpm1(result, 
3799                                __ctfe ? D.PRECISION : DecimalControl.precision, 
3800                                __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
3801     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.overflow | ExceptionFlags.underflow);
3802     DecimalControl.raiseFlags(flags);
3803     return result;
3804 }
3805 
3806 /**
3807 Calculates |x|.
3808 This operation is silent, no error flags are set and no exceptions are thrown.
3809 */
3810 @IEEECompliant("abs", 23)
3811 D fabs(D)(auto const ref D x)
3812 if (isDecimal!D)
3813 {
3814     Unqual!D result = x;
3815     static if (is(D: decimal128))
3816         result.data.hi &= ~D.MASK_SGN.hi;
3817     else
3818         result.data &= ~D.MASK_SGN;
3819     return result;
3820 }
3821 
3822 ///
3823 unittest
3824 {
3825     assert(fabs(-decimal32.max) == decimal32.max);
3826     assert(fabs(decimal64.infinity) == decimal64.infinity);
3827 }
3828 
3829 
3830 /**
3831 Returns the positive difference between x and y. If x ≤ y, retuns 0.0
3832 Throws:
3833 $(BOOKTABLE,
3834     $(TR $(TD $(MYREF InvalidOperationException)) 
3835          $(TD either x or y is $(B signaling NaN)))
3836     $(TR $(TD $(MYREF UnderflowException)) 
3837          $(TD result is subnormal))
3838     $(TR $(TD $(MYREF InexactException)) 
3839          $(TD result is inexact))
3840 )
3841 Special_values:
3842 $(BOOKTABLE,
3843     $(TR $(TH x) $(TH y) $(TH fdim(x, y)))
3844     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
3845     $(TR $(TD any) $(TD $(B NaN)) $(TD $(B NaN)))
3846     $(TR $(TD x > y) $(TD) $(TD x - y))
3847     $(TR $(TD x ≤ y) $(TD) $(TD 0.0))
3848 )
3849 */
3850 auto fdim(D1, D2)(auto const ref D1 x, auto const ref D2 y)
3851 {
3852     alias D = CommonDecimal!(D1, D2);
3853     D result = x;
3854 
3855     if (isInfinity(x) && isInfinity(y))
3856     {
3857         if (signbit(x) == signbit(y))
3858             return D.zero;
3859         else
3860             return result;
3861     }
3862 
3863     if (decimalCmp(y, x) >= 0)
3864         return D.zero;
3865 
3866     auto flags = decimalSub(result, y,
3867                        __ctfe ? 0 : DecimalControl.precision,
3868                        __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
3869     if (!isNaN(result) && signbit(result))
3870         result = D.zero;
3871     DecimalControl.raiseFlags(flags);
3872     return result;
3873 }
3874 
3875 ///
3876 unittest
3877 {
3878     decimal32 x = "10.4";
3879     decimal32 y = "7.3";
3880 
3881     assert (fdim(x, y) == decimal32("3.1"));
3882     assert (fdim(y, x) == 0);
3883 }
3884 
3885 /**
3886 Returns the value of x rounded downward to the previous integer (toward negative infinity).
3887 This operation is silent, doesn't throw any exception.
3888 Special_values:
3889 $(BOOKTABLE,
3890     $(TR $(TH x) $(TH floor(x)))
3891     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
3892     $(TR $(TD ±0.0) $(TD ±0.0))
3893     $(TR $(TD ±∞) $(TD ±∞))
3894 )
3895 */
3896 D floor(D)(auto const ref D x)
3897 if (isDecimal!D)
3898 {
3899     Unqual!D result = x;
3900     decimalRound(result, 0, RoundingMode.towardNegative);
3901     return result;
3902 }
3903 
3904 ///
3905 unittest
3906 {
3907     assert (floor(decimal32("123.456")) == 123);
3908     assert (floor(decimal32("-123.456")) == -124);
3909 }
3910 
3911 /**
3912 Returns (x * y) + z, rounding only once according to the current precision and rounding mode
3913 Throws:
3914 $(BOOKTABLE,
3915     $(TR $(TD $(MYREF InvalidOperationException)) 
3916          $(TD x, y or z is signaling $(B NaN)))
3917     $(TR $(TD $(MYREF InvalidOperationException)) 
3918          $(TD (x, y) = (±∞, ±0.0) or (±0.0, ±∞)))
3919     $(TR $(TD $(MYREF InvalidOperationException)) 
3920          $(TD x or y is infinite, z is infinite but has opposing sign))
3921     $(TR $(TD $(MYREF UnderflowException)) 
3922          $(TD result is too small to be represented))
3923     $(TR $(TD $(MYREF OverflowException)) 
3924          $(TD result is too big to be represented))
3925     $(TR $(TD $(MYREF InexactException)) 
3926          $(TD the result is inexact))
3927 )
3928 Special_values:
3929 $(BOOKTABLE,
3930     $(TR $(TH x) $(TH y) $(TH z) $(TH fma(x, y, z)))
3931     $(TR $(TD $(B NaN)) $(TD any) $(TD any) $(TD $(B NaN)))
3932     $(TR $(TD any) $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
3933     $(TR $(TD any) $(TD any) $(TD $(B NaN)) $(TD $(B NaN)))
3934     $(TR $(TD ±∞) $(TD ±0.0) $(TD any) $(TD $(B NaN)))
3935     $(TR $(TD ±0.0) $(TD ±∞) $(TD any) $(TD $(B NaN)))
3936     $(TR $(TD +∞) $(TD >0.0) $(TD -∞) $(TD $(B NaN)))
3937     $(TR $(TD -∞) $(TD <0.0) $(TD -∞) $(TD $(B NaN)))
3938     $(TR $(TD -∞) $(TD <0.0) $(TD -∞) $(TD $(B NaN)))
3939     $(TR $(TD +∞) $(TD >0.0) $(TD -∞) $(TD $(B NaN)))
3940     $(TR $(TD -∞) $(TD >0.0) $(TD +∞) $(TD $(B NaN)))
3941     $(TR $(TD +∞) $(TD <0.0) $(TD +∞) $(TD $(B NaN)))
3942     $(TR $(TD +∞) $(TD <0.0) $(TD +∞) $(TD $(B NaN)))
3943     $(TR $(TD -∞) $(TD >0.0) $(TD +∞) $(TD $(B NaN)))
3944     $(TR $(TD >0.0) $(TD +∞) $(TD -∞) $(TD $(B NaN)))
3945     $(TR $(TD <0.0) $(TD -∞) $(TD -∞) $(TD $(B NaN)))
3946     $(TR $(TD <0.0) $(TD -∞) $(TD -∞) $(TD $(B NaN)))
3947     $(TR $(TD >0.0) $(TD +∞) $(TD -∞) $(TD $(B NaN)))
3948     $(TR $(TD >0.0) $(TD -∞) $(TD +∞) $(TD $(B NaN)))
3949     $(TR $(TD <0.0) $(TD +∞) $(TD +∞) $(TD $(B NaN)))
3950     $(TR $(TD <0.0) $(TD +∞) $(TD +∞) $(TD $(B NaN)))
3951     $(TR $(TD >0.0) $(TD -∞) $(TD +∞) $(TD $(B NaN)))
3952     $(TR $(TD +∞) $(TD >0.0) $(TD +∞) $(TD +∞))
3953     $(TR $(TD -∞) $(TD <0.0) $(TD +∞) $(TD +∞))
3954     $(TR $(TD +∞) $(TD <0.0) $(TD -∞) $(TD -∞))
3955     $(TR $(TD -∞) $(TD >0.0) $(TD -∞) $(TD -∞))
3956     $(TR $(TD >0.0) $(TD +∞) $(TD +∞) $(TD +∞))
3957     $(TR $(TD <0.0) $(TD -∞) $(TD +∞) $(TD +∞))
3958     $(TR $(TD <0.0) $(TD +∞) $(TD -∞) $(TD -∞))
3959     $(TR $(TD >0.0) $(TD -∞) $(TD -∞) $(TD -∞))
3960     $(TR $(TD +∞) $(TD >0.0) $(TD any) $(TD +∞))
3961     $(TR $(TD -∞) $(TD <0.0) $(TD any) $(TD +∞))
3962     $(TR $(TD +∞) $(TD <0.0) $(TD any) $(TD -∞))
3963     $(TR $(TD -∞) $(TD >0.0) $(TD any) $(TD -∞))
3964     $(TR $(TD >0.0) $(TD +∞) $(TD any) $(TD +∞))
3965     $(TR $(TD <0.0) $(TD -∞) $(TD any) $(TD +∞))
3966     $(TR $(TD <0.0) $(TD +∞) $(TD any) $(TD -∞))
3967     $(TR $(TD >0.0) $(TD -∞) $(TD any) $(TD -∞))
3968 )
3969 */
3970 @IEEECompliant("fusedMultiplyAdd", 4)
3971 auto fma(D1, D2, D3)(auto const ref D1 x, auto const ref D2 y, auto const ref D3 z)
3972 if (isDecimal!(D1, D2, D3))
3973 {
3974     alias D = CommonDecimal!(D1, D2, D3);
3975     D result;
3976     auto flags = decimalFMA!(D1, D2, D3)(x, y, z, result, 
3977                         __ctfe ? D.PRECISION : DecimalControl.precision, 
3978                         __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
3979     DecimalControl.raiseFlags(flags);
3980     return result;
3981 }
3982 
3983 ///
3984 unittest
3985 {
3986     decimal32 x = 2;
3987     decimal64 y = 3;
3988     decimal128 z = 5;
3989     assert (fma(x, y, z) == 11);
3990 }
3991 
3992 /**
3993 Returns the larger _decimal value between x and y
3994 Throws:
3995     $(MYREF InvalidOperationException) if x or y is signaling $(B NaN)
3996 Special_values:
3997 $(BOOKTABLE,
3998     $(TR $(TH x) $(TH y) $(TH fmax(x, y)))
3999     $(TR $(TD $(B NaN)) $(TD any) $(TD y))
4000     $(TR $(TD any) $(TD $(B NaN)) $(TD x))
4001 )
4002 */
4003 @IEEECompliant("maxNum", 19)
4004 auto fmax(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4005 if (isDecimal!D1 && isDecimal!D2)
4006 {
4007     CommonDecimal!(D1, D2) result;
4008     auto flags = decimalMax(x, y, result);
4009     DecimalControl.raiseFlags(flags);
4010     return result;
4011 }
4012 
4013 ///
4014 unittest
4015 {
4016     decimal32 x = 3;
4017     decimal64 y = -4;
4018     assert (fmax(x, y) == 3);
4019 }
4020 
4021 /**
4022 Returns the larger _decimal value between absolutes of x and y
4023 Throws:
4024     $(MYREF InvalidOperationException) if x or y is signaling $(B NaN)
4025 Special_values:
4026 $(BOOKTABLE,
4027     $(TR $(TH x) $(TH y) $(TH fmaxAbs(x, y)))
4028     $(TR $(TD $(B NaN)) $(TD any) $(TD y))
4029     $(TR $(TD any) $(TD $(B NaN)) $(TD x))
4030 )
4031 */
4032 @IEEECompliant("maxNumMag", 19)
4033 auto fmaxAbs(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4034 if (isDecimal!D1 && isDecimal!D2)
4035 {
4036     CommonDecimal!(D1, D2) result;
4037     auto flags = decimalMaxAbs(x, y, result) & ExceptionFlags.invalidOperation;
4038     DecimalControl.raiseFlags(flags);
4039     return result;
4040 }
4041 
4042 ///
4043 unittest
4044 {
4045     decimal32 x = 3;
4046     decimal64 y = -4;
4047     assert (fmaxAbs(x, y) == -4);
4048 }
4049 
4050 /**
4051 Returns the smaller _decimal value between x and y
4052 Throws:
4053     $(MYREF InvalidOperationException) if x or y is signaling $(B NaN)
4054 Special_values:
4055 $(BOOKTABLE,
4056     $(TR $(TH x) $(TH y) $(TH fmin(x, y)))
4057     $(TR $(TD $(B NaN)) $(TD any) $(TD y))
4058     $(TR $(TD any) $(TD $(B NaN)) $(TD x))
4059 )
4060 */
4061 @IEEECompliant("minNum", 19)
4062 auto fmin(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4063 if (isDecimal!D1 && isDecimal!D2)
4064 {
4065     CommonDecimal!(D1, D2) result;
4066     auto flags = decimalMin(x, y, result) & ExceptionFlags.invalidOperation;
4067     DecimalControl.raiseFlags(flags);
4068     return result;
4069 }
4070 
4071 ///
4072 unittest
4073 {
4074     decimal32 x = 3;
4075     decimal64 y = -4;
4076     assert (fmin(x, y) == -4);
4077 }
4078 
4079 /**
4080 Returns the smaller _decimal value between absolutes of x and y
4081 Throws:
4082     $(MYREF InvalidOperationException) if x or y is signaling $(B NaN)
4083 Special_values:
4084 $(BOOKTABLE,
4085     $(TR $(TH x) $(TH y) $(TH fminAbs(x, y)))
4086     $(TR $(TD $(B NaN)) $(TD any) $(TD y))
4087     $(TR $(TD any) $(TD $(B NaN)) $(TD x))
4088 )
4089 */
4090 @IEEECompliant("minNumMag", 19)
4091 auto fminAbs(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4092 if (isDecimal!D1 && isDecimal!D2)
4093 {
4094     CommonDecimal!(D1, D2) result;
4095     auto flags = decimalMinAbs(x, y, result) & ExceptionFlags.invalidOperation;
4096     DecimalControl.raiseFlags(flags);
4097     return result;
4098 }
4099 
4100 ///
4101 unittest
4102 {
4103     decimal32 x = 3;
4104     decimal64 y = -4;
4105     assert (fminAbs(x, y) == 3);
4106 }
4107 
4108 /**
4109 Calculates the remainder of the division x / y
4110 Params:
4111     x = dividend
4112     y = divisor
4113 Returns:
4114     The value of x - n * y, where n is the quotient rounded toward zero of the division x / y  
4115 Throws:
4116 $(BOOKTABLE,
4117     $(TR $(TD $(MYREF InvalidOperationException)) 
4118          $(TD x or y is signaling $(B NaN), x = ±∞, y = ±0.0))
4119     $(TR $(TD $(MYREF UnderflowException)) 
4120          $(TD result is too small to be represented))
4121     $(TR $(TD $(MYREF DivisionByZeroException)) 
4122          $(TD y = 0.0))
4123     $(TR $(TD $(MYREF InexactException)) 
4124          $(TD the result is inexact))
4125 )
4126 Special_values:
4127 $(BOOKTABLE,
4128     $(TR $(TH x) $(TH y) $(TH fmod(x, y)))
4129     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
4130     $(TR $(TD any) $(TD $(B NaN)) $(TD $(B NaN)))
4131     $(TR $(TD ±∞) $(TD any) $(TD $(B NaN)))
4132     $(TR $(TD any) $(TD 0.0) $(TD $(B NaN)))
4133     $(TR $(TD any) $(TD ±∞) $(TD $(B NaN)))
4134 )
4135 */
4136 auto fmod(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4137 {
4138     alias D = CommonDecimal!(D1, D2);
4139     D result = x;
4140     auto flags = decimalMod(result, y, 
4141                             __ctfe ? D.PRECISION : DecimalControl.precision, 
4142                             RoundingMode.towardZero);
4143     DecimalControl.raiseFlags(flags & ~ExceptionFlags.underflow);
4144     return result;
4145 }
4146 
4147 ///
4148 unittest
4149 {
4150     decimal32 x = "18.5";
4151     decimal32 y = "4.2";
4152     assert (fmod(x, y) == decimal32("1.7"));
4153 }
4154 
4155 
4156 /**
4157 Separates _decimal _value into coefficient and exponent. 
4158 This operation is silent, doesn't throw any exception.
4159 Returns:
4160     a result such as x = result * 10$(SUPERSCRIPT y) and |result| < 1.0
4161 Special_values:
4162 $(BOOKTABLE,
4163     $(TR $(TH x) $(TH y) $(TH frexp(x, y)))
4164     $(TR $(TD $(B NaN)) $(TD 0) $(TD $(B NaN)))
4165     $(TR $(TD +∞) $(TD 0) $(TD +∞))
4166     $(TR $(TD -∞) $(TD 0) $(TD -∞))
4167     $(TR $(TD ±0.0) $(TD 0) $(TD ±0.0))
4168 )
4169 Notes:
4170     This operation is silent, doesn't throw any exceptions and doesn't set any error flags.
4171     Signaling NaNs are quieted by this operation
4172 
4173 */
4174 D frexp(D)(auto const ref D x, out int y)
4175 {
4176     DataType!D cx; int ex; bool sx;
4177     Unqual!D result;
4178     final switch(fastDecode(x, cx, ex, sx))
4179     {
4180         case FastClass.signalingNaN:
4181             result.invalidPack(sx, cx);
4182             return result;
4183         case FastClass.quietNaN:
4184             y = 0;
4185             return x;
4186         case FastClass.infinite:
4187             y = 0;
4188             return x;
4189         case FastClass.zero:
4190             y = 0;
4191             return sx ? -D.zero : D.zero;
4192         case FastClass.finite:
4193             auto targetPower = -prec(cx);
4194             y = ex - targetPower;
4195             result.adjustedPack(cx, targetPower, sx, 0, RoundingMode.implicit);
4196             return result;
4197     }
4198 }
4199 /**
4200 Extracts the current payload from a $(B NaN) value
4201 Note:
4202     These functions do not check if x is truly a $(B NaN) value
4203     before extracting the payload. Using them on finite values will extract a part of the coefficient
4204 */
4205 @nogc nothrow pure @safe
4206 uint getNaNPayload(const decimal32 x)
4207 {
4208     return x.data & decimal32.MASK_PAYL;
4209 }
4210 
4211 ///ditto
4212 @nogc nothrow pure @safe
4213 ulong getNaNPayload(const decimal64 x)
4214 {
4215     return x.data & decimal64.MASK_PAYL;
4216 }
4217 
4218 ///ditto
4219 @nogc nothrow pure @safe
4220 ulong getNaNPayload(const decimal128 x, out ulong payloadHi)
4221 {
4222     auto payload = x.data & decimal128.MASK_PAYL;
4223     payloadHi = payload.hi;
4224     return payload.lo;
4225 }
4226 
4227 ///
4228 unittest
4229 {
4230     decimal32 x = decimal32("nan(123)");
4231     decimal64 y = decimal64("nan(456)");
4232     decimal128 z = decimal128("nan(789)");
4233 
4234     assert (getNaNPayload(x) == 123);
4235     assert (getNaNPayload(y) == 456);
4236     ulong hi;
4237     assert (getNaNPayload(z, hi) == 789 && hi == 0);
4238 
4239 }
4240 
4241 
4242 /**
4243 Calculates the length of the hypotenuse of a right-angled triangle with sides 
4244 of length x and y. The hypotenuse is the value of the square root of the sums 
4245 of the squares of x and y.
4246 Throws:
4247 $(BOOKTABLE,
4248     $(TR $(TD $(MYREF InvalidOperationException)) 
4249          $(TD x, y is signaling $(B NaN)))
4250     $(TR $(TD $(MYREF OverflowException)) 
4251          $(TD result is too big to be represented))
4252     $(TR $(TD $(MYREF InexactException)) 
4253          $(TD the result is inexact))
4254 )
4255 Special_values:
4256 $(BOOKTABLE,
4257     $(TR $(TH x) $(TH y) $(TH hypot(x, y)))
4258     $(TR $(TD ±∞) $(TD any) $(TD +∞))
4259     $(TR $(TD any) $(TD ±∞) $(TD +∞))
4260     $(TR $(TD $(B NaN)) $(TD $(B NaN)) $(TD nan))
4261     $(TR $(TD $(B NaN)) $(TD any) $(TD nan))
4262     $(TR $(TD any) $(TD $(B NaN)) $(TD nan))
4263     $(TR $(TD 0.0) $(TD any) $(TD y))
4264     $(TR $(TD any) $(TD 0.0) $(TD x))
4265 )
4266 */
4267 @IEEECompliant("hypot", 42)
4268 auto hypot(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4269 if (isDecimal!D1 && isDecimal!D2)
4270 {
4271     alias D = CommonDecimal!(D1, D2);
4272     D result;
4273     auto flags = decimalHypot(x, y, result, 
4274                               __ctfe ? D.PRECISION : DecimalControl.precision,
4275                               __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
4276     DecimalControl.raiseFlags(flags);
4277     return result;
4278 }
4279 
4280 ///
4281 unittest
4282 {
4283     decimal32 x = 3;
4284     decimal32 y = 4;
4285     assert (hypot(x, y) == 5);
4286 }
4287 
4288 /**
4289 Returns the 10-exponent of x as a signed integral value..
4290 Throws:
4291     $(MYREF InvalidOperationException) if x is $(B NaN), infinity or 0
4292 Special_values:
4293 $(BOOKTABLE,
4294     $(TR $(TH x) $(TH ilogb(x)))
4295     $(TR $(TD $(B NaN)) $(TD int.min))
4296     $(TR $(TD ±∞) $(TD int min + 1))
4297     $(TR $(TD ±0.0) $(TD int.min + 2))
4298     $(TR $(TD ±1.0) $(TD 0))
4299 )
4300 */
4301 @IEEECompliant("logB", 17)
4302 int ilogb(D)(auto const ref D x)
4303 if (isDecimal!D)
4304 {
4305     int result;
4306     auto flags = decimalLog(x, result);
4307     DecimalControl.raiseFlags(flags);
4308     return result;
4309 }
4310 
4311 ///
4312 unittest
4313 {
4314     assert (ilogb(decimal32(1234)) == 3);
4315 }
4316 
4317 /**
4318 Determines if x is canonical.
4319 This operation is silent, no error flags are set and no exceptions are thrown.
4320 Params:
4321 x = a _decimal value
4322 Returns: 
4323     true if x is canonical, false otherwise
4324 Notes:
4325     A _decimal value is considered canonical:<br/>
4326     - if the value is $(B NaN), the payload must be less than 10 $(SUPERSCRIPT precision - 1);<br/>
4327     - if the value is infinity, no trailing bits are accepted;<br/>
4328     - if the value is finite, the coefficient must be less than 10 $(SUPERSCRIPT precision). 
4329 */
4330 @IEEECompliant("isCanonical", 25)
4331 bool isCanonical(D)(auto const ref D x)
4332 if (isDecimal!D)
4333 {
4334     static if (is(D: decimal32) || is(D: decimal64))
4335     {
4336         if ((x.data & D.MASK_QNAN) == D.MASK_QNAN)
4337             return (x.data & D.MASK_PAYL) <= D.PAYL_MAX && (x.data & ~(D.MASK_SNAN | D.MASK_SGN | D.MASK_PAYL)) == 0U;
4338         if ((x.data & D.MASK_INF) == D.MASK_INF)
4339             return (x.data & ~(D.MASK_INF | D.MASK_SGN)) == 0U;
4340         if ((x.data & D.MASK_EXT) == D.MASK_EXT)
4341             return ((x.data & D.MASK_COE2) | D.MASK_COEX) <= D.COEF_MAX;
4342         else
4343             return ((x.data & D.MASK_COE1) <= D.COEF_MAX);
4344     }
4345     else
4346     {
4347         if ((x.data.hi & D.MASK_QNAN.hi) == D.MASK_QNAN.hi)
4348             return (x.data & D.MASK_PAYL) <= D.PAYL_MAX && (x.data & ~(D.MASK_SNAN | D.MASK_SGN | D.MASK_PAYL)) == 0U;
4349         if ((x.data.hi & D.MASK_INF.hi) == D.MASK_INF.hi)
4350             return (x.data.hi & ~(D.MASK_INF.hi | D.MASK_SGN.hi)) == 0U && x.data.lo == 0U;
4351         if ((x.data.hi & D.MASK_EXT.hi) == D.MASK_EXT.hi)
4352             return false;
4353         else
4354             return ((x.data & D.MASK_COE1) <= D.COEF_MAX);
4355     }
4356 
4357 
4358 }
4359 
4360 ///
4361 unittest
4362 {
4363     assert(isCanonical(decimal32.max));
4364     assert(isCanonical(decimal64.max));
4365     assert(!isCanonical(decimal32("nan(0x3fffff)")));
4366 
4367 }
4368 
4369 unittest
4370 {
4371 
4372     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
4373     {
4374         assert(isCanonical(T.zero));
4375         assert(isCanonical(T.max));
4376         assert(isCanonical(T.nan));
4377         assert(isCanonical(T.snan));
4378         assert(isCanonical(T.infinity));
4379     }
4380 }
4381 
4382 /**
4383 Determines if x is a finite value.
4384 This operation is silent, no error flags are set and no exceptions are thrown.
4385 Params:
4386     x = a _decimal value
4387 Returns: 
4388     true if x is finite, false otherwise ($(B NaN) or infinity) 
4389 */
4390 @IEEECompliant("isFinite", 25)
4391 bool isFinite(D: Decimal!bits, int bits)(auto const ref D x)
4392 {
4393     static if (is(D: decimal32) || is(D: decimal64))
4394     {
4395         return (x.data & D.MASK_INF) != D.MASK_INF; 
4396     }
4397     else
4398     {
4399         return (x.data.hi & D.MASK_INF.hi) != D.MASK_INF.hi;
4400     }
4401 }
4402 
4403 ///
4404 unittest
4405 {
4406     assert(isFinite(decimal32.max));
4407     assert(!isFinite(decimal64.nan));
4408     assert(!isFinite(decimal128.infinity));
4409 }
4410 
4411 unittest
4412 {
4413     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
4414     {
4415         assert(isFinite(T.max));
4416         assert(!isFinite(T.infinity));
4417         assert(!isFinite(T.snan));
4418         assert(!isFinite(T.qnan));
4419     }
4420 }
4421 
4422 /**
4423 Checks if two _decimal values are identical
4424 Params:
4425     x = a _decimal value
4426     y = a _decimal value
4427 Returns:
4428     true if x has the same internal representation as y
4429 Notes:
4430     Even if two _decimal values are equal, their internal representation can be different:<br/>
4431     - $(B NaN) values must have the same sign and the same payload to be considered identical; 
4432       $(B NaN)(12) is not identical to $(B NaN)(13)<br/>
4433     - Zero values must have the same sign and the same exponent to be considered identical; 
4434       0 * 10$(SUPERSCRIPT 3) is not identical to 0 * 10$(SUPERSCRIPT 5)<br/>
4435     - Finite _values must be represented based on same exponent to be considered identical;
4436       123 * 10$(SUPERSCRIPT -3) is not identical to 1.23 * 10$(SUPERSCRIPT -1)
4437 */
4438 bool isIdentical(D)(auto const ref D x, auto const ref D y)
4439 if (isDecimal!D)
4440 {
4441     return x.data == y.data;
4442 }
4443 
4444 ///
4445 unittest
4446 {
4447     assert (isIdentical(decimal32.min_normal, decimal32.min_normal));
4448     assert (!isIdentical(decimal64("nan"), decimal64("nan<200>")));
4449 }
4450 
4451 /**
4452 Determines if x represents infinity.
4453 This operation is silent, no error flags are set and no exceptions are thrown.
4454 Params:
4455     x = a _decimal value
4456 Returns: 
4457     true if x is infinite, false otherwise ($(B NaN) or any finite value)
4458 */
4459 @IEEECompliant("isInfinite", 25)
4460 bool isInfinity(D)(auto const ref D x)
4461 if (isDecimal!D)
4462 {
4463     static if (is(D: decimal32) || is(D: decimal64))
4464     {
4465         return (x.data & D.MASK_QNAN) == D.MASK_INF;  
4466     }
4467     else
4468     {
4469         return (x.data.hi & D.MASK_QNAN.hi) == D.MASK_INF.hi;  
4470     }
4471 }
4472 
4473 ///
4474 unittest
4475 {
4476     assert(isInfinity(decimal32.infinity));
4477     assert(isInfinity(-decimal64.infinity));
4478     assert(!isInfinity(decimal128.nan));
4479 }
4480 
4481 unittest
4482 {
4483     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
4484     {
4485         assert(isInfinity(T.infinity));
4486         assert(isInfinity(-T.infinity));
4487         assert(!isInfinity(T.ten));
4488         assert(!isInfinity(T.snan));
4489         assert(!isInfinity(T.qnan));
4490     }
4491 }
4492 
4493 /**
4494 Determines if x represents a $(B NaN).
4495 This operation is silent, no error flags are set and no exceptions are thrown.
4496 Params:
4497     x = a _decimal value
4498 Returns: 
4499     true if x is $(B NaN) (quiet or signaling), false otherwise (any other value than $(B NaN))
4500 */
4501 @IEEECompliant("isNaN", 25)
4502 bool isNaN(D)(auto const ref D x)
4503 if (isDecimal!D)
4504 {
4505     static if (is(D: decimal32) || is(D: decimal64))
4506     {
4507         return (x.data & D.MASK_QNAN) == D.MASK_QNAN;  
4508     }
4509     else
4510     {
4511         return (x.data.hi & D.MASK_QNAN.hi) == D.MASK_QNAN.hi;  
4512     }
4513 }
4514 
4515 ///
4516 unittest
4517 {
4518     assert(isNaN(decimal32()));
4519     assert(isNaN(decimal64.nan));
4520     assert(!isNaN(decimal128.max));
4521 }
4522 
4523 unittest
4524 {
4525     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
4526     {
4527         assert(isNaN(T.snan));
4528         assert(isNaN(T()));
4529         assert(!isSignaling(T.ten));
4530         assert(!isSignaling(T.min_normal));
4531         assert(isNaN(T.qnan));
4532     }
4533 }
4534 
4535 /**
4536 Determines if x is normalized.
4537 This operation is silent, no error flags are set and no exceptions are thrown.
4538 Params:
4539     x = a _decimal value
4540 Returns: 
4541     true if x is normal, false otherwise ($(B NaN), infinity, zero, subnormal)
4542 */
4543 @IEEECompliant("isNormal", 25)
4544 bool isNormal(D)(auto const ref D x)
4545 if (isDecimal!D)
4546 {
4547     DataType!D coefficient;
4548     uint exponent;
4549 
4550     static if (is(D: decimal32) || is(D: decimal64))
4551     {
4552         if ((x.data & D.MASK_INF) == D.MASK_INF)
4553             return false;
4554         if ((x.data & D.MASK_EXT) == D.MASK_EXT)
4555         {
4556             coefficient = (x.data & D.MASK_COE2) | D.MASK_COEX;
4557             if (coefficient > D.COEF_MAX)
4558                 return false;
4559             exponent = cast(uint)((x.data & D.MASK_EXP2) >>> D.SHIFT_EXP2);
4560         }
4561         else
4562         {
4563             coefficient = x.data & D.MASK_COE1;
4564             if (coefficient == 0U)
4565                 return false;
4566             exponent = cast(uint)((x.data & D.MASK_EXP1) >>> D.SHIFT_EXP1);
4567         }  
4568     }
4569     else
4570     {
4571         if ((x.data.hi & D.MASK_INF.hi) == D.MASK_INF.hi)
4572             return false;
4573         if ((x.data.hi & D.MASK_EXT.hi) == D.MASK_EXT.hi)
4574             return false;
4575         coefficient = x.data & D.MASK_COE1;
4576         if (coefficient == 0U || coefficient > D.COEF_MAX)
4577             return false;
4578         exponent = cast(uint)((x.data.hi & D.MASK_EXP1.hi) >>> (D.SHIFT_EXP1 - 64));
4579     }
4580 
4581     if (exponent < D.PRECISION - 1)
4582         return prec(coefficient) >= D.PRECISION - exponent;
4583 
4584     return true;
4585 }
4586 
4587 ///
4588 unittest
4589 {
4590     assert(isNormal(decimal32.max));
4591     assert(!isNormal(decimal64.nan));
4592     assert(!isNormal(decimal32("0x1p-101")));
4593 }
4594 
4595 unittest
4596 {
4597    
4598     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
4599     {
4600         assert(!isNormal(T.zero));
4601         assert(isNormal(T.ten));
4602         assert(!isNormal(T.nan));
4603         assert(isNormal(T.min_normal));
4604         assert(!isNormal(T.subn));
4605     }
4606 }
4607 
4608 /**
4609 Checks whether a _decimal value is a power of ten. This operation is silent, 
4610 no exception flags are set and no exceptions are thrown.
4611 Params:
4612     x = any _decimal value
4613 Returns:
4614     true if x is power of ten, false otherwise ($(B NaN), infinity, 0, negative)
4615 */
4616 bool isPowerOf10(D)(auto const ref D x)
4617 if (isDecimal!D)
4618 {
4619     if (isNaN(x) || isInfinity(x) || isZero(x) || signbit(x) != 0U)
4620         return false;
4621 
4622     alias U = DataType!D;
4623     U c;
4624     int e;
4625     x.unpack(c, e);
4626     coefficientShrink(c, e);
4627     return c == 1U;
4628 }
4629 
4630 ///
4631 unittest
4632 {
4633     assert (isPowerOf10(decimal32("1000")));
4634     assert (isPowerOf10(decimal32("0.001")));
4635 }
4636 
4637 /**
4638 Determines if x represents a signaling $(B NaN).
4639 This operation is silent, no error flags are set and no exceptions are thrown.
4640 Params:
4641     x = a _decimal value
4642 Returns: 
4643     true if x is $(B NaN) and is signaling, false otherwise (quiet $(B NaN), any other value)
4644 */
4645 @IEEECompliant("isSignaling", 25)
4646 bool isSignaling(D)(auto const ref D x)
4647 if (isDecimal!D)
4648 {
4649     static if (is(D: decimal32) || is(D: decimal64))
4650     {
4651         return (x.data & D.MASK_SNAN) == D.MASK_SNAN;  
4652     }
4653     else
4654     {
4655         return (x.data.hi & D.MASK_SNAN.hi) == D.MASK_SNAN.hi;  
4656     }
4657 }
4658 
4659 ///
4660 unittest
4661 {
4662     assert(isSignaling(decimal32()));
4663     assert(!isSignaling(decimal64.nan));
4664     assert(!isSignaling(decimal128.max));
4665 }
4666 
4667 unittest
4668 {
4669     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
4670     {
4671         assert(isSignaling(T.snan));
4672         assert(isSignaling(T()));
4673         assert(!isSignaling(T.ten));
4674         assert(!isSignaling(T.min_normal));
4675         assert(!isSignaling(T.qnan));
4676     }
4677 }
4678 
4679 /**
4680 Determines if x is subnormal (denormalized).
4681 This operation is silent, no error flags are set and no exceptions are thrown.
4682 Params:
4683     x = a _decimal value
4684 Returns: 
4685     true if x is subnormal, false otherwise ($(B NaN), infinity, zero, normal)
4686 */
4687 @IEEECompliant("isSubnormal", 25)
4688 bool isSubnormal(D)(auto const ref D x)
4689 if (isDecimal!D)
4690 {
4691     DataType!D coefficient;
4692     uint exponent;
4693 
4694     static if (is(D: decimal32) || is(D: decimal64))
4695     {
4696         if ((x.data & D.MASK_INF) == D.MASK_INF)
4697             return false;
4698         if ((x.data & D.MASK_EXT) == D.MASK_EXT)
4699         {
4700             coefficient = (x.data & D.MASK_COE2) | D.MASK_COEX;
4701             if (coefficient > D.COEF_MAX)
4702                 return false;
4703             exponent = cast(uint)((x.data & D.MASK_EXP2) >>> D.SHIFT_EXP2);
4704         }
4705         else
4706         {
4707             coefficient = x.data & D.MASK_COE1;
4708             if (coefficient == 0U)
4709                 return false;
4710             exponent = cast(uint)((x.data & D.MASK_EXP1) >>> D.SHIFT_EXP1);
4711         }  
4712     }
4713     else
4714     {
4715         if ((x.data.hi & D.MASK_INF.hi) == D.MASK_INF.hi)
4716             return false;
4717         if ((x.data.hi & D.MASK_EXT.hi) == D.MASK_EXT.hi)
4718             return false;
4719         coefficient = x.data & D.MASK_COE1;
4720         if (coefficient == 0U || coefficient > D.COEF_MAX)
4721             return false;
4722         exponent = cast(uint)((x.data.hi & D.MASK_EXP1.hi) >>> (D.SHIFT_EXP1 - 64));
4723     }
4724 
4725     if (exponent < D.PRECISION - 1)
4726         return prec(coefficient) < D.PRECISION - exponent;
4727 
4728     return false;
4729 }
4730 
4731 ///
4732 unittest
4733 {
4734     assert(isSubnormal(decimal32("0x1p-101")));
4735     assert(!isSubnormal(decimal32.max));
4736     assert(!isSubnormal(decimal64.nan));
4737     
4738 }
4739 
4740 unittest
4741 {
4742 
4743     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
4744     {
4745         assert(!isSubnormal(T.zero));
4746         assert(!isSubnormal(T.ten));
4747         assert(!isSubnormal(T.nan));
4748         assert(!isSubnormal(T.min_normal));
4749         assert(isSubnormal(T.subn));
4750         assert(isSubnormal(-T.subn));
4751     }
4752 }
4753 
4754 
4755 
4756 /**
4757 Determines if x represents the value zero.
4758 This operation is silent, no error flags are set and no exceptions are thrown.
4759 Params:
4760     x = a _decimal value
4761 Returns: 
4762     true if x is zero, false otherwise (any other value than zero)
4763 Standards: 
4764     If the internal representation of the _decimal data type has a coefficient 
4765     greater that 10$(SUPERSCRIPT precision) - 1, is considered 0 according to 
4766     IEEE standard.
4767 */
4768 @("this must be fast")
4769 @IEEECompliant("isZero", 25)
4770 bool isZero(D)(auto const ref D x)
4771 if (isDecimal!D)
4772 {
4773     static if (is(D: decimal32) || is(D: decimal64))
4774     {
4775         if ((x.data & D.MASK_INF) != D.MASK_INF)
4776         {
4777             if ((x.data & D.MASK_EXT) == D.MASK_EXT)
4778                 return ((x.data & D.MASK_COE2) | D.MASK_COEX) > D.COEF_MAX;
4779             else
4780                 return (x.data & D.MASK_COE1) == 0;
4781         }
4782         else
4783             return false;
4784     }
4785     else
4786     {
4787         if ((x.data.hi & D.MASK_INF.hi) != D.MASK_INF.hi)
4788         {
4789             if ((x.data.hi & D.MASK_EXT.hi) == D.MASK_EXT.hi)
4790                 return true;
4791             else
4792             {
4793                 auto cx = x.data & D.MASK_COE1;
4794                 return !cx || cx > D.COEF_MAX;
4795             }
4796         }
4797         else
4798             return false;
4799     }
4800     
4801 }
4802 
4803 ///
4804 unittest
4805 {
4806     assert(isZero(decimal32(0)));
4807     assert(!isZero(decimal64.nan));
4808     assert(isZero(decimal32("0x9FFFFFp+10")));
4809 }
4810 
4811 unittest
4812 {
4813     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
4814     {
4815         assert(isZero(T.zero));
4816         assert(isZero(T.minusZero));
4817         assert(!isZero(T.ten));
4818         assert(isZero(T(T.MASK_NONE, T.MASK_EXT, T.MASK_COE2 | T.MASK_COEX)));
4819     }
4820 }
4821 
4822 
4823 
4824 /**
4825 Compares two _decimal operands.
4826 This operation is silent, no exception flags are set and no exceptions are thrown.
4827 Returns:
4828     true if the specified condition is satisfied
4829 Notes:
4830     By default, comparison operators will throw $(MYREF InvalidOperationException) or will 
4831     set the $(MYREF ExceptionFlags.invalidOperation) context flag if a trap is not set.
4832     The equivalent functions are silent and will not throw any exception (or will not set any flag)
4833     if a $(B NaN) value is encountered.
4834 */
4835 @IEEECompliant("compareQuietGreater", 24)
4836 bool isGreater(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4837 if (isDecimal!(D1, D2))
4838 {
4839     auto c = decimalCmp(x, y);
4840     if (c == -3)
4841         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
4842     return c > 0;
4843 }
4844 
4845 ///ditto
4846 @IEEECompliant("compareQuietGreaterEqual", 24)
4847 bool isGreaterOrEqual(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4848 if (isDecimal!(D1, D2))
4849 {
4850     auto c = decimalCmp(x, y);
4851     if (c == -3)
4852         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
4853     return c >= 0;
4854 }
4855 
4856 ///ditto
4857 @IEEECompliant("compareQuietGreaterUnordered", 24)
4858 bool isGreaterOrUnordered(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4859 if (isDecimal!(D1, D2))
4860 {
4861     auto c = decimalCmp(x, y);
4862     if (c == -3)
4863         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
4864     return c > 0 || c < -1;
4865 }
4866 
4867 ///ditto
4868 @IEEECompliant("compareQuietLess", 24)
4869 @IEEECompliant("compareQuietNotLess", 24)
4870 bool isLess(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4871 if (isDecimal!(D1, D2))
4872 {
4873     auto c = decimalCmp(x, y);
4874     if (c == -3)
4875         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
4876     return c == -1;
4877 }
4878 
4879 ///ditto
4880 @IEEECompliant("compareQuietLessEqual", 24)
4881 bool isLessOrEqual(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4882 if (isDecimal!(D1, D2))
4883 {
4884     auto c = decimalCmp(x, y);
4885     if (c == -3)
4886         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
4887     return c <= 0 && c > -2;
4888 }
4889 
4890 ///ditto
4891 @IEEECompliant("compareQuietLessUnordered", 24)
4892 bool isLessOrUnordered(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4893 if (isDecimal!(D1, D2))
4894 {
4895     auto c = decimalCmp(x, y);
4896     if (c == -3)
4897         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
4898     return c < 0;
4899 }
4900 
4901 ///ditto
4902 @IEEECompliant("compareQuietOrdered", 24)
4903 @IEEECompliant("compareQuietUnordered", 24)
4904 bool isUnordered(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4905 if (isDecimal!(D1, D2))
4906 {
4907     auto c = decimalCmp(x, y);
4908     if (c == -3)
4909         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
4910     return c < -1;
4911 }
4912 
4913 ///
4914 unittest
4915 {
4916     assert(isUnordered(decimal32.nan, decimal64.max));
4917     assert(isGreater(decimal32.infinity, decimal128.max));
4918     assert(isGreaterOrEqual(decimal32.infinity, decimal64.infinity));
4919     assert(isLess(decimal64.max, decimal128.max));
4920     assert(isLessOrEqual(decimal32.min_normal, decimal32.min_normal));
4921 }
4922 
4923 unittest
4924 {
4925     
4926 
4927     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
4928     {
4929         assert(isUnordered(T.nan, T.one));
4930         assert(isUnordered(T.one, T.nan));
4931         assert(isUnordered(T.nan, T.nan));
4932 
4933         assert(isGreater(T.max, T.ten));
4934         assert(isGreater(T.ten, T.one));
4935         assert(isGreater(-T.ten, -T.max));
4936         assert(isGreater(T.zero, -T.max));
4937         assert(isGreater(T.max, T.zero));
4938         
4939         assert(isLess(T.one, T.ten), T.stringof);
4940         assert(isLess(T.ten, T.max));
4941         assert(isLess(-T.max, -T.one));
4942         assert(isLess(T.zero, T.max));
4943         assert(isLess(T.max, T.infinity));
4944     }
4945 }
4946 
4947 /**
4948 Compares two _decimal operands for equality
4949 Returns:
4950     true if the specified condition is satisfied, false otherwise or if any of the operands is $(B NaN).
4951 Notes:
4952     By default, $(MYREF Decimal.opEquals) is silent, returning false if a $(B NaN) value is encountered.
4953     isEqual and isNotEqual will throw $(MYREF InvalidOperationException) or will 
4954     set the $(MYREF ExceptionFlags.invalidOperation) context flag if a trap is not set.
4955 */
4956 
4957 @IEEECompliant("compareSignalingEqual", 24)
4958 bool isEqual(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4959 if (isDecimal!(D1, D2))
4960 {
4961     auto c = decimalEqu(x, y);
4962     if (c < 0)
4963         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
4964     return c == 1;
4965 }
4966 
4967 ///ditto
4968 @IEEECompliant("compareSignalingNotEqual", 24)
4969 bool isNotEqual(D1, D2)(auto const ref D1 x, auto const ref D2 y)
4970 if (isDecimal!(D1, D2))
4971 {
4972     auto c = decimalEqu(x, y);
4973     if (c < 0)
4974         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
4975     return c != 1;
4976 }
4977 
4978 ///
4979 unittest
4980 {
4981     assert (isEqual(decimal32.max, decimal32.max));
4982     assert (isNotEqual(decimal32.max, decimal32.min_normal));
4983 }
4984 
4985 /**
4986 Efficiently calculates 2 * 10$(SUPERSCRIPT n).
4987 $(BOOKTABLE,
4988     $(TR $(TD $(MYREF InvalidOperationException)) 
4989          $(TD x is $(B signaling NaN)))
4990     $(TR $(TD $(MYREF UnderflowException)) 
4991          $(TD result is subnormal or too small to be represented)
4992     $(TR $(TD $(MYREF OverflowException)) 
4993          $(TD result is too big to be represented)
4994     $(TR $(TD $(MYREF InexactException)) 
4995          $(TD result is inexact)
4996 )
4997 Special_values:
4998 $(BOOKTABLE,
4999     $(TR $(TH x) $(TH n) $(TH ldexp(x, n)))
5000     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
5001     $(TR $(TD ±∞) $(TD any) $(TD ±∞))
5002     $(TR $(TD ±0) $(TD any) $(TD ±0))
5003     $(TR $(TD any) $(TD 0) $(TD x))
5004 )
5005 */
5006 D ldexp(D)(auto const ref D x, const int n)
5007 if (isDecimal!D)
5008 {
5009     Unqual!D result = x;
5010     auto flags = decimalMulPow2(result, n,
5011                                 __ctfe ? D.PRECISION : DecimalControl.precision, 
5012                                 __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
5013     DecimalControl.raiseFlags(flags);
5014     return result;
5015 }
5016 
5017 ///
5018 unittest
5019 {
5020     decimal32 d = "1.0";
5021     assert (ldexp(d, 3) == 8);
5022 }
5023 
5024 /**
5025 Calculates the natural logarithm of log$(SUBSCRIPT e)x.
5026 Throws:
5027 $(BOOKTABLE,
5028     $(TR $(TD $(MYREF InvalidOperationException)) 
5029          $(TD x is signaling $(B NaN) or x < 0))
5030     $(TR $(TD $(MYREF DivisionByZero)) 
5031          $(TD x is ±0.0))
5032     $(TR $(TD $(MYREF Underflow)) 
5033          $(TD result is too small to be represented))
5034     $(TR $(TD $(MYREF InexactException)) 
5035          $(TD the result is inexact))
5036 )
5037 Special_values:
5038 $(BOOKTABLE,
5039     $(TR $(TH x) $(TH log(x)))
5040     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5041     $(TR $(TD ±0.0) $(TD -∞))
5042     $(TR $(TD -∞) $(TD $(B NaN)))
5043     $(TR $(TD +∞) $(TD +∞))
5044     $(TR $(TD e) $(TD +1.0))
5045     $(TR $(TD < 0.0) $(TD $(B NaN)))
5046 )
5047 */
5048 @IEEECompliant("log", 42)
5049 D log(D)(auto const ref D x)
5050 if (isDecimal!D)
5051 {
5052     Unqual!D result = x;
5053     auto flags = decimalLog(result, 
5054                              __ctfe ? D.PRECISION : DecimalControl.precision, 
5055                              __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
5056     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero);
5057     DecimalControl.raiseFlags(flags);
5058     return result;
5059 }
5060 
5061 ///
5062 unittest
5063 {
5064     assert (log(decimal32.E) == 1);
5065 }
5066 
5067 
5068 /**
5069 Calculates log$(SUBSCRIPT 10)x.
5070 Throws:
5071 $(BOOKTABLE,
5072     $(TR $(TD $(MYREF InvalidOperationException)) 
5073          $(TD x is signaling $(B NaN) or x < 0.0))
5074     $(TR $(TD $(MYREF DivisionByZero)) 
5075          $(TD x is ±0.0))
5076     $(TR $(TD $(MYREF Underflow)) 
5077          $(TD result is too small to be represented))
5078     $(TR $(TD $(MYREF InexactException)) 
5079          $(TD the result is inexact))
5080 )
5081 Special_values:
5082 $(BOOKTABLE,
5083     $(TR $(TH x) $(TH log(x)))
5084     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5085     $(TR $(TD ±0.0) $(TD -∞))
5086     $(TR $(TD -∞) $(TD $(B NaN)))
5087     $(TR $(TD +∞) $(TD +∞))
5088     $(TR $(TD +10.0) $(TD +1.0))
5089     $(TR $(TD < 0.0) $(TD $(B NaN)))
5090 )
5091 */
5092 @IEEECompliant("log10", 42)
5093 D log10(D)(auto const ref D x)
5094 if (isDecimal!D)
5095 {
5096     Unqual!D result = x;
5097     auto flags = decimalLog10(result, 
5098                             __ctfe ? D.PRECISION : DecimalControl.precision, 
5099                             __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
5100     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero);
5101     DecimalControl.raiseFlags(flags);
5102     return result;
5103 }
5104 
5105 /**
5106 Calculates log$(SUBSCRIPT 10)(x + 1).
5107 Throws:
5108 $(BOOKTABLE,
5109     $(TR $(TD $(MYREF InvalidOperationException)) 
5110          $(TD x is signaling $(B NaN) or x < 1.0))
5111     $(TR $(TD $(MYREF DivisionByZero)) 
5112          $(TD x is -1.0))
5113     $(TR $(TD $(MYREF Underflow)) 
5114          $(TD result is too small to be represented))
5115     $(TR $(TD $(MYREF InexactException)) 
5116          $(TD the result is inexact))
5117 )
5118 Special_values:
5119 $(BOOKTABLE,
5120     $(TR $(TH x) $(TH log(x)))
5121     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5122     $(TR $(TD -1.0) $(TD -∞))
5123     $(TR $(TD -∞) $(TD $(B NaN)))
5124     $(TR $(TD +∞) $(TD +∞))
5125     $(TR $(TD +9.0) $(TD +1.0))
5126     $(TR $(TD < -1.0) $(TD $(B NaN)))
5127 )
5128 */
5129 @IEEECompliant("log10p1", 42)
5130 D log10p1(D)(auto const ref D x)
5131 if (isDecimal!D)
5132 {
5133     Unqual!D result = x;
5134     auto flags = decimalLog10p1(result, 
5135                               __ctfe ? D.PRECISION : DecimalControl.precision, 
5136                               __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
5137     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero);
5138     DecimalControl.raiseFlags(flags);
5139     return result;
5140 }
5141 
5142 /**
5143 Calculates log$(SUBSCRIPT 2)x.
5144 Throws:
5145 $(BOOKTABLE,
5146     $(TR $(TD $(MYREF InvalidOperationException)) 
5147          $(TD x is signaling $(B NaN) or x < 0))
5148     $(TR $(TD $(MYREF DivisionByZero)) 
5149          $(TD x is ±0.0))
5150     $(TR $(TD $(MYREF Underflow)) 
5151          $(TD result is too small to be represented))
5152     $(TR $(TD $(MYREF InexactException)) 
5153          $(TD the result is inexact))
5154 )
5155 Special_values:
5156 $(BOOKTABLE,
5157     $(TR $(TH x) $(TH log(x)))
5158     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5159     $(TR $(TD ±0.0) $(TD -∞))
5160     $(TR $(TD -∞) $(TD $(B NaN)))
5161     $(TR $(TD +∞) $(TD +∞))
5162     $(TR $(TD +2.0) $(TD +1.0))
5163     $(TR $(TD < 0.0) $(TD $(B NaN)))
5164 )
5165 */
5166 @IEEECompliant("log2", 42)
5167 D log2(D)(auto const ref D x)
5168 if (isDecimal!D)
5169 {
5170     Unqual!D result = x;
5171     auto flags = decimalLog2(result, 
5172                               __ctfe ? D.PRECISION : DecimalControl.precision, 
5173                               __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
5174     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero);
5175     DecimalControl.raiseFlags(flags);
5176     return result;
5177 }
5178 
5179 /**
5180 Calculates log$(SUBSCRIPT 2)(x + 1).
5181 Throws:
5182 $(BOOKTABLE,
5183     $(TR $(TD $(MYREF InvalidOperationException)) 
5184          $(TD x is signaling $(B NaN) or x < 0))
5185     $(TR $(TD $(MYREF DivisionByZero)) 
5186          $(TD x is -1.0))
5187     $(TR $(TD $(MYREF Underflow)) 
5188          $(TD result is too small to be represented))
5189     $(TR $(TD $(MYREF InexactException)) 
5190          $(TD the result is inexact))
5191 )
5192 Special_values:
5193 $(BOOKTABLE,
5194     $(TR $(TH x) $(TH log(x)))
5195     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5196     $(TR $(TD ±0.0) $(TD -∞))
5197     $(TR $(TD -∞) $(TD $(B NaN)))
5198     $(TR $(TD +∞) $(TD +∞))
5199     $(TR $(TD +1.0) $(TD +1.0))
5200     $(TR $(TD < -1.0) $(TD $(B NaN)))
5201 )
5202 */
5203 @IEEECompliant("log2p1", 42)
5204 D log2p1(D)(auto const ref D x)
5205 if (isDecimal!D)
5206 {
5207     Unqual!D result = x;
5208     auto flags = decimalLog2p1(result, 
5209                              __ctfe ? D.PRECISION : DecimalControl.precision, 
5210                              __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
5211     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero);
5212     DecimalControl.raiseFlags(flags);
5213     return result;
5214 }
5215 
5216 /**
5217 Calculates log$(SUBSCRIPT e)(x + 1).
5218 Throws:
5219 $(BOOKTABLE,
5220     $(TR $(TD $(MYREF InvalidOperationException)) 
5221          $(TD x is signaling $(B NaN) or x < 0))
5222     $(TR $(TD $(MYREF DivisionByZero)) 
5223          $(TD x is -1.0))
5224     $(TR $(TD $(MYREF Underflow)) 
5225          $(TD result is too small to be represented))
5226     $(TR $(TD $(MYREF InexactException)) 
5227          $(TD the result is inexact))
5228 )
5229 Special_values:
5230 $(BOOKTABLE,
5231     $(TR $(TH x) $(TH log(x)))
5232     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5233     $(TR $(TD ±0.0) $(TD -∞))
5234     $(TR $(TD -∞) $(TD $(B NaN)))
5235     $(TR $(TD +∞) $(TD +∞))
5236     $(TR $(TD e - 1) $(TD +1.0))
5237     $(TR $(TD < -1.0) $(TD $(B NaN)))
5238 )
5239 */
5240 @IEEECompliant("logp1", 42)
5241 D logp1(D)(auto const ref D x)
5242 if (isDecimal!D)
5243 {
5244     Unqual!D result = x;
5245     auto flags = decimalLogp1(result, 
5246                                __ctfe ? D.PRECISION : DecimalControl.precision, 
5247                                __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
5248     flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero);
5249     DecimalControl.raiseFlags(flags);
5250     return result;
5251 }
5252 
5253 /**
5254 Returns the value of x rounded using the specified rounding _mode.
5255 If no rounding _mode is specified the default context rounding _mode is used instead.
5256 Throws:
5257 $(BOOKTABLE,
5258     $(TR $(TD $(MYREF InvalidOperationException)) 
5259          $(TD x is $(B NaN) or ±∞))
5260    $(TR $(TD $(MYREF OverflowException)) 
5261          $(TD result is too big to be represented))
5262     $(TR $(TD $(MYREF InexactException)) 
5263          $(TD the result is inexact))
5264 )
5265 Special_values:
5266 $(BOOKTABLE,
5267     $(TR $(TH x) $(TH lrint(x)))
5268     $(TR $(TD $(B NaN)) $(TD 0))
5269     $(TR $(TD -∞) $(TD long.min))
5270     $(TR $(TD +∞) $(TD long.max))
5271 )
5272 */
5273 long lrint(D)(auto const ref D x, const RoundingMode mode)
5274 if (isDecimal!D)
5275 {
5276     long result;
5277     auto flags = decimalToSigned(x, result, mode);
5278     DecimalControl.raiseFlags(flags & (ExceptionFlags.invalidOperation | ExceptionFlags.inexact));
5279     return result;
5280 }
5281 
5282 ///ditto
5283 long lrint(D)(auto const ref D x)
5284 if (isDecimal!D)
5285 {
5286     return lrint(x, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
5287 }
5288 
5289 /**
5290 Returns the value of x rounded away from zero.
5291 Throws:
5292     $(BOOKTABLE,
5293     $(TR $(TD $(MYREF InvalidOperationException)) 
5294          $(TD x is $(B NaN) or ±∞))
5295     $(TR $(TD $(MYREF OverflowException)) 
5296          $(TD result is too big to be represented))
5297 )
5298 Special_values:
5299 $(BOOKTABLE,
5300     $(TR $(TH x) $(TH lround(x)))
5301     $(TR $(TD $(B NaN)) $(TD 0))
5302     $(TR $(TD -∞) $(TD long.min))
5303     $(TR $(TD +∞) $(TD long.max))
5304 )
5305 */
5306 long lround(D)(auto const ref D x)
5307 {
5308     long result;
5309     auto flags = decimalToSigned(x, result, RoundingMode.tiesToAway);
5310     DecimalControl.raiseFlags(flags & ExceptionFlags.invalidOperation);
5311     //todo: intel does not set ovf, is that correct?
5312     return result;
5313 }
5314 
5315 /**
5316 Splits x in integral and fractional part.
5317 Params:
5318     x = value to split
5319     y = value of x truncated toward zero
5320 Returns:
5321     Fractional part of x. 
5322 Throws:
5323 $(BOOKTABLE,
5324     $(TR $(TD $(MYREF InvalidOperationException)) 
5325          $(TD x is $(B signaling NaN)))
5326 Special_values:
5327 $(BOOKTABLE,
5328     $(TR $(TH x) $(TH modf(x)) $(TH y))
5329     $(TR $(TD $(B NaN)) $(TD $(B NaN)) $(TD $(B NaN)))
5330     $(TR $(TD 0.0) $(TD 0.0) $(TD 0.0))
5331     $(TR $(TD ±∞) $(TD 0.0) $(TD ±∞))
5332 )
5333 */
5334 D modf(D)(auto const ref D x, ref D y)
5335 if (isDecimal!D)
5336 {
5337     if (isSignaling(x))
5338     {
5339         y = copysign(D.nan, x);
5340         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
5341         return y;
5342     }
5343     else if (isNaN(x))
5344     {
5345         y = copysign(D.nan, x);
5346         return y;
5347     }
5348     else if (isZero(x))
5349     {
5350         y = copysign(D.zero, x);
5351         return y;
5352     }
5353     else if (isInfinity(x))
5354     {
5355         y = x;
5356         return copysign(D.zero, x);
5357     }
5358     else
5359     {
5360         Unqual!D fractional = x;
5361         y = x;
5362         decimalRound(y, 0, RoundingMode.towardZero);
5363         decimalSub(fractional, y, 0, RoundingMode.tiesToAway);
5364         return copysign(fractional, x);
5365     }
5366 }
5367 
5368 /**
5369 Creates a quiet $(B NaN) value using the specified payload
5370 Notes:
5371    Payloads are masked to fit the current representation, having a limited bit width of to $(B mant_dig) - 2;
5372 */
5373 D NaN(D, T)(const T payload)
5374 if (isDecimal!D && isUnsigned!T)
5375 {
5376     D result = void;
5377     result.data = D.MASK_QNAN | (cast(DataType!D)payload & D.MASK_PAYL);
5378     return result;
5379 }
5380 
5381 ///ditto
5382 decimal128 NaN(T)(const T payloadHi, const T payloadLo)
5383 if (isUnsigned!T)
5384 {
5385     decimal128 result = void;
5386     result.data = decimal128.MASK_QNAN | (uint128(payloadHi, payloadLo) & decimal128.MASK_PAYL);
5387     return result;
5388 }
5389 
5390 ///
5391 unittest
5392 {
5393     auto a = NaN!decimal32(12345U);
5394     auto b = NaN!decimal64(12345UL);
5395     decimal128 c = NaN(123U, 456U);
5396 }
5397 
5398 /**
5399 Returns the value of x rounded using the specified rounding _mode.
5400 If no rounding _mode is specified the default context rounding _mode is used instead.
5401 Throws:
5402     $(MYREF InvalidOperationException) if x is signaling $(B NaN)
5403 Special_values:
5404 $(BOOKTABLE,
5405     $(TR $(TH x) $(TH nearbyint(x)))
5406     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5407     $(TR $(TD ±∞) $(TD ±∞))
5408     $(TR $(TD ±0.0) $(TD ±0.0))
5409 )
5410 */
5411 @IEEECompliant("roundToIntegralTiesToAway", 19)
5412 @IEEECompliant("roundToIntegralTiesToEven", 19)
5413 @IEEECompliant("roundToIntegralTowardNegative", 19)
5414 @IEEECompliant("roundToIntegralTowardPositive", 19)
5415 @IEEECompliant("roundToIntegralTowardZero", 19)
5416 D nearbyint(D)(auto const ref D x, const RoundingMode mode)
5417 if (isDecimal!D)
5418 {
5419     Unqual!D result = x;
5420     auto flags = decimalRound(result, __ctfe ? D.PRECISION : DecimalControl.precision, mode);
5421     flags &= ExceptionFlags.invalidOperation;
5422     DecimalControl.raiseFlags(flags);
5423     return result;
5424 }
5425 
5426 ///ditto
5427 D nearbyint(D)(auto const ref D x)
5428 if (isDecimal!D)
5429 {
5430     return nearbyint(x, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
5431 }
5432 
5433 ///
5434 unittest
5435 {
5436     assert(nearbyint(decimal32("1.2"), RoundingMode.tiesToEven) == 1);
5437     assert(nearbyint(decimal64("2.7"), RoundingMode.tiesToAway) == 3);
5438     assert(nearbyint(decimal128("-7.9"), RoundingMode.towardZero) == -7);
5439     assert(nearbyint(decimal128("6.66")) == 7);
5440 }
5441 
5442 
5443 /**
5444 Returns the previous _decimal value before x.
5445 Throws:
5446     $(MYREF InvalidOperationException) if x is signaling $(B NaN)
5447 Special_values:
5448 $(BOOKTABLE,
5449     $(TR $(TH x) $(TH nextDown(x)))
5450     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5451     $(TR $(TD -∞) $(TD -∞))
5452     $(TR $(TD -max) $(TD -∞))
5453     $(TR $(TD ±0.0) $(TD -min_normal * epsilon))
5454     $(TR $(TD +∞) $(TD D.max))
5455 )
5456 */
5457 @IEEECompliant("nextDown", 19)
5458 D nextDown(D)(auto const ref D x)
5459 if (isDecimal!D)
5460 {
5461     Unqual!D result = x;
5462     auto flags = decimalNextDown(result) & ExceptionFlags.invalidOperation;
5463     DecimalControl.raiseFlags(flags);
5464     return result;
5465 }
5466 
5467 /**
5468 Gives the next power of 10 after x. 
5469 Throws:
5470 $(BOOKTABLE,
5471     $(TR $(TD $(MYREF InvalidOperationException)) 
5472          $(TD x is signaling $(B NaN)))
5473     $(TR $(TD $(MYREF OverflowException)) 
5474          $(TD result is too big to be represented))
5475 )
5476 Special_values:
5477 $(BOOKTABLE,
5478     $(TR $(TH x) $(TH nextPow10(x)))
5479     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5480     $(TR $(TD ±∞) $(TD ±∞))
5481     $(TR $(TD ±0.0) $(TD +1.0))
5482 )
5483 */
5484 D nextPow10(D)(auto const ref D x)
5485 if (isDecimal!D)
5486 {
5487     ExceptionFlags flags;
5488     Unqual!D result;
5489 
5490     if (isSignaling(x))
5491     {
5492         result = D.nan;
5493         flags = ExceptionFlags.invalidOperation;
5494     }
5495     else if (isNaN(x) || isInfinity(x))
5496         result = x;
5497     else if (isZero(x))
5498         result = D.one;
5499     else
5500     {
5501         alias U = DataType!D;
5502         U c;
5503         int e;
5504         bool s = x.unpack(c, e);
5505         for (size_t i = 0; i < pow10!U.length; ++i)
5506         {
5507             if (c == pow10!U[i])
5508             {
5509                 ++e;
5510                 break;
5511             }
5512             else if (c < pow10!U[i])
5513             {
5514                 c = pow10!U[i];
5515                 break;
5516             }
5517         }
5518         if (i == pow10!U.length)
5519         {
5520             c = pow10!U[$ - 1];
5521             ++e;
5522         }
5523         
5524         flags = result.adjustedPack(c, e, s, RoundingMode.towardZero, ExceptionFlags.none);
5525     }
5526 
5527     DecimalControl.raiseFlags(flags);
5528     return result;
5529 }
5530 
5531 /**
5532 Returns the next value after or before x, toward y.
5533 Throws:
5534     $(BOOKTABLE,
5535     $(TR $(TD $(MYREF InvalidOperationException)) 
5536          $(TD either x or y is $(B signaling NaN)))
5537     $(TR $(TD $(MYREF OverflowException)) 
5538          $(TD result is ±∞))
5539     $(TR $(TD $(MYREF UnderflowException)) 
5540          $(TD result is subnormal or ±0.0))
5541     $(TR $(TD $(MYREF InexactException)) 
5542          $(TD result is ±∞, subnormal or ±0.0))
5543 )
5544 Special_values:
5545 $(BOOKTABLE,
5546     $(TR $(TH x) $(TH y) $(TH nextAfter(x, y)))
5547     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)) )
5548     $(TR $(TD any) $(TD $(B NaN)) $(TD $(B NaN)) )
5549     $(TR $(TD x = y)  $(TD) $(TD x) )
5550     $(TR $(TD x < y)  $(TD) $(TD $(MYREF nextUp)(x)) )
5551     $(TR $(TD x > y)  $(TD) $(TD $(MYREF nextDown)(x)) )
5552 )
5553 */
5554 D1 nextAfter(D1, D2)(auto const ref D1 x, auto const ref D2 y)
5555 if (isDecimal!(D1, D2))
5556 {
5557     if (isSignaling(x))
5558     {
5559         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
5560         return copysign(D1.nan, x);
5561     }
5562 
5563     if (isSignaling(y))
5564     {
5565         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
5566         return copysign(D1.nan, y);
5567     }
5568 
5569     if (isNaN(x))
5570         return copysign(D1.nan, x);
5571 
5572     if (isNaN(y))
5573         return copysign(D1.nan, y);
5574 
5575     Unqual!D1 result = x;
5576     ExceptionFlags flags;
5577     int c = decimalCmp(x, y);
5578     if (c == 0)
5579     {
5580         decimalToDecimal(y, result, 0, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
5581         DecimalControl.raiseFlags(flags);
5582         return result;
5583     }
5584     else
5585     {
5586         flags = c < 0 ? decimalNextUp(result) : decimalNextDown(result);
5587         flags &= ~ExceptionFlags.inexact;
5588     }
5589     if (isInfinity(result))
5590         flags |= ExceptionFlags.overflow | ExceptionFlags.inexact;
5591     else if (isZero(result) || isSubnormal(result))
5592         flags |= ExceptionFlags.underflow | ExceptionFlags.inexact;
5593     DecimalControl.raiseFlags(flags);
5594     return result;
5595 }
5596 
5597 ///ditto
5598 alias nextToward = nextAfter;
5599 
5600 /**
5601 Returns the next representable _decimal value after x.
5602 Throws:
5603     $(MYREF InvalidOperationException) if x is signaling $(B NaN)
5604 Special_values:
5605 $(BOOKTABLE,
5606     $(TR $(TH x) $(TH nextUp(x)))
5607     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5608     $(TR $(TD -∞) $(TD -D.max))
5609     $(TR $(TD ±0.0) $(TD D.min_normal * epsilon))
5610     $(TR $(TD D.max) $(TD +∞))
5611     $(TR $(TD +∞) $(TD +∞))
5612 )
5613 */
5614 @IEEECompliant("nextUp", 19)
5615 D nextUp(D)(auto const ref D x)
5616 if (isDecimal!D)
5617 {
5618     Unqual!D result = x;
5619     auto flags = decimalNextUp(result) & ExceptionFlags.invalidOperation;
5620     DecimalControl.raiseFlags(flags);
5621     return result;
5622 }
5623 
5624 
5625 
5626 
5627 /**
5628 Calculates a$(SUBSCRIPT 0) + a$(SUBSCRIPT 1)x + a$(SUBSCRIPT 2)x$(SUPERSCRIPT 2) + .. + a$(SUBSCRIPT n)x$(SUPERSCRIPT n)
5629 Throws:
5630     $(BOOKTABLE,
5631     $(TR $(TD $(MYREF InvalidOperationException)) 
5632          $(TD x is signaling $(B NaN) or any a$(SUBSCRIPT i) is signaling $(B NaN)))
5633     $(TR $(TD $(MYREF InvalidOperationException)) 
5634          $(TD x is ±∞ and any a$(SUBSCRIPT i) is ±0.0))
5635     $(TR $(TD $(MYREF InvalidOperationException)) 
5636          $(TD x is ±0.0 and any a$(SUBSCRIPT i) is ±∞))
5637     $(TR $(TD $(MYREF OverflowException)) 
5638          $(TD result is too big to be represented))
5639     $(TR $(TD $(MYREF UnderflowException)) 
5640          $(TD result is too small to be represented))
5641     $(TR $(TD $(MYREF InexactException)) 
5642          $(TD result is inexact))
5643 )
5644 */
5645 auto poly(D1, D2)(auto const ref D1 x, const(D2)[] a)
5646 if (isDecimal!(D1, D2))
5647 {
5648     ExceptionFlags flags;
5649     alias D = CommonDecimal!(D1, D2);
5650     D result;
5651     auto flags = decimalPoly(x, a, result, 
5652                             __ctfe ? D.PRECISION : DecimalControl.precision,
5653                             __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
5654     DecimalControl.raiseFlags(flags);
5655     return result;
5656 }
5657 
5658 /**
5659 Compute the value of x$(SUPERSCRIPT n), where n is integral
5660 Throws:
5661     $(BOOKTABLE,
5662     $(TR $(TD $(MYREF InvalidOperationException)) 
5663          $(TD x is signaling $(B NaN)))
5664     $(TR $(TD $(MYREF DivisionByZeroException)) 
5665          $(TD x = ±0.0 and n < 0))
5666     $(TR $(TD $(MYREF OverflowException)) 
5667          $(TD result is too big to be represented))
5668     $(TR $(TD $(MYREF UnderflowException)) 
5669          $(TD result is too small to be represented))
5670     $(TR $(TD $(MYREF InexactException)) 
5671          $(TD result is inexact))
5672 )
5673 Special_values:
5674 $(BOOKTABLE,
5675     $(TR $(TH x) $(TH n) $(TH pow(x, n)) )
5676     $(TR $(TD sNaN) $(TD any) $(TD $(B NaN)) )
5677     $(TR $(TD any) $(TD 0) $(TD +1.0) )
5678     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
5679     $(TR $(TD ±∞) $(TD any) $(TD ±∞) )
5680     $(TR $(TD ±0.0) $(TD odd n < 0) $(TD ±∞))
5681     $(TR $(TD ±0.0) $(TD even n < 0) $(TD +∞) )
5682     $(TR $(TD ±0.0) $(TD odd n > 0) $(TD ±0.0)  )
5683     $(TR $(TD ±0.0) $(TD even n > 0) $(TD +0.0) )
5684 )
5685 */
5686 @IEEECompliant("pown", 42)
5687 D pow(D, T)(auto const ref D x, const T n)
5688 if (isDecimal!D && isIntegral!T)
5689 {
5690     ExceptionFlags flags;
5691     Unqual!D result = x;
5692     auto flags = decimalPow(result, n, 
5693                            __ctfe ? D.PRECISION : DecimalControl.precision,
5694                            __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
5695     DecimalControl.raiseFlags(flags);
5696     return result;
5697 }
5698 
5699 /**
5700 Compute the value of x$(SUPERSCRIPT y)
5701 Throws:
5702     $(BOOKTABLE,
5703     $(TR $(TD $(MYREF InvalidOperationException)) 
5704          $(TD x is signaling $(B NaN)))
5705     $(TR $(TD $(MYREF DivisionByZeroException)) 
5706          $(TD x = ±0.0 and y < 0.0))
5707     $(TR $(TD $(MYREF OverflowException)) 
5708          $(TD result is too big to be represented))
5709     $(TR $(TD $(MYREF UnderflowException)) 
5710          $(TD result is too small to be represented))
5711     $(TR $(TD $(MYREF InexactException)) 
5712          $(TD result is inexact))
5713 )
5714 Special_values:
5715 $(BOOKTABLE,
5716     $(TR $(TH x) $(TH y) $(TH pow(x, y)) )
5717     $(TR $(TD sNaN) $(TD any) $(TD $(B NaN)) )
5718     $(TR $(TD any) $(TD 0) $(TD +1.0) )
5719     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
5720     $(TR $(TD ±∞) $(TD any) $(TD ±∞) )
5721     $(TR $(TD ±0.0) $(TD odd n < 0) $(TD ±∞))
5722     $(TR $(TD ±0.0) $(TD even n < 0) $(TD +∞) )
5723     $(TR $(TD ±0.0) $(TD odd n > 0) $(TD ±0.0)  )
5724     $(TR $(TD ±0.0) $(TD even n > 0) $(TD +0.0) )
5725 )
5726 */
5727 @IEEECompliant("pow", 42)
5728 @IEEECompliant("powr", 42)
5729 auto pow(D1, D2)(auto const ref D1 x, auto const ref D2 x)
5730 {
5731     ExceptionFlags flags;
5732     Unqual!D1 result = x;
5733     auto flags = decimalPow(result, y, 
5734                             __ctfe ? D.PRECISION : DecimalControl.precision,
5735                             __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
5736     DecimalControl.raiseFlags(flags);
5737     return result;
5738 }
5739 
5740 
5741 
5742 
5743 /**
5744 Express a value using another value exponent
5745 Params:
5746     x = source value
5747     y = value used as exponent source
5748 Returns:
5749     a value with the same numerical value as x but with the exponent of y
5750 Throws:
5751     $(BOOKTABLE,
5752     $(TR $(TD $(MYREF InvalidOperationException)) 
5753          $(TD x is signaling $(B NaN)))
5754     $(TR $(TD $(MYREF InvalidOperationException)) 
5755          $(TD only one of x or y is ±∞))
5756     $(TR $(TD $(MYREF InexactException)) 
5757          $(TD result is inexact))
5758 )
5759 Special_values:
5760 $(BOOKTABLE,
5761     $(TR $(TH x) $(TH y) $(TH quantize(x, y)))
5762     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
5763     $(TR $(TD any) $(TD $(B NaN)) $(TD $(B NaN)))
5764     $(TR $(TD ±∞) $(TD ±∞) $(TD ±∞))
5765     $(TR $(TD ±∞) $(TD any) $(TD $(B NaN)))
5766     $(TR $(TD any) $(TD ±∞) $(TD $(B NaN)))
5767 )
5768 */
5769 @IEEECompliant("quantize", 18)
5770 D1 quantize(D1, D2)(auto const ref D1 x, auto const ref D2 y)
5771 if (isDecimal!(D1, D2))
5772 {
5773     D1 result = x;
5774     auto flags = decimalQuantize(result, y,
5775                                  __ctfe ? D1.PRECISION : DecimalControl.precision,
5776                                  __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
5777     flags &= ExceptionFlags.invalidOperation | ExceptionFlags.inexact; 
5778     DecimalControl.raiseFlags(flags);
5779     return result;
5780 }
5781 
5782 /**
5783 Returns the exponent encoded into the specified _decimal value;
5784 Throws:
5785     $(BOOKTABLE,
5786     $(TR $(TD $(MYREF InvalidOperationException)) 
5787          $(TD x is $(B NaN) or ±∞))
5788 )
5789 Special_values:
5790 $(BOOKTABLE,
5791     $(TR $(TH x) $(TH quantexp(x)))
5792     $(TR $(TD $(B NaN)) $(TD int.min) )
5793     $(TR $(TD ±∞) $(TD int.min) )
5794 )
5795 Notes:
5796 Unlike $(MYREF frexp) where the exponent is calculated for a |coefficient| < 1.0, this
5797 functions returns the raw encoded exponent.
5798 */
5799 int quantexp(D)(auto const ref D x)
5800 if (isDecimal!D)
5801 {
5802     DataType!D cx; int ex; bool sx;
5803     switch (fastDecode(x, cx, ex, sx))
5804     {
5805         case FastClass.finite:
5806         case FastClass.zero:
5807             return ex;
5808         default:
5809             DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
5810             return int.min;
5811     }
5812 }
5813 
5814 ///
5815 unittest
5816 {
5817     auto d = decimal32("0x0001p+12"); //1 * 10^^12
5818     auto z = decimal64("0x0000p-3");  //0 * 10^^-3
5819 
5820     int calculatedExponent, rawExponent;
5821 
5822     //d is 0.1 * 10^^13
5823     frexp(d, calculatedExponent);
5824     rawExponent = quantexp(d);
5825     assert (calculatedExponent == 13  && rawExponent == 12);
5826 
5827     //z is 0.0
5828     frexp(z, calculatedExponent);
5829     rawExponent = quantexp(z);
5830     assert (calculatedExponent == 0  && rawExponent == -3);
5831 }
5832 
5833 /**
5834 Calculates the _remainder of the division x / y
5835 Params:
5836     x = dividend
5837     y = divisor
5838 Returns:
5839     The value of x - n * y, where n is the quotient rounded to nearest even of the division x / y  
5840 Throws:
5841 $(BOOKTABLE,
5842     $(TR $(TD $(MYREF InvalidOperationException)) 
5843          $(TD x or y is signaling $(B NaN), x = ±∞, y = ±0.0))
5844     $(TR $(TD $(MYREF UnderflowException)) 
5845          $(TD result is too small to be represented))
5846     $(TR $(TD $(MYREF DivisionByZeroException)) 
5847          $(TD y = 0.0))
5848     $(TR $(TD $(MYREF InexactException)) 
5849          $(TD the result is inexact))
5850 )
5851 Special_values:
5852 $(BOOKTABLE,
5853     $(TR $(TH x) $(TH y) $(TH remainder(x, y)))
5854     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
5855     $(TR $(TD any) $(TD $(B NaN)) $(TD $(B NaN)))
5856     $(TR $(TD ±∞) $(TD any) $(TD $(B NaN)))
5857     $(TR $(TD any) $(TD 0.0) $(TD $(B NaN)))
5858     $(TR $(TD any) $(TD ±∞) $(TD $(B NaN)))
5859 )
5860 */
5861 @IEEECompliant("remainder", 25)
5862 auto remainder(D1, D2)(auto const ref D1 x, auto const ref D2 y)
5863 {
5864     CommonDecimal!(D1, D2) result = x;
5865     auto flags = decimalMod(result, y, 
5866                             __ctfe ? D1.PRECISION : DecimalControl.precision,
5867                             RoundingMode.tiesToEven);
5868     DecimalControl.raiseFlags(flags);
5869     return result;
5870 }
5871 
5872 
5873 
5874 /**
5875 Returns the value of x rounded using the specified rounding _mode.
5876 If no rounding _mode is specified the default context rounding _mode is used instead.
5877 This function is similar to $(MYREF nearbyint), but if the rounded value is not exact it will throw
5878 $(MYREF InexactException)
5879 Throws:
5880     $(BOOKTABLE,
5881     $(TR $(TD $(MYREF InvalidOperationException)) 
5882          $(TD x is signaling $(B NaN)))
5883     $(TR $(TD $(MYREF InexactException)) 
5884          $(TD the result is inexact))
5885 )
5886 Special_values:
5887 $(BOOKTABLE,
5888     $(TR $(TH x) $(TH rint(x)))
5889     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5890     $(TR $(TD ±∞) $(TD ±∞))
5891     $(TR $(TD ±0.0) $(TD ±0.0))
5892 )
5893 */
5894 @IEEECompliant("roundToIntegralExact", 25)
5895 D rint(D)(auto const ref D x, const RoundingMode mode)
5896 if (isDecimal!D)
5897 {
5898     Unqual!D result = x;
5899     auto flags = decimalRound(result, __ctfe ? D.PRECISION : DecimalControl.precision, mode);
5900     flags &= ExceptionFlags.invalidOperation | ExceptionFlags.inexact;
5901     DecimalControl.raiseFlags(flags);
5902     return result;
5903 }
5904 
5905 ///ditto
5906 @IEEECompliant("roundToIntegralExact", 25)
5907 D rint(D)(auto const ref D x)
5908 if (isDecimal!D)
5909 {
5910     return rint(x, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
5911 }
5912 
5913 ///
5914 unittest
5915 {
5916     DecimalControl.resetFlags(ExceptionFlags.inexact);
5917     assert(rint(decimal32("9.9")) == 10);
5918     assert(DecimalControl.inexact);
5919 
5920     DecimalControl.resetFlags(ExceptionFlags.inexact);
5921     assert(rint(decimal32("9.0")) == 9);
5922     assert(!DecimalControl.inexact);
5923 }
5924 
5925 /**
5926 Returns the value of x rounded using the specified rounding _mode.
5927 If no rounding _mode is specified the default context rounding _mode is used instead.
5928 If the value doesn't fit in a long data type $(MYREF OverflowException) is thrown.
5929 Throws:
5930 $(BOOKTABLE,
5931     $(TR $(TD $(MYREF InvalidOperationException)) 
5932          $(TD x is $(B NaN)))
5933     $(TR $(TD $(MYREF OverflowException)) 
5934          $(TD result does not fit in a long data type))
5935     $(TR $(TD $(MYREF InexactException)) 
5936          $(TD the result is inexact))
5937 )
5938 Special_values:
5939 $(BOOKTABLE,
5940     $(TR $(TH x) $(TH rndtonl(x)))
5941     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
5942     $(TR $(TD ±∞) $(TD ±∞))
5943     $(TR $(TD ±0.0) $(TD ±0.0))
5944 )
5945 */
5946 D rndtonl(D)(auto const ref D x, const RoundingMode mode)
5947 if (isDecimal!D)
5948 {
5949     Unqual!D result = x;
5950     ExceptionFlags flags;
5951     long l;
5952     if (isNaN(x))
5953     {
5954         flags = ExceptionFlags.invalidOperation;
5955         result = signbit(x) ? -D.nan : D.nan;
5956     }
5957     else if (isInfinity(x))
5958         flags = ExceptionFlags.overflow;
5959     else 
5960     {
5961         flags = decimalToSigned(x, l, mode);
5962         result.packIntegral(l, 0, mode);
5963     }
5964     DecimalControl.raiseFlags(flags);
5965     return result;
5966 }
5967 
5968 ///ditto
5969 @safe
5970 D rndtonl(D)(auto const ref D x)
5971 if (isDecimal!D)
5972 {
5973     return rndtonl(x, __ctfe ? RoundingMode.tiesToAway : DecimalControl.rounding);
5974 }
5975 
5976 /**
5977 Compute the value of x$(SUPERSCRIPT 1/n), where n is an integer
5978 Throws:
5979 $(BOOKTABLE,
5980     $(TR $(TD $(MYREF InvalidOperationException)) 
5981          $(TD x is signaling $(B NaN)))
5982     $(TR $(TD $(MYREF DivisionByZeroException)) 
5983          $(TD x = ±0.0 and n < 0.0))
5984     $(TR $(TD $(MYREF OverflowException)) 
5985          $(TD result is too big to be represented or n = -1))
5986     $(TR $(TD $(MYREF UnderflowException)) 
5987          $(TD result is too small to be represented or n = -1))
5988     $(TR $(TD $(MYREF InexactException)) 
5989          $(TD result is inexact))
5990 )
5991 Special_values:
5992 $(BOOKTABLE,
5993     $(TR $(TH x) $(TH y) $(TH root(x, n)) )
5994     $(TR $(TD sNaN) $(TD any) $(TD $(B NaN)) )
5995     $(TR $(TD any) $(TD 0) $(TD $(B NaN)) )
5996     $(TR $(TD any) $(TD -1) $(TD $(B NaN)) )
5997     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
5998     $(TR $(TD ±∞) $(TD any) $(TD ±∞) )
5999     $(TR $(TD ±0.0) $(TD odd n < 0) $(TD ±∞))
6000     $(TR $(TD ±0.0) $(TD even n < 0) $(TD +∞) )
6001     $(TR $(TD ±0.0) $(TD odd n > 0) $(TD ±0.0)  )
6002     $(TR $(TD ±0.0) $(TD even n > 0) $(TD +0.0) )
6003 )
6004 */
6005 @IEEECompliant("rootn", 42)
6006 D root(D)(auto const ref D x, const T n)
6007 if (isDecimal!D & isIntegral!T)
6008 {
6009     ExceptionFlags flags;
6010     Unqual!D1 result = x;
6011     auto flags = decimalRoot(result, n, 
6012                             __ctfe ? D.PRECISION : DecimalControl.precision,
6013                             __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6014     DecimalControl.raiseFlags(flags);
6015     return result;
6016 }
6017 
6018 /**
6019 Returns the value of x rounded away from zero.
6020 This operation is silent, doesn't throw any exception.
6021 Special_values:
6022 $(BOOKTABLE,
6023     $(TR $(TH x) $(TH round(x)))
6024     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
6025     $(TR $(TD ±0.0) $(TD ±0.0))
6026     $(TR $(TD ±∞) $(TD ±∞))
6027 )
6028 */
6029 D round(D)(auto const ref D x)
6030 if (isDecimal!D)
6031 {
6032     Unqual!D result = x;
6033     decimalRound(result, 0, RoundingMode.tiesToAway);
6034     return result;
6035 }
6036 
6037 /**
6038 Computes the inverse square root of x
6039 Throws:
6040     $(MYREF InvalidOperationException) if x is signaling $(B NaN) or negative,
6041     $(MYREF InexactException), $(MYREF UnderflowException),
6042     $(MYREF DivisionByZeroException)
6043 Special_values:
6044 $(BOOKTABLE,
6045     $(TR $(TH x) $(TH rsqrt(x)))
6046     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
6047     $(TR $(TD < 0.0) $(TD $(B NaN)))
6048     $(TR $(TD ±0.0) $(TD $(B NaN)))
6049     $(TR $(TD +∞) $(TD +∞))
6050 )
6051 */
6052 @IEEECompliant("rSqrt", 42)
6053 D rsqrt(D)(auto const ref D x)
6054 if (isDecimal!D)
6055 {
6056     ExceptionFlags flags;
6057 
6058     Unqual!D result = x;
6059 
6060     flags = decimalRSqrt(result, 
6061                             __ctfe ? D.PRECISION : DecimalControl.precision, 
6062                             __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6063     DecimalControl.raiseFlags(flags);
6064     return result;
6065 }
6066 
6067 /**
6068 Compares the exponents of two _decimal values
6069 Params:
6070     x = a _decimal value
6071     y = a _decimal value
6072 Returns:
6073     true if the internal representation of x and y use the same exponent, false otherwise
6074 Notes:
6075     Returns also true if both operands are $(B NaN) or both operands are infinite.
6076 */
6077 @IEEECompliant("sameQuantum", 26)
6078 bool sameQuantum(D1, D2)(auto const ref D1 x, auto const ref D2 y)
6079 if (isDecimal!(D1, D2))
6080 {
6081     if ((x.data & D1.MASK_INF) == D1.MASK_INF)
6082     {
6083         if ((x.data & D1.MASK_QNAN) == D1.MASK_QNAN)
6084             return (y.data & D2.MASK_QNAN) == D2.MASK_QNAN;
6085         return (y.data & D2.MASK_SNAN) == D2.MASK_INF;
6086     }
6087 
6088     if ((y.data & D2.MASK_INF) == D2.MASK_INF)
6089         return false;
6090 
6091     auto expx = (x.data & D1.MASK_EXT) == D1.MASK_EXT ?
6092         (x.data & D1.MASK_EXP2) >>> D1.SHIFT_EXP2 :
6093         (x.data & D1.MASK_EXP1) >>> D1.SHIFT_EXP1;
6094     auto expy = (x.data & D2.MASK_EXT) == D2.MASK_EXT ?
6095         (y.data & D2.MASK_EXP2) >>> D2.SHIFT_EXP2 :
6096         (y.data & D2.MASK_EXP1) >>> D2.SHIFT_EXP1;
6097 
6098     int ex = cast(int)cast(uint)expx;
6099     int ey = cast(int)cast(uint)expy;
6100     return ex - D1.EXP_BIAS == ey - D2.EXP_BIAS;
6101 }
6102 
6103 ///
6104 unittest
6105 {
6106     assert(sameQuantum(decimal32.infinity, -decimal64.infinity));
6107 
6108     auto x = decimal32("123456e+23");
6109     auto y = decimal64("911911e+23");
6110     assert(sameQuantum(x, y));
6111 
6112 }
6113 
6114 /**
6115 Returns:
6116     x efficiently multiplied by 10$(SUPERSCRIPT n)
6117 Throws:
6118     $(MYREF InvalidOperationException) if x is signaling $(B NaN), $(MYREF OverflowException), 
6119     $(MYREF UnderflowException), $(MYREF InexactException)   
6120 Special_values:
6121 $(BOOKTABLE,
6122     $(TR $(TH x) $(TH n) $(TH scalbn(x, n)))
6123     $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)))
6124     $(TR $(TD ±∞) $(TD any) $(TD ±∞))
6125     $(TR $(TD ±0) $(TD any) $(TD ±0))
6126     $(TR $(TD any) $(TD 0) $(TD x))
6127 )
6128 */
6129 @IEEECompliant("scaleB", 17)
6130 D scalbn(D)(auto const ref D x, const int n)
6131 if (isDecimal!D)
6132 {
6133     Unqual!D result = x;
6134     auto flags = decimalScale(result, n, 
6135                             __ctfe ? D.PRECISION : DecimalControl.precision,
6136                             __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6137     DecimalControl.raiseFlags(flags);
6138     return result;
6139 }
6140 
6141 /**
6142 Multiplies elements of x using a higher precision, rounding only once at the end.
6143 Returns:
6144     x$(SUBSCRIPT 0) * x$(SUBSCRIPT 1) * ... * x$(SUBSCRIPT n)
6145 Notes:
6146     To avoid overflow, an additional scale is provided that the final result is to be multiplied py 10$(SUPERSCRIPT scale)
6147 Throws:
6148 $(BOOKTABLE,
6149     $(TR $(TD $(MYREF InvalidOperationException)) 
6150          $(TD any x is signaling $(B NaN)))
6151     $(TR $(TD $(MYREF InvalidOperationException)) 
6152          $(TD there is one infinite element and one 0.0 element))
6153     $(TR $(TD $(MYREF OverflowException)) 
6154          $(TD result is too big to be represented))
6155     $(TR $(TD $(MYREF UnderflowException)) 
6156          $(TD result is too small to be represented))
6157     $(TR $(TD $(MYREF InexactException)) 
6158          $(TD result is inexact))
6159 )
6160 */
6161 @IEEECompliant("scaledProd", 47)
6162 D scaledProd(D)(const(D)[] x, out int scale)
6163 if (isDecimal!D)
6164 {
6165     Unqual!D result;
6166     flags = decimalProd(x, result, scale, 
6167                          __ctfe ? D.PRECISION : DecimalControl.precision,
6168                          __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6169     DecimalControl.raiseFlags(flags);
6170     return result;
6171 }
6172 
6173 /**
6174 Multiplies results of x$(SUBSCRIPT i) + y$(SUBSCRIPT i) using a higher precision, rounding only once at the end.
6175 Returns:
6176     (x$(SUBSCRIPT 0) + y$(SUBSCRIPT 0)) * (x$(SUBSCRIPT 1) + y$(SUBSCRIPT 1)) * ... * (x$(SUBSCRIPT n) + y$(SUBSCRIPT n))
6177 Notes:
6178     To avoid overflow, an additional scale is provided that the final result is to be multiplied py 10$(SUPERSCRIPT scale).<br/>
6179     If x and y arrays are not of the same length, operation is performed for min(x.length, y.length);
6180 Throws:
6181 $(BOOKTABLE,
6182     $(TR $(TD $(MYREF InvalidOperationException)) 
6183          $(TD any x is signaling $(B NaN)))
6184     $(TR $(TD $(MYREF InvalidOperationException)) 
6185          $(TD any x[i] and y[i] are infinite and with different sign))
6186     $(TR $(TD $(MYREF InvalidOperationException)) 
6187          $(TD there is one infinite element and one x$(SUBSCRIPT i) + y$(SUBSCRIPT i) == 0.0))
6188     $(TR $(TD $(MYREF OverflowException)) 
6189          $(TD result is too big to be represented))
6190     $(TR $(TD $(MYREF UnderflowException)) 
6191          $(TD result is too small to be represented))
6192     $(TR $(TD $(MYREF InexactException)) 
6193          $(TD result is inexact))
6194 )
6195 */
6196 @IEEECompliant("scaledProdSum", 47)
6197 D scaledProdSum(D)(const(D)[] x, const(D)[] y, out int scale)
6198 if (isDecimal!D)
6199 {
6200     Unqual!D result;
6201     flags = decimalProdSum(x, y, result, scale, 
6202                         __ctfe ? D.PRECISION : DecimalControl.precision,
6203                         __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6204     DecimalControl.raiseFlags(flags);
6205     return result;
6206 }
6207 
6208 /**
6209 Multiplies results of x$(SUBSCRIPT i) - y$(SUBSCRIPT i) using a higher precision, rounding only once at the end.
6210 Returns:
6211     (x$(SUBSCRIPT 0) - y$(SUBSCRIPT 0)) * (x$(SUBSCRIPT 1) - y$(SUBSCRIPT 1)) * ... * (x$(SUBSCRIPT n) - y$(SUBSCRIPT n))
6212 Notes:
6213     To avoid overflow, an additional scale is provided that the final result is to be multiplied py 10$(SUPERSCRIPT scale)</br>
6214     If x and y arrays are not of the same length, operation is performed for min(x.length, y.length);
6215 Throws:
6216 $(BOOKTABLE,
6217     $(TR $(TD $(MYREF InvalidOperationException)) 
6218          $(TD any x is signaling $(B NaN)))
6219     $(TR $(TD $(MYREF InvalidOperationException)) 
6220          $(TD any x$(SUBSCRIPT i) and y$(SUBSCRIPT i) are infinite and with different sign))
6221     $(TR $(TD $(MYREF InvalidOperationException)) 
6222          $(TD there is one infinite element and one x$(SUBSCRIPT i) - y$(SUBSCRIPT i) == 0.0))
6223     $(TR $(TD $(MYREF OverflowException)) 
6224          $(TD result is too big to be represented))
6225     $(TR $(TD $(MYREF UnderflowException)) 
6226          $(TD result is too small to be represented))
6227     $(TR $(TD $(MYREF InexactException)) 
6228          $(TD result is inexact))
6229 )
6230 */
6231 @IEEECompliant("scaledProdDiff", 47)
6232 D scaledProdDiff(D)(const(D)[] x, const(D)[] y, out int scale)
6233 if (isDecimal!D)
6234 {
6235     Unqual!D result;
6236     flags = decimalProdDiff(x, y, result, scale, 
6237                            __ctfe ? D.PRECISION : DecimalControl.precision,
6238                            __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6239     DecimalControl.raiseFlags(flags);
6240     return result;
6241 }
6242 
6243 /**
6244 Determines if x is negative
6245 This operation is silent, no error flags are set and no exceptions are thrown.
6246 Params:
6247     x = a _decimal value
6248 Returns: 
6249     -1.0 if x is negative, 0.0 if x is zero, 1.0 if x is positive
6250 */
6251 @safe pure nothrow @nogc
6252 D sgn(D: Decimal!bits, int bits)(auto const ref D x)
6253 {
6254     if (isZero(x))
6255         return D.zero;
6256     return (x.data & D.MASK_SGN) ? D.minusOne : D.one;
6257 }
6258 
6259 
6260 
6261 ///
6262 unittest
6263 {
6264     assert(sgn(decimal32.max) == 1);
6265     assert(sgn(-decimal32.max) == -1);
6266     assert(sgn(decimal64(0)) == 0);
6267 }
6268 
6269 unittest
6270 {
6271 
6272     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
6273     {
6274         assert(sgn(T.nan) == 1);
6275         assert(sgn(T.infinity) == 1);
6276         assert(sgn(T.minusInfinity) == -1);
6277     }
6278 }
6279 
6280 /**
6281 Returns the sign bit of the specified value.
6282 This operation is silent, no error flags are set and no exceptions are thrown.
6283 Params:
6284     x = a _decimal value
6285 Returns: 
6286     1 if the sign bit is set, 0 otherwise
6287 */
6288 @IEEECompliant("isSignMinus", 25)
6289 int signbit(D: Decimal!bits, int bits)(auto const ref D x)
6290 {
6291     static if (is(D: decimal32) || is(D: decimal64))
6292     {
6293         return cast(uint)((x.data & D.MASK_SGN) >>> ((D.sizeof * 8) - 1)); 
6294     }
6295     else
6296     {
6297         return cast(uint)((x.data.hi & D.MASK_SGN.hi) >>> ((D.sizeof * 4) - 1));
6298     }
6299 }
6300 
6301 ///
6302 unittest
6303 {
6304     assert(signbit(-decimal32.infinity) == 1);
6305     assert(signbit(decimal64.min_normal) == 0);
6306     assert(signbit(-decimal128.max) == 1);
6307 }
6308 
6309 unittest
6310 {
6311     foreach(T; TypeTuple!(decimal32, decimal64, decimal128))
6312     {
6313         assert(signbit(T.snan) == 0);
6314         assert(signbit(T.minusInfinity) == 1);
6315         assert(signbit(T.zero) == 0);
6316         assert(signbit(T.minusZero) == 1);
6317     }
6318 }
6319 
6320 /**
6321 Returns sine of x.
6322 Throws:
6323 $(BOOKTABLE,
6324     $(TR $(TD $(MYREF InvalidOperationException)) 
6325          $(TD x is signaling $(B NaN) or ±∞))
6326     $(TR $(TD $(MYREF UnderflowException)) 
6327          $(TD result is too small to be represented))
6328     $(TR $(TD $(MYREF InexactException)) 
6329          $(TD the result is inexact))
6330 )
6331 Special_values:
6332 $(BOOKTABLE,
6333     $(TR $(TH x) $(TH sin(x)))
6334     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
6335     $(TR $(TD ±∞) $(TD $(B NaN)))
6336     $(TR $(TD -π/2) $(TD -1.0))
6337     $(TR $(TD -π/3) $(TD -√3/2))
6338     $(TR $(TD -π/4) $(TD -√2/2))
6339     $(TR $(TD -π/6) $(TD -0.5))
6340     $(TR $(TD ±0.0) $(TD +0.0))
6341     $(TR $(TD +π/6) $(TD +0.5))
6342     $(TR $(TD +π/4) $(TD +√2/2))
6343     $(TR $(TD +π/3) $(TD +√3/2))
6344     $(TR $(TD +π/2) $(TD +1.0))
6345 )
6346 */
6347 @IEEECompliant("sin", 42)
6348 D sin(D)(auto const ref D x)
6349 if (isDecimal!D)
6350 {
6351     Unqual!D result = x;
6352     auto flags = decimalSin(result, 
6353                              __ctfe ? D.PRECISION : DecimalControl.precision, 
6354                              __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6355 
6356     DecimalControl.raiseFlags(flags);
6357 
6358 
6359 
6360 
6361     return result;
6362 }
6363 
6364 /**
6365 Calculates the hyperbolic sine of x.
6366 Throws:
6367 $(BOOKTABLE,
6368     $(TR $(TD $(MYREF InvalidOperationException)) 
6369          $(TD x is signaling $(B NaN)))
6370     $(TR $(TD $(MYREF OverflowException)) 
6371          $(TD result is too big to be represented))
6372     $(TR $(TD $(MYREF InexactException)) 
6373          $(TD the result is inexact))
6374 )
6375 Special_values:
6376 $(BOOKTABLE,
6377     $(TR $(TH x) $(TH sinh(x)))
6378     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
6379     $(TR $(TD ±∞) $(TD +∞))
6380     $(TR $(TD ±0.0) $(TD +0.0))
6381 )
6382 */
6383 @IEEECompliant("sinh", 42)
6384 D sinh(D)(auto const ref D x)
6385 if (isDecimal!D)
6386 {
6387     Unqual!D result = x;
6388     auto flags = decimalSinh(result, 
6389                             __ctfe ? D.PRECISION : DecimalControl.precision, 
6390                             __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6391 
6392     DecimalControl.raiseFlags(flags);
6393     return result;
6394 }
6395 
6396 /**
6397 Returns sine of x*π.
6398 Throws:
6399 $(BOOKTABLE,
6400     $(TR $(TD $(MYREF InvalidOperationException)) 
6401          $(TD x is signaling $(B NaN) or ±∞))
6402     $(TR $(TD $(MYREF UnderflowException)) 
6403          $(TD result is too small to be represented))
6404     $(TR $(TD $(MYREF InexactException)) 
6405          $(TD the result is inexact))
6406 )
6407 Special_values:
6408 $(BOOKTABLE,
6409     $(TR $(TH x) $(TH sin(x)))
6410     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
6411     $(TR $(TD ±∞) $(TD $(B NaN)))
6412     $(TR $(TD -1/2) $(TD -1.0))
6413     $(TR $(TD -1/3) $(TD -√3/2))
6414     $(TR $(TD -1/4) $(TD -√2/2))
6415     $(TR $(TD -1/6) $(TD -0.5))
6416     $(TR $(TD ±0.0) $(TD +0.0))
6417     $(TR $(TD +1/6) $(TD +0.5))
6418     $(TR $(TD +1/4) $(TD +√2/2))
6419     $(TR $(TD +1/3) $(TD +√3/2))
6420     $(TR $(TD +1/2) $(TD +1.0))
6421 )
6422 */
6423 @IEEECompliant("sinPi", 42)
6424 D sinPi(D)(auto const ref D x)
6425 if (isDecimal!D)
6426 {
6427     Unqual!D result = x;
6428     auto flags = decimalSinPi(result, 
6429                              __ctfe ? D.PRECISION : DecimalControl.precision, 
6430                              __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6431 
6432     DecimalControl.raiseFlags(flags);
6433     return result;
6434 }
6435 
6436 
6437 /**
6438 Computes the square root of x
6439 Throws:
6440     $(MYREF InvalidOperationException) if x is signaling $(B NaN) or negative,
6441     $(MYREF InexactException), $(MYREF UnderflowException)
6442 Special_values:
6443 $(BOOKTABLE,
6444     $(TR $(TH x) $(TH sqrt(x)))
6445     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
6446     $(TR $(TD < 0.0) $(TD $(B NaN)))
6447     $(TR $(TD ±0.0) $(TD ±0.0))
6448     $(TR $(TD +∞) $(TD +∞))
6449 )
6450 */
6451 @IEEECompliant("squareRoot", 42)
6452 D sqrt(D)(auto const ref D x)
6453 if (isDecimal!D)
6454 {
6455 
6456     Unqual!D result = x;
6457     auto flags = decimalSqrt(result, 
6458                         __ctfe ? D.PRECISION : DecimalControl.precision, 
6459                         __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6460 
6461     DecimalControl.raiseFlags(flags);
6462     return result;
6463 }
6464 
6465 /**
6466 Sums elements of x using a higher precision, rounding only once at the end.</br>
6467 Returns:
6468     x$(SUBSCRIPT 0) + x$(SUBSCRIPT 1) + ... + x$(SUBSCRIPT n)
6469 Throws:
6470 $(BOOKTABLE,
6471     $(TR $(TD $(MYREF InvalidOperationException)) 
6472          $(TD any x is signaling $(B NaN)))
6473     $(TR $(TD $(MYREF InvalidOperationException)) 
6474          $(TD there are two infinite elements with different sign))
6475     $(TR $(TD $(MYREF OverflowException)) 
6476          $(TD result is too big to be represented))
6477     $(TR $(TD $(MYREF UnderflowException)) 
6478          $(TD result is too small to be represented))
6479     $(TR $(TD $(MYREF InexactException)) 
6480          $(TD result is inexact))
6481 )
6482 */
6483 @IEEECompliant("sum", 47)
6484 D sum(D)(const(D)[] x)
6485 if (isDecimal!D)
6486 {
6487     Unqual!D result;
6488     auto flags = decimalSum(x, result, 
6489                              __ctfe ? D.PRECISION : DecimalControl.precision, 
6490                              __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6491 
6492     DecimalControl.raiseFlags(flags);
6493     return result;
6494 }
6495 
6496 /**
6497 Sums absolute elements of x using a higher precision, rounding only once at the end.
6498 Returns:
6499     |x$(SUBSCRIPT 0)| + |x$(SUBSCRIPT 1)| + ... + |x$(SUBSCRIPT n)|
6500 Throws:
6501 $(BOOKTABLE,
6502     $(TR $(TD $(MYREF InvalidOperationException)) 
6503          $(TD any x is signaling $(B NaN)))
6504     $(TR $(TD $(MYREF OverflowException)) 
6505          $(TD result is too big to be represented))
6506     $(TR $(TD $(MYREF UnderflowException)) 
6507          $(TD result is too small to be represented))
6508     $(TR $(TD $(MYREF InexactException)) 
6509          $(TD result is inexact))
6510 )
6511 */
6512 @IEEECompliant("sumAbs", 47)
6513 D sumAbs(D)(const(D)[] x)
6514 if (isDecimal!D)
6515 {
6516     Unqual!D result;
6517     auto flags = decimalSumAbs(x, result, 
6518                             __ctfe ? D.PRECISION : DecimalControl.precision, 
6519                             __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6520 
6521     DecimalControl.raiseFlags(flags);
6522     return result;
6523 }
6524 
6525 /**
6526 Sums squares of elements of x using a higher precision, rounding only once at the end.
6527 Returns:
6528     x$(SUBSCRIPT 0)$(SUPERSCRIPT 2) + x$(SUBSCRIPT 1)$(SUPERSCRIPT 2) + ... + x$(SUBSCRIPT n)$(SUPERSCRIPT 2)
6529 Throws:
6530 $(BOOKTABLE,
6531     $(TR $(TD $(MYREF InvalidOperationException)) 
6532          $(TD any x is signaling $(B NaN)))
6533     $(TR $(TD $(MYREF OverflowException)) 
6534          $(TD result is too big to be represented))
6535     $(TR $(TD $(MYREF UnderflowException)) 
6536          $(TD result is too small to be represented))
6537     $(TR $(TD $(MYREF InexactException)) 
6538          $(TD result is inexact))
6539 )
6540 */
6541 @IEEECompliant("sumSquare", 47)
6542 D sumSquare(D)(const(D)[] x)
6543 if (isDecimal!D)
6544 {
6545     Unqual!D result;
6546     auto flags = decimalSumSquare(x, result, 
6547                             __ctfe ? D.PRECISION : DecimalControl.precision, 
6548                             __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6549 
6550     DecimalControl.raiseFlags(flags);
6551     return result;
6552 }
6553 
6554 /**
6555 Returns tangent of x.
6556 Throws:
6557 $(BOOKTABLE,
6558     $(TR $(TD $(MYREF InvalidOperationException)) 
6559          $(TD x is signaling $(B NaN) or ±∞))
6560     $(TR $(TD $(MYREF UnderflowException)) 
6561          $(TD result is too small to be represented))
6562     $(TR $(TD $(MYREF OverflowException)) 
6563          $(TD result is too big to be represented))
6564     $(TR $(TD $(MYREF InexactException)) 
6565          $(TD the result is inexact))
6566 )
6567 Special_values:
6568 $(BOOKTABLE,
6569     $(TR $(TH x) $(TH tan(x)))
6570     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
6571     $(TR $(TD ±∞) $(TD $(B NaN)))
6572     $(TR $(TD -π/2) $(TD -∞))
6573     $(TR $(TD -π/3) $(TD -√3))
6574     $(TR $(TD -π/4) $(TD -1.0))
6575     $(TR $(TD -π/6) $(TD -1/√3))
6576     $(TR $(TD ±0.0) $(TD +0.0))
6577     $(TR $(TD +π/6) $(TD +1/√3))
6578     $(TR $(TD +π/4) $(TD +1.0))
6579     $(TR $(TD +π/3) $(TD +√3))
6580     $(TR $(TD +π/2) $(TD +∞))
6581 )
6582 */
6583 @IEEECompliant("tan", 42)
6584 D tan(D)(auto const ref D x)
6585 if (isDecimal!D)
6586 {
6587     Unqual!D result = x;
6588     auto flags = decimalTan(result, 
6589                              __ctfe ? D.PRECISION : DecimalControl.precision, 
6590                              __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6591 
6592     DecimalControl.raiseFlags(flags);
6593     return result;
6594 }
6595 
6596 /**
6597 Returns tangent of x.
6598 Throws:
6599 $(BOOKTABLE,
6600     $(TR $(TD $(MYREF InvalidOperationException)) 
6601          $(TD x is signaling $(B NaN) ))
6602     $(TR $(TD $(MYREF UnderflowException)) 
6603          $(TD result is too small to be represented))
6604     $(TR $(TD $(MYREF OverflowException)) 
6605          $(TD result is too big to be represented))
6606     $(TR $(TD $(MYREF InexactException)) 
6607          $(TD the result is inexact))
6608 )
6609 Special_values:
6610 $(BOOKTABLE,
6611     $(TR $(TH x) $(TH tanh(x)))
6612     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
6613     $(TR $(TD ±∞) $(TD ±1.0))
6614     $(TR $(TD ±0.0) $(TD ±0.0))
6615 )
6616 */
6617 @IEEECompliant("tanh", 42)
6618 D tanh(D)(auto const ref D x)
6619 if (isDecimal!D)
6620 {
6621     Unqual!D result = x;
6622     auto flags = decimalTanh(result, 
6623                             __ctfe ? D.PRECISION : DecimalControl.precision, 
6624                             __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6625 
6626     DecimalControl.raiseFlags(flags);
6627     return result;
6628 }
6629 
6630 
6631 /**
6632 Converts x to the specified integral type rounded if necessary by mode
6633 Throws:
6634     $(MYREF InvalidOperationException) if x is $(B NaN),
6635     $(MYREF UnderflowException), $(MYREF OverflowException)
6636 Special_values:
6637 $(BOOKTABLE,
6638     $(TR $(TH x) $(TH to!T(x)))
6639     $(TR $(TD $(B NaN)) $(TD 0))
6640     $(TR $(TD +∞) $(TD T.max))
6641     $(TR $(TD -∞) $(TD T.min))
6642     $(TR $(TD ±0.0) $(TD 0))
6643 )
6644 */
6645 @IEEECompliant("convertToIntegerTiesToAway", 22)
6646 @IEEECompliant("convertToIntegerTiesToEven", 22)
6647 @IEEECompliant("convertToIntegerTowardNegative", 22)
6648 @IEEECompliant("convertToIntegerTowardPositive", 22)
6649 @IEEECompliant("convertToIntegerTowardZero", 22)
6650 T to(T, D)(auto const ref D x, const RoundingMode mode)
6651 if (isIntegral!T && isDecimal!D)
6652 {
6653     Unqual!T result;
6654     static if (isUnsigned!T)
6655         auto flags = decimalToUnsigned(x, result, mode);
6656     else
6657         auto flags = decimalToSigned(x, result, mode);
6658     DecimalControl.raiseFlags(flags & ExceptionFlags.invalidOperation);
6659     return result;
6660 }
6661 
6662 
6663 /**
6664 Converts x to the specified binary floating point type rounded if necessary by mode
6665 Throws:
6666     $(MYREF UnderflowException), $(MYREF OverflowException)
6667 */
6668 F to(F, D)(auto const ref D x, const RoundingMode mode)
6669 if (isFloatingPoint!F && isDecimal!D)
6670 {
6671     Unqual!F result;
6672     flags = decimalToFloat(x, result, mode);
6673     flags &= ~ExceptionFlags.inexact;
6674     if (__ctfe)
6675         DecimalControl.checkFlags(flags, ExceptionFlags.severe);
6676     else
6677     {
6678         if (flags)
6679             DecimalControl.raiseFlags(flags);
6680     }
6681     return result;
6682 }
6683 
6684 /**
6685 Converts the specified value from internal encoding from/to densely packed decimal encoding
6686 Notes:
6687    _Decimal values are represented internaly using 
6688    $(LINK2 https://en.wikipedia.org/wiki/Binary_Integer_Decimal, binary integer _decimal encoding), 
6689    supported by Intel (BID).
6690    This function converts the specified value to/from 
6691    $(LINK2 https://en.wikipedia.org/wiki/Densely_Packed_Decimal, densely packed _decimal encoding), 
6692    supported by IBM (DPD).
6693    Please note that a DPD encoded _decimal cannot be passed to a function from this module, there is no way
6694    to determine if a _decimal value is BID-encoded or DPD-encoded, all functions will assume a BID-encoding.
6695 */
6696 @IEEECompliant("encodeDecimal", 23)
6697 @safe pure nothrow @nogc
6698 decimal32 toDPD(const decimal32 x) 
6699 {
6700     if (isNaN(x) || isInfinity(x) || isZero(x))
6701         return canonical(x);
6702 
6703     uint cx;
6704     int ex;
6705     bool sx = x.unpack(cx, ex);
6706 
6707     uint[7] digits;
6708     size_t index = digits.length;
6709     while (cx)
6710         digits[--index] = divrem(cx, 10U);
6711     
6712     cx = packDPD(digits[$ - 3], digits[$ - 2], digits[$ - 1]);
6713     cx |= packDPD(digits[$ - 6], digits[$ - 5], digits[$ - 4]) << 10;
6714     cx |= cast(uint)digits[0] << 20;
6715 
6716     decimal32 result;
6717     result.pack(cx, ex, sx); 
6718     return result;
6719 }
6720 
6721 ///ditto
6722 @IEEECompliant("encodeDecimal", 23)
6723 @safe pure nothrow @nogc
6724 decimal64 toDPD(const decimal64 x) 
6725 {
6726     if (isNaN(x) || isInfinity(x) || isZero(x))
6727         return canonical(x);
6728 
6729     ulong cx;
6730     int ex;
6731     bool sx = x.unpack(cx, ex);
6732 
6733     uint[16] digits;
6734     size_t index = digits.length;
6735     while (cx)
6736         digits[--index] = cast(uint)(divrem(cx, 10U));
6737 
6738     cx = cast(ulong)(packDPD(digits[$ - 3], digits[$ - 2], digits[$ - 1]));
6739     cx |= cast(ulong)packDPD(digits[$ - 6], digits[$ - 5], digits[$ - 4]) << 10;
6740     cx |= cast(ulong)packDPD(digits[$ - 9], digits[$ - 8], digits[$ - 7]) << 20;
6741     cx |= cast(ulong)packDPD(digits[$ - 12], digits[$ - 11], digits[$ - 10]) << 30;
6742     cx |= cast(ulong)packDPD(digits[$ - 15], digits[$ - 14], digits[$ - 13]) << 40;
6743     cx |= cast(ulong)digits[0] << 50;
6744 
6745     decimal64 result;
6746     result.pack(cx, ex, sx); 
6747     return result;
6748 }
6749 
6750 ///ditto
6751 @IEEECompliant("encodeDecimal", 23)
6752 @safe pure nothrow @nogc
6753 decimal128 toDPD(const decimal128 x) 
6754 {
6755     if (isNaN(x) || isInfinity(x) || isZero(x))
6756         return canonical(x);
6757 
6758     uint128 cx;
6759     int ex;
6760     bool sx = x.unpack(cx, ex);
6761 
6762     uint[34] digits;
6763     size_t index = digits.length;
6764     while (cx)
6765         digits[--index] = cast(uint)(divrem(cx, 10U));
6766 
6767     cx = uint128(packDPD(digits[$ - 3], digits[$ - 2], digits[$ - 1]));
6768     cx |= uint128(packDPD(digits[$ - 6], digits[$ - 5], digits[$ - 4])) << 10;
6769     cx |= uint128(packDPD(digits[$ - 9], digits[$ - 8], digits[$ - 7])) << 20;
6770     cx |= uint128(packDPD(digits[$ - 12], digits[$ - 11], digits[$ - 10])) << 30;
6771     cx |= uint128(packDPD(digits[$ - 15], digits[$ - 14], digits[$ - 13])) << 40;
6772     cx |= uint128(packDPD(digits[$ - 18], digits[$ - 17], digits[$ - 16])) << 50;
6773     cx |= uint128(packDPD(digits[$ - 21], digits[$ - 20], digits[$ - 19])) << 60;
6774     cx |= uint128(packDPD(digits[$ - 24], digits[$ - 23], digits[$ - 22])) << 70;
6775     cx |= uint128(packDPD(digits[$ - 27], digits[$ - 26], digits[$ - 25])) << 80;
6776     cx |= uint128(packDPD(digits[$ - 30], digits[$ - 29], digits[$ - 28])) << 90;
6777     cx |= uint128(packDPD(digits[$ - 33], digits[$ - 32], digits[$ - 31])) << 100;
6778     cx |= uint128(digits[0]) << 110;
6779 
6780     decimal128 result;
6781     result.pack(cx, ex, sx); 
6782     return result;
6783 }
6784 
6785 ///ditto
6786 @IEEECompliant("decodeDecimal", 23)
6787 @safe pure nothrow @nogc
6788 decimal32 fromDPD(const decimal32 x) 
6789 {
6790     if (isNaN(x) || isInfinity(x) || isZero(x))
6791         return canonical(x);
6792 
6793     uint[7] digits;
6794     uint cx;
6795     int ex;
6796     bool sx = x.unpack(cx, ex);
6797 
6798     unpackDPD(cx & 1023, digits[$ - 1], digits[$ - 2], digits[$ - 3]);
6799     unpackDPD((cx >>> 10) & 1023, digits[$ - 4], digits[$ - 5], digits[$ - 6]);
6800     digits[0] = (cx >>> 20) & 15;
6801 
6802     cx = 0U;
6803     for (size_t i = 0; i < digits.length; ++i)
6804         cx += digits[i] * pow10!uint[6 - i];
6805 
6806     decimal32 result;
6807     result.pack(cx, ex, sx); 
6808     return result;
6809 }
6810 
6811 ///ditto
6812 @IEEECompliant("decodeDecimal", 23)
6813 @safe pure nothrow @nogc
6814 decimal64 fromDPD(const decimal64 x) 
6815 {
6816     if (isNaN(x) || isInfinity(x) || isZero(x))
6817         return canonical(x);
6818 
6819     uint[16] digits;
6820     ulong cx;
6821     int ex;
6822     bool sx = x.unpack(cx, ex);
6823 
6824     unpackDPD(cast(uint)cx & 1023, digits[$ - 1], digits[$ - 2], digits[$ - 3]);
6825     unpackDPD(cast(uint)(cx >>> 10) & 1023, digits[$ - 4], digits[$ - 5], digits[$ - 6]);
6826     unpackDPD(cast(uint)(cx >>> 20) & 1023, digits[$ - 7], digits[$ - 8], digits[$ - 9]);
6827     unpackDPD(cast(uint)(cx >>> 30) & 1023, digits[$ - 10], digits[$ - 11], digits[$ - 12]);
6828     unpackDPD(cast(uint)(cx >>> 40) & 1023, digits[$ - 13], digits[$ - 14], digits[$ - 15]);
6829     digits[0] = cast(uint)(cx >>> 50) & 15;
6830 
6831     cx = 0U;
6832     for (size_t i = 0; i < digits.length; ++i)
6833         cx += digits[i] * pow10!ulong[15 - i];
6834 
6835     decimal64 result;
6836     result.pack(cx, ex, sx); 
6837     return result;
6838 }
6839 
6840 ///ditto
6841 @safe pure nothrow @nogc
6842 @IEEECompliant("decodeDecimal", 23)
6843 decimal128 fromDPD(const decimal128 x) 
6844 {
6845     if (isNaN(x) || isInfinity(x) || isZero(x))
6846         return canonical(x);
6847 
6848     uint[34] digits;
6849     uint128 cx;
6850     int ex;
6851     bool sx = x.unpack(cx, ex);
6852 
6853     unpackDPD(cast(uint)cx & 1023U, digits[$ - 1], digits[$ - 2], digits[$ - 3]);
6854     unpackDPD(cast(uint)(cx >>> 10) & 1023, digits[$ - 4], digits[$ - 5], digits[$ - 6]);
6855     unpackDPD(cast(uint)(cx >>> 20) & 1023, digits[$ - 7], digits[$ - 8], digits[$ - 9]);
6856     unpackDPD(cast(uint)(cx >>> 30) & 1023, digits[$ - 10], digits[$ - 11], digits[$ - 12]);
6857     unpackDPD(cast(uint)(cx >>> 40) & 1023, digits[$ - 13], digits[$ - 14], digits[$ - 15]);
6858     unpackDPD(cast(uint)(cx >>> 50) & 1023, digits[$ - 16], digits[$ - 17], digits[$ - 18]);
6859     unpackDPD(cast(uint)(cx >>> 60) & 1023, digits[$ - 19], digits[$ - 20], digits[$ - 21]);
6860     unpackDPD(cast(uint)(cx >>> 70) & 1023, digits[$ - 22], digits[$ - 23], digits[$ - 24]);
6861     unpackDPD(cast(uint)(cx >>> 80) & 1023, digits[$ - 25], digits[$ - 26], digits[$ - 27]);
6862     unpackDPD(cast(uint)(cx >>> 90) & 1023, digits[$ - 28], digits[$ - 29], digits[$ - 30]);
6863     unpackDPD(cast(uint)(cx >>> 100) & 1023, digits[$ - 31], digits[$ - 32], digits[$ - 33]);
6864     digits[0] = cast(uint)(cx >>> 110) & 15;
6865 
6866     cx = 0U;
6867     for (size_t i = 0; i < digits.length; ++i)
6868         cx += pow10!uint128[34 - i] * digits[i];
6869 
6870     decimal128 result;
6871     result.pack(cx, ex, sx); 
6872     return result;
6873 }
6874 
6875 /**
6876 Converts x to the specified integral type rounded if necessary by mode
6877 Throws:
6878 $(MYREF InvalidOperationException) if x is $(B NaN),
6879 $(MYREF InexactException)
6880 $(MYREF UnderflowException), $(MYREF OverflowException)
6881 Special_values:
6882 $(BOOKTABLE,
6883 $(TR $(TH x) $(TH toExact!T(x)))
6884 $(TR $(TD $(B NaN)) $(TD 0))
6885 $(TR $(TD +∞) $(TD T.max))
6886 $(TR $(TD -∞) $(TD T.min))
6887 $(TR $(TD ±0.0) $(TD 0))
6888 )
6889 */
6890 @IEEECompliant("convertToIntegerExactTiesToAway", 22)
6891 @IEEECompliant("convertToIntegerExactTiesToEven", 22)
6892 @IEEECompliant("convertToIntegerExactTowardNegative", 22)
6893 @IEEECompliant("convertToIntegerExactTowardPositive", 22)
6894 @IEEECompliant("convertToIntegerExactTowardZero", 22)
6895 T toExact(T, D)(auto const ref D x, const RoundingMode mode)
6896 if (isIntegral!T && isDecimal!D)
6897 {
6898     Unqual!T result;
6899     static if (isUnsigned!T)
6900         auto flags = decimalToUnsigned(x, result, mode);
6901     else
6902         auto flags = decimalToSigned(x, result, mode);
6903     DecimalControl.raiseFlags(flags & (ExceptionFlags.invalidOperation | ExceptionFlags.inexact));
6904     return result;
6905 }
6906 
6907 /**
6908 Converts x to the specified binary floating point type rounded if necessary by mode
6909 Throws:
6910     $(MYREF UnderflowException), $(MYREF OverflowException),
6911     $(MYREF InexactException)
6912 */
6913 F toExact(F, D)(auto const ref D x, const RoundingMode mode)
6914 if (isFloatingPoint!F && isDecimal!D)
6915 {
6916     Unqual!F result;
6917     flags = decimalToFloat(x, result, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6918     DecimalControl.raiseFlags(flags);
6919     return result;
6920 }
6921 
6922 /**
6923 Converts the specified value to/from Microsoft currency data type;
6924 Throws:
6925 $(BOOKTABLE,
6926     $(TR $(TD $(MYREF InvalidOperationException)) 
6927         $(TD x is $(B NaN)))
6928     $(TR $(TD $(MYREF OverflowException)) 
6929         $(TD x is infinite or outside the Currency limits))
6930     $(TR $(TD $(MYREF UnderflowException)) 
6931         $(TD x is too small to be represented as Currency))
6932     $(TR $(TD $(MYREF InexactException)) 
6933          $(TD x cannot be represented exactly))
6934 )
6935 Notes:
6936     The Microsoft currency data type is stored as long 
6937     always scaled by 10$(SUPERSCRIPT -4)
6938 */
6939 long toMsCurrency(D)(auto const ref D x)
6940 if (isDecimal!D)
6941 {
6942     ExceptionFlags flags;
6943 
6944     if (isNaN(x))
6945     {
6946         DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
6947         return 0;
6948     }
6949 
6950     if (isInfinity(x))
6951     {
6952         DecimalControl.raiseFlags(ExceptionFlags.overflow);
6953         return signbit(x) ? long.max : long.min;
6954     }
6955 
6956     if (isZero(x))
6957         return 0;
6958 
6959     ex +=4;
6960 
6961     long result;
6962     flags = decimalToSigned!long(x, result, 
6963                                  __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6964     DecimalControl.raiseFlags(flags);
6965     return result;
6966 }
6967 
6968 ///ditto
6969 D fromMsCurrency(D)(const ulong x)
6970 if (isDecimal!D)
6971 {
6972     ExceptionFlags flags;
6973     Unqual!D result;
6974     flags = result.packIntegral(result, D.PRECISION, RoundingMode.implicit);
6975     flags |= decimalDiv(result, 100, 
6976                         __ctfe ? D.PRECISION : DecimalControl.precision, 
6977                         __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
6978     DecimalControl.raiseFlags(flags);
6979     return result;
6980 }
6981 
6982 /**
6983 Converts the specified value to/from Microsoft _decimal data type;
6984 Throws:
6985 $(BOOKTABLE,
6986     $(TR $(TD $(MYREF InvalidOperationException)) 
6987         $(TD x is $(B NaN)))
6988     $(TR $(TD $(MYREF OverflowException)) 
6989         $(TD x is infinite or outside the DECIMAL limits))
6990     $(TR $(TD $(MYREF UnderflowException)) 
6991         $(TD x is too small to be represented as DECIMAL))
6992     $(TR $(TD $(MYREF InexactException)) 
6993          $(TD x cannot be represented exactly))
6994 )
6995 Notes:
6996     The Microsoft _decimal data type is stored as a 96 bit integral 
6997     scaled by a variable exponent between 10$(SUPERSCRIPT -28) and 10$(SUPERSCRIPT 0). 
6998 */
6999 DECIMAL toMsDecimal(D)(auto const ref D x)
7000 {
7001     ExceptionFlags flags;
7002     DECIMAL result;
7003 
7004     if (isNaN(x))
7005     {
7006         if (__ctfe)
7007             DecimalControl.checkFlags(ExceptionFlags.invalidOperation, ExceptionFlags.severe);
7008         else
7009         {
7010             DecimalControl.raiseFlags(ExceptionFlags.invalidOperation);
7011         }
7012         return result;
7013     }
7014 
7015     if (isInfinity(x))
7016     {
7017         if (__ctfe)
7018             DecimalControl.checkFlags(ExceptionFlags.overflow, ExceptionFlags.severe);
7019         else
7020         {
7021             DecimalControl.raiseFlags(ExceptionFlags.overflow);
7022         }
7023         result.Lo64 = ulong.max;
7024         result.Hi32 = uint.max;
7025         if (signbit(x))
7026             result.sign = DECIMAL.DECIMAL_NEG;
7027         return result;
7028     }
7029 
7030     if (isZero(x))
7031         return result;
7032 
7033     DataType!D cx;
7034     int ex;
7035     bool sx = x.unpack(cx, ex);
7036 
7037         
7038     static if (is(D == decimal128))
7039         alias cxx = cx;
7040     else
7041         uint128 cxx = cx;
7042 
7043     enum cmax = uint128(cast(ulong)(uint.max), ulong.max);
7044 
7045     flags = coefficientAdjust(cxx, ex, -28, 0, cmax, sx, 
7046                                 __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
7047 
7048     if (flags & ExceptionFlags.overflow)
7049     {
7050         result.Lo64 = ulong.max;
7051         result.Hi32 = uint.max;
7052         if (signbit(x))
7053             result.sign = DECIMAL.DECIMAL_NEG;
7054     }
7055     else if (flags & ExceptionFlags.underflow)
7056     {
7057         result.Lo64 = 0;
7058         result.Hi32 = 0;
7059         if (sx)
7060             result.sign = DECIMAL.DECIMAL_NEG;
7061     }
7062     else
7063     {
7064         result.Lo64 = cxx.lo;
7065         result.Hi32 = cast(uint)(cxx.hi);
7066         result.scale = -ex;
7067         if (sx)
7068             result.sign = DECIMAL.DECIMAL_NEG;
7069     }
7070         
7071     DecimalControl.raiseFlags(flags);
7072     return result;
7073 }
7074 
7075 
7076 ///ditto
7077 D fromMsDecimal(D)(auto const ref DECIMAL x)
7078 {
7079     ExceptionFlags flags;
7080     Unqual!D result;
7081 
7082     uint128 cx = uint128(cast(ulong)(x.Hi32), x.Lo64);
7083     int ex = -x.scale;
7084     bool sx = (x.sign & DECIMAL.DECIMAL_NEG) == DECIMAL.DECIMAL_NEG; 
7085         
7086     flags = coefficientAdjust(cx, ex, cvt!uint128(D.COEF_MAX), RoundingMode.implicit);
7087 
7088     flags |= result.adjustedPack(cvt!(DataType!D)(cx), ex, sx,
7089                                     __ctfe ?  D.PRECISION : DecimalControl.precision,
7090                                     __ctfe ? RoundingMode.implicit  : DecimalControl.rounding,
7091                                     flags);
7092     DecimalControl.raiseFlags(flags);
7093     return result;
7094 }
7095 
7096 
7097 
7098 /**
7099 Checks the order between two _decimal values
7100 Params:
7101     x = a _decimal value
7102     y = a _decimal value
7103 Returns:
7104     true if x precedes y, false otherwise
7105 Notes:
7106     totalOrderAbs checks the order between |x| and |y|
7107 See_Also:
7108     $(MYREF cmp)
7109 */
7110 @IEEECompliant("totalOrder", 25)
7111 bool totalOrder(D1, D2)(auto const ref D1 x, auto const ref D2 y)
7112 if (isDecimal!(D1, D2))
7113 {
7114     return cmp(x, y) <= 0;
7115 }
7116 
7117 ///ditto
7118 @IEEECompliant("totalOrderAbs", 25)
7119 bool totalOrderAbs(D1, D2)(auto const ref D1 x, auto const ref D2 y)
7120 if (isDecimal!(D1, D2))
7121 {
7122     return cmp(fabs(x), fabs(y)) <= 0;
7123 }
7124 
7125 ///
7126 unittest
7127 {
7128     assert (totalOrder(decimal32.min_normal, decimal64.max));
7129     assert (!totalOrder(decimal32.max, decimal128.min_normal));
7130     assert (totalOrder(-decimal64(0), decimal64(0)));
7131     assert (totalOrderAbs(decimal64(0), -decimal64(0)));
7132 }
7133 
7134 /**
7135 Returns the value of x rounded up or down, depending on sign (toward zero).
7136 This operation is silent, doesn't throw any exception.
7137 Special_values:
7138 $(BOOKTABLE,
7139 $(TR $(TH x) $(TH trunc(x)))
7140 $(TR $(TD $(B NaN)) $(TD $(B NaN)))
7141 $(TR $(TD ±0.0) $(TD ±0.0))
7142 $(TR $(TD ±∞) $(TD ±∞))
7143 )
7144 */
7145 @safe pure nothrow @nogc
7146 D trunc(D)(auto const ref D x)
7147 if (isDecimal!D)
7148 {
7149     Unqual!D result = x;
7150     decimalRound(result, 0, RoundingMode.towardZero);
7151     return result;
7152 }
7153 
7154 /**
7155 Gives the previous power of 10 before x. 
7156 Throws:
7157     $(MYREF InvalidOperationException),
7158     $(MYREF OverflowException),
7159     $(MYREF UnderflowException),
7160     $(MYREF InexactException)
7161 Special_values:
7162 $(BOOKTABLE,
7163     $(TR $(TH x) $(TH truncPow10(x)))
7164     $(TR $(TD $(B NaN)) $(TD $(B NaN)))
7165     $(TR $(TD ±∞) $(TD ±∞))
7166     $(TR $(TD ±0.0) $(TD ±0.0))
7167 )
7168 */
7169 D truncPow10(D)(auto const ref D x)
7170 if (isDecimal!D)
7171 {
7172     ExceptionFlags flags;
7173     Unqual!D result;
7174 
7175     if (isSignaling(x))
7176     {
7177         result = D.nan;
7178         flags = ExceptionFlags.invalidOperation;
7179     }
7180     else if (isNaN(x) || isInfinity(x) || isZero(x))
7181         result = x;
7182     else
7183     {
7184         alias U = DataType!D;
7185         U c;
7186         int e;
7187         bool s = x.unpack(c, e);
7188         for (size_t i = 0; i < pow10!U.length; ++i)
7189         {
7190             if (c == pow10!U[i])
7191                 break;
7192             else if (c < pow10!U[i])
7193             {
7194                 c = pow10!U[i - 1];
7195                 break;
7196             }
7197         }
7198         if (i == pow10!U.length)
7199             c = pow10!U[$ - 1];
7200         flags = adjustCoefficient(c, e, D.EXP_MIN, D.EXP_MAX, D.COEF_MAX, s, RoundingMode.towardZero);
7201         flags |= result.pack(c, e, s, flags);
7202     }
7203 
7204     if (__ctfe)
7205         DecimalControl.checkFlags(flags, ExceptionFlags.severe);
7206     else
7207     {
7208         if (flags)
7209             DecimalControl.raiseFlags(flags);
7210     }
7211     return result;
7212 }
7213 
7214 
7215 package:
7216 
7217 template DataType(D)
7218 {
7219     static if (is(Unqual!D == decimal32))
7220         alias DataType = uint;
7221     else static if (is(Unqual!D == decimal64))
7222         alias DataType = ulong;
7223     else static if (is(Unqual!D == decimal128))
7224         alias DataType = uint128;
7225     else
7226         static assert(0);
7227 }
7228 
7229 mixin template ExceptionConstructors()
7230 {
7231     @nogc @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null)
7232     {
7233         super(msg, file, line, next);
7234     }
7235 
7236     @nogc @safe pure nothrow this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__)
7237     {
7238         super(msg, file, line, next);
7239     }
7240 }
7241 
7242 
7243 /* ****************************************************************************************************************** */
7244 /* DECIMAL STRING CONVERSION                                                                                          */
7245 /* ****************************************************************************************************************** */
7246 
7247 
7248 //sinks %a
7249 void sinkHexadecimal(C, T)(auto const ref FormatSpec!C spec, scope void delegate(const(C)[]) sink, 
7250                            auto const ref T coefficient, const int exponent, const bool signed) 
7251 if (isSomeChar!C && isAnyUnsigned!T)
7252 {
7253     int w = 4; //0x, p, exponent sign
7254     if (spec.flPlus || spec.flSpace || signed)
7255         ++w;
7256 
7257     int p = prec(coefficient);
7258     if (p == 0)
7259         p = 1;
7260 
7261     int precision = spec.precision == spec.UNSPECIFIED || spec.precision <= 0 ? p : spec.precision;
7262 
7263     Unqual!T c = coefficient;
7264     int e = exponent;
7265 
7266     coefficientAdjust(c, e, precision, signed, __ctfe ? RoundingMode.implicit : DecimalControl.rounding);
7267 
7268 
7269     Unqual!C[T.sizeof / 2] buffer;
7270     Unqual!C[prec(uint.max)] exponentBuffer;
7271 
7272     int digits = dumpUnsignedHex(buffer, c, spec.spec <= 'Z');
7273 
7274     bool signedExponent = e < 0;
7275     uint ex = signedExponent ? -e : e;
7276     int exponentDigits = dumpUnsigned(exponentBuffer, ex);
7277 
7278     w += digits;
7279     w += exponentDigits;
7280 
7281     int pad = spec.width - w;
7282     sinkPadLeft(spec, sink, pad);
7283     sinkSign(spec, sink, signed);
7284     sink("0");
7285     sink(spec.spec <= 'Z' ? "X" : "x");
7286     sinkPadZero(spec, sink, pad);
7287     sink(buffer[$ - digits .. $]);
7288     sink(spec.spec < 'Z' ? "P" : "p");
7289     sink(signedExponent ? "-" : "+");
7290     sink(exponentBuffer[$ - exponentDigits .. $]);
7291     sinkPadRight(sink, pad);
7292 }
7293 
7294 
7295 //sinks %f
7296 void sinkFloat(C, T)(auto const ref FormatSpec!C spec, scope void delegate(const(C)[]) sink, const T coefficient, 
7297                      const int exponent, const bool signed, const RoundingMode mode, const bool skipTrailingZeros = false) 
7298 if (isSomeChar!C)
7299 {
7300     if (coefficient == 0U)
7301         sinkZero(spec, sink, signed, skipTrailingZeros);
7302     else
7303     {
7304         Unqual!T c = coefficient;
7305         int e = exponent;
7306         coefficientShrink(c, e);
7307 
7308         Unqual!C[40] buffer;
7309         int w = spec.flPlus || spec.flSpace || signed ? 1 : 0;
7310 
7311         if (e >= 0) //coefficient[0...].[0...]
7312         {
7313             ptrdiff_t digits = dumpUnsigned(buffer, c);
7314             w += digits;
7315             w += e;
7316             int requestedDecimals = spec.precision == spec.UNSPECIFIED ? 6 : spec.precision;
7317             if (skipTrailingZeros)
7318                 requestedDecimals = 0;
7319             if (requestedDecimals || spec.flHash)
7320                 w += requestedDecimals + 1;
7321             int pad = spec.width - w;
7322             sinkPadLeft(spec, sink, pad);
7323             sinkSign(spec, sink, signed);
7324             sinkPadZero(spec, sink, pad);
7325             sink(buffer[$ - digits .. $]);
7326             sinkRepeat(sink, '0', e);
7327             if (requestedDecimals || spec.flHash)
7328             {
7329                 sink(".");
7330                 sinkRepeat(sink, '0', requestedDecimals);
7331             }
7332             sinkPadRight(sink, pad);
7333         }
7334         else
7335         {
7336             int digits = prec(c);
7337             int requestedDecimals = spec.precision == spec.UNSPECIFIED ? 6 : spec.precision;
7338 
7339             if (-e < digits) //coef.ficient[0...]
7340             {
7341                 int integralDigits = digits + e;
7342                 int fractionalDigits = digits - integralDigits;
7343                 if (fractionalDigits > requestedDecimals)
7344                 {
7345                     divpow10(c, fractionalDigits - requestedDecimals, signed, mode);
7346                     digits = prec(c);
7347                     fractionalDigits = digits - integralDigits;
7348                     if (fractionalDigits > requestedDecimals)
7349                     {
7350                         c /= 10U;
7351                         --fractionalDigits;
7352                     }
7353                 }
7354                 if (requestedDecimals > fractionalDigits && skipTrailingZeros)
7355                     requestedDecimals = fractionalDigits;
7356                 w += integralDigits;
7357                 if (requestedDecimals || spec.flHash)
7358                     w += requestedDecimals + 1;
7359                 int pad = spec.width - w;
7360                 sinkPadLeft(spec, sink, pad);
7361                 sinkSign(spec, sink, signed);
7362                 sinkPadZero(spec, sink, pad);
7363                 dumpUnsigned(buffer, c);
7364                 sink(buffer[$ - digits .. $ - fractionalDigits]);
7365                 if (requestedDecimals || spec.flHash)
7366                 {
7367                     sink(".");
7368                     if (fractionalDigits)
7369                         sink(buffer[$ - fractionalDigits .. $]);
7370                     sinkRepeat(sink, '0', requestedDecimals - fractionalDigits);
7371                 }
7372                 sinkPadRight(sink, pad);
7373             }
7374             else if (-e == digits) //0.coefficient[0...]
7375             {
7376                 if (skipTrailingZeros && requestedDecimals > digits)
7377                     requestedDecimals = digits;
7378                 if (requestedDecimals == 0) //special case, no decimals, round
7379                 {
7380                     divpow10(c, digits - 1, signed, mode);
7381                     divpow10(c, 1, signed, mode);
7382                     w += 1;
7383                     if (spec.flHash)
7384                         ++w;
7385                     int pad = spec.width - w;
7386                     sinkPadLeft(spec, sink, pad);
7387                     sinkSign(spec, sink, signed);
7388                     sinkPadZero(spec, sink, pad);
7389                     sink(c != 0U ? "1": "0");
7390                     if (spec.flHash)
7391                         sink(".");
7392                     sinkPadRight(sink, pad);
7393                 }
7394                 else
7395                 {
7396                     w += 2;
7397                     w += requestedDecimals;
7398                     if (digits > requestedDecimals)
7399                     {
7400                         divpow10(c, digits - requestedDecimals, signed, mode);
7401                         digits = prec(c);
7402                         if (digits > requestedDecimals)
7403                         {
7404                             c /= 10U;
7405                             --digits;
7406                         }
7407                     }
7408                     int pad = spec.width - w;
7409                     sinkPadLeft(spec, sink, pad);
7410                     sinkSign(spec, sink, signed);
7411                     sinkPadZero(spec, sink, pad);
7412                     sink("0.");
7413                     dumpUnsigned(buffer, c);
7414                     sink(buffer[$ - digits .. $]);
7415                     sinkRepeat(sink, '0', requestedDecimals - digits);
7416                     sinkPadRight(sink, pad);
7417                 }
7418             }
7419             else //-e > 0.[0...][coefficient]
7420             {
7421                 int zeros = -e - digits;
7422                 
7423                 if (requestedDecimals > digits - e && skipTrailingZeros)
7424                     requestedDecimals = digits - e - 1;
7425 
7426                 if (requestedDecimals <= zeros) //special case, coefficient does not fit
7427                 {
7428                     divpow10(c, digits - 1, signed, mode);
7429                     divpow10(c, 1, signed, mode);
7430                     if (requestedDecimals == 0)  //special case, 0 or 1
7431                     {
7432                         w += 1;
7433                         int pad = spec.width - w;
7434                         sinkPadLeft(spec, sink, pad);
7435                         sinkSign(spec, sink, signed);
7436                         sinkPadZero(spec, sink, pad);
7437                         sink(c != 0U ? "1": "0");
7438                         sinkPadRight(sink, pad);
7439                     }
7440                     else  //special case 0.[0..][0/1]
7441                     {
7442                         w += 2;
7443                         w += requestedDecimals;
7444                         int pad = spec.width - w;
7445                         sinkPadLeft(spec, sink, pad);
7446                         sinkSign(spec, sink, signed);
7447                         sinkPadZero(spec, sink, pad);
7448                         sink("0.");
7449                         sinkRepeat(sink, '0', requestedDecimals - 1);
7450                         sink(c != 0U ? "1": "0");
7451                         sinkPadRight(sink, pad);
7452                     }
7453                 }
7454                 else //0.[0...]coef
7455                 {
7456                     if (digits > requestedDecimals - zeros)
7457                     {
7458                         divpow10(c, digits - (requestedDecimals - zeros), signed, mode);
7459                         digits = prec(c);
7460                         if (digits > requestedDecimals - zeros)
7461                             c /= 10U;
7462                         digits = prec(c);
7463                     }
7464                     w += 2;
7465                     w += requestedDecimals;
7466                     int pad = spec.width - w;
7467                     sinkPadLeft(spec, sink, pad);
7468                     sinkSign(spec, sink, signed);
7469                     sinkPadZero(spec, sink, pad);
7470                     sink("0.");
7471                     sinkRepeat(sink, '0', zeros);
7472                     digits = dumpUnsigned(buffer, c);
7473                     sink(buffer[$ - digits .. $]);
7474                     sinkRepeat(sink, '0', requestedDecimals - digits - zeros);
7475                     sinkPadRight(sink, pad);
7476                 }
7477             }
7478         }
7479     }
7480 }
7481 
7482 //sinks %e
7483 void sinkExponential(C, T)(auto const ref FormatSpec!C spec, scope void delegate(const(C)[]) sink, const T coefficient, 
7484                      const int exponent, const bool signed, const RoundingMode mode, const bool skipTrailingZeros = false) 
7485 if (isSomeChar!C)
7486 {
7487     int w = 3; /// N e +/-
7488     if (spec.flPlus || spec.flSpace || signed)
7489         ++w;
7490     Unqual!C[T.sizeof * 8 / 3 + 1] buffer;
7491     Unqual!C[10] exponentBuffer;
7492     Unqual!T c = coefficient;
7493     int ex = exponent;
7494     coefficientShrink(c, ex);
7495     int digits = prec(c);
7496     int e = digits == 0 ? 0 : ex + (digits - 1);    
7497     int requestedDecimals = spec.precision == spec.UNSPECIFIED ? 6 : spec.precision;
7498 
7499     int targetPrecision = requestedDecimals + 1;
7500 
7501     if (digits > targetPrecision)
7502     {
7503         divpow10(c, digits - targetPrecision, signed, mode);
7504         digits = prec(c);
7505         if (digits > targetPrecision)
7506             c /= 10U;
7507         --digits;
7508     }
7509     
7510 
7511     bool signedExponent = e < 0;
7512     uint ue = signedExponent ? -e : e;
7513     int exponentDigits = dumpUnsigned(exponentBuffer, ue);
7514     w += exponentDigits <= 2 ? 2 : exponentDigits;
7515     digits = dumpUnsigned(buffer, c);
7516 
7517     if (skipTrailingZeros && requestedDecimals > digits - 1)
7518         requestedDecimals = digits - 1;
7519 
7520     if (requestedDecimals || spec.flHash)
7521         w += requestedDecimals + 1;
7522     
7523     int pad = spec.width - w;
7524     sinkPadLeft(spec, sink, pad);
7525     sinkSign(spec, sink, signed);
7526     sinkPadZero(spec, sink, pad);
7527     sink(buffer[$ - digits .. $ - digits + 1]);
7528     if (requestedDecimals || spec.flHash)
7529     {
7530         sink(".");
7531         if (digits > 1)
7532             sink(buffer[$ - digits + 1 .. $]);
7533         sinkRepeat(sink, '0', requestedDecimals - (digits - 1));
7534     }
7535     sink(spec.spec <= 'Z' ? "E" : "e");
7536     sink(signedExponent ? "-" : "+");
7537     if (exponentDigits < 2)
7538         sink("0");
7539     sink(exponentBuffer[$ - exponentDigits .. $]);
7540     sinkPadRight(sink, pad);    
7541 }
7542 
7543 //sinks %g
7544 void sinkGeneral(C, T)(auto const ref FormatSpec!C spec, scope void delegate(const(C)[]) sink, const T coefficient, 
7545                            const int exponent, const bool signed, const RoundingMode mode) 
7546 if (isSomeChar!C)
7547 {
7548     int precision = spec.precision == spec.UNSPECIFIED ? 6 : (spec.precision <= 0 ? 1 : spec.precision);
7549     Unqual!T c = coefficient;
7550     int e = exponent;
7551     coefficientShrink(c, e);
7552     coefficientAdjust(c, e, precision, signed, mode);
7553     if (c == 0U)
7554         e = 0;
7555     int cp = prec(c);
7556 
7557     int expe = cp > 0 ? e + cp - 1 : 0;
7558 
7559     if (precision > expe && expe >= -4)
7560     {
7561         FormatSpec!C fspec = spec;
7562         fspec.precision = precision - 1 - expe;
7563         sinkFloat(fspec, sink, coefficient, exponent, signed, mode, !fspec.flHash);
7564     }
7565     else
7566     {
7567         FormatSpec!C espec = spec;
7568         espec.precision = precision - 1;
7569         sinkExponential(espec, sink, coefficient, exponent, signed, mode, !espec.flHash);
7570     }
7571 
7572 }
7573 
7574 //sinks a decimal value
7575 void sinkDecimal(C, D)(auto const ref FormatSpec!C spec, scope void delegate(const(C)[]) sink, auto const ref D decimal,
7576                        const RoundingMode mode)
7577 if (isDecimal!D && isSomeChar!C)
7578 {
7579     DataType!D coefficient; int exponent; bool isNegative;
7580     auto fx = fastDecode(decimal, coefficient, exponent, isNegative);
7581     if (fx == FastClass.signalingNaN)
7582         sinkNaN(spec, sink, isNegative, true, coefficient, spec.spec == 'a' || spec.spec == 'A');
7583     else if (fx == FastClass.quietNaN)
7584         sinkNaN(spec, sink, isNegative, false, coefficient, spec.spec == 'a' || spec.spec == 'A');
7585     else if (fx == FastClass.infinite)
7586         sinkInfinity(spec, sink, signbit(decimal) != 0);
7587     else
7588     {
7589         switch (spec.spec)
7590         {
7591             case 'f':
7592             case 'F':
7593                 sinkFloat(spec, sink, coefficient, exponent, isNegative, mode);
7594                 break;
7595             case 'e':
7596             case 'E':
7597                 sinkExponential(spec, sink, coefficient, exponent, isNegative, mode);
7598                 break;
7599             case 'g':
7600             case 'G':
7601             case 's':
7602             case 'S':
7603                 sinkGeneral(spec, sink, coefficient, exponent, isNegative, mode);
7604                 break;
7605             case 'a':
7606             case 'A':
7607                 sinkHexadecimal(spec, sink, coefficient, exponent, isNegative);
7608                 break;
7609             default:
7610                 throw new FormatException("Unsupported format specifier");
7611         }
7612     }
7613 }
7614 
7615 //converts decimal to string using %g
7616 immutable(C)[] decimalToString(C, D)(auto const ref D decimal, const RoundingMode mode)
7617 if (isDecimal!D && isSomeChar!C) 
7618 {
7619     immutable(C)[] result;
7620     void localSink(const(C)[] s)
7621     {
7622         result ~= s;
7623     }
7624 
7625     sinkDecimal(FormatSpec!C("%g"), &localSink, decimal, mode);
7626 
7627     return result;
7628 }
7629 
7630 //converts decimal to string
7631 immutable(C)[] decimalToString(C, D)(auto const ref FormatSpec!C spec, auto const ref D decimal, const RoundingMode mode)
7632 if (isDecimal!D && isSomeChar!C) 
7633 {
7634     immutable(C)[] result;
7635     void localSink(const(C)[] s)
7636     {
7637         result ~= s;
7638     }
7639 
7640     sinkDecimal(spec, &localSink, decimal, mode);
7641 
7642     return result;
7643 }
7644 
7645 unittest
7646 {
7647     import std.format;
7648     decimal32 x = "1.234567";
7649     assert (format("%0.7f", x) == "1.2345670");
7650     assert (format("%0.6f", x) == "1.234567");
7651     assert (format("%0.5f", x) == "1.23457");
7652     assert (format("%0.4f", x) == "1.2346");
7653     assert (format("%0.3f", x) == "1.235");
7654     assert (format("%0.2f", x) == "1.23");
7655     assert (format("%0.1f", x) == "1.2");
7656     assert (format("%0.0f", x) == "1");
7657     assert (format("%+0.1f", x) == "+1.2");
7658     assert (format("%+0.1f", -x) == "-1.2");
7659     assert (format("% 0.1f", x) == " 1.2");
7660     assert (format("% 0.1f", -x) == "-1.2");
7661     assert (format("%8.2f", x) == "    1.23");
7662     assert (format("%+8.2f", x) == "   +1.23");
7663     assert (format("%+8.2f", -x) == "   -1.23");
7664     assert (format("% 8.2f", x) == "    1.23");
7665     assert (format("%-8.2f", x) == "1.23    ");
7666     assert (format("%-8.2f", -x) == "-1.23   ");
7667 
7668     struct S 
7669     {
7670         string fmt;
7671         string v;
7672         string expected;
7673     }
7674     
7675     S[] tests = 
7676     [
7677         S("%+.3e","0.0","+0.000e+00"),
7678   	    S("%+.3e","1.0","+1.000e+00"),
7679   	    S("%+.3f","-1.0","-1.000"),
7680   	    S("%+.3F","-1.0","-1.000"),
7681   	    S("%+07.2f","1.0","+001.00"),
7682   	    S("%+07.2f","-1.0","-001.00"),
7683   	    S("%-07.2f","1.0","1.00   "),
7684   	    S("%-07.2f","-1.0","-1.00  "),
7685   	    S("%+-07.2f","1.0","+1.00  "),
7686   	    S("%+-07.2f","-1.0","-1.00  "),
7687   	    S("%-+07.2f","1.0","+1.00  "),
7688   	    S("%-+07.2f","-1.0","-1.00  "),
7689   	    S("%+10.2f","+1.0","     +1.00"),
7690   	    S("%+10.2f","-1.0","     -1.00"),
7691   	    S("% .3E","-1.0","-1.000E+00"),
7692   	    S("% .3e","1.0"," 1.000e+00"),
7693   	    S("%+.3g","0.0","+0"),
7694   	    S("%+.3g","1.0","+1"),
7695   	    S("%+.3g","-1.0","-1"),
7696   	    S("% .3g","-1.0","-1"),
7697   	    S("% .3g","1.0"," 1"),
7698   	    S("%a","1","0x1p+0"),
7699   	    S("%#g","1e-32","1.00000e-32"),
7700   	    S("%#g","-1.0","-1.00000"),
7701   	    S("%#g","1.1","1.10000"),
7702   	    S("%#g","123456.0","123456."),
7703   	    S("%#g","1234567.0","1.23457e+06"),
7704   	    S("%#g","1230000.0","1.23000e+06"),
7705   	    S("%#g","1000000.0","1.00000e+06"),
7706   	    S("%#.0f","1.0","1."),
7707   	    S("%#.0e","1.0","1.e+00"),
7708   	    S("%#.0g","1.0","1."),
7709   	    S("%#.0g","1100000.0","1.e+06"),
7710   	    S("%#.4f","1.0","1.0000"),
7711   	    S("%#.4e","1.0","1.0000e+00"),
7712   	    S("%#.4g","1.0","1.000"),
7713   	    S("%#.4g","100000.0","1.000e+05"),
7714   	    S("%#.0f","123.0","123."),
7715   	    S("%#.0e","123.0","1.e+02"),
7716   	    S("%#.0g","123.0","1.e+02"),
7717   	    S("%#.4f","123.0","123.0000"),
7718   	    S("%#.4e","123.0","1.2300e+02"),
7719   	    S("%#.4g","123.0","123.0"),
7720   	    S("%#.4g","123000.0","1.230e+05"),
7721   	    S("%#9.4g","1.0","    1.000"),
7722   	    S("%.4a","1","0x1p+0"),
7723   	    S("%.4a","-1","-0x1p+0"),
7724   	    S("%f","+inf","inf"),
7725   	    S("%.1f","-inf","-inf"),
7726   	    S("% f","$(B NaN)"," nan"),
7727   	    S("%20f","+inf","                 inf"),
7728   	    S("% 20F","+inf","                 INF"),
7729   	    S("% 20e","-inf","                -inf"),
7730   	    S("%+20E","-inf","                -INF"),
7731   	    S("% +20g","-Inf","                -inf"),
7732   	    S("%+-20G","+inf","+INF                "),
7733   	    S("%20e","$(B NaN)","                 nan"),
7734   	    S("% +20E","$(B NaN)","                +NAN"),
7735   	    S("% -20g","$(B NaN)"," nan                "),
7736   	    S("%+-20G","$(B NaN)","+NAN                "),
7737   	    S("%+020e","+inf","                +inf"),
7738   	    S("%-020f","-inf","-inf                "),
7739   	    S("%-020E","$(B NaN)","NAN                 "),
7740         S("%e","1.0","1.000000e+00"),
7741   	    S("%e","1234.5678e3","1.234568e+06"),
7742   	    S("%e","1234.5678e-8","1.234568e-05"),
7743   	    S("%e","-7.0","-7.000000e+00"),
7744   	    S("%e","-1e-9","-1.000000e-09"),
7745   	    S("%f","1234.567e2","123456.700000"),
7746   	    S("%f","1234.5678e-8","0.000012"),
7747   	    S("%f","-7.0","-7.000000"),
7748   	    S("%f","-1e-9","-0.000000"),
7749   	    S("%g","1234.5678e3","1.23457e+06"),
7750   	    S("%g","1234.5678e-8","1.23457e-05"),
7751   	    S("%g","-7.0","-7"),
7752   	    S("%g","-1e-9","-1e-09"),
7753   	    S("%E","1.0","1.000000E+00"),
7754   	    S("%E","1234.5678e3","1.234568E+06"),
7755   	    S("%E","1234.5678e-8","1.234568E-05"),
7756   	    S("%E","-7.0","-7.000000E+00"),
7757   	    S("%E","-1e-9","-1.000000E-09"),
7758   	    S("%G","1234.5678e3","1.23457E+06"),
7759   	    S("%G","1234.5678e-8","1.23457E-05"),
7760   	    S("%G","-7.0","-7"),
7761   	    S("%G","-1e-9","-1E-09"),
7762   	    S("%20.6e","1.2345e3","        1.234500e+03"),
7763   	    S("%20.6e","1.2345e-3","        1.234500e-03"),
7764   	    S("%20e","1.2345e3","        1.234500e+03"),
7765   	    S("%20e","1.2345e-3","        1.234500e-03"),
7766   	    S("%20.8e","1.2345e3","      1.23450000e+03"),
7767   	    S("%20f","1.23456789e3","         1234.568000"),
7768   	    S("%20f","1.23456789e-3","            0.001235"),
7769   	    S("%20f","12345678901.23456789","  12345680000.000000"),
7770   	    S("%-20f","1.23456789e3","1234.568000         "),
7771         S("%20.8f","1.23456789e3","       1234.56800000"),
7772         S("%20.8f","1.23456789e-3","          0.00123457"),
7773         S("%g","1.23456789e3","1234.57"),
7774         S("%g","1.23456789e-3","0.00123457"),
7775         S("%g","1.23456789e20","1.23457e+20"),
7776         S("%.2f","1.0","1.00"),
7777   	    S("%.2f","-1.0","-1.00"),
7778   	    S("% .2f","1.0"," 1.00"),
7779   	    S("% .2f","-1.0","-1.00"),
7780   	    S("%+.2f","1.0","+1.00"),
7781   	    S("%+.2f","-1.0","-1.00"),
7782   	    S("%7.2f","1.0","   1.00"),
7783   	    S("%7.2f","-1.0","  -1.00"),
7784   	    S("% 7.2f","1.0","   1.00"),
7785   	    S("% 7.2f","-1.0","  -1.00"),
7786   	    S("%+7.2f","1.0","  +1.00"),
7787   	    S("%+7.2f","-1.0","  -1.00"),
7788   	    S("% +7.2f","1.0","  +1.00"),
7789   	    S("% +7.2f","-1.0","  -1.00"),
7790   	    S("%07.2f","1.0","0001.00"),
7791   	    S("%07.2f","-1.0","-001.00"),
7792   	    S("% 07.2f","1.0"," 001.00"),
7793   	    S("% 07.2f","-1.0","-001.00"),
7794   	    S("%+07.2f","1.0","+001.00"),
7795   	    S("%+07.2f","-1.0","-001.00"),
7796   	    S("% +07.2f","1.0","+001.00"),
7797   	    S("% +07.2f","-1.0","-001.00"),
7798   
7799   
7800     ];
7801 
7802     foreach(s; tests)
7803     {
7804         string result = format(s.fmt, decimal32(s.v));
7805         assert(result == s.expected, "value: '" ~ s.v ~ "', format: '" ~ s.fmt ~ "', result :'" ~ result ~ "', expected: '" ~ s.expected ~ "'");
7806     }
7807 }
7808 
7809 
7810 //returns true if a decimal number can be read in value, stops if doesn't fit in value
7811 ExceptionFlags parseNumberAndExponent(R, T)(ref R range, out T value, out int exponent, bool zeroPrefix) 
7812 if (isInputRange!R && isSomeChar!(ElementType!R))
7813 {
7814     bool afterDecimalPoint = false;
7815     bool atLeastOneDigit = parseZeroes(range) > 0 || zeroPrefix;
7816     bool atLeastOneFractionalDigit = false;
7817     ExceptionFlags flags = ExceptionFlags.none;
7818     while (!range.empty)
7819     {
7820         if (range.front >= '0' && range.front <= '9')
7821         {
7822             uint digit = range.front - '0';
7823             bool overflow = false;
7824             Unqual!T v = fma(value, 10U, digit, overflow);
7825             if (overflow)
7826             {
7827                 //try to shrink the coefficient, this will loose some zeros
7828                 coefficientShrink(value, exponent);
7829                 overflow = false;
7830                 v = fma(value, 10U, digit, overflow);
7831                 if (overflow)
7832                     break;
7833             }
7834             range.popFront();
7835             value = v;
7836             if (afterDecimalPoint)
7837             {
7838                 atLeastOneFractionalDigit = true;
7839                 --exponent;
7840             }
7841             else
7842                 atLeastOneDigit = true;
7843         }
7844         else if (range.front == '.' && !afterDecimalPoint)
7845         {
7846             afterDecimalPoint = true;
7847             range.popFront();
7848         }
7849         else if (range.front == '_')
7850             range.popFront();
7851         else
7852             break;
7853     }
7854 
7855     //no more space in coefficient, just increase exponent before decimal point
7856     //detect if rounding is necessary
7857     int lastDigit = 0;
7858     bool mustRoundUp = false;
7859     while (!range.empty)
7860     {
7861         if (range.front >= '0' && range.front <= '9')
7862         {       
7863             uint digit = range.front - '0';
7864             if (afterDecimalPoint)
7865                 atLeastOneFractionalDigit = true;
7866             else
7867                 ++exponent;
7868             range.popFront();
7869             if (digit != 0)
7870                 flags = ExceptionFlags.inexact;
7871             if (digit <= 3)
7872                 break;
7873             else if (digit >= 5)
7874             {
7875                 if (lastDigit == 4)
7876                 {
7877                     mustRoundUp = true;
7878                     break;
7879                 }
7880             }
7881             else
7882                 lastDigit = 4;
7883 
7884         }
7885         else if (range.front == '.' && !afterDecimalPoint)
7886         {
7887             afterDecimalPoint = true;
7888             range.popFront();
7889         }
7890         else if (range.front == '_')
7891             range.popFront();
7892         else
7893             break;
7894     }
7895 
7896     //just increase exponent before decimal point
7897     while (!range.empty)
7898     {
7899         if (range.front >= '0' && range.front <= '9')
7900         {       
7901             if (range.front != '0')
7902                 flags = ExceptionFlags.inexact;
7903             if (!afterDecimalPoint)
7904                ++exponent;
7905             else
7906                 atLeastOneFractionalDigit = true;
7907             range.popFront();
7908         }
7909         else if (range.front == '.' && !afterDecimalPoint)
7910         {
7911             afterDecimalPoint = true;
7912             range.popFront();
7913         }
7914         else if (range.front == '_')
7915             range.popFront();
7916         else
7917             break;
7918     }
7919 
7920     if (mustRoundUp)
7921     {
7922         if (value < T.max)
7923             ++value;
7924         else
7925         {
7926             auto r = divrem(value, 10U);
7927             ++value;
7928             if (r >= 5U)
7929                 ++value;
7930             else if (r == 4U && mustRoundUp)
7931                 ++value;
7932         }
7933     }
7934 
7935 
7936     if (afterDecimalPoint)
7937         return flags;
7938         //return atLeastOneFractionalDigit ? flags : flags | ExceptionFlags.invalidOperation;
7939     else
7940         return atLeastOneDigit ? flags : flags | ExceptionFlags.invalidOperation;
7941 }
7942 
7943 //parses hexadecimals if starts with 0x, otherwise decimals, false on failure
7944 bool parseHexNumberOrNumber(R, T)(ref R range, ref T value, out bool wasHex) 
7945 if (isInputRange!R && isSomeChar!(ElementType!R))
7946 {
7947     if (expect(range, '0'))
7948     {
7949         if (expectInsensitive(range, 'x'))
7950         {
7951             wasHex = true;
7952             return parseHexNumber(range, value);
7953         }
7954         else
7955             return parseNumber(range, value);
7956     }
7957     else
7958         return parseNumber(range, value);
7959 }
7960 
7961 //parses $(B NaN) and optional payload, expect payload as number in optional (), [], {}, <>. invalidOperation on failure
7962 bool parseNaN(R, T)(ref R range, out T payload) 
7963 if (isInputRange!R && isSomeChar!(ElementType!R))
7964 {
7965     if (expectInsensitive(range, "nan"))
7966     {
7967         auto closingBracket = parseBracket(range);  
7968         bool wasHex;
7969         if (!parseHexNumberOrNumber(range, payload, wasHex))
7970         {
7971             if (wasHex)
7972                 return false;
7973         }
7974         if (closingBracket)
7975             return expect(range, closingBracket);
7976         return true;
7977     }
7978     return false;
7979 }
7980 
7981 @safe
7982 ExceptionFlags parseDecimalHex(R, T)(ref R range, out T coefficient, out int exponent)
7983 if (isInputRange!R && isSomeChar!(ElementType!R))
7984 {
7985     if (parseHexNumber(range, coefficient))
7986     {
7987         if (expectInsensitive(range, 'p'))
7988         {
7989             bool signedExponent;
7990             parseSign(range, signedExponent);
7991             uint e;
7992             if (parseNumber(range, e))
7993             {
7994                 if (signedExponent && e > -int.min)
7995                 {
7996                     exponent = int.min;
7997                     return ExceptionFlags.underflow;
7998                 }
7999                 else if (!signedExponent && e > int.max)
8000                 {
8001                     exponent = int.max;
8002                     return ExceptionFlags.overflow;
8003                 }
8004                 exponent = signedExponent ? -e : e;
8005                 return ExceptionFlags.none;
8006             }
8007         }
8008     }
8009     return ExceptionFlags.invalidOperation;
8010 }
8011 
8012 ExceptionFlags parseDecimalFloat(R, T)(ref R range, out T coefficient, out int exponent, const bool zeroPrefix)
8013 if (isInputRange!R && isSomeChar!(ElementType!R))
8014 {
8015     auto flags = parseNumberAndExponent(range, coefficient, exponent, zeroPrefix);
8016     if ((flags & ExceptionFlags.invalidOperation) == 0)
8017     {
8018         if (expectInsensitive(range, 'e'))
8019         {
8020             bool signedExponent;
8021             parseSign(range, signedExponent);
8022             uint ue;
8023             if (!parseNumber(range, ue))
8024                 flags |= ExceptionFlags.invalidOperation;
8025             else
8026             {       
8027                 
8028                 bool overflow;          
8029                 if (!signedExponent)
8030                 {
8031                     if (ue > int.max)
8032                     {
8033                         exponent = int.max;
8034                         flags |= ExceptionFlags.overflow;
8035                     }
8036                     else
8037                         exponent = adds(exponent, cast(int)ue, overflow);
8038                 }
8039                 else
8040                 {
8041                     if (ue > -int.min || overflow)
8042                     {
8043                         exponent = int.min;
8044                         flags |= ExceptionFlags.underflow;
8045                     }
8046                     else
8047                         exponent = adds(exponent, cast(int)(-ue), overflow);
8048                 }
8049                 if (overflow)
8050                     flags |= exponent > 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow;
8051             }
8052         }
8053     }
8054     return flags;
8055 }
8056 
8057 @safe
8058 ExceptionFlags parseDecimal(R, T)(ref R range, out T coefficient, out int exponent, out bool isinf, out bool isnan, 
8059                                   out bool signaling, out bool signed, out bool wasHex)
8060 if (isInputRange!R && isSomeChar!(ElementType!R))
8061 {
8062     while (expect(range, '_')) { }
8063     if (range.empty)
8064         return ExceptionFlags.invalidOperation;
8065     bool hasSign = parseSign(range, signed);
8066     if (range.empty && hasSign)
8067         return ExceptionFlags.invalidOperation;
8068     while (expect(range, '_')) { }
8069     switch (range.front)
8070     {
8071         case 'i':
8072         case 'I':
8073             isinf = true;
8074             return parseInfinity(range) ? ExceptionFlags.none : ExceptionFlags.invalidOperation;
8075         case 'n':
8076         case 'N':
8077             isnan = true;
8078             signaling = false;
8079             return parseNaN(range, coefficient) ? ExceptionFlags.none : ExceptionFlags.invalidOperation;
8080         case 's':
8081         case 'S':
8082             isnan = true;
8083             signaling = true;
8084             range.popFront();
8085             return parseNaN(range, coefficient) ? ExceptionFlags.none : ExceptionFlags.invalidOperation;
8086         case '0':
8087             range.popFront();
8088             if (expectInsensitive(range, 'x'))
8089             {
8090                 wasHex = true;
8091                 return parseDecimalHex(range, coefficient, exponent);
8092             }
8093             else
8094                 return parseDecimalFloat(range, coefficient, exponent, true);
8095         case '1': .. case '9':
8096             return parseDecimalFloat(range, coefficient, exponent, false);
8097         case '.':
8098             return parseDecimalFloat(range, coefficient, exponent, false);
8099         default:
8100             return ExceptionFlags.invalidOperation;
8101     }
8102 }
8103 
8104 ExceptionFlags parse(D, R)(ref R range, out D decimal, const int precision, const RoundingMode mode)
8105 if (isInputRange!R && isSomeChar!(ElementType!R) && isDecimal!D)
8106 {
8107     DataType!D coefficient;
8108     bool isinf, isnan, signaling, signed;
8109     int exponent;
8110     auto flags = parseDecimal(range, coefficient, exponent, isinf, isnan, signaling, isnegative);
8111  
8112     if (flags & ExceptionFlags.invalidOperation)
8113     {   
8114         decimal.data = D.MASK_QNAN;
8115         decimal.data |= coefficient | D.MASK_PAYL;
8116         if (isnegative)
8117             decimal.data |= D.MASK_SGN;
8118         return flags;
8119     }
8120 
8121     if (signaling)
8122         decimal.data = D.MASK_SNAN;
8123     else if (isnan)
8124         decimal.data = D.MASK_QNAN;
8125     else if (isinf)
8126         decimal.data = D.MASK_INF;
8127     else if (coefficient == 0)
8128         decimal.data - D.MASK_ZERO;
8129     else
8130     {
8131         flags |= adjustCoefficient(coefficient, exponent, D.EXP_MIN, D.EXP_MAX, D.COEF_MAX, isnegative, mode);
8132         flags |= adjustPrecision(coefficient, exponent, D.EXP_MIN, D.EXP_MAX, precision, isnegative, mode);
8133         if (flags & ExceptionFlags.overflow)
8134             decimal.data = D.MASK_INF;
8135         else if ((flags & ExceptionFlags.underflow)  || coefficient == 0)
8136             decimal.data = D.MASK_ZERO;
8137         else
8138         {
8139             flags |= decimal.pack(coefficient, exponent, isnegative);
8140             if (flags & ExceptionFlags.overflow)
8141                 decimal.data = D.MASK_INF;
8142             else if ((flags & ExceptionFlags.underflow)  || coefficient == 0)
8143                 decimal.data = D.MASK_ZERO;                
8144         }
8145     }
8146 
8147     if (isNegative)
8148         decimal.data |= D.MASK_SGN;
8149     return flags;
8150 }
8151 
8152 D fromString(D, C)(const(C)[] s)
8153 if (isDecimal!D && isSomeChar!C)
8154 {
8155     Unqual!D result = void;
8156     auto flags = result.packString(s, 
8157                                    __ctfe ? D.PRECISION : DecimalControl.precision,
8158                                    __ctfe ? RoundingMode.implicit: DecimalControl.rounding);
8159     DecimalControl.raiseFlags(flags);
8160     return result;
8161 }
8162 
8163 
8164 /* ****************************************************************************************************************** */
8165 /* DECIMAL TO DECIMAL CONVERSION                                                                                      */
8166 /* ****************************************************************************************************************** */
8167 
8168 ExceptionFlags decimalToDecimal(D1, D2)(auto const ref D1 source, out D2 target, 
8169                                         const int precision, const RoundingMode mode) 
8170 if (isDecimal!(D1, D2))
8171 {
8172     DataType!D1 cx; int ex; bool sx;
8173     final switch(fastDecode(source, cx, ex, sx))
8174     {
8175         case FastClass.finite:
8176             static if (D2.sizeof == D1.sizeof)
8177             {
8178                 target.data = source.data;
8179                 return ExceptionFlags.none;
8180             }
8181             else
8182                 return target.adjustedPack(cx, ex, sx, precision, mode);
8183         case FastClass.zero:
8184             target = sx ? -D2.zero : D2.zero;
8185             return ExceptionFlags.none;
8186         case FastClass.infinite:
8187             target = sx ? -D2.infinity : D2.infinity;
8188             return ExceptionFlags.none;
8189         case FastClass.quietNaN:
8190             target = sx ? -D2.nan : D2.nan;
8191             return ExceptionFlags.none;
8192         case FastClass.signalingNaN:
8193             target = sx ? -D2.nan : D2.nan;
8194             return ExceptionFlags.invalidOperation;
8195     }
8196 }
8197 
8198 ExceptionFlags decimalToUnsigned(D, T)(auto const ref D source, out T target, const RoundingMode mode) 
8199 if (isDecimal!D && isUnsigned!T)
8200 {   
8201     alias U = CommonStorage!(D, T);
8202     U cx; int ex; bool sx;
8203     final switch (fastDecode(source, cx, ex, sx))
8204     {
8205         case FastClass.finite:
8206             auto flags = coefficientAdjust(cx, ex, 0, 0, U(T.max), sx, mode);
8207             if (flags & ExceptionFlags.overflow)
8208             {
8209                 target = T(1) << (T.sizeof * 8 - 1);
8210                 flags = ExceptionFlags.overflow | ExceptionFlags.invalidOperation;
8211             }
8212             else if (flags & ExceptionFlags.underflow)
8213                 target = 0;
8214             else if (sx)
8215             {
8216                 target = T(1) << (T.sizeof * 8 - 1);
8217                 return ExceptionFlags.overflow | ExceptionFlags.invalidOperation;
8218             }
8219             else
8220                 target = cast(T)cx;
8221             return flags;
8222         case FastClass.zero:
8223             target = 0;
8224             return ExceptionFlags.none;
8225         case FastClass.infinite:
8226             target = T(1) << (T.sizeof * 8 - 1);
8227             return ExceptionFlags.overflow | ExceptionFlags.invalidOperation;
8228         case FastClass.quietNaN:
8229         case FastClass.signalingNaN:
8230             target = T(1) << (T.sizeof * 8 - 1);
8231             return ExceptionFlags.invalidOperation;
8232     }
8233 }
8234 
8235 ExceptionFlags decimalToSigned(D, T)(auto const ref D source, out T target, const RoundingMode mode) 
8236 if (isDecimal!D && isSigned!T)
8237 {
8238     alias U = CommonStorage!(D, T);
8239     U cx; int ex; bool sx;
8240     final switch (fastDecode(source, cx, ex, sx))
8241     {
8242         case FastClass.finite:
8243             U max = sx ? unsign!U(T.min) : unsign!U(T.max);
8244             auto flags = coefficientAdjust(cx, ex, 0, 0, max, sx, mode);
8245             if (flags & ExceptionFlags.overflow)
8246             {
8247                 target = T.min;
8248                 flags = ExceptionFlags.overflow | ExceptionFlags.invalidOperation;
8249             }
8250             else if (flags & ExceptionFlags.underflow)
8251                 target = 0;
8252             else
8253                 target = sign!T(cx, sx);
8254             return flags;
8255         case FastClass.zero:
8256             target = 0;
8257             return ExceptionFlags.none;
8258         case FastClass.infinite:
8259             target = T.min;
8260             return ExceptionFlags.overflow | ExceptionFlags.invalidOperation;
8261         case FastClass.quietNaN:
8262         case FastClass.signalingNaN:
8263             target = T.min;
8264             return ExceptionFlags.invalidOperation;
8265     }
8266 }
8267 
8268 ExceptionFlags decimalToFloat(D, T)(auto const ref D source, out T target, const RoundingMode mode)
8269 if (isDecimal!D && isFloatingPoint!T)
8270 {
8271     DataType!D cx; int ex; bool sx;
8272     final switch (fastDecode(source, cx, ex, sx))
8273     {
8274         case FastClass.finite:
8275 
8276 
8277 //s_max_float     = "3.402823466385288598117041834845169e+0038",
8278 //    s_min_float     = "1.401298464324817070923729583289916e-0045",
8279 //    s_max_double    = "1.797693134862315708145274237317043e+0308",
8280 //    s_min_double    = "4.940656458412465441765687928682213e-0324",
8281 //    s_max_real      = "1.189731495357231765021263853030970e+4932",
8282 //    s_min_real      = "3.645199531882474602528405933619419e-4951",
8283 
8284 
8285             static if (is(Unqual!T == float) ||
8286                        (is(Unqual!T == double) && D.sizeof > 4) ||
8287                        (is(Unqual!T == real) && real.mant_dig == 64 && D.sizeof > 8) ||
8288                        (is(Unqual!T == real) && real.mant_dig != 64 && D.sizeof > 4))
8289             {
8290                 static if (is(T == float))
8291                 {
8292                     auto c1 = decimalCmp(fabs(source), decimal128.maxFloat);
8293                     auto c2 = decimalCmp(fabs(source), decimal128.minFloat);
8294                 }
8295                 else static if (is(T == real) && (real.mant_dig == 64))
8296                 {
8297                     auto c1 = decimalCmp(fabs(source), decimal128.maxReal);
8298                     auto c2 = decimalCmp(fabs(source), decimal128.minReal);
8299                 }
8300                 else
8301                 {
8302                     auto c1 = decimalCmp(fabs(source), decimal128.maxDouble);
8303                     auto c2 = decimalCmp(fabs(source), decimal128.minDouble);
8304                 }
8305 
8306                 if (c1 > 0)
8307                 {
8308                     target = sx ? -T.infinity: T.infinity;
8309                     return ExceptionFlags.overflow;
8310                 }
8311 
8312                 if (c2 < 0)
8313                 {
8314                     target = sx ? -0.0 : +0.0;
8315                     return ExceptionFlags.underflow | ExceptionFlags.inexact;
8316                 }
8317 
8318                 if (c1 == 0)
8319                 {
8320                     target = sx ? -T.max: T.max;
8321                     return ExceptionFlags.inexact;
8322                 }
8323 
8324                 if (c2 == 0)
8325                 {
8326                     target = (sx ? -T.min_normal : T.min_normal) * T.epsilon;
8327                     return ExceptionFlags.inexact;
8328                 }
8329             }
8330 
8331             ExceptionFlags flags;
8332             static if (is(D: decimal128))
8333                 flags = coefficientAdjust(cx, ex, uint128(ulong.max), sx, mode);
8334             ulong m = cvt!ulong(cx);
8335             final switch (mode)
8336             {
8337                 case RoundingMode.tiesToAway:
8338                     flags |= exp10to2!(RoundingMode.tiesToAway)(m, ex, sx);
8339                     break;
8340                 case RoundingMode.tiesToEven:
8341                     flags |= exp10to2!(RoundingMode.tiesToEven)(m, ex, sx);
8342                     break;
8343                 case RoundingMode.towardNegative:
8344                     flags |= exp10to2!(RoundingMode.towardNegative)(m, ex, sx);
8345                     break;
8346                 case RoundingMode.towardPositive:
8347                     flags |= exp10to2!(RoundingMode.towardPositive)(m, ex, sx);
8348                     break;
8349                 case RoundingMode.towardZero:
8350                     flags |= exp10to2!(RoundingMode.towardZero)(m, ex, sx);
8351                     break;
8352             }
8353             synchronized
8354             {              
8355                 FloatingPointControl fpctrl;
8356                 auto savedExceptions = fpctrl.enabledExceptions;
8357                 fpctrl.disableExceptions(FloatingPointControl.allExceptions);
8358                 auto savedMode = fpctrl.rounding;
8359                 switch (mode)
8360                 {
8361                     case RoundingMode.tiesToAway:
8362                     case RoundingMode.tiesToEven:
8363                         fpctrl.rounding = FloatingPointControl.roundToNearest;
8364                         break;
8365                     case RoundingMode.towardNegative:
8366                         fpctrl.rounding = FloatingPointControl.roundDown;
8367                         break;
8368                     case RoundingMode.towardPositive:
8369                         fpctrl.rounding = FloatingPointControl.roundUp;
8370                         break;
8371                     case RoundingMode.towardZero:
8372                         fpctrl.rounding = FloatingPointControl.roundToZero;
8373                         break;
8374                     default:
8375                         break;
8376                 }
8377                 resetIeeeFlags();
8378                 
8379                 real r = m;
8380                 if (sx)
8381                     r = -r;
8382                 target = ldexp(r, ex);
8383                 
8384 
8385                 if (ieeeFlags.inexact)
8386                     flags |= ExceptionFlags.inexact;
8387                 if (ieeeFlags.underflow)
8388                     flags |= ExceptionFlags.underflow;
8389                 if (ieeeFlags.overflow)
8390                     flags |= ExceptionFlags.overflow;
8391                 if (ieeeFlags.invalid)
8392                     flags |= ExceptionFlags.invalidOperation;
8393                 if (ieeeFlags.divByZero)
8394                     flags |= ExceptionFlags.divisionByZero;
8395                 fpctrl.enableExceptions(savedExceptions);
8396             }
8397             
8398             return flags;         
8399         case FastClass.zero:
8400             target = sx ? -0.0: 0.0;
8401             return ExceptionFlags.none;
8402         case FastClass.infinite:
8403             target = sx ? -T.infinity : T.infinity;
8404             return ExceptionFlags.none;
8405         case FastClass.quietNaN:
8406         case FastClass.signalingNaN:
8407             target = T.nan;
8408             return ExceptionFlags.none;
8409     }
8410 
8411 
8412 
8413 }
8414 
8415 /* ****************************************************************************************************************** */
8416 /* DECIMAL ARITHMETIC                                                                                      */
8417 /* ****************************************************************************************************************** */
8418 
8419 template CommonStorage(D, T) if (isDecimal!D && isDecimal!T)
8420 {
8421     static if (D.sizeof >= T.sizeof)
8422         alias CommonStorage = DataType!D;
8423     else
8424         alias CommonStorage = DataType!T;
8425 }
8426 
8427 template CommonStorage(D, T) if (isDecimal!D && isIntegral!T)
8428 {
8429     static if (D.sizeof >= T.sizeof)
8430         alias CommonStorage = DataType!D;
8431     else
8432         alias CommonStorage = Unsigned!T;
8433 }
8434 
8435 template CommonStorage(D, T) if (isDecimal!D && isFloatingPoint!T)
8436 {
8437     static if (is(Unqual!T == float))
8438         alias CommonStorage = DataType!D;
8439     else
8440         alias CommonStorage = CommonStorage!(D, ulong);
8441 }
8442 
8443 
8444 @safe pure nothrow @nogc
8445 D canonical(D)(auto const ref D x)
8446 if (isDecimal!D)
8447 {
8448     Unqual!D result = x;
8449     canonicalize(result);
8450     return x;
8451 }
8452 
8453 @safe pure nothrow @nogc
8454 void canonicalize(D)(ref D x)
8455 if (isDecimal!D)
8456 {
8457     if ((x.data & D.MASK_INF) == D.MASK_INF)
8458     {
8459         if ((x.data & D.MASK_QNAN) == D.MASK_QNAN)
8460             x.data &= D.MASK_SNAN | D.MASK_SGN | D.MASK_PAYL;
8461         else
8462             x.data &= D.MASK_INF | D.MASK_SGN;
8463     }
8464     else if ((x.data & D.MASK_EXT) == D.MASK_EXT && 
8465              (((x.data & D.MASK_COE2) | D.MASK_COEX) > D.COEF_MAX))
8466         x.data &= D.MASK_ZERO | D.MASK_SGN;    
8467     else if ((x.data & D.MASK_COE1) == 0U)
8468         x.data &= D.MASK_ZERO | D.MASK_SGN;
8469 }
8470 
8471 @safe pure nothrow @nogc
8472 void unsignalize(D)(ref D x)
8473 if (isDecimal!D)
8474 {
8475     x.data &= ~D.MASK_SNANBIT;
8476 }
8477 
8478 @safe pure nothrow @nogc
8479 DecimalClass decimalDecode(D, T)(auto const ref D x, out T cx, out int ex, out bool sx) 
8480 if (isDecimal!D && is(T: DataType!D))
8481 {
8482     sx = cast(bool)(x.data & D.MASK_SGN);
8483 
8484     if ((x.data & D.MASK_INF) == D.MASK_INF)
8485         if ((x.data & D.MASK_QNAN) == D.MASK_QNAN)
8486             if ((x.data & D.MASK_SNAN) == D.MASK_SNAN)
8487                 return DecimalClass.signalingNaN;
8488             else
8489                 return DecimalClass.quietNaN;
8490         else
8491             return sx ? DecimalClass.negativeInfinity : DecimalClass.positiveInfinity;
8492     else if ((x.data & D.MASK_EXT) == D.MASK_EXT)
8493     {
8494         cx = (x.data & D.MASK_COE2) | D.MASK_COEX;
8495         if (cx > D.COEF_MAX)
8496         {
8497             return sx ? DecimalClass.negativeZero : DecimalClass.positiveZero; 
8498         }
8499         ex = cast(uint)((x.data & D.MASK_EXP2) >>> D.SHIFT_EXP2) - D.EXP_BIAS;
8500     }
8501     else
8502     {
8503         cx = x.data & D.MASK_COE1;
8504         if (cx == 0U || cx > D.COEF_MAX)
8505         {
8506             ex = 0;
8507             return sx ? DecimalClass.negativeZero : DecimalClass.positiveZero; 
8508         }
8509         ex = cast(uint)((x.data & D.MASK_EXP1) >>> D.SHIFT_EXP1) - D.EXP_BIAS;
8510     }
8511 
8512     if (ex + D.EXP_BIAS < D.PRECISION - 1)
8513     {
8514         if (prec(cx) < D.PRECISION - ex + D.EXP_BIAS)
8515             return sx ? DecimalClass.negativeSubnormal : DecimalClass.positiveSubnormal;
8516     }
8517     return sx ? DecimalClass.negativeNormal : DecimalClass.positiveNormal;
8518 }
8519 
8520 enum FastClass
8521 {
8522     signalingNaN,
8523     quietNaN,
8524     infinite,
8525     zero,
8526     finite,
8527 }
8528 
8529 @safe pure nothrow @nogc
8530 FastClass fastDecode(D, T)(auto const ref D x, out T cx, out int ex, out bool sx) 
8531 if ((is(D: decimal32) || is(D: decimal64)) && isAnyUnsigned!T)
8532 {
8533     static assert (T.sizeof >= D.sizeof);
8534 
8535     sx = cast(bool)(x.data & D.MASK_SGN);
8536 
8537     if ((x.data & D.MASK_INF) == D.MASK_INF)
8538         if ((x.data & D.MASK_QNAN) == D.MASK_QNAN)
8539         {
8540             cx = x.data & D.MASK_PAYL;
8541             if (cx > D.PAYL_MAX)
8542                 cx = 0U;
8543             if ((x.data & D.MASK_SNAN) == D.MASK_SNAN)
8544                 return FastClass.signalingNaN;
8545             else
8546                 return FastClass.quietNaN;
8547             
8548         }
8549         else
8550             return FastClass.infinite;
8551     else if ((x.data & D.MASK_EXT) == D.MASK_EXT)
8552     {
8553         cx = (x.data & D.MASK_COE2) | D.MASK_COEX;
8554         if (cx > D.COEF_MAX)
8555             cx = 0U;
8556         ex = cast(uint)((x.data & D.MASK_EXP2) >>> D.SHIFT_EXP2) - D.EXP_BIAS;
8557     }
8558     else
8559     {
8560         cx = x.data & D.MASK_COE1;
8561         ex = cast(uint)((x.data & D.MASK_EXP1) >>> D.SHIFT_EXP1) - D.EXP_BIAS;
8562     }
8563 
8564     return cx == 0U ? FastClass.zero : FastClass.finite;
8565 }
8566 
8567 @safe pure nothrow @nogc
8568 FastClass fastDecode(D, T)(auto const ref D x, out T cx, out int ex, out bool sx) 
8569 if (is(D: decimal128) && isAnyUnsigned!T)
8570 {
8571     static assert (T.sizeof >= D.sizeof);
8572 
8573     sx = cast(bool)(x.data.hi & D.MASK_SGN.hi);
8574 
8575     if ((x.data.hi & D.MASK_INF.hi) == D.MASK_INF.hi)
8576         if ((x.data.hi & D.MASK_QNAN.hi) == D.MASK_QNAN.hi)
8577         {
8578             cx = x.data & D.MASK_PAYL; 
8579             if (cx > D.PAYL_MAX)
8580                 cx = 0U;
8581             if ((x.data.hi & D.MASK_SNAN.hi) == D.MASK_SNAN.hi)
8582                 return FastClass.signalingNaN;
8583             else
8584                 return FastClass.quietNaN;
8585         }
8586         else
8587             return FastClass.infinite;
8588     else if ((x.data.hi & D.MASK_EXT.hi) == D.MASK_EXT.hi)
8589     {
8590         cx = 0U;
8591         ex = cast(uint)((x.data.hi & D.MASK_EXP2.hi) >>> (D.SHIFT_EXP2 - 64)) - D.EXP_BIAS;
8592     }
8593     else
8594     {
8595         cx = x.data & D.MASK_COE1;
8596         if (cx > D.COEF_MAX)
8597             cx = 0U;
8598         ex = cast(uint)((x.data.hi & D.MASK_EXP1.hi) >>> (D.SHIFT_EXP1 - 64)) - D.EXP_BIAS;
8599     }
8600 
8601     return cx == 0U ? FastClass.zero : FastClass.finite;
8602 }
8603 
8604 @safe pure nothrow @nogc
8605 FastClass fastDecode(F, T)(auto const ref F x, out T cx, out int ex, out bool sx, const RoundingMode mode, out ExceptionFlags flags)
8606 if (isFloatingPoint!F && isAnyUnsigned!T)
8607 {
8608     bool nan, inf;
8609     static if (is(Unqual!F == float))
8610     {
8611         uint m;
8612         sx = funpack(x, ex, m, inf, nan);
8613     }
8614     else static if (is(Unqual!F == real) && real.mant_dig == 64)
8615     {
8616         ulong m;
8617         sx = runpack(x, ex, m, inf, nan);
8618     }
8619     else
8620     {
8621         ulong m;
8622         sx = dunpack(cast(double)x, ex, m, inf, nan);
8623     }
8624 
8625     if (x == 0.0)
8626         return FastClass.zero;
8627 
8628     if (inf)
8629         return FastClass.infinite;
8630 
8631     if (nan)
8632     {
8633         cx = cvt!T(m);
8634         return FastClass.quietNaN;
8635     }
8636 
8637     static if (is(F == float) && T.sizeof > uint.sizeof)
8638         alias U = uint;
8639     else static if (is(F == double) && T.sizeof > ulong.sizeof)
8640         alias U = ulong;
8641     else static if (is(F == real) && T.sizeof > uint128.sizeof)
8642         alias U = uint128;
8643     else static if (T.sizeof < typeof(m).sizeof)
8644         alias U = typeof(m);
8645     else
8646         alias U = T;
8647 
8648     U u = m;
8649 
8650     final switch(mode)
8651     {
8652         case RoundingMode.tiesToAway:
8653             flags = exp2to10!(RoundingMode.tiesToAway)(u, ex, sx);
8654             break;
8655         case RoundingMode.tiesToEven:
8656             flags = exp2to10!(RoundingMode.tiesToEven)(u, ex, sx);
8657             break;
8658         case RoundingMode.towardZero:
8659             flags = exp2to10!(RoundingMode.towardZero)(u, ex, sx);
8660             break;
8661         case RoundingMode.towardNegative:
8662             flags = exp2to10!(RoundingMode.towardNegative)(u, ex, sx);
8663             break;
8664         case RoundingMode.towardPositive:
8665             flags = exp2to10!(RoundingMode.towardPositive)(u, ex, sx);
8666             break;
8667     }
8668 
8669     static if (T.sizeof < U.sizeof)
8670     {
8671         flags |= coefficientAdjust(u, ex, cvt!U(T.max), sx, mode);
8672     }
8673 
8674     cx = cvt!T(u);
8675     return cx ? FastClass.finite : FastClass.zero;
8676 
8677 }
8678 
8679 @safe pure nothrow @nogc
8680 ExceptionFlags decimalInc(D)(ref D x, const int precision, const RoundingMode mode)
8681 {
8682 
8683     DataType!D cx; int ex; bool sx;
8684     final switch(fastDecode(x, cx, ex, sx))
8685     {
8686         case FastClass.finite:
8687             auto flags = coefficientAdd(cx, ex, sx, DataType!D(1U), 0, false, RoundingMode.implicit);
8688             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
8689         case FastClass.zero:
8690             x = D.one;
8691             return ExceptionFlags.none;
8692         case FastClass.quietNaN:
8693         case FastClass.infinite:
8694             return ExceptionFlags.none;
8695         case FastClass.signalingNaN:
8696             unsignalize(x);
8697             return ExceptionFlags.invalidOperation;
8698     }
8699 }
8700 
8701 @safe pure nothrow @nogc
8702 ExceptionFlags decimalDec(D)(ref D x, const int precision, const RoundingMode mode)
8703 {
8704     DataType!D cx; int ex; bool sx;
8705     final switch(fastDecode(x, cx, ex, sx))
8706     {
8707         case FastClass.finite:
8708             auto flags = coefficientAdd(cx, ex, sx, DataType!D(1U), 0, true, RoundingMode.implicit);
8709             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
8710         case FastClass.zero:
8711             x = -D.one;
8712             return ExceptionFlags.none;
8713         case FastClass.infinite:
8714         case FastClass.quietNaN:
8715             return ExceptionFlags.none;
8716         case FastClass.signalingNaN:
8717             unsignalize(x);
8718             return ExceptionFlags.invalidOperation;
8719     }
8720 }
8721 
8722 @safe pure nothrow @nogc
8723 ExceptionFlags decimalRound(D)(ref D x, const int precision, const RoundingMode mode)
8724 if (isDecimal!D)
8725 {
8726     DataType!D cx; int ex; bool sx;
8727     final switch(fastDecode(x, cx, ex, sx))
8728     {
8729         case FastClass.finite:
8730             auto flags = coefficientAdjust(cx, ex, 0, D.EXP_MAX, D.COEF_MAX, sx, mode);
8731             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
8732         case FastClass.zero:
8733         case FastClass.infinite:
8734         case FastClass.quietNaN:
8735             return ExceptionFlags.none;
8736         case FastClass.signalingNaN:
8737             unsignalize(x);
8738             return ExceptionFlags.invalidOperation; 
8739     }
8740 }
8741 
8742 @safe pure nothrow @nogc
8743 ExceptionFlags decimalAdjust(D)(ref D x, const int precision, const RoundingMode mode)
8744 {
8745     DataType!D cx; int ex; bool sx;
8746     final switch(fastDecode(x, cx, ex, sx))
8747     {
8748         case FastClass.finite:
8749             return x.adjustedPack(cx, ex, sx, precision, mode, ExceptionFlags.none);
8750         case FastClass.zero:
8751         case FastClass.infinite:
8752         case FastClass.quietNaN:
8753             return ExceptionFlags.none;
8754         case FastClass.signalingNaN:
8755             unsignalize(x);
8756             return ExceptionFlags.invalidOperation; 
8757     }
8758 }
8759 
8760 @safe pure nothrow @nogc
8761 ExceptionFlags decimalNextUp(D)(ref D x)
8762 if (isDecimal!D)
8763 {
8764     DataType!D cx; int ex; bool sx;
8765     final switch(fastDecode(x, cx, ex, sx))
8766     {
8767         case FastClass.finite:
8768             coefficientExpand(cx, ex);
8769             if (sx)
8770                 --cx;
8771             else
8772                 ++cx;
8773             return x.adjustedPack(cx, ex, sx, 0, RoundingMode.towardPositive, ExceptionFlags.none);
8774         case FastClass.zero:
8775             x.pack(DataType!D(1U), D.EXP_MIN, false);
8776             return ExceptionFlags.none;
8777         case FastClass.infinite:
8778             if (sx)
8779                 x = -D.max;
8780             return ExceptionFlags.none;
8781         case FastClass.quietNaN:
8782             return ExceptionFlags.none;
8783         case FastClass.signalingNaN:
8784             unsignalize(x);
8785             return ExceptionFlags.invalidOperation; 
8786     }  
8787 }
8788 
8789 @safe pure nothrow @nogc
8790 ExceptionFlags decimalNextDown(D)(ref D x)
8791 if (isDecimal!D)
8792 {
8793     DataType!D cx; int ex; bool sx;
8794     final switch(fastDecode(x, cx, ex, sx))
8795     {
8796         case FastClass.finite:
8797             coefficientExpand(cx, ex);
8798             if (!sx)
8799                 --cx;
8800             else
8801                 ++cx;
8802             return x.adjustedPack(cx, ex, sx, 0, RoundingMode.towardNegative, ExceptionFlags.none);
8803         case FastClass.zero:
8804             x.pack(DataType!D(1U), D.EXP_MIN, true);
8805             return ExceptionFlags.none;
8806         case FastClass.infinite:
8807             if (!sx)
8808                 x = D.max;
8809             return ExceptionFlags.none;
8810         case FastClass.quietNaN:
8811             return ExceptionFlags.none;
8812         case FastClass.signalingNaN:
8813             unsignalize(x);
8814             return ExceptionFlags.invalidOperation;  
8815     }
8816 }
8817 
8818 ExceptionFlags decimalMin(D1, D2, D)(auto const ref D1 x, auto const ref D2 y, out D z)
8819 if (isDecimal!(D1, D2, D) && is(D: CommonDecimal!(D1, D2)))
8820 {
8821     DataType!D cx, cy; int ex, ey; bool sx, sy;
8822     immutable fx = fastDecode(x, cx, ex, sx);
8823     immutable fy = fastDecode(y, cy, ey, sy);
8824 
8825     if (fx == FastClass.signalingNaN)
8826     {
8827         z = copysign(D.nan, x);
8828         return ExceptionFlags.invalidOperation;
8829     }
8830 
8831     if (fy == FastClass.signalingNaN)
8832     {
8833         if (fx == FastClass.quietNaN)
8834             z = copysign(D.nan, x);
8835         else
8836             z = copysign(D.nan, y);
8837         return ExceptionFlags.invalidOperation;
8838     }
8839 
8840     if (fx == FastClass.quietNaN)
8841     {
8842         if (fy == FastClass.quietNaN)
8843             z = x;
8844         else
8845             z = y;
8846         return ExceptionFlags.none;
8847     }
8848 
8849     if (fy == FastClass.quietNaN)
8850     {
8851         z = x;
8852         return ExceptionFlags.none;
8853     }
8854 
8855     if (fx == FastClass.infinite)
8856     {
8857         if (sx)
8858             z = x;
8859         else
8860             z = y;
8861         return ExceptionFlags.none;
8862     }
8863 
8864     if (fy == FastClass.infinite)
8865     {
8866         if (sy)
8867             z = y;
8868         else
8869             z = x;
8870         return ExceptionFlags.none;
8871     }
8872 
8873     if (fx == FastClass.zero)
8874     {
8875         if (sy)
8876             z = y;
8877         else
8878             z = x;
8879         return ExceptionFlags.none;
8880     }
8881 
8882     if (fy == FastClass.zero)
8883     {
8884         if (sx)
8885             z = x;
8886         else
8887             z = y;
8888         return ExceptionFlags.none;
8889     }
8890 
8891     immutable c = coefficientCmp(cx, ex, sx, cy, ey, sy);
8892     if (c <= 0)
8893         z = x;
8894     else
8895         z = y;
8896     return ExceptionFlags.none;
8897 }
8898 
8899 ExceptionFlags decimalMinAbs(D1, D2, D)(auto const ref D1 x, auto const ref D2 y, out D z)
8900 if (isDecimal!(D1, D2, D) && is(D: CommonDecimal!(D1, D2)))
8901 {
8902     DataType!D cx, cy; int ex, ey; bool sx, sy;
8903     immutable fx = fastDecode(x, cx, ex, sx);
8904     immutable fy = fastDecode(y, cy, ey, sy);
8905 
8906     if (fx == FastClass.signalingNaN)
8907     {
8908         z = copysign(D.nan, x);
8909         return ExceptionFlags.invalidOperation;
8910     }
8911 
8912     if (fy == FastClass.signalingNaN)
8913     {
8914         if (fx == FastClass.quietNaN)
8915             z = copysign(D.nan, x);
8916         else
8917             z = copysign(D.nan, y);
8918         return ExceptionFlags.invalidOperation;
8919     }
8920 
8921     if (fx == FastClass.quietNaN)
8922     {
8923         if (fy == FastClass.quietNaN)
8924             z = x;
8925         else
8926             z = y;
8927         return ExceptionFlags.none;
8928     }
8929 
8930     if (fy == FastClass.quietNaN)
8931     {
8932         z = x;
8933         return ExceptionFlags.none;
8934     }
8935 
8936     if (fx == FastClass.infinite)
8937     {
8938         if (fy == FastClass.infinite && sx)
8939             z = x;
8940         else
8941             z = y;
8942         return ExceptionFlags.none;
8943     }
8944 
8945     if (fy == FastClass.infinite)
8946     {
8947         z = x;
8948         return ExceptionFlags.none;
8949     }
8950 
8951     if (fx == FastClass.zero)
8952     {
8953         z = x;
8954         return ExceptionFlags.none;
8955     }
8956 
8957     if (fy == FastClass.zero)
8958     {
8959         z = y;
8960         return ExceptionFlags.none;
8961     }
8962 
8963     immutable c = coefficientCmp(cx, ex, cy, ey);
8964     if (c < 0)
8965         z = x;
8966     else if (c == 0 && sx)
8967         z = x;
8968     else
8969         z = y;
8970     return ExceptionFlags.none;
8971 }
8972 
8973 ExceptionFlags decimalMax(D1, D2, D)(auto const ref D1 x, auto const ref D2 y, out D z)
8974 if (isDecimal!(D1, D2, D) && is(D: CommonDecimal!(D1, D2)))
8975 {
8976     DataType!D cx, cy; int ex, ey; bool sx, sy;
8977     immutable fx = fastDecode(x, cx, ex, sx);
8978     immutable fy = fastDecode(y, cy, ey, sy);
8979 
8980     if (fx == FastClass.signalingNaN)
8981     {
8982         z = copysign(D.nan, x);
8983         return ExceptionFlags.invalidOperation;
8984     }
8985 
8986     if (fy == FastClass.signalingNaN)
8987     {
8988         if (fx == FastClass.quietNaN)
8989             z = copysign(D.nan, x);
8990         else
8991             z = copysign(D.nan, y);
8992         return ExceptionFlags.invalidOperation;
8993     }
8994 
8995     if (fx == FastClass.quietNaN)
8996     {
8997         if (fy == FastClass.quietNaN)
8998             z = x;
8999         else
9000             z = y;
9001         return ExceptionFlags.none;
9002     }
9003 
9004     if (fy == FastClass.quietNaN)
9005     {
9006         z = x;
9007         return ExceptionFlags.none;
9008     }
9009 
9010     if (fx == FastClass.infinite)
9011     {
9012         if (sx)
9013             z = y;
9014         else
9015             z = x;
9016         return ExceptionFlags.none;
9017     }
9018 
9019     if (fy == FastClass.infinite)
9020     {
9021         if (sy)
9022             z = x;
9023         else
9024             z = y;
9025         return ExceptionFlags.none;
9026     }
9027 
9028     if (fx == FastClass.zero)
9029     {
9030         if (sy)
9031             z = x;
9032         else
9033             z = y;
9034         return ExceptionFlags.none;
9035     }
9036 
9037     if (fy == FastClass.zero)
9038     {
9039         if (sx)
9040             z = y;
9041         else
9042             z = x;
9043         return ExceptionFlags.none;
9044     }
9045 
9046     immutable c = coefficientCmp(cx, ex, sx, cy, ey, sy);
9047     if (c >= 0)
9048         z = x;
9049     else
9050         z = y;
9051     return ExceptionFlags.none;
9052 }
9053 
9054 ExceptionFlags decimalMaxAbs(D1, D2, D)(auto const ref D1 x, auto const ref D2 y, out D z)
9055 if (isDecimal!(D1, D2, D) && is(D: CommonDecimal!(D1, D2)))
9056 {
9057     DataType!D cx, cy; int ex, ey; bool sx, sy;
9058     immutable fx = fastDecode(x, cx, ex, sx);
9059     immutable fy = fastDecode(y, cy, ey, sy);
9060 
9061     if (fx == FastClass.signalingNaN)
9062     {
9063         z = copysign(D.nan, x);
9064         return ExceptionFlags.invalidOperation;
9065     }
9066 
9067     if (fy == FastClass.signalingNaN)
9068     {
9069         if (fx == FastClass.quietNaN)
9070             z = copysign(D.nan, x);
9071         else
9072             z = copysign(D.nan, y);
9073         return ExceptionFlags.invalidOperation;
9074     }
9075 
9076     if (fx == FastClass.quietNaN)
9077     {
9078         if (fy == FastClass.quietNaN)
9079             z = x;
9080         else
9081             z = y;
9082         return ExceptionFlags.none;
9083     }
9084 
9085     if (fy == FastClass.quietNaN)
9086     {
9087         z = x;
9088         return ExceptionFlags.none;
9089     }
9090 
9091     if (fx == FastClass.infinite)
9092     {
9093         if (!sx || fy != FastClass.infinite)
9094             z = x;
9095         else
9096             z = y;
9097         return ExceptionFlags.none;
9098     }
9099 
9100     if (fy == FastClass.infinite)
9101     {
9102         z = y;
9103         return ExceptionFlags.none;
9104     }
9105 
9106     if (fx == FastClass.zero)
9107     {
9108         z = y;
9109         return ExceptionFlags.none;
9110     }
9111 
9112     if (fy == FastClass.zero)
9113     {
9114         z = x;
9115         return ExceptionFlags.none;
9116     }
9117 
9118     immutable c = coefficientCmp(cx, ex, cy, ey);
9119     if (c > 0)
9120         z = x;
9121     else if (c == 0 && !sx)
9122         z = x;
9123     else
9124         z = y;
9125     return ExceptionFlags.none;
9126 }
9127 
9128 @safe pure nothrow @nogc
9129 ExceptionFlags decimalQuantize(D1, D2)(ref D1 x, auto const ref D2 y, const int precision, const RoundingMode mode)
9130 if (isDecimal!(D1, D2))
9131 {
9132     alias U = CommonStorage!(D1, D2);
9133     U cx, cy; int ex, ey; bool sx, sy;
9134     immutable fx = fastDecode(x, cx, ex, sx);
9135     immutable fy = fastDecode(y, cy, ey, sy);
9136 
9137     if (fx == FastClass.signalingNaN)
9138     {
9139         unsignalize(x);
9140         return ExceptionFlags.invalidOperation;
9141     }
9142 
9143     if (fy == FastClass.signalingNaN)
9144     {
9145         x = D1.nan;
9146         return ExceptionFlags.invalidOperation;
9147     }
9148     
9149     if (fx == FastClass.quietNaN)
9150         return ExceptionFlags.none;
9151 
9152     if (fy == FastClass.quietNaN)
9153     {
9154         x = D1.nan;
9155         return ExceptionFlags.none;
9156     }
9157 
9158     if (fx == FastClass.infinite)
9159     {
9160         if (fy == FastClass.infinite)
9161             return ExceptionFlags.none;
9162         x = D1.nan;
9163         return ExceptionFlags.invalidOperation;
9164     }
9165 
9166     if (fy == FastClass.infinite)
9167     {
9168         x = D1.nan;
9169         return ExceptionFlags.invalidOperation;
9170     }
9171     
9172     auto flags = coefficientAdjust(cx, ex, ey, ey, cvt!U(D1.COEF_MAX), sx, mode);
9173     if (flags & ExceptionFlags.overflow)
9174         flags = ExceptionFlags.invalidOperation;
9175     return x.adjustedPack(cx, ex, sx, precision, mode, flags);
9176        
9177 }
9178 
9179 @safe pure nothrow @nogc
9180 ExceptionFlags decimalScale(D)(ref D x, const int n, const int precision, const RoundingMode mode)
9181 if (isDecimal!D)
9182 {
9183     DataType!D cx; int ex; bool sx;
9184     final switch(fastDecode(x, cx, ex, sx))
9185     {
9186         case FastClass.finite:
9187             if (!n)
9188                 return ExceptionFlags.none;
9189             auto remainder = cappedAdd(ex, n) - n;
9190             ExceptionFlags flags;
9191             if (remainder)
9192             {
9193                 if (remainder < 0)
9194                     coefficientShrink(cx, ex);
9195                 else
9196                     coefficientExpand(cx, ex);
9197                 if (cappedAdd(ex, remainder) != remainder)
9198                     flags = ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow;
9199             }                
9200             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
9201         case FastClass.zero:
9202         case FastClass.infinite:
9203         case FastClass.quietNaN:
9204             return ExceptionFlags.none;
9205         case FastClass.signalingNaN:
9206             unsignalize(x);
9207             return ExceptionFlags.invalidOperation;
9208     }   
9209 }
9210 
9211 
9212 @safe pure nothrow @nogc
9213 ExceptionFlags decimalMulPow2(D)(ref D x, const int n, const int precision, const RoundingMode mode)
9214 if (isDecimal!D)
9215 {
9216     DataType!D cx; int ex; bool sx;
9217     final switch(fastDecode(x, cx, ex, sx))
9218     {
9219         case FastClass.finite:
9220             if (!n)
9221                 return ExceptionFlags.none;
9222             DataType!D cy = 1U;
9223             int ey = n;
9224             ExceptionFlags flags;
9225             final switch(mode)
9226             {
9227                 case RoundingMode.tiesToAway:
9228                     flags = exp2to10!(RoundingMode.tiesToAway)(cy, ey, false);
9229                     break;
9230                 case RoundingMode.tiesToEven:
9231                     flags = exp2to10!(RoundingMode.tiesToEven)(cy, ey, false);
9232                     break;
9233                 case RoundingMode.towardZero:
9234                     flags = exp2to10!(RoundingMode.towardZero)(cy, ey, false);
9235                     break;
9236                 case RoundingMode.towardNegative:
9237                     flags = exp2to10!(RoundingMode.towardNegative)(cy, ey, false);
9238                     break;
9239                 case RoundingMode.towardPositive:
9240                     flags = exp2to10!(RoundingMode.towardPositive)(cy, ey, false);
9241                     break;
9242             }
9243             flags |= coefficientMul(cx, ex, sx, cy, ey, false, mode);
9244             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
9245         case FastClass.zero:
9246         case FastClass.infinite:
9247         case FastClass.quietNaN:
9248             return ExceptionFlags.none;
9249         case FastClass.signalingNaN:
9250             unsignalize(x);
9251             return ExceptionFlags.invalidOperation;
9252     }   
9253 }
9254 
9255 @safe pure nothrow @nogc
9256 ExceptionFlags decimalLog(D)(auto const ref D x, out int y)
9257 if (isDecimal!D)
9258 {
9259     DataType!D cx; int ex; bool sx;
9260     final switch(fastDecode(x, cx, ex, sx))
9261     {
9262         case FastClass.finite:
9263             y = prec(cx) + ex - 1;
9264             return ExceptionFlags.none;
9265         case FastClass.zero:
9266             y = int.min;
9267             return ExceptionFlags.invalidOperation;
9268         case FastClass.infinite:
9269             y = int.max;
9270             return ExceptionFlags.invalidOperation;
9271         case FastClass.quietNaN:
9272         case FastClass.signalingNaN:
9273             y = int.min;
9274             return ExceptionFlags.invalidOperation;  
9275     }   
9276 }
9277 
9278 @safe pure nothrow @nogc
9279 ExceptionFlags decimalMul(D1, D2)(ref D1 x, auto const ref D2 y, const int precision, const RoundingMode mode)
9280 if (isDecimal!(D1, D2))
9281 {
9282     alias D = CommonDecimal!(D1, D2);
9283     alias T = DataType!D;
9284     alias T1 = DataType!D1;
9285 
9286     T cx, cy; int ex, ey; bool sx, sy;
9287 
9288     immutable fx = fastDecode(x, cx, ex, sx);
9289     immutable fy = fastDecode(y, cy, ey, sy);
9290 
9291     if (fx == FastClass.signalingNaN || fy == FastClass.signalingNaN)
9292     {
9293         x = sx ^ sy ? -D1.nan : D1.nan;
9294         return ExceptionFlags.invalidOperation;
9295     }
9296 
9297     if (fx == FastClass.quietNaN || fy == FastClass.quietNaN)
9298     {
9299         x = sx ^ sy ? -D1.nan : D1.nan;
9300         return ExceptionFlags.none;
9301     }
9302 
9303     if (fx == FastClass.infinite)
9304     {
9305         if (fy == FastClass.zero)
9306         {
9307             x = sx ^ sy ? -D1.nan : D1.nan;
9308             return ExceptionFlags.invalidOperation;
9309         }
9310         x = sx ^ sy ? -D1.infinity : D1.infinity;
9311         return ExceptionFlags.none;
9312     }
9313 
9314     if (fy == FastClass.infinite)
9315     {
9316         if (fx == FastClass.zero)
9317         {
9318             x = sx ^ sy ? -D1.nan : D1.nan;
9319             return ExceptionFlags.invalidOperation;
9320         }
9321         x = sx ^ sy ? -D1.infinity : D1.infinity;
9322         return ExceptionFlags.none;
9323     }
9324 
9325     if (fx == FastClass.zero || fy == FastClass.zero)
9326     {
9327         x = sx ^ sy ? -D1.zero : D1.zero;
9328         return ExceptionFlags.none;
9329     }
9330 
9331     auto flags = coefficientMul(cx, ex, sx, cy, ey, sy, mode);
9332     return x.adjustedPack(cx, ex, sx, precision, mode, flags);
9333 }
9334 
9335 @safe pure nothrow @nogc
9336 ExceptionFlags decimalMul(D, T)(ref D x, auto const ref T y, const int precision, const RoundingMode mode)
9337 if (isDecimal!D && isIntegral!T)
9338 {
9339     alias U = CommonStorage!(D, T);
9340     alias X = DataType!D;
9341     U cx; int ex; bool sx;
9342     bool sy;
9343     U cy = unsign!U(y, sy);
9344     final switch(fastDecode(x, cx, ex, sx))
9345     {
9346         case FastClass.finite:
9347             if (!y)
9348             {
9349                 x = sx ^ sy ? -D.zero : D.zero;
9350                 return ExceptionFlags.none;
9351             }
9352             auto flags = coefficientMul(cx, ex, sx, cy, 0, sy, RoundingMode.implicit);
9353             flags |= coefficientAdjust(cx, ex, cvt!U(X.max), sx, RoundingMode.implicit);
9354             return x.adjustedPack(cvt!X(cx), ex, sx, precision, mode, flags);
9355         case FastClass.zero:
9356             x = sx ^ sy ? -D.zero : D.zero;
9357             return ExceptionFlags.none;
9358         case FastClass.infinite:
9359             if (!y)
9360             {
9361                 x = sx ^ sy ? -D.nan : D.nan;
9362                 return ExceptionFlags.invalidOperation;
9363             }
9364             return ExceptionFlags.none;
9365         case FastClass.quietNaN:
9366             return ExceptionFlags.none;
9367         case FastClass.signalingNaN:
9368             unsignalize(x);
9369             return ExceptionFlags.invalidOperation;
9370     }
9371 }
9372 
9373 @safe pure nothrow @nogc
9374 ExceptionFlags decimalMul(D, F)(ref D x, auto const ref F y, const int precision, const RoundingMode mode)
9375 if (isDecimal!D && isFloatingPoint!F)
9376 {
9377     alias T = CommonStorage!(D, F);
9378 
9379     T cx, cy; int ex, ey; bool sx, sy;
9380     ExceptionFlags flags;
9381     immutable fx = fastDecode(x, cx, ex, sx);
9382     immutable fy = fastDecode(y, cy, ey, sy, mode, flags);
9383 
9384     if (fx == FastClass.signalingNaN)
9385     {
9386         x = sx ^ sy ? -D.nan : D.nan;
9387         return ExceptionFlags.invalidOperation;
9388     }
9389 
9390     if (fx == FastClass.quietNaN || fy == FastClass.quietNaN)
9391     {
9392         x = sx ^ sy ? -D.nan : D.nan;
9393         return ExceptionFlags.none;
9394     }
9395 
9396     if (fx == FastClass.infinite)
9397     {
9398         if (fy == FastClass.zero)
9399         {
9400             x = sx ^ sy ? -D.nan : D.nan;
9401             return ExceptionFlags.invalidOperation;
9402         }
9403         x = sx ^ sy ? -D.infinity : D.infinity;
9404         return ExceptionFlags.none;
9405     }
9406 
9407     if (fy == FastClass.infinite)
9408     {
9409         if (fx == FastClass.zero)
9410         {
9411             x = sx ^ sy ? -D.nan : D.nan;
9412             return ExceptionFlags.invalidOperation;
9413         }
9414         x = sx ^ sy ? -D.infinity : D.infinity;
9415         return ExceptionFlags.none;
9416     }
9417 
9418     if (fx == FastClass.zero || fy == FastClass.zero)
9419     {
9420         x = sx ^ sy ? -D.zero : D.zero;
9421         return ExceptionFlags.none;
9422     }
9423     flags |= coefficientAdjust(cy, ey, realFloatPrecision!F(0), sy, mode);
9424     flags |= coefficientMul(cx, ex, sx, cy, ey, sy, mode);
9425     return x.adjustedPack(cx, ex, sx, precision, mode, flags);
9426 }
9427 
9428 @safe pure nothrow @nogc
9429 ExceptionFlags decimalMul(T, D)(auto const ref T x, auto const ref D y, out D z, const int precision, const RoundingMode mode)
9430 if (isDecimal!D && isIntegral!T)
9431 {
9432    z = y;
9433    return decimalMul(z, x, precision, mode);
9434 }
9435 
9436 @safe pure nothrow @nogc
9437 ExceptionFlags decimalMul(F, D)(auto const ref F x, auto const ref D y, out D z, const int precision, const RoundingMode mode)
9438 if (isDecimal!D && isFloatingPoint!F)
9439 {
9440     z = y;
9441     return decimalMul(z, x, precision, mode);
9442 }
9443 
9444 @safe pure nothrow @nogc
9445 ExceptionFlags decimalDiv(D1, D2)(ref D1 x, auto const ref D2 y, const int precision, const RoundingMode mode)
9446 if (isDecimal!(D1, D2))
9447 {
9448     alias D = CommonDecimal!(D1, D2);
9449     alias T = DataType!D;
9450     alias T1 = DataType!D1;
9451 
9452     T cx, cy; int ex, ey; bool sx, sy;
9453 
9454     immutable fx = fastDecode(x, cx, ex, sx);
9455     immutable fy = fastDecode(y, cy, ey, sy);
9456 
9457     if (fx == FastClass.signalingNaN || fy == FastClass.signalingNaN)
9458     {
9459         x = sx ^ sy ? -D1.nan : D1.nan;
9460         return ExceptionFlags.invalidOperation;
9461     }
9462 
9463     if (fx == FastClass.quietNaN || fy == FastClass.quietNaN)
9464     {
9465         x = sx ^ sy ? -D1.nan : D1.nan;
9466         return ExceptionFlags.none;
9467     }
9468 
9469     if (fx == FastClass.infinite)
9470     {
9471         if (fy == FastClass.infinite)
9472         {
9473             x = sx ^ sy ? -D1.nan : D1.nan;
9474             return ExceptionFlags.invalidOperation;
9475         }
9476         x = sx ^ sy ? -D1.infinity : D1.infinity;
9477         return ExceptionFlags.none;
9478     }
9479 
9480     
9481 
9482     if (fx == FastClass.zero)
9483     {
9484         if (fy == FastClass.zero)
9485         {
9486             x = sx ^ sy ? -D1.nan : D1.nan;
9487             return ExceptionFlags.invalidOperation;
9488         }
9489 
9490         x = sx ^ sy ? -D1.zero : D1.zero;
9491         return ExceptionFlags.none;
9492     }
9493 
9494     if (fy == FastClass.infinite)
9495     {
9496         x = sx ^ sy ? -D1.zero : D1.zero;
9497         return ExceptionFlags.none;
9498     }
9499 
9500     if (fy == FastClass.zero)
9501     {
9502         x = sx ^ sy ? -D1.infinity : D1.infinity;
9503         return ExceptionFlags.divisionByZero;
9504     }
9505  
9506     auto flags = coefficientDiv(cx, ex, sx, cy, ey, sy, RoundingMode.implicit);
9507     flags |= coefficientAdjust(cx, ex, cvt!T(T1.max), sx, RoundingMode.implicit);
9508     return x.adjustedPack(cvt!T1(cx), ex, sx, precision, mode, flags);
9509 }
9510 
9511 @safe pure nothrow @nogc
9512 ExceptionFlags decimalDiv(D, T)(ref D x, auto const ref T y, const int precision, const RoundingMode mode)
9513 if (isDecimal!D && isIntegral!T)
9514 {
9515     alias U = CommonStorage!(D, T);
9516     U cx; int ex; bool sx;
9517     bool sy;
9518     U cy = unsign!U(y, sy);
9519     final switch (fastDecode(x, cx, ex, sx))
9520     {
9521         case FastClass.finite:
9522             if (!y)
9523             {
9524                 x = sx ^ sy ? -D.infinity : D.infinity;
9525                 return ExceptionFlags.divisionByZero;
9526             }
9527             auto flags = coefficientDiv(cx, ex, sx, cy, 0, sy, mode);
9528             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
9529         case FastClass.zero:
9530             x = sx ^ sy ? -D.zero : D.zero;
9531             return ExceptionFlags.none;
9532         case FastClass.infinite:
9533             if (!y)
9534             {
9535                 x = sx ^ sy ? -D.nan : D.nan;
9536                 return ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero;
9537             }
9538             return ExceptionFlags.none;
9539         case FastClass.quietNaN:
9540             return ExceptionFlags.none;
9541         case FastClass.signalingNaN:
9542             unsignalize(x);
9543             return ExceptionFlags.invalidOperation;
9544     }
9545 }
9546 
9547 @safe pure nothrow @nogc
9548 ExceptionFlags decimalDiv(T, D)(auto const ref T x, auto const ref D y, out D z, const int precision, const RoundingMode mode)
9549 if (isDecimal!D && isIntegral!T)
9550 {
9551     alias U = CommonStorage!(D, T);
9552     U cy; int ey; bool sy;
9553     int ex = 0;
9554     bool sx;
9555     U cx = unsign!U(x, sx);
9556     final switch (fastDecode(y, cy, ey, sy))
9557     {
9558         case FastClass.finite:
9559             auto flags = coefficientDiv(cx, ex, sx, cy, 0, sy, RoundingMode.implicit);
9560             flags |= coefficientAdjust(cx, ex, cvt!U(DataType!D.max), sx, RoundingMode.implicit);
9561             return z.adjustedPack(cvt!(DataType!D)(cx), ex, sx, precision, mode, flags);
9562         case FastClass.zero:
9563             z = sx ^ sy ? -D.infinity : D.infinity;
9564             return ExceptionFlags.divisionByZero;
9565         case FastClass.infinite:
9566             z = y;
9567             return ExceptionFlags.none;
9568         case FastClass.quietNaN:
9569             z = sx ^ sy ? -D.nan : D.nan;
9570             return ExceptionFlags.none;
9571         case FastClass.signalingNaN:
9572             z = sx ^ sy ? -D.nan : D.nan;
9573             return ExceptionFlags.invalidOperation;
9574     }
9575 }
9576 
9577 @safe pure nothrow @nogc
9578 ExceptionFlags decimalDiv(D, F)(ref D x, auto const ref F y, const int precision, const RoundingMode mode)
9579 if (isDecimal!D && isFloatingPoint!F)
9580 {
9581     alias T = CommonStorage!(D, F);
9582    
9583     T cx, cy; int ex, ey; bool sx, sy;
9584 
9585     ExceptionFlags flags;
9586     immutable fx = fastDecode(x, cx, ex, sx);
9587     immutable fy = fastDecode(y, cy, ey, sy, mode, flags);
9588 
9589     if (fx == FastClass.signalingNaN)
9590     {
9591         x = sx ^ sy ? -D.nan : D.nan;
9592         return ExceptionFlags.invalidOperation;
9593     }
9594 
9595     if (fx == FastClass.quietNaN || fy == FastClass.quietNaN)
9596     {
9597         x = sx ^ sy ? -D.nan : D.nan;
9598         return ExceptionFlags.none;
9599     }
9600 
9601     if (fx == FastClass.infinite)
9602     {
9603         if (fy == FastClass.zero)
9604         {
9605             x = sx ^ sy ? -D.nan : D.nan;
9606             return ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero;
9607         }
9608 
9609         if (fy == FastClass.infinite)
9610         {
9611             x = sx ^ sy ? -D.nan : D.nan;
9612             return ExceptionFlags.invalidOperation;
9613         }
9614         x = sx ^ sy ? -D.infinity : D.infinity;
9615         return ExceptionFlags.none;
9616     }
9617 
9618     if (fy == FastClass.infinite)
9619     {
9620         x = sx ^ sy ? -D.infinity : D.infinity;
9621         return ExceptionFlags.none;
9622     }
9623 
9624     if (fx == FastClass.zero)
9625     {
9626         x = sx ^ sy ? -D.zero : D.zero;
9627         return ExceptionFlags.none;
9628     }
9629 
9630     if (fy == FastClass.zero)
9631     {
9632         x = sx ^ sy ? -D.infinity : D.infinity;
9633         return ExceptionFlags.divisionByZero;
9634     }
9635 
9636     flags |= coefficientAdjust(cy, ey, realFloatPrecision!F(0), sy, mode);
9637     flags |= coefficientDiv(cx, ex, sx, cy, ey, sy, mode);
9638     return x.adjustedPack(cx, ex, sx, precision, mode, flags);
9639 }
9640 
9641 @safe pure nothrow @nogc
9642 ExceptionFlags decimalDiv(F, D)(auto const ref F x, auto const ref D y, out D z, const int precision, const RoundingMode mode)
9643 if (isDecimal!D && isFloatingPoint!F)
9644 {
9645     alias T = CommonStorage!(D, F);
9646 
9647     T cx, cy; int ex, ey; bool sx, sy;
9648     ExceptionFlags flags;
9649     immutable fx = fastDecode(x, cx, ex, sx, mode, flags);
9650     immutable fy = fastDecode(y, cy, ey, sy);
9651 
9652     if (fy == FastClass.signalingNaN)
9653     {
9654         z = sx ^ sy ? -D.nan : D.nan;
9655         return ExceptionFlags.invalidOperation;
9656     }
9657 
9658     if (fx == FastClass.quietNaN || fy == FastClass.quietNaN)
9659     {
9660         z = sx ^ sy ? -D.nan : D.nan;
9661         return ExceptionFlags.none;
9662     }
9663 
9664     if (fx == FastClass.infinite)
9665     {
9666         if (fy == FastClass.zero)
9667         {
9668             z = sx ^ sy ? -D.nan : D.nan;
9669             return ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero;
9670         }
9671 
9672         if (fy == FastClass.infinite)
9673         {
9674             z = sx ^ sy ? -D.nan : D.nan;
9675             return ExceptionFlags.invalidOperation;
9676         }
9677         z = sx ^ sy ? -D.infinity : D.infinity;
9678         return ExceptionFlags.none;
9679     }
9680 
9681     if (fy == FastClass.infinite)
9682     {
9683         z = sx ^ sy ? -D.infinity : D.infinity;
9684         return ExceptionFlags.none;
9685     }
9686 
9687     if (fx == FastClass.zero)
9688     {
9689         z = sx ^ sy ? -D.zero : D.zero;
9690         return ExceptionFlags.none;
9691     }
9692 
9693     if (fy == FastClass.zero)
9694     {
9695         z = sx ^ sy ? -D.infinity : D.infinity;
9696         return ExceptionFlags.divisionByZero;
9697     }
9698     flags |= coefficientAdjust(cx, ex, realFloatPrecision!F(0), sx, mode);
9699     flags |= coefficientDiv(cx, ex, sx, cy, ey, sy, mode);
9700     return z.adjustedPack(cx, ex, sx, precision, mode, flags);
9701 }
9702 
9703 @safe pure nothrow @nogc
9704 ExceptionFlags decimalAdd(D1, D2)(ref D1 x, auto const ref D2 y, const int precision, const RoundingMode mode)
9705 if (isDecimal!(D1, D2))
9706 {
9707     alias D = CommonDecimal!(D1, D2);
9708     alias T = DataType!D;
9709     alias T1 = DataType!D1;
9710 
9711     T cx, cy; int ex, ey; bool sx, sy;
9712 
9713     immutable fx = fastDecode(x, cx, ex, sx);
9714     immutable fy = fastDecode(y, cy, ey, sy);
9715 
9716     if (fx == FastClass.signalingNaN)
9717     {
9718         x = sx  ? -D1.nan : D1.nan;
9719         return ExceptionFlags.invalidOperation;
9720     }
9721 
9722     if (fy == FastClass.signalingNaN)
9723     {
9724         x = sy && (fx == FastClass.quietNaN ? sx : true) ? -D1.nan : D1.nan;
9725         return ExceptionFlags.invalidOperation;
9726     }
9727 
9728     if (fx == FastClass.quietNaN)
9729         return ExceptionFlags.none;
9730 
9731     if (fy == FastClass.quietNaN)
9732     {
9733         x = sy ? -D1.nan : D1.nan;
9734         return ExceptionFlags.none;
9735     }
9736 
9737     if (fx == FastClass.infinite)
9738     {
9739         if (fy == FastClass.infinite && sx != sy)
9740         {
9741             x = D1.nan;
9742             return ExceptionFlags.invalidOperation;
9743         }
9744         return ExceptionFlags.none;  
9745     }
9746 
9747     if (fy == FastClass.infinite)
9748     {
9749         x = sy ? -D1.infinity : D1.infinity;
9750         return ExceptionFlags.none;   
9751     }
9752 
9753     if (fx == FastClass.zero)
9754     {
9755         if (fy == FastClass.zero)
9756         {
9757             x = (mode == RoundingMode.towardNegative && sx != sy)  || (sx && sy) ? -D1.zero : D1.zero;
9758             return ExceptionFlags.none; 
9759         }
9760         return decimalToDecimal(y, x, precision, mode);
9761     }
9762 
9763     if (fy == FastClass.zero)
9764         return ExceptionFlags.none;
9765 
9766     ExceptionFlags flags = coefficientAdd(cx, ex, sx, cy, ey, sy, mode);
9767     flags = x.adjustedPack(cx, ex, sx, precision, mode, flags);
9768     if (isZero(x))
9769         x = (mode == RoundingMode.towardNegative && sx != sy)  || (sx && sy) ? -D1.zero : D1.zero;
9770     return flags;
9771 }
9772 
9773 @safe pure nothrow @nogc
9774 ExceptionFlags decimalAdd(D, T)(ref D x, auto const ref T y, const int precision, const RoundingMode mode)
9775 if (isDecimal!D && isIntegral!T)
9776 {
9777     alias U = CommonStorage!(D, T);
9778     alias X = DataType!D;
9779     U cx; int ex; bool sx; 
9780     final switch(fastDecode(x, cx, ex, sx))
9781     {
9782         case FastClass.finite:
9783             if (!y)
9784                 return ExceptionFlags.none;
9785             bool sy;
9786             U cy = unsign!U(y, sy);
9787             auto flags = coefficientAdd(cx, ex, sx, cy, 0, sy, RoundingMode.implicit);
9788             flags |= coefficientAdjust(cx, ex, cvt!U(X.max), sx, RoundingMode.implicit);
9789             return x.adjustedPack(cvt!X(cx), ex, sx, precision, mode, flags);
9790         case FastClass.zero:
9791             return x.packIntegral(y, precision, mode);
9792         case FastClass.infinite:
9793         case FastClass.quietNaN:
9794             return ExceptionFlags.none;
9795         case FastClass.signalingNaN:
9796             unsignalize(x);
9797             return ExceptionFlags.invalidOperation;
9798     }
9799 }
9800 
9801 int realFloatPrecision(F)(const int precision)
9802 {
9803     static if (is(F == float))
9804         return precision == 0 ? 9 : (precision > 9 ? 9 : precision);
9805     else static if (is(F == float))
9806         return precision == 0 ? 17 : (precision > 17 ? 17 : precision);
9807     else
9808         return precision == 0 ? 21 : (precision > 21 ? 21 : precision);
9809 }
9810 
9811 @safe pure nothrow @nogc
9812 ExceptionFlags decimalAdd(D, F)(ref D x, auto const ref F y, const int precision, const RoundingMode mode)
9813 if (isDecimal!D && isFloatingPoint!F)
9814 {
9815     alias T = CommonStorage!(D, F);
9816     alias X = DataType!D;
9817 
9818     T cx, cy; int ex, ey; bool sx, sy;
9819     ExceptionFlags flags;
9820     immutable fx = fastDecode(x, cx, ex, sx);
9821     immutable fy = fastDecode(y, cy, ey, sy, mode, flags);
9822 
9823     if (fx == FastClass.signalingNaN)
9824     {
9825         x = sy ? -D.nan : D.nan;
9826         return ExceptionFlags.invalidOperation;
9827     }
9828 
9829     if (fx == FastClass.quietNaN)
9830         return ExceptionFlags.none;
9831 
9832     if (fy == FastClass.quietNaN)
9833     {
9834         x = sy ? -D.nan : D.nan;
9835         return ExceptionFlags.invalidOperation;
9836     }
9837 
9838     if (fx == FastClass.infinite)
9839     {
9840         if (fy == FastClass.infinite && sx != sy)
9841         {
9842             x = sx ? -D.nan : D.nan;
9843             return ExceptionFlags.invalidOperation;
9844         }
9845         return ExceptionFlags.none;  
9846     }
9847 
9848     if (fy == FastClass.infinite)
9849     {
9850         x = sy ? -D.infinity : D.infinity;
9851         return ExceptionFlags.none;   
9852     }
9853 
9854     if (fx == FastClass.zero)
9855         return x.adjustedPack(cy, ey, sy, realFloatPrecision!F(precision), mode, flags);
9856 
9857     if (fy == FastClass.zero)
9858         return x.adjustedPack(cx, ex, sx, precision, mode, flags);
9859 
9860     flags |= coefficientAdjust(cy, ey, realFloatPrecision!F(0), sy, mode);
9861     flags |= coefficientAdd(cx, ex, sx, cy, ey, sy, mode);
9862     return x.adjustedPack(cx, ex, sx, precision, mode, flags);
9863 }
9864 
9865 @safe pure nothrow @nogc
9866 ExceptionFlags decimalAdd(T, D)(auto const ref T x, auto const ref D y, out D z, const int precision, const RoundingMode mode)
9867 if (isDecimal!D && isIntegral!T)
9868 {
9869     z = y;
9870     return decimalAdd(z, x, precision, mode);
9871 }
9872 
9873 @safe pure nothrow @nogc
9874 ExceptionFlags decimalAdd(F, D)(auto const ref F x, auto const ref D y, out D z, const int precision, const RoundingMode mode)
9875 if (isDecimal!D && isFloatingPoint!F)
9876 {
9877     z = y;
9878     return decimalAdd(z, x, precision, mode);
9879 }
9880 
9881 @safe pure nothrow @nogc
9882 ExceptionFlags decimalSub(D1, D2)(ref D1 x, auto const ref D2 y, const int precision, const RoundingMode mode)
9883 if (isDecimal!(D1, D2))
9884 {
9885    return decimalAdd(x, -y, precision, mode);
9886 }
9887 
9888 @safe pure nothrow @nogc
9889 ExceptionFlags decimalSub(D, T)(ref D x, auto const ref T y, const int precision, const RoundingMode mode)
9890 if (isDecimal!D && isIntegral!T)
9891 {
9892     alias U = CommonStorage!(D, T);
9893     alias X = DataType!D;
9894     U cx; int ex; bool sx;
9895     final switch(fastDecode(x, cx, ex, sx))
9896     {
9897         case FastClass.finite:
9898             if (!y)
9899                 return x.adjustedPack(cvt!X(cx), ex, sx, precision, mode, ExceptionFlags.none);
9900             bool sy;
9901             U cy = unsign!U(y, sy);
9902             auto flags = coefficientAdd(cx, ex, sx, cy, 0, !sy, RoundingMode.implicit);
9903             flags |= coefficientAdjust(cx, ex, cvt!U(X.max), sx, RoundingMode.implicit);
9904             return x.adjustedPack(cvt!X(cx), ex, sx, precision, mode, flags);
9905         case FastClass.zero:
9906             auto flags = x.packIntegral(y, precision, mode);
9907             x = -x;
9908             return flags;
9909         case FastClass.infinite:
9910         case FastClass.quietNaN:
9911             return ExceptionFlags.none;
9912         case FastClass.signalingNaN:
9913             unsignalize(x);
9914             return ExceptionFlags.invalidOperation;
9915     }
9916 }
9917 
9918 @safe pure nothrow @nogc
9919 ExceptionFlags decimalSub(D, F)(ref D x, auto const ref F y, const int precision, const RoundingMode mode)
9920 if (isDecimal!D && isFloatingPoint!F)
9921 {
9922     return decimalAdd(x, -y, precision, mode);
9923 }
9924 
9925 @safe pure nothrow @nogc
9926 ExceptionFlags decimalSub(T, D)(auto const ref T x, auto const ref D y, out D z, const int precision, const RoundingMode mode)
9927 if (isDecimal!D && isIntegral!T)
9928 {
9929     z = -y;
9930     return decimalAdd(z, x, precision, mode);
9931 }
9932 
9933 @safe pure nothrow @nogc
9934 ExceptionFlags decimalSub(F, D)(auto const ref F x, auto const ref D y, out D z, const int precision, const RoundingMode mode)
9935 if (isDecimal!D && isFloatingPoint!F)
9936 {
9937     z = -y;
9938     return decimalAdd(z, x, precision, mode);
9939 }
9940 
9941 @safe pure nothrow @nogc
9942 ExceptionFlags decimalMod(D1, D2)(ref D1 x, auto const ref D2 y, const int precision, const RoundingMode mode)
9943 if (isDecimal!(D1, D2))
9944 {
9945 
9946     alias D = CommonDecimal!(D1, D2);
9947     alias T = DataType!D;
9948     alias T1 = DataType!D1;
9949 
9950     T cx, cy; int ex, ey; bool sx, sy;
9951 
9952     immutable fx = fastDecode(x, cx, ex, sx);
9953     immutable fy = fastDecode(y, cy, ey, sy);
9954     immutable sxx = sx;
9955 
9956     if (fx == FastClass.signalingNaN)
9957     {
9958         unsignalize(x);
9959         return ExceptionFlags.invalidOperation;
9960     }
9961 
9962     if (fy == FastClass.signalingNaN)
9963     {
9964         x = sy ? -D1.nan : D1.nan;
9965         return ExceptionFlags.invalidOperation;
9966     }
9967     
9968     if (fx == FastClass.quietNaN)
9969         return ExceptionFlags.none;
9970 
9971     if (fy == FastClass.quietNaN)
9972     {
9973         x = sy ? -D1.nan : D1.nan;
9974         return ExceptionFlags.none;
9975     }
9976 
9977     if (fx == FastClass.infinite)
9978     {
9979         x = sx ? -D1.nan : D1.nan;
9980         return ExceptionFlags.invalidOperation;
9981     }
9982 
9983     if (fy == FastClass.zero)
9984     {
9985         x = sx ? -D1.nan : D1.nan;
9986         return ExceptionFlags.invalidOperation;
9987     }
9988 
9989     if (fx == FastClass.zero)
9990         return ExceptionFlags.none;
9991 
9992     
9993 
9994     if (fy == FastClass.infinite)
9995         return ExceptionFlags.none;
9996 
9997     ////coefficientShrink(cx, ex);
9998     //coefficientShrink(cy, ey);
9999     //
10000     //if (cy == 1U && ey == 0)
10001     //{
10002     //    //if (cx == 1U && ex == 0)
10003     //        x = sx ? -D1.zero : D1.zero;
10004     //    return ExceptionFlags.none;
10005     //}
10006     
10007     
10008      
10009     ExceptionFlags flags = coefficientMod(cx, ex, sx, cy, ey, sy, mode);
10010     flags = x.adjustedPack(cx, ex, sx, precision, mode, flags);
10011 
10012     if (isZero(x))
10013         x = sxx ? -D1.zero : D1.zero; 
10014     return flags;
10015 }
10016 
10017 @safe pure nothrow @nogc
10018 ExceptionFlags decimalMod(D, T)(ref D x, auto const ref T y, const int precision, const RoundingMode mode)
10019 if (isDecimal!D && isIntegral!T)
10020 {
10021     alias U = CommonStorage!(D, T);
10022     alias X = DataType!D;
10023 
10024     U cx; int ex; bool sx;
10025     bool sy;
10026     U cy = unsign!U(y, sy);
10027 
10028     if (!y)
10029     {
10030         x = sx ^ sy ? -D.nan : D.nan;
10031         return ExceptionFlags.invalidOperation;
10032     }
10033 
10034     final switch (fastDecode(x, cx, ex, sx))
10035     {
10036         case FastClass.finite:
10037             auto flags = coefficientMod(cx, ex, sx, cy, 0, sy, mode);
10038             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
10039         case FastClass.zero:
10040             return ExceptionFlags.none;
10041         case FastClass.infinite:
10042             x = sx ? -D.nan : D.nan;
10043             return ExceptionFlags.invalidOperation;
10044         case FastClass.quietNaN:
10045             return ExceptionFlags.none;
10046         case FastClass.signalingNaN:
10047             unsignalize(x);
10048             return ExceptionFlags.invalidOperation;
10049     }
10050 }
10051 
10052 @safe pure nothrow @nogc
10053 ExceptionFlags decimalMod(T, D)(auto const ref T x, auto const ref D y, out D z, const int precision, const RoundingMode mode)
10054 if (isDecimal!D && isIntegral!T)
10055 {
10056 
10057     alias U = CommonStorage!(D, T);
10058     alias X = DataType!D;
10059     U cy; int ey; bool sy;
10060     int ex = 0;
10061     bool sx;
10062     U cx = unsign!U(x, sx);
10063     final switch (fastDecode(y, cy, ey, sy))
10064     {
10065         case FastClass.finite:
10066             if (x == 0)
10067             {
10068                 z = D.zero;
10069                 return ExceptionFlags.none;
10070             }
10071             auto flags = coefficientMod(cx, ex, sx, cy, 0, sy, mode);
10072             flags |= coefficientAdjust(cx, ex, cvt!U(X.max), sx, RoundingMode.implicit);
10073             return z.adjustedPack(cvt!X(cx), ex, sx, precision, mode, flags);
10074         case FastClass.zero:
10075             z = sy ? -D.nan : D.nan;
10076             return ExceptionFlags.invalidOperation;
10077         case FastClass.infinite:
10078             return z.packIntegral(x, precision, mode);
10079         case FastClass.quietNaN:
10080             z = sy ? -D.nan : D.nan;
10081             return ExceptionFlags.none;
10082         case FastClass.signalingNaN:
10083             z = sy ? -D.nan : D.nan;
10084             return ExceptionFlags.invalidOperation;
10085     }
10086 
10087 }
10088 
10089 @safe pure nothrow @nogc
10090 ExceptionFlags decimalMod(D, F)(ref D x, auto const ref F y, const int precision, const RoundingMode mode)
10091 if (isDecimal!D && isFloatingPoint!F)
10092 {
10093     alias T = CommonStorage!(D, F);
10094 
10095     T cx, cy; int ex, ey; bool sx, sy;
10096     ExceptionFlags flags;
10097     immutable fx = fastDecode(x, cx, ex, sx);
10098     immutable fy = fastDecode(y, cy, ey, sy, mode, flags);
10099 
10100     if (fx == FastClass.signalingNaN)
10101     {
10102         unsignalize(x);
10103         return ExceptionFlags.invalidOperation;
10104     }
10105 
10106     if (fx == FastClass.quietNaN)
10107         return ExceptionFlags.none;
10108 
10109     if (fy == FastClass.quietNaN)
10110     {
10111         x = sy ? -D.nan : D.nan;
10112         return ExceptionFlags.none;
10113     }
10114 
10115     if (fx == FastClass.infinite || fy == FastClass.zero)
10116     {
10117         x = sx ? -D.nan : D.nan;
10118         return ExceptionFlags.invalidOperation;
10119     }
10120 
10121     if (fx == FastClass.zero)
10122         return ExceptionFlags.none;
10123 
10124     if (fy == FastClass.infinite)
10125         return ExceptionFlags.none;
10126 
10127     flags |= coefficientAdjust(cy, ey, realFloatPrecision!F(0), sy, mode);
10128     flags |= coefficientMod(cx, ex, sx, cy, ey, sy, mode);
10129     return x.adjustedPack(cx, ex, sx, precision, mode, flags);
10130 }
10131 
10132 @safe pure nothrow @nogc
10133 ExceptionFlags decimalMod(F, D)(auto const ref F x, auto const ref D y, out D z, const int precision, const RoundingMode mode)
10134 if (isDecimal!D && isFloatingPoint!F)
10135 {
10136     alias T = CommonStorage!(D, F);
10137     alias X = DataType!D;
10138 
10139     T cx, cy; int ex, ey; bool sx, sy;
10140     ExceptionFlags flags;
10141     immutable fx = fastDecode(x, cx, ex, sx, mode, flags);
10142     immutable fy = fastDecode(y, cy, ey, sy);
10143 
10144     if (fy == FastClass.signalingNaN)
10145     {
10146         z = sy ? -D.nan : D.nan;
10147         return ExceptionFlags.invalidOperation;
10148     }
10149 
10150     if (fx == FastClass.quietNaN)
10151     {
10152         z = sx ? -D.nan : D.nan;
10153         return ExceptionFlags.none;
10154     }
10155 
10156     if (fy == FastClass.quietNaN)
10157     {
10158         z = sy ? -D.nan : D.nan;
10159         return ExceptionFlags.none;
10160     }
10161 
10162     if (fx == FastClass.infinite || fy == FastClass.zero)
10163     {
10164         z = sx ? -D.nan : D.nan;
10165         return ExceptionFlags.invalidOperation;
10166     }
10167 
10168     if (fy == FastClass.infinite)
10169         return ExceptionFlags.none;
10170 
10171     flags |= coefficientAdjust(cx, ex, realFloatPrecision!F(0), sx, mode);
10172     flags |= coefficientMod(cx, ex, sx, cy, ey, sy, mode);
10173     return z.adjustedPack(cx, ex, sx, precision, mode, flags);
10174 
10175 }
10176 
10177 @safe pure nothrow @nogc
10178 int decimalCmp(D1, D2)(auto const ref D1 x, auto const ref D2 y)
10179 if (isDecimal!(D1, D2))
10180 {
10181     //-3 signan
10182     //-2 nan
10183     alias D = CommonDecimal!(D1, D2);
10184     DataType!D cx, cy; int ex, ey; bool sx, sy;
10185     immutable fx = fastDecode(x, cx, ex, sx);
10186     immutable fy = fastDecode(y, cy, ey, sy);
10187     final switch(fx) 
10188     {
10189         case FastClass.finite:
10190             if (fy == FastClass.finite)
10191                 return coefficientCmp(cx, ex, sx, cy, ey, sy);
10192             if (fy == FastClass.zero)
10193                 return sx ? -1: 1;
10194             if (fy == FastClass.infinite)
10195                 return sy ? 1 : -1;
10196             return fy == FastClass.signalingNaN ? -3 : -2;
10197         case FastClass.zero:
10198             if (fy == FastClass.finite || fy == FastClass.infinite)
10199                 return sy ? 1 : -1;
10200             if (fy == FastClass.zero)
10201                 return 0;
10202             return fy == FastClass.signalingNaN ? -3 : -2;
10203         case FastClass.infinite:
10204             if (fy == FastClass.finite || fy == FastClass.zero)
10205                 return sx ? -1 : 1;
10206             if (fy == FastClass.infinite)
10207                 return sx == sy ? 0 : (sx ? -1 : 1);
10208             return fy == FastClass.signalingNaN ? -3 : -2;
10209         case FastClass.quietNaN:
10210             return fy == FastClass.signalingNaN ? -3 : -2;
10211         case FastClass.signalingNaN:
10212             return -3;
10213 
10214     }
10215 }
10216 
10217 @safe pure nothrow @nogc
10218 int decimalCmp(D, T)(auto const ref D x, auto const ref T y)
10219 if (isDecimal!D && isIntegral!T)
10220 {
10221     alias U = CommonStorage!(D, T);
10222     U cx; int ex; bool sx;
10223     final switch(fastDecode(x, cx, ex, sx))
10224     {
10225         case FastClass.finite:
10226             bool sy;
10227             U cy = unsign!U(y, sy);   
10228             return coefficientCmp(cx, ex, sx, cy, 0, sy);
10229         case FastClass.zero:
10230             static if (isUnsigned!T)
10231                 return y == 0 ? 0 : -1;
10232             else
10233                 return y == 0 ? 0 : (y < 0 ? 1 : -1);
10234         case FastClass.infinite:
10235             return sx ? -1 : 1;
10236         case FastClass.quietNaN:
10237         case FastClass.signalingNaN:
10238             return -2;
10239     }
10240 }
10241 
10242 @safe pure nothrow @nogc
10243 int decimalCmp(D, F)(auto const ref D x, auto const  ref F y)
10244 if (isDecimal!D && isFloatingPoint!F)
10245 {
10246     if (isSignaling(x))
10247         return -3;
10248     if (isNaN(x) || isNaN(y))
10249         return -2;
10250 
10251     bool sx = cast(bool)signbit(x);
10252     bool sy = cast(bool)signbit(y);
10253 
10254     if (isZero(x))
10255     {
10256         if (y == 0.0)
10257             return 0;
10258         return sy ? 1 : -1;
10259     }
10260 
10261     if (y == 0.0)
10262         return sx ? -1 : 1;
10263 
10264     if (sx != sy)
10265         return sx ? -1 : 1;
10266 
10267     if (isInfinity(x))
10268     {
10269         if (isInfinity(y))
10270             return 0;
10271         return sx ? -1 : 1;
10272     }
10273 
10274     if (isInfinity(y))
10275         return sx ? 1 : -1;
10276 
10277     Unqual!D v = void;
10278 
10279     auto flags = v.packFloatingPoint(y, 0, RoundingMode.towardZero);
10280 
10281     if (flags & ExceptionFlags.overflow)
10282     {
10283         //floating point is too big
10284         return sx ? 1 : -1;
10285     }
10286     else if (flags & ExceptionFlags.underflow)
10287     {
10288         //floating point is too small
10289         return sx ? -1 : 1;
10290     }
10291 
10292     auto result = decimalCmp(x, v);
10293 
10294     if (result == 0 && (flags & ExceptionFlags.inexact))
10295     {
10296         //seems equal, but float was truncated toward zero, so it's smaller
10297         return sx ? -1 : 1;
10298     }
10299 
10300     return result;
10301 }
10302 
10303 @safe pure nothrow @nogc
10304 int decimalEqu(D1, D2)(auto const ref D1 x, auto const ref D2 y)
10305 if (isDecimal!(D1, D2))
10306 {
10307     alias D = CommonDecimal!(D1, D2);
10308     DataType!D cx, cy; int ex, ey; bool sx, sy;
10309     immutable fx = fastDecode(x, cx, ex, sx);
10310     immutable fy = fastDecode(y, cy, ey, sy);
10311 
10312     final switch(fx) 
10313     {
10314         case FastClass.finite:
10315                 if (fy == FastClass.finite  && coefficientEqu(cx, ex, sx, cy, ey, sy))
10316                     return 1;
10317                 if (fy == FastClass.zero || fy == FastClass.infinite)
10318                     return 0;
10319                 return fy == FastClass.signalingNaN ? -3 : -2;
10320         case FastClass.zero:
10321             if (fy == FastClass.zero)
10322                 return 1;
10323             if (fy == FastClass.finite || fy == FastClass.infinite)
10324                 return 0;
10325             return fy == FastClass.signalingNaN ? -3 : -2;
10326         case FastClass.infinite:
10327             if (fy == FastClass.infinite)
10328                 return sx == sy ? 1 : 0;
10329             if (fy == FastClass.finite || fy == FastClass.zero)
10330                 return 0;
10331             return fy == FastClass.signalingNaN ? -3 : -2;
10332         case FastClass.quietNaN:
10333             return fy == FastClass.signalingNaN ? -3 : -2;
10334         case FastClass.signalingNaN:
10335             return -3;
10336     }
10337 }
10338 
10339 @safe pure nothrow @nogc
10340 int decimalEqu(D, T)(auto const ref D x, auto const ref T y)
10341 if (isDecimal!D && isIntegral!T)
10342 {
10343     alias U = CommonStorage!(D, T);
10344     U cx; int ex; bool sx;
10345     final switch(fastDecode(x, cx, ex, sx))
10346     {
10347         case FastClass.finite:
10348             bool sy;
10349             U cy = unsign!U(y, sy);   
10350             return coefficientEqu(cx, ex, sx, cy, 0, sy) ? 1 : 0;
10351         case FastClass.zero:
10352             return y == 0 ? 1 : 0;
10353         case FastClass.infinite:
10354             return 0;
10355         case FastClass.quietNaN:
10356             return -2;
10357         case FastClass.signalingNaN:
10358             return -3;
10359     }
10360     return ExceptionFlags.none;
10361 }
10362 
10363 @safe pure nothrow @nogc
10364 int decimalEqu(D, F)(auto const ref D x, auto const ref F y)
10365 if (isDecimal!D && isFloatingPoint!F)
10366 {
10367     if (isSignaling(x))
10368         return -3;
10369     if (isNaN(x) || isNaN(y))
10370         return -2;
10371     if (isZero(x))
10372         return y == 0.0 ? 1 : 0;
10373     if (y == 0.0)
10374         return 0;
10375 
10376     bool sx = cast(bool)signbit(x);
10377     bool sy = cast(bool)signbit(y);
10378 
10379     if (sx != sy)
10380         return 0;
10381     if (isInfinity(x))
10382         return isInfinity(y) ? 1 : 0;
10383     if (isInfinity(y))
10384         return 0;
10385     Unqual!D v = void;
10386     auto flags = v.packFloatingPoint(y, D.PRECISION, RoundingMode.towardZero);
10387     if (flags)
10388         return 0;
10389     else
10390         return decimalEqu(x, v);
10391 
10392 }
10393 
10394 @safe pure nothrow @nogc
10395 ExceptionFlags decimalSqrt(D)(ref D x, const int precision, const RoundingMode mode)
10396 if (isDecimal!D)
10397 {
10398     DataType!D cx; int ex; bool sx;
10399     final switch(fastDecode(x, cx, ex, sx))
10400     {
10401         case FastClass.finite:
10402             if (sx)
10403             {
10404                 x = -D.nan;
10405                 return ExceptionFlags.invalidOperation;
10406             }
10407             auto flags = coefficientSqrt(cx, ex);
10408             return x.adjustedPack(cx, ex, false, precision, mode, flags);
10409         case FastClass.zero:
10410             return ExceptionFlags.none;
10411         case FastClass.infinite:
10412             if (sx)
10413             {
10414                 x = -D.nan;
10415                 return ExceptionFlags.invalidOperation;
10416             }
10417             return ExceptionFlags.none;
10418         case FastClass.quietNaN:
10419             return ExceptionFlags.none;
10420         case FastClass.signalingNaN:
10421             unsignalize(x);
10422             return ExceptionFlags.invalidOperation;
10423     }
10424 
10425  }
10426 
10427 @safe pure nothrow @nogc
10428 ExceptionFlags decimalRSqrt(D)(ref D x, const int precision, const RoundingMode mode)
10429 if (isDecimal!D)
10430 {
10431     DataType!D cx; int ex; bool sx;
10432     final switch(fastDecode(x, cx, ex, sx))
10433     {
10434         case FastClass.finite:
10435             if (sx)
10436             {
10437                 x = -D.nan;
10438                 return ExceptionFlags.invalidOperation;
10439             }
10440             auto flags = coefficientRSqrt(cx, ex);
10441             return x.adjustedPack(cx, ex, false, precision, mode, flags);
10442         case FastClass.zero:
10443             x = D.infinity;
10444             return ExceptionFlags.divisionByZero;
10445         case FastClass.infinite:
10446             if (sx)
10447             {
10448                 x = -D.nan;
10449                 return ExceptionFlags.invalidOperation;
10450             }
10451             x = D.zero;
10452             return ExceptionFlags.none;
10453         case FastClass.quietNaN:
10454             return ExceptionFlags.none;
10455         case FastClass.signalingNaN:
10456             unsignalize(x);
10457             return ExceptionFlags.invalidOperation;
10458     }
10459 }
10460 
10461 @safe pure nothrow @nogc
10462 ExceptionFlags decimalSqr(D)(ref D x, const int precision, const RoundingMode mode)
10463 if (isDecimal!D)
10464 {
10465     DataType!D cx; int ex; bool sx;
10466     final switch(fastDecode(x, cx, ex, sx))
10467     {
10468         case FastClass.finite:
10469             auto flags = coefficientSqr(cx, ex, RoundingMode.implicit);
10470             return x.adjustedPack(cx, ex, false, precision, mode, flags);
10471         case FastClass.zero:
10472             x = D.zero;
10473             return ExceptionFlags.none;
10474         case FastClass.infinite:
10475             x = D.infinity;
10476             return ExceptionFlags.none;
10477         case FastClass.quietNaN:
10478             return ExceptionFlags.none;
10479         case FastClass.signalingNaN:
10480             unsignalize(x);
10481             return ExceptionFlags.invalidOperation;
10482     }
10483 }
10484 
10485 @safe pure nothrow @nogc
10486 ExceptionFlags decimalCbrt(D)(ref D x, const int precision, const RoundingMode mode)
10487 if (isDecimal!D)
10488 {
10489     DataType!D cx; int ex; bool sx;
10490     final switch(fastDecode(x, cx, ex, sx))
10491     {
10492         case FastClass.finite:
10493             auto flags = coefficientCbrt(cx, ex);
10494             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
10495         case FastClass.zero:
10496         case FastClass.infinite:
10497         case FastClass.quietNaN:
10498             return ExceptionFlags.none;
10499         case FastClass.signalingNaN:
10500             unsignalize(x);
10501             return ExceptionFlags.invalidOperation;
10502     }
10503 }
10504 
10505 @safe pure nothrow @nogc
10506 ExceptionFlags decimalHypot(D1, D2, D)(auto const ref D1 x, auto const ref D2 y, out D z,
10507                                     const int precision, const RoundingMode mode)
10508 if (isDecimal!(D1, D2) && is(D: CommonDecimal!(D1, D2)))
10509 {
10510     alias U = DataType!D;
10511 
10512     U cx, cy; int ex, ey; bool sx, sy;
10513 
10514     immutable fx = fastDecode(x, cx, ex, sx);
10515     immutable fy = fastDecode(y, cy, ey, sy);
10516 
10517     if (fx == FastClass.signalingNaN || fy == FastClass.signalingNaN)
10518     {
10519         z = D.nan;
10520         return ExceptionFlags.invalidOperation;
10521     }
10522 
10523     if (fx == FastClass.infinite || fy == FastClass.infinite)
10524     {
10525         z = D.infinity;
10526         return ExceptionFlags.none;
10527     }
10528 
10529     if (fx == FastClass.quietNaN || fy == FastClass.quietNaN)
10530     {
10531         z = D.nan;
10532         return ExceptionFlags.none;
10533     }
10534 
10535     if (fx == FastClass.zero)
10536         return z.adjustedPack(cy, cy ? ey : 0, false, precision, mode, ExceptionFlags.none);
10537 
10538     if (fy == FastClass.zero)
10539         return z.adjustedPack(cx, cx ? ex : 0, false, precision, mode, ExceptionFlags.none);
10540 
10541     auto flags = coefficientHypot(cx, ex, cy, ey);
10542     return z.adjustedPack(cx, ex, false, precision, mode, flags);
10543 }
10544 
10545 
10546 @safe pure nothrow @nogc
10547 ExceptionFlags decimalFMA(D1, D2, D3, D)(auto const ref D1 x, auto const ref D2 y, auto const ref D3 z, 
10548                                       out D result, 
10549                                       const int precision, const RoundingMode mode)
10550 if (isDecimal!(D1, D2, D3) && is(D : CommonDecimal!(D1, D2, D3))) 
10551 {
10552     alias U = DataType!D;
10553 
10554     U cx, cy, cz; int ex, ey, ez; bool sx, sy, sz;
10555 
10556     immutable fx = fastDecode(x, cx, ex, sx);
10557     immutable fy = fastDecode(y, cy, ey, sy);
10558     immutable fz = fastDecode(z, cz, ez, sz);
10559 
10560     if (fx == FastClass.signalingNaN || fy == FastClass.signalingNaN || fz == FastClass.signalingNaN)
10561     {
10562         result = D.nan;
10563         return ExceptionFlags.invalidOperation;
10564     }
10565 
10566     if (fx == FastClass.quietNaN || fy == FastClass.quietNaN || fz == FastClass.quietNaN)
10567     {
10568         result = D.nan;
10569         return ExceptionFlags.none;
10570     }
10571 
10572     if (fx == FastClass.infinite)
10573     {
10574         if (fy == FastClass.zero)
10575         {
10576             result = D.nan;
10577             return ExceptionFlags.invalidOperation;
10578         }
10579 
10580         if (fz == FastClass.infinite)
10581         {
10582             if ((sx ^ sy) != sz)
10583             {
10584                 result = D.nan;
10585                 return ExceptionFlags.invalidOperation;
10586             }
10587         }
10588         result = sx ^ sy ? -D.infinity : D.infinity;
10589         return ExceptionFlags.none;
10590     }
10591 
10592     if (fy == FastClass.infinite)
10593     {
10594         if (fx == FastClass.zero)
10595         {
10596             result = D.nan;
10597             return ExceptionFlags.invalidOperation;
10598         }
10599 
10600         if (fz == FastClass.infinite)
10601         {
10602             if ((sx ^ sy) != sz)
10603             {
10604                 result = D.nan;
10605                 return ExceptionFlags.invalidOperation;
10606             }
10607         }
10608         result = sx ^ sy ? -D.infinity : D.infinity;
10609         return ExceptionFlags.none;
10610     }
10611 
10612     if (fz == FastClass.infinite)
10613     {
10614         auto flags = coefficientMul(cx, ex, sx, cy, ey, sy, mode);
10615         if (flags & ExceptionFlags.overflow)
10616         {
10617             if (sy != sx)
10618                 return result.invalidPack(sz, U(0U));
10619             else
10620                 return result.infinityPack(sz);
10621         }
10622         return result.infinityPack(sz);
10623     }
10624 
10625     if (fx == FastClass.zero || fy == FastClass.zero)
10626         return result.adjustedPack(cz, ez, sz, precision, mode, ExceptionFlags.none);
10627 
10628     if (fz == FastClass.zero)
10629     {
10630         auto flags = coefficientMul(cx, ex, sx, cy, ey, sy, RoundingMode.implicit);
10631         return result.adjustedPack(cx, ex, sx, precision, mode, flags);
10632     }
10633 
10634     auto flags = coefficientFMA(cx, ex, sx, cy, ey, sy, cz, ez, sz, mode);
10635     return result.adjustedPack(cx, ex, sx, precision, mode, flags);
10636 }
10637 
10638 ExceptionFlags decimalPow(D, T)(ref D x, const T n, const int precision, const RoundingMode mode)
10639 if (isDecimal!D & isIntegral!T)
10640 {
10641     DataType!D cx; int ex; bool sx;
10642 
10643     final switch (fastDecode(x, cx, ex, sx))
10644     {
10645         case FastClass.finite:
10646             if (!n)
10647             {
10648                 x = D.one;
10649                 return ExceptionFlags.none;
10650             }
10651 
10652             DataType!D cv; int ev; bool sv;
10653             ExceptionFlags flags;
10654             static if (isSigned!T)
10655             {
10656                 auto m = unsign!(Unsigned!T)(n);
10657                 if (n < 0)
10658                 {
10659                     cv = 1U;
10660                     ev = 0;
10661                     sv = false;
10662                     flags = coefficientDiv(cv, ev, sv, cx, ex, sx, RoundingMode.implicit);
10663                 }
10664                 else
10665                 {
10666                     cv = cx;
10667                     ev = ex;
10668                     sv = sx;
10669                 }
10670             }
10671             else
10672             {
10673                 Unqual!T m = n;
10674                 cv = cx;
10675                 ev = ex;
10676                 sv = sx;
10677             }
10678 
10679             cx = 1U;
10680             ex = 0;
10681             sx = false;
10682 
10683             ExceptionFlags sqrFlags;
10684             while (m)
10685             {
10686                 if (m & 1)
10687                 {
10688                     flags |= sqrFlags | coefficientMul(cx, ex, sx, cv, ev, sv, RoundingMode.implicit);
10689                     sqrFlags = ExceptionFlags.none;
10690                     if (flags & (ExceptionFlags.overflow | ExceptionFlags.underflow))
10691                         break;
10692                 }
10693                 m >>>= 1;
10694                 sqrFlags |= coefficientSqr(cv, ev, RoundingMode.implicit);
10695                 sv = false;
10696             }
10697 
10698             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
10699         case FastClass.zero:
10700             if (!n)
10701                 x = D.one;
10702             else
10703             {
10704                 if (n & 1) //odd
10705                     return n < 0 ? ExceptionFlags.divisionByZero : ExceptionFlags.none;
10706                 else //even
10707                 {
10708                     if (n < 0)
10709                         return ExceptionFlags.divisionByZero;
10710                     else
10711                     {
10712                         x = D.zero;
10713                         return ExceptionFlags.none;
10714                     }
10715                 }
10716             }
10717             return ExceptionFlags.none;
10718         case FastClass.infinite:
10719             if (!n)
10720                 x = D.one;
10721             else
10722                 x = !sx || (n & 1) ? D.infinity : -D.infinity;
10723             return ExceptionFlags.none;
10724         case FastClass.quietNaN:
10725             if (!n)
10726                 x = D.one;
10727             return ExceptionFlags.none;
10728         case FastClass.signalingNaN:
10729             unsignalize(x);
10730             return ExceptionFlags.invalidOperation;
10731     }
10732 
10733  
10734 }
10735 
10736 ExceptionFlags decimalPow(D1, D2)(ref D1 x, auto const ref D2 y, const int precision, const RoundingMode mode)
10737 if (isDecimal!(D1, D2))
10738 {
10739     long ip;
10740     auto flags = decimalToSigned(y, ip, mode);
10741     if (flags == ExceptionFlags.none)
10742         return decimalPow(x, ip, precision, mode);
10743 
10744     flags = decimalLog(x, 0, mode);
10745     flags |= decimalMul(x, y, 0, mode);
10746     return flags | decimalExp(x, precision, mode);
10747 }
10748 
10749 ExceptionFlags decimalPow(D, F)(ref D x, auto const ref F y, const int precision, const RoundingMode mode)
10750 if (isDecimal!D && isFloatingPoint!F)
10751 {
10752     Unqual!D z;
10753     auto flags = z.packFloatingPoint(y, 0, mode);
10754     return flags | decimalPow(x, z, precision, mode);
10755 }
10756 
10757 ExceptionFlags decimalPow(T, D)(auto const ref T x, auto const ref D y, out D result, const int precision, const RoundingMode mode)
10758 if (isDecimal!D && isIntegral!T)
10759 {
10760     decimal128 r = x;
10761     auto flags = decimalPow(r, y, precision, mode);
10762     return flags | decimalToDecimal(r, result, precision, mode);
10763 }
10764 
10765 ExceptionFlags decimalPow(F, D)(auto const ref F x, auto const ref D y, out D result, const int precision, const RoundingMode mode)
10766 if (isDecimal!D && isFloatingPoint!F)
10767 {
10768     decimal128 r = x;
10769     auto flags = decimalPow(r, y, precision, mode);
10770     return flags | decimalToDecimal(r, result, precision, mode);
10771 }
10772 
10773 ExceptionFlags decimalExp(D)(ref D x, const int precision, const RoundingMode mode)
10774 if (isDecimal!D)
10775 {
10776     if (isSignaling(x))
10777     {
10778         x = D.nan;
10779         return ExceptionFlags.invalidOperation;
10780     }
10781 
10782     if (isZero(x))
10783     {
10784         x = D.one;
10785         return ExceptionFlags.none;
10786     }
10787 
10788     if (isNaN(x))
10789         return ExceptionFlags.none;
10790 
10791     if (isInfinity(x))
10792     {
10793         x = signbit(x) ? D.zero : D.infinity;
10794         return ExceptionFlags.none;
10795     }
10796  
10797     long n;
10798     auto flags = decimalToSigned(x, n, mode);
10799     if (flags == ExceptionFlags.none)
10800     {
10801         x = D.E;
10802         return decimalPow(x, n, precision, mode);
10803     }
10804 
10805     static if (is(D : decimal32))
10806     {
10807         enum lnmax = decimal32("+223.3507");
10808         enum lnmin = decimal32("-232.5610");
10809     }
10810     else static if (is(D: decimal64))
10811     {
10812         enum lnmax = decimal64("+886.4952608027075");
10813         enum lnmin = decimal64("-916.4288670116301");
10814     }
10815     else
10816     {
10817         enum lnmax = decimal128("+14149.38539644841072829055748903541");
10818         enum lnmin = decimal128("-14220.76553433122614449511522413063");
10819     }   
10820 
10821     if (isLess(x, lnmin))
10822     {
10823         x = D.zero;
10824         return ExceptionFlags.underflow | ExceptionFlags.inexact;
10825     }
10826 
10827     if (isGreater(x, lnmax))
10828     {
10829         x = D.infinity;
10830         return ExceptionFlags.overflow | ExceptionFlags.inexact;
10831     }
10832     
10833     DataType!D cx;
10834     int ex;
10835 
10836     bool sx = x.unpack(cx, ex);
10837     flags = coefficientExp(cx, ex, sx);
10838     return x.adjustedPack(cx, ex, sx, precision, mode, flags);
10839 }
10840 
10841 ExceptionFlags decimalLog(D)(ref D x, const int precision, const RoundingMode mode)
10842 if (isDecimal!D)
10843 {
10844     if (isSignaling(x))
10845     {
10846         x = D.nan;
10847         return ExceptionFlags.invalidOperation;
10848     }
10849 
10850     if (isNaN(x))
10851         return ExceptionFlags.none;
10852 
10853     if (signbit(x))
10854     {
10855         x = D.nan;
10856         return ExceptionFlags.invalidOperation;
10857     }
10858 
10859     if (isInfinity(x))
10860     {
10861         x = D.infinity;
10862         return ExceptionFlags.none;
10863     }
10864 
10865     if (isZero(x))
10866     {
10867         x = -D.infinity;
10868         return ExceptionFlags.divisionByZero;
10869     }
10870 
10871     DataType!D cx;
10872     int ex;
10873     bool sx = x.unpack(cx, ex);
10874     auto flags = coefficientLog(cx, ex, sx);
10875     return x.adjustedPack(cx, ex, sx, precision, mode, flags);
10876 }
10877 
10878 ExceptionFlags decimalExp10(D)(out D x, int n, const int precision, const RoundingMode mode)
10879 if (isDecimal!D)
10880 { 
10881     if (n == 0)
10882     {
10883         x = D.one;
10884         return ExceptionFlags.none;
10885     }
10886     alias T = DataType!D;
10887     return x.adjustedPack(T(1U), n, false, precision, mode, ExceptionFlags.none);
10888 }
10889 
10890 ExceptionFlags decimalExp10(D)(ref D x, const int precision, const RoundingMode mode)
10891 if (isDecimal!D)
10892 { 
10893     if (isSignaling(x))
10894     {
10895         x = D.nan;
10896         return ExceptionFlags.invalidOperation;
10897     }
10898 
10899     if (isZero(x))
10900     {
10901         x = D.one;
10902         return ExceptionFlags.none;
10903     }
10904 
10905     if (isNaN(x))
10906         return ExceptionFlags.none;
10907 
10908     if (isInfinity(x))
10909     {
10910         x = signbit(x) ? D.zero : D.infinity;
10911         return ExceptionFlags.none;
10912     }
10913    
10914     int n;
10915     auto flags = decimalToSigned(x, n, RoundingMode.implicit);
10916     if (flags == ExceptionFlags.none)
10917         return decimalExp10(x, n, precision, mode);
10918 
10919     flags = decimalMul(x, D.LN10, 0, mode);
10920     return flags | decimalExp(x, precision, mode);
10921 }
10922 
10923 ExceptionFlags decimalExp10m1(D)(ref D x, const int precision, const RoundingMode mode)
10924 if (isDecimal!D)
10925 { 
10926     if (isSignaling(x))
10927     {
10928         x = D.nan;
10929         return ExceptionFlags.invalidOperation;
10930     }
10931 
10932     if (isZero(x))
10933         return ExceptionFlags.none;
10934 
10935     if (isNaN(x))
10936         return ExceptionFlags.none;
10937 
10938     if (isInfinity(x))
10939     {
10940         x = signbit(x) ? -D.one : D.infinity;
10941         return ExceptionFlags.none;
10942     }
10943 
10944     auto flags = decimalExp10(x, 0, mode);
10945     return flags | decimalAdd(x, -1, precision, mode);
10946 }
10947 
10948 
10949 ExceptionFlags decimalExpm1(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 (isZero(x))
10959         return ExceptionFlags.none;
10960 
10961     if (isNaN(x))
10962         return ExceptionFlags.none;
10963 
10964     if (isInfinity(x))
10965     {
10966         x = signbit(x) ? -D.one : D.infinity;
10967         return ExceptionFlags.none;
10968     }
10969 
10970     auto flags = decimalExp(x, 0, mode);
10971     return flags | decimalAdd(x, -1, precision, mode);
10972 }
10973 
10974 ExceptionFlags decimalExp2(D)(ref D x, const int precision, const RoundingMode mode)
10975 if (isDecimal!D)
10976 {
10977     if (isSignaling(x))
10978     {
10979         x = D.nan;
10980         return ExceptionFlags.invalidOperation;
10981     }
10982 
10983     if (isZero(x))
10984     {
10985         x = D.one;
10986         return ExceptionFlags.none;
10987     }
10988 
10989     if (isNaN(x))
10990         return ExceptionFlags.none;
10991 
10992     if (isInfinity(x))
10993     {
10994         x = signbit(x) ? D.zero : D.infinity;
10995         return ExceptionFlags.none;
10996     }
10997 
10998     int n;
10999     auto flags = decimalToSigned(x, n, RoundingMode.implicit);
11000     if (flags == ExceptionFlags.none)
11001     {
11002         x = D.two;
11003         return decimalPow(x, n, precision, mode);
11004     }
11005 
11006     flags = decimalMul(x, D.LN2, 0, mode);
11007     return flags | decimalExp(x, precision, mode);
11008 }
11009 
11010 ExceptionFlags decimalExp2m1(D)(ref D x, const int precision, const RoundingMode mode)
11011 if (isDecimal!D)
11012 {
11013     if (isSignaling(x))
11014     {
11015         x = D.nan;
11016         return ExceptionFlags.invalidOperation;
11017     }
11018 
11019     if (isZero(x))
11020         return ExceptionFlags.none;
11021 
11022     if (isNaN(x))
11023         return ExceptionFlags.none;
11024 
11025     if (isInfinity(x))
11026     {
11027         x = signbit(x) ? -D.one : D.infinity;
11028         return ExceptionFlags.none;
11029     }
11030 
11031     auto flags = decimalExp2(x, 0, mode);
11032     return flags |= decimalAdd(x, -1, precision, mode);
11033 }
11034 
11035 ExceptionFlags decimalLog2(D)(ref D x, const int precision, const RoundingMode mode)
11036 if (isDecimal!D)
11037 {
11038     auto flags = decimalLog(x, 0, mode);
11039     return flags | decimalDiv(x, D.LN2, precision, mode);
11040 }
11041 
11042 ExceptionFlags decimalLog10(D)(ref D x, const int precision, const RoundingMode mode)
11043 if (isDecimal!D)
11044 {
11045     if (isSignaling(x))
11046     {
11047         x = D.nan;
11048         return ExceptionFlags.invalidOperation;
11049     }
11050 
11051     if (isNaN(x))
11052         return ExceptionFlags.none;
11053 
11054     if (signbit(x))
11055     {
11056         x = D.nan;
11057         return ExceptionFlags.invalidOperation;
11058     }
11059 
11060     if (isInfinity(x))
11061     {
11062         x = D.infinity;
11063         return ExceptionFlags.none;
11064     }
11065 
11066     if (isZero(x))
11067     {
11068         x = -D.infinity;
11069         return ExceptionFlags.divisionByZero;
11070     }
11071 
11072     DataType!D c;
11073     int e;
11074     x.unpack(c, e);
11075     coefficientShrink(c, e);
11076 
11077     Unqual!D y = e;
11078     auto flags = decimalMul(y, D.LN10, 0, RoundingMode.implicit);
11079     x = c;
11080     flags |= decimalLog(x, 0, mode);
11081     return flags | decimalAdd(x, y, precision, mode);
11082 }
11083 
11084 ExceptionFlags decimalLogp1(D)(ref D x, const int precision, const RoundingMode mode)
11085 if (isDecimal!D)
11086 {
11087     auto flags = decimalAdd(x, 1U, 0, mode);
11088     return flags | decimalLog(x);
11089 }
11090 
11091 ExceptionFlags decimalLog2p1(D)(ref D x, const int precision, const RoundingMode mode)
11092 if (isDecimal!D)
11093 {
11094     auto flags = decimalAdd(x, 1U, 0, mode);
11095     return flags | decimalLog2(x, precision, mode);
11096 }
11097 
11098 ExceptionFlags decimalLog10p1(D)(ref D x, const int precision, const RoundingMode mode)
11099 if (isDecimal!D)
11100 {
11101     auto flags = decimalAdd(x, 1U, 0, mode);
11102     return flags | decimalLog10(x, precision, mode);
11103 }
11104 
11105 ExceptionFlags decimalCompound(D)(ref D x, const int n, const int precision, const RoundingMode mode)
11106 if (isDecimal!D)
11107 {
11108     if (isSignaling(x))
11109     {
11110         x = D.nan;
11111         return ExceptionFlags.invalidOperation;
11112     }
11113 
11114     if (isLess(x, -D.one))
11115     {
11116         x = D.nan;
11117         return ExceptionFlags.invalidOperation;
11118     }
11119 
11120     if (n == 0)
11121     {
11122         x = D.one;
11123         return ExceptionFlags.none;
11124     }
11125 
11126     if (x == -1 && n < 0)
11127     {
11128         x = D.infinity;
11129         return ExceptionFlags.divisionByZero;
11130     }
11131 
11132     if (x == -1)
11133     {
11134         x = D.zero;
11135         return ExceptionFlags.none;
11136     }
11137 
11138     if (isNaN(x))
11139         return ExceptionFlags.none;
11140 
11141     if (isInfinity(x))
11142     {
11143         if (signbit(x))
11144             x = n & 1 ? -D.infinity : D.infinity;
11145         else
11146             x = D.infinity;
11147         return ExceptionFlags.none;
11148     }
11149     
11150     Unqual!D y = x;
11151     auto flags = decimalAdd(x, 1U, 0, mode);
11152     if ((flags & ExceptionFlags.overflow) && n < 0)
11153     {
11154         x = y;
11155         flags &= ~ExceptionFlags.overflow;
11156     }
11157 
11158     if (flags & ExceptionFlags.overflow)
11159         return flags;
11160 
11161     return flags | decimalPow(x, n, precision, mode);
11162 }
11163 
11164 ExceptionFlags decimalRoot(D, T)(ref D x, const T n, const int precision, const RoundingMode mode)
11165 if (isDecimal!D && isIntegral!T)
11166 {
11167     if (isSignaling(x))
11168     {
11169         x = D.nan;
11170         return ExceptionFlags.invalidOperation;
11171     }
11172 
11173     if (!n)
11174     {
11175         x = D.nan;
11176         return ExceptionFlags.invalidOperation;
11177     }
11178 
11179     if (n == -1)
11180     {
11181         return ExceptionFlags.overflow | ExceptionFlags.underflow;
11182     }
11183 
11184     if (isNaN(x))
11185         return ExceptionFlags.none;
11186 
11187     if (isInfinity(x))
11188     {
11189         x = !signbit(x) || (n & 1) ? D.infinity : -D.infinity;
11190     }
11191 
11192     if (isZero(x))
11193     {
11194         if (n & 1) //odd
11195         {
11196             if (n < 0)
11197             {
11198                 x = signbit(x) ? -D.infinity : D.infinity;
11199                 return ExceptionFlags.divisionByZero;
11200             }
11201             else
11202                 return ExceptionFlags.none;
11203         }
11204         else //even
11205         {
11206             if (n < 0)
11207             {
11208                 x = D.infinity;
11209                 return ExceptionFlags.divisionByZero;
11210             }
11211             else
11212             {
11213                 x = D.zero;
11214                 return ExceptionFlags.none;
11215             }
11216         }
11217     }
11218 
11219     if (n == 1)
11220         return ExceptionFlags.none;
11221     Unqual!D y = 1U;
11222     auto flags = decimalDiv(y, n, 0, mode);
11223     return flags | decimalPow(x, y, precision, mode);
11224 }
11225 
11226 ExceptionFlags decimalSin(D)(ref D x, const int precision, const RoundingMode mode)
11227 if (isDecimal!D)
11228 {
11229     DataType!D cx; int ex; bool sx;
11230     switch(fastDecode(x, cx, ex, sx))
11231     {
11232         case FastClass.signalingNaN:
11233             unsignalize(x);
11234             return ExceptionFlags.invalidOperation;
11235         case FastClass.infinite:
11236             x = sx ? -D.nan : D.nan;
11237             return ExceptionFlags.invalidOperation;
11238         case FastClass.quietNaN:
11239         case FastClass.zero:
11240             return ExceptionFlags.none;
11241         default:
11242             int quadrant;
11243             auto flags = coefficientCapAngle(cx, ex, sx, quadrant);
11244             switch (quadrant)
11245             {
11246                 case 1:
11247                     flags |= coefficientSinQ(cx, ex, sx);
11248                     break;
11249                 case 2:
11250                     flags |= coefficientCosQ(cx, ex, sx);
11251                     break;
11252                 case 3:
11253                     flags |= coefficientSinQ(cx, ex, sx);
11254                     sx = !sx;
11255                     break;
11256                 case 4:
11257                     flags |= coefficientCosQ(cx, ex, sx);
11258                     sx = !sx;
11259                     break;
11260                 default:
11261                     assert(0);
11262             }
11263             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
11264     }
11265 }
11266 
11267 ExceptionFlags decimalCos(D)(ref D x, const int precision, const RoundingMode mode)
11268 if (isDecimal!D)
11269 {
11270     DataType!D cx; int ex; bool sx;
11271     switch(fastDecode(x, cx, ex, sx))
11272     {
11273         case FastClass.signalingNaN:
11274             return ExceptionFlags.invalidOperation;
11275         case FastClass.infinite:
11276             x = sx ? -D.nan : D.nan;
11277             return ExceptionFlags.invalidOperation;
11278         case FastClass.quietNaN:
11279             return ExceptionFlags.none;
11280         case FastClass.zero:
11281             x = D.one;
11282             return ExceptionFlags.none;
11283         default:
11284             int quadrant;
11285             auto flags = coefficientCapAngle(cx, ex, sx, quadrant);
11286             switch (quadrant)
11287             {
11288                 case 1:
11289                     flags |= coefficientCosQ(cx, ex, sx);
11290                     break;
11291                 case 2:
11292                     flags |= coefficientSinQ(cx, ex, sx);
11293                     sx = !sx;
11294                     break;
11295                 case 3:
11296                     flags |= coefficientCosQ(cx, ex, sx);
11297                     sx = !sx;
11298                     break;
11299                 case 4:
11300                     flags |= coefficientSinQ(cx, ex, sx);
11301                     break;
11302                 default:
11303                     assert(0);
11304             }
11305             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
11306     }
11307 }
11308 
11309 ExceptionFlags decimalTan(D)(ref D x, const int precision, const RoundingMode mode)
11310 if (isDecimal!D)
11311 {
11312 
11313     DataType!D cx; int ex; bool sx;
11314     switch(fastDecode(x, cx, ex, sx))
11315     {
11316         case FastClass.signalingNaN:
11317             return ExceptionFlags.invalidOperation;
11318         case FastClass.infinite:
11319             x = sx ? -D.nan : D.nan;
11320             return ExceptionFlags.invalidOperation;
11321         case FastClass.quietNaN:
11322         case FastClass.zero:
11323             return ExceptionFlags.none;
11324         default:
11325             int quadrant;
11326             auto flags = coefficientCapAngle(cx, ex, sx, quadrant);
11327             DataType!D csin, ccos; int esin, ecos; bool ssin, scos;
11328             flags |= coefficientSinCosQ(cx, ex, sx, csin, esin, ssin, ccos, ecos, scos);
11329             switch (quadrant)
11330             {
11331                 case 1:
11332                     //sin/cos, -sin/-cos
11333                 case 3:
11334                     cx = csin; ex = esin; sx = ssin;
11335                     flags |= coefficientDiv(cx, ex, sx, ccos, ecos, scos, RoundingMode.implicit);
11336                     break;
11337                 case 2:
11338                     //cos/-sin
11339                     cx = ccos; ex = ecos; sx = scos;
11340                     flags |= coefficientDiv(cx, ex, sx, csin, esin, !ssin, RoundingMode.implicit);
11341                     break;
11342                 case 4://-cos/sin
11343                     cx = ccos; ex = ecos; sx = !scos;
11344                     flags |= coefficientDiv(cx, ex, sx, csin, esin, ssin, RoundingMode.implicit);
11345                     break;
11346                 default:
11347                     assert(0);
11348             }
11349             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
11350     }
11351 }
11352 
11353 ExceptionFlags decimalAtan(D)(ref D x, const int precision, const RoundingMode mode)
11354 if (isDecimal!D)
11355 {
11356     DataType!D cx; int ex; bool sx;
11357     switch (fastDecode(x, cx, ex, sx))
11358     {
11359         case FastClass.signalingNaN:
11360             return ExceptionFlags.invalidOperation;
11361         case FastClass.quietNaN:
11362         case FastClass.zero:
11363             return ExceptionFlags.none;
11364         case FastClass.infinite:
11365             x = signbit(x) ? -D.PI_2 : D.PI_2;
11366             return decimalAdjust(x, precision, mode);
11367         default:
11368             DataType!D reductions;
11369             coefficientCapAtan(cx, ex, sx, reductions);
11370             auto flags = coefficientAtan(cx, ex, sx);
11371             if (reductions)
11372             {
11373                 flags |= coefficientMul(cx, ex, sx, reductions, 0, false, RoundingMode.implicit);
11374                 flags |= coefficientMul(cx, ex, sx, DataType!D(2U), 0, false, RoundingMode.implicit);
11375             }
11376             return x.adjustedPack(cx, ex, sx, precision, mode, flags);
11377     }
11378 }
11379 
11380 ExceptionFlags decimalSinPi(D)(ref D x, const int precision, const RoundingMode mode)
11381 if (isDecimal!D)
11382 {
11383     if (isSignaling(x) || isInfinity(x))
11384     {
11385         x = D.nan;
11386         return ExceptionFlags.invalidOperation;
11387     }
11388 
11389     if (isNaN(x))
11390         return ExceptionFlags.none;
11391 
11392     decimalReduceAngle(x);
11393 
11394     auto flags = decimalMul(x, D.PI, 0, mode);
11395     return flags | decimalSin(x, precision, mode);
11396 }
11397 
11398 ExceptionFlags decimalCosPi(D)(ref D x, const int precision, const RoundingMode mode)
11399 if (isDecimal!D)
11400 {
11401     if (isSignaling(x) || isInfinity(x))
11402     {
11403         x = D.nan;
11404         return ExceptionFlags.invalidOperation;
11405     }
11406 
11407     if (isNaN(x))
11408         return ExceptionFlags.none;
11409 
11410     decimalReduceAngle(x);
11411 
11412     auto flags = decimalMul(x, D.PI, 0, mode);
11413     return flags | decimalCos(x, precision, mode);
11414 }
11415 
11416 ExceptionFlags decimalAtanPi(D)(ref D x, const int precision, const RoundingMode mode)
11417 if (isDecimal!D)
11418 {
11419 
11420     if (isSignaling(x))
11421     {
11422         x = D.nan;
11423         return ExceptionFlags.invalidOperation;
11424     }
11425 
11426     if (isNaN(x) || isZero(x))
11427         return ExceptionFlags.none;
11428 
11429     if (isInfinity(x))
11430     {
11431         x = signbit(x) ? -D.half : D.half;
11432         return ExceptionFlags.none;
11433     }
11434 
11435     bool sx = cast(bool)signbit(x);
11436     x = fabs(x);
11437 
11438     //if (decimalEqu(x, D.SQRT3))
11439     //{
11440     //    x = sx ? -D.onethird : D.onethird;
11441     //    return ExceptionFlags.none;
11442     //}
11443     //
11444     //if (decimalEqu(x, D.one))
11445     //{
11446     //    x = sx ? -D.quarter : D.quarter;
11447     //    return ExceptionFlags.none;
11448     //}
11449     //
11450     //if (decimalEqu(x, D.M_SQRT3))
11451     //{
11452     //    x = sx ? -D._1_6 : D._1_6;
11453     //    return ExceptionFlags.none;
11454     //}
11455 
11456 
11457     auto flags = decimalAtan(x, 0, mode);
11458     return flags | decimalDiv(x, D.PI, precision, mode);
11459 }
11460 
11461 ExceptionFlags decimalAtan2(D1, D2, D3)(auto const ref D1 y, auto const ref D2 x, out D3 z, 
11462                                     const int precision, const RoundingMode mode)
11463 {
11464     alias D = CommonDecimal!(D1, D2);
11465 
11466     if (isSignaling(x) || isSignaling(y))
11467     {
11468         z = D.nan;
11469         return ExceptionFlags.invalidOperation;
11470     }
11471 
11472     if (isNaN(x) || isNaN(y))
11473     {
11474         z = D.nan;
11475         return ExceptionFlags.none;
11476     }
11477     
11478     if (isZero(y))
11479     {
11480         if (signbit(x))
11481             z = signbit(y) ? -D.PI : D.PI;
11482         else
11483             z = signbit(y) ? -D.zero : D.zero;
11484         return ExceptionFlags.inexact;
11485     }
11486 
11487     if (isZero(x))
11488     {
11489         z = signbit(y) ? -D.PI_2 : D.PI_2;
11490         return ExceptionFlags.inexact;
11491     }
11492 
11493     if (isInfinity(y))
11494     {
11495         if (isInfinity(x))
11496         {
11497             if (signbit(x))
11498                 z = signbit(y) ? -D._3PI_4 : D._3PI_4;
11499             else
11500                 z = signbit(y) ? -D.PI_4 : D.PI_4;
11501         }
11502         else
11503             z = signbit(y) ? -D.PI_2 : D.PI_2;
11504         return ExceptionFlags.inexact;
11505     }
11506 
11507     if (isInfinity(x))
11508     {
11509         if (signbit(x))
11510             z = signbit(y) ? -D.PI : D.PI;
11511         else
11512             z = signbit(y) ? -D.zero : D.zero;
11513         return ExceptionFlags.inexact; 
11514     }
11515 
11516     z = y;
11517     D xx = x;
11518     auto flags = decimalDiv(z, xx, 0, mode);
11519     z = fabs(z);
11520     flags |= decimalAtan(z, 0, mode);
11521     
11522     if (signbit(x))
11523     {
11524         z = -z;
11525         return (flags | decimalAdd(z, D.PI, precision, mode)) & ExceptionFlags.inexact;
11526     }
11527     else
11528         return (flags | decimalAdjust(z, precision, mode)) & (ExceptionFlags.inexact | ExceptionFlags.underflow);
11529 }
11530 
11531 ExceptionFlags decimalAtan2Pi(D1, D2, D3)(auto const ref D1 y, auto const ref D2 x, out D3 z, const int precision, const RoundingMode mode)
11532 if (isDecimal!(D1, D2, D3))
11533 {
11534     alias D = CommonDecimal!(D1, D2);
11535 
11536     if (isSignaling(x) || isSignaling(y))
11537     {
11538         z = D.nan;
11539         return ExceptionFlags.invalidOperation;
11540     }
11541 
11542     if (isNaN(x) || isNaN(y))
11543     {
11544         z = D.nan;
11545         return ExceptionFlags.none;
11546     }
11547 
11548     if (isZero(y))
11549     {
11550         if (signbit(x))
11551             z = signbit(y) ? -D.one : D.one;
11552         else
11553             z = signbit(y) ? -D.zero : D.zero;
11554         return ExceptionFlags.inexact;
11555     }
11556 
11557     if (isZero(x))
11558     {
11559         z = signbit(y) ? -D.half : D.half;
11560         return ExceptionFlags.inexact;
11561     }
11562 
11563     if (isInfinity(y))
11564     {
11565         if (isInfinity(x))
11566         {
11567             if (signbit(x))
11568                 z = signbit(y) ? -D.threequarters : D.threequarters;
11569             else
11570                 z = signbit(y) ? -D.quarter : D.quarter;
11571         }
11572         else
11573             z = signbit(y) ? -D.half : D.half;
11574         return ExceptionFlags.inexact;
11575     }
11576 
11577     if (isInfinity(x))
11578     {
11579         if (signbit(x))
11580             z = signbit(y) ? -D.one : D.one;
11581         else
11582             z = signbit(y) ? -D.zero : D.zero;
11583         return ExceptionFlags.inexact; 
11584     }
11585     auto flags = decimalAtan2(y, x, z, 0, mode);
11586     return flags | decimalDiv(z, D.PI, precision, mode);
11587 }
11588 
11589 ExceptionFlags decimalAsin(D)(ref D x, const int precision, const RoundingMode mode)
11590 {
11591     if (isSignaling(x))
11592     {
11593         x = D.nan;
11594         return ExceptionFlags.invalidOperation;
11595     }
11596 
11597     if (isNaN(x))
11598         return ExceptionFlags.none;
11599 
11600     if (isLess(x, -D.one) || isGreater(x, D.one))
11601     {
11602         x = D.nan;
11603         return ExceptionFlags.invalidOperation;
11604     }
11605 
11606     if (isZero(x))
11607         return ExceptionFlags.none;
11608     
11609 
11610     if (x == -D.one)
11611     {
11612         x = -D.PI_2;
11613         return decimalAdjust(x, precision, mode);
11614     }
11615 
11616     if (x == D.one)
11617     {
11618         x = D.PI_2;
11619         return ExceptionFlags.none;
11620     }
11621 
11622 
11623 
11624     if (x == -D.SQRT3_2)
11625     {
11626         x = -D.PI_3;
11627         return ExceptionFlags.none;
11628     }
11629 
11630     if (x == -D.SQRT2_2)
11631     {
11632         x = -D.PI_4;
11633         return ExceptionFlags.none;
11634     }
11635 
11636     if (x == -D.half)
11637     {
11638         x  = -D.PI_6;
11639         return ExceptionFlags.none;
11640     }
11641 
11642     if (x == D.half)
11643     {
11644         x  = D.PI_6;
11645         return ExceptionFlags.none;
11646     }
11647 
11648     if (x == D.SQRT2_2)
11649     {
11650         x = D.PI_4;
11651         return ExceptionFlags.none;
11652     }
11653 
11654     if (x == D.SQRT3_2)
11655     {
11656         x = D.PI_6;
11657         return ExceptionFlags.none;
11658     }
11659 
11660     //asin(x) = 2 * atan(x / ( 1 + sqrt(1 - x* x))
11661     Unqual!D x2 = x;
11662     auto flags = decimalSqr(x2, 0, mode);
11663     x2 = -x2;
11664     flags |= decimalAdd(x2, 1U, 0, mode);
11665     flags |= decimalSqrt(x2, 0, mode);
11666     flags |= decimalAdd(x2, 1U, 0, mode);
11667     flags |= decimalDiv(x, x2, 0, mode);
11668     flags |= decimalAtan(x, 0, mode);
11669     return flags | decimalMul(x, 2U, precision, mode);
11670 }
11671 
11672 ExceptionFlags decimalAcos(D)(ref D x, const int precision, const RoundingMode mode)
11673 {
11674     if (isSignaling(x))
11675     {
11676         x = D.nan;
11677         return ExceptionFlags.invalidOperation;
11678     }
11679 
11680     if (isNaN(x))
11681         return ExceptionFlags.none;
11682 
11683     if (isLess(x, -D.one) || isGreater(x, D.one))
11684     {
11685         x = D.nan;
11686         return ExceptionFlags.invalidOperation;
11687     }
11688 
11689     if (isZero(x))
11690     {
11691         x = D.PI_2;
11692         return decimalAdjust(x, precision, mode);
11693     }
11694 
11695     if (x == -D.one)
11696     {
11697         x = D.PI;
11698         return decimalAdjust(x, precision, mode);
11699     }
11700 
11701     if (x == D.one)
11702     {
11703         x = D.zero;
11704         return ExceptionFlags.none;
11705     }
11706 
11707     
11708 
11709     if (x == -D.SQRT3_2)
11710     {
11711         x = D._5PI_6;
11712         return ExceptionFlags.none;
11713     }
11714 
11715     if (x == -D.SQRT2_2)
11716     {
11717         x = D._3PI_4;
11718         return ExceptionFlags.none;
11719     }
11720 
11721     if (x == -D.half)
11722     {
11723         x  = D._2PI_3;
11724         return ExceptionFlags.none;
11725     }
11726 
11727     if (x == D.half)
11728     {
11729         x  = D.PI_2;
11730         return ExceptionFlags.none;
11731     }
11732 
11733     if (x == D.SQRT2_2)
11734     {
11735         x = D.PI_4;
11736         return ExceptionFlags.none;
11737     }
11738 
11739     if (x == D.SQRT3_2)
11740     {
11741         x = D.PI_6;
11742         return ExceptionFlags.none;
11743     }
11744 
11745     
11746 
11747     Unqual!D x2 = x;
11748     auto flags = decimalSqr(x2, 0, mode);
11749     x2 = -x2;
11750     flags |= decimalAdd(x2, 1U, 0, mode);
11751     flags |= decimalSqrt(x2, 0, mode);
11752     flags |= decimalAdd(x, 1U, 0, mode);
11753     flags |= decimalDiv(x2, x, 0, mode);
11754     x = x2;
11755     flags |= decimalAtan(x, 0, mode);
11756     return flags | decimalMul(x, 2U, precision, mode);
11757 }
11758 
11759 ExceptionFlags decimalSinh(D)(ref D x, const int precision, const RoundingMode mode)
11760 {
11761     if (isSignaling(x))
11762     {
11763         x = D.nan;
11764         return ExceptionFlags.invalidOperation;
11765     }
11766 
11767     if (isNaN(x))
11768         return ExceptionFlags.none;
11769 
11770     if (isInfinity(x))
11771     {
11772         x = D.infinity;
11773         return ExceptionFlags.none;
11774     }
11775 
11776     if (isZero(x))
11777         return ExceptionFlags.none;
11778 
11779     Unqual!D x1 = x;
11780     Unqual!D x2 = -x;
11781 
11782     
11783     auto flags = decimalExp(x1, 0, mode);
11784     flags |= decimalExp(x2, 0, mode);
11785     flags |= decimalSub(x1, x2, 0, mode);
11786     x = x1;
11787     return flags | decimalMul(x, 2U, precision, mode);
11788 }
11789 
11790 ExceptionFlags decimalCosh(D)(ref D x, const int precision, const RoundingMode mode)
11791 {
11792     if (isSignaling(x))
11793     {
11794         x = D.nan;
11795         return ExceptionFlags.invalidOperation;
11796     }
11797 
11798     if (isNaN(x))
11799         return ExceptionFlags.none;
11800 
11801     if (isInfinity(x))
11802     {
11803         x = D.infinity;
11804         return ExceptionFlags.none;
11805     }
11806 
11807     if (isZero(x))
11808     {
11809         x = D.one;
11810         return ExceptionFlags.none;
11811     }
11812 
11813     Unqual!D x1 = x;
11814     Unqual!D x2 = -x;
11815     auto flags = decimalExp(x1, 0, mode);
11816     flags |= decimalExp(x2, 0, mode);
11817     flags |= decimalAdd(x1, x2, 0, mode);
11818     x = x1;
11819     return flags | decimalMul(x, D.half, precision, mode);
11820 }
11821 
11822 ExceptionFlags decimalTanh(D)(ref D x, const int precision, const RoundingMode mode)
11823 {
11824 
11825     if (isSignaling(x))
11826     {
11827         x = D.nan;
11828         return ExceptionFlags.invalidOperation;
11829     }
11830 
11831     if (isNaN(x))
11832         return ExceptionFlags.none;
11833 
11834     if (isInfinity(x))
11835     {
11836         x = signbit(x) ? -D.one : D.one;
11837         return ExceptionFlags.none;
11838     }
11839 
11840     if (isZero(x))
11841         return ExceptionFlags.none;
11842 
11843     Unqual!D x1 = x;
11844     Unqual!D x2 = -x;
11845     auto flags = decimalSinh(x1, 0, mode);
11846     flags |= decimalCosh(x2, 0, mode);
11847     x = x1;
11848     return flags | decimalDiv(x, x2, precision, mode);
11849 }
11850 
11851 ExceptionFlags decimalAsinh(D)(ref D x, const int precision, const RoundingMode mode)
11852 {
11853     if (isSignaling(x))
11854     {
11855         x = D.nan;
11856         return ExceptionFlags.invalidOperation;
11857     }
11858 
11859     if (isNaN(x) || isZero(x) || isInfinity(x))
11860         return ExceptionFlags.none;
11861 
11862     //+- ln(|x| + sqrt(x*x + 1))
11863     //+-[ln(2) + ln(|x|)] for very big x,
11864 
11865     //sqrt(D.max)/2
11866     static if (is(D: decimal32))
11867     {
11868         enum asinhmax = decimal32("1.581138e51");
11869     }
11870     else static if (is(D: decimal64))
11871     {
11872         enum asinhmax = decimal64("1.581138830084189e192");
11873     }
11874     else
11875     {
11876         enum asinhmax = decimal128("1.581138830084189665999446772216359e3072");
11877     }
11878 
11879     bool sx = cast(bool)signbit(x);
11880     x = fabs(x);
11881 
11882     ExceptionFlags flags;
11883     if (isGreater(x, asinhmax))
11884     {
11885         flags = decimalLog(x, 0, mode) | ExceptionFlags.inexact;
11886         flags |= decimalAdd(x, D.LN2, 0, mode);
11887         
11888     }
11889     else
11890     {
11891         Unqual!D x1 = x;
11892         flags = decimalSqr(x1, 0, mode);
11893         flags |= decimalAdd(x1, 1U, 0, mode);
11894         flags |= decimalSqrt(x1, 0, mode);
11895         flags |= decimalAdd(x, x1, 0, mode);
11896         flags |= decimalLog(x, 0, mode);
11897     }
11898 
11899     if (sx)
11900         x = -x;
11901     return flags | decimalAdjust(x, precision, mode);
11902     
11903     
11904 }
11905 
11906 ExceptionFlags decimalAcosh(D)(ref D x, const int precision, const RoundingMode mode)
11907 {
11908     if (isSignaling(x))
11909     {
11910         x = D.nan;
11911         return ExceptionFlags.invalidOperation;
11912     }
11913 
11914     if (isNaN(x))
11915         return ExceptionFlags.none;
11916 
11917     if (isLess(x, D.one))
11918     {
11919         x = D.nan;
11920         return ExceptionFlags.invalidOperation;
11921     }
11922 
11923     if (x == D.one)
11924     {
11925         x = D.zero;
11926         return ExceptionFlags.none;
11927     }
11928 
11929     if (isInfinity(x))
11930         return ExceptionFlags.none;
11931 
11932     ExceptionFlags flags;
11933 
11934     /*
11935         ln(x+sqrt(x*x - 1))
11936         for very big x: (ln(x + x) = ln(2) + ln(x), otherwise will overflow
11937     */
11938 
11939     //sqrt(D.max)/2
11940     static if (is(D: decimal32))
11941     {
11942         enum acoshmax = decimal32("1.581138e51");
11943     }
11944     else static if (is(D: decimal64))
11945     {
11946         enum acoshmax = decimal64("1.581138830084189e192");
11947     }
11948     else
11949     {
11950         enum acoshmax = decimal128("1.581138830084189665999446772216359e3072");
11951     }
11952 
11953     if (isGreater(x, acoshmax))
11954     {
11955         flags = decimalLog(x, 0, mode) | ExceptionFlags.inexact;
11956         return flags |= decimalAdd(x, D.LN2, precision, mode);
11957     }
11958     else
11959     {
11960         Unqual!D x1 = x;
11961         flags = decimalSqr(x1, 0, mode);
11962         flags |= decimalSub(x1, 1U, 0, mode);
11963         flags |= decimalSqrt(x1, 0, mode);
11964         flags |= decimalAdd(x, x1, 0, mode);
11965         return flags | decimalLog(x, precision, mode);
11966     }
11967 }
11968 
11969 ExceptionFlags decimalAtanh(D)(ref D x, const int precision, const RoundingMode mode)
11970 {
11971     if (isSignaling(x))
11972     {
11973         x = D.nan;
11974         return ExceptionFlags.invalidOperation;
11975     }
11976 
11977     if (isNaN(x) || isZero(x))
11978         return ExceptionFlags.none;
11979 
11980     alias T = DataType!D;
11981     T cx;
11982     int ex;
11983     bool sx = x.unpack(cx, ex);
11984 
11985     auto cmp = coefficientCmp(cx, ex, false, T(1U), 0, false);
11986 
11987     if (cmp > 0)
11988     {
11989         x = signbit(x) ? -D.nan : D.nan;
11990         return ExceptionFlags.none;
11991     }
11992 
11993     if (cmp == 0)
11994     {
11995         x = signbit(x) ? -D.infinity : D.infinity;
11996         return ExceptionFlags.none;
11997     }
11998     
11999     auto flags = coefficientAtanh(cx, ex, sx);
12000     return x.adjustedPack(cx, ex, sx, precision, mode, flags);
12001 
12002 }
12003 
12004 ExceptionFlags decimalSum(D)(const(D)[] x, out D result, const int precision, const RoundingMode mode)
12005 if (isDecimal!D)
12006 {
12007     ExceptionFlags flags;
12008     alias T = MakeUnsigned!(D.sizeof * 16);
12009     DataType!D cx;
12010     T cxx, cr;
12011     int ex, er;
12012     bool sx, sr;
12013 
12014     result = 0;
12015     bool hasPositiveInfinity, hasNegativeInfinity;
12016     size_t i = 0;
12017     while (i < x.length)
12018     {
12019         if (isSignaling(x[i]))
12020         {
12021             result = D.nan;
12022             return ExceptionFlags.invalidOperation;
12023         }
12024 
12025         if (isNaN(x[i]))
12026         {
12027             result = D.nan;
12028             return ExceptionFlags.none;
12029         }
12030 
12031         if (isInfinity(x[i]))
12032         {
12033             if (signbit(x[i]))
12034                 hasNegativeInfinity = true;
12035             else
12036                 hasPositiveInfinity = true;
12037             ++i;
12038             break;
12039         }
12040 
12041         if (isZero(x[i]))
12042         {
12043             ++i;
12044             continue;
12045         }
12046         
12047         sx = x.unpack(cx, ex);
12048         cxx = cx;
12049         flags |= coefficientAdd(cr, er, sr, cxx, ex, sx, mode);
12050         ++i;
12051 
12052         if (flags & ExceptionFlags.overflow)
12053             break;
12054     }
12055 
12056     while (i < x.length)
12057     {
12058         //infinity or overflow detected
12059         if (isSignaling(x[i]))
12060         {
12061             result = D.nan;
12062             return ExceptionFlags.invalidOperation;
12063         }
12064 
12065         if (isNaN(x[i]))
12066         {
12067             result = D.nan;
12068             return ExceptionFlags.none;
12069         }
12070 
12071         if (isInfinity(x[i]))
12072         {
12073             if (signbit(x[i]))
12074                 hasNegativeInfinity = true;
12075             else
12076                 hasPositiveInfinity = true;
12077         }
12078         ++i;
12079     }
12080 
12081     if (hasPositiveInfinity)
12082     {
12083         if (hasNegativeInfinity)
12084         {
12085             result = D.nan;
12086             return ExceptionFlags.invalidOperation;
12087         }
12088         result = D.infinity;
12089         return ExceptionFlags.none;
12090     }
12091 
12092     if (hasNegativeInfinity)
12093     {
12094         result = -D.infinity;
12095         return ExceptionFlags.none;
12096     }
12097 
12098     flags |= coefficientAdjust(cr, er, cvt!T(DataType!D.max), sr, mode);
12099     return result.adjustedPack(cvt!(DataType!D)(cr), er, sr, precision, mode, flags);
12100 }
12101 
12102 ExceptionFlags decimalSumSquare(D)(const(D)[] x, out D result, const int precision, const RoundingMode mode)
12103 if (isDecimal!D)
12104 {
12105     ExceptionFlags flags;
12106     alias T = MakeUnsigned!(D.sizeof * 16);
12107     DataType!D cx;
12108     T cxx, cr;
12109     int ex, er;
12110     bool sr;
12111     result = 0;
12112     bool hasInfinity;
12113     size_t i = 0;
12114     while (i < x.length)
12115     {
12116         if (isSignaling(x[i]))
12117         {
12118             result = D.nan;
12119             return ExceptionFlags.invalidOperation;
12120         }
12121 
12122         if (isNaN(x[i]))
12123         {
12124             result = D.nan;
12125             return ExceptionFlags.none;
12126         }
12127 
12128         if (isInfinity(x[i]))
12129         {
12130             hasInfinity = true;
12131             ++i;
12132             break;
12133         }
12134 
12135         if (isZero(x[i]))
12136         {
12137             ++i;
12138             continue;
12139         }
12140 
12141         x.unpack(cx, ex);
12142         cxx = cx;
12143         flags |= coefficientSqr(cxx, ex);
12144         flags |= coefficientAdd(cr, er, sr, cxx, ex, false, mode);
12145         ++i;
12146 
12147         if (flags & ExceptionFlags.overflow)
12148             break;
12149     }
12150 
12151     while (i < x.length)
12152     {
12153         //infinity or overflow detected
12154         if (isSignaling(x[i]))
12155         {
12156             result = D.nan;
12157             return ExceptionFlags.invalidOperation;
12158         }
12159 
12160         if (isNaN(x[i]))
12161         {
12162             result = D.nan;
12163             return ExceptionFlags.none;
12164         }
12165 
12166         if (isInfinity(x[i]))
12167             hasInfinity = true;
12168         ++i;
12169     }
12170 
12171     if (hasInfinity)
12172     {
12173         result = D.infinity;
12174         return ExceptionFlags.none;
12175     }
12176 
12177     flags |= coefficientAdjust(cr, er, cvt!T(DataType!D.max), sr, mode);
12178     return result.adjustedPack(cvt!(DataType!D)(cr), er, sr, precision, mode, flags);
12179 
12180 }
12181 
12182 ExceptionFlags decimalSumAbs(D)(const(D)[] x, out D result, const int precision, const RoundingMode mode)
12183 if (isDecimal!D)
12184 {
12185     ExceptionFlags flags;
12186     alias T = MakeUnsigned!(D.sizeof * 16);
12187     DataType!D cx;
12188     T cxx, cr;
12189     int ex, er;
12190     bool sr;
12191 
12192     result = 0;
12193     bool hasInfinity;
12194     size_t i = 0;
12195     while (i < x.length)
12196     {
12197         if (isSignaling(x[i]))
12198         {
12199             result = D.nan;
12200             return ExceptionFlags.invalidOperation;
12201         }
12202 
12203         if (isNaN(x[i]))
12204         {
12205             result = D.nan;
12206             return ExceptionFlags.none;
12207         }
12208 
12209         if (isInfinity(x[i]))
12210         {
12211             hasInfinity = true;
12212             ++i;
12213             break;
12214         }
12215 
12216         if (isZero(x[i]))
12217         {
12218             ++i;
12219             continue;
12220         }
12221 
12222         x.unpack(cx, ex);
12223         cxx = cx;
12224         flags |= coefficientAdd(cr, er, sr, cxx, ex, false, mode);
12225         ++i;
12226 
12227         if (flags & ExceptionFlags.overflow)
12228             break;
12229     }
12230 
12231     while (i < x.length)
12232     {
12233         //infinity or overflow detected
12234         if (isSignaling(x[i]))
12235         {
12236             result = D.nan;
12237             return ExceptionFlags.invalidOperation;
12238         }
12239 
12240         if (isNaN(x[i]))
12241         {
12242             result = D.nan;
12243             return ExceptionFlags.none;
12244         }
12245 
12246         if (isInfinity(x[i]))
12247             hasInfinity = true;
12248         ++i;
12249     }
12250 
12251 
12252 
12253     if (hasInfinity)
12254     {
12255         result = D.infinity;
12256         return ExceptionFlags.none;
12257     }
12258 
12259     flags |= coefficientAdjust(cr, er, cvt!T(DataType!D.max), sr, mode);
12260     return result.adjustedPack(cvt!(DataType!D)(cr), er, sr, precision, mode, flags);
12261 }
12262 
12263 ExceptionFlags decimalDot(D)(const(D)[] x, const(D)[] y, out D result, const int precision, const RoundingMode mode)
12264 if (isDecimal!D)
12265 {
12266     size_t len = x.length;
12267     if (len > y.length)
12268         len = y.length;
12269 
12270     bool hasPositiveInfinity, hasNegativeInfinity;
12271 
12272     alias T = MakeUnsigned!(D.sizeof * 16);
12273     DataType!D cx, cy;
12274     T cxx, cyy, cr;
12275     int ex, ey, er;
12276     bool sx, sy, sr;
12277 
12278     size_t i = 0;
12279     while (i < len)
12280     {
12281         if (isSignaling(x[i]) || isSignaling(y[i]))
12282         {
12283             result = D.nan;
12284             return ExceptionFlags.invalidOperation;
12285         }
12286 
12287         if (isNaN(x[i]) || isNaN(y[i]))
12288         {
12289             result = D.nan;
12290             return ExceptionFlags.none;
12291         }
12292 
12293         if (isInfinity(x[i]))
12294         {
12295             if (isZero(y[i]))
12296             {
12297                 result = D.nan;
12298                 return ExceptionFlags.invalidOperation;
12299             }
12300 
12301             if (isInfinity(y[i]))
12302             {
12303                 if (signbit(x[i]) ^ signbit(y[i]))
12304                     hasNegativeInfinity = true;
12305                 else
12306                     hasPositiveInfinity = true;
12307                 
12308             }
12309             else
12310             {
12311                 if (signbit(x[i]))
12312                     hasNegativeInfinity = true;
12313                 else
12314                     hasPositiveInfinity = true;
12315             }
12316             ++i;
12317             break;
12318         }
12319 
12320         if (isInfinity(y[i]))
12321         {
12322             if (isZero(x[i]))
12323             {
12324                 result = D.nan;
12325                 return ExceptionFlags.invalidOperation;
12326             }
12327 
12328           
12329             if (signbit(y[i]))
12330                 hasNegativeInfinity = true;
12331             else
12332                 hasPositiveInfinity = true;
12333             
12334             ++i;
12335             break;
12336         }
12337 
12338         if (isZero(x[i]) || isZero(y[i]))
12339         {
12340             ++i;
12341             continue;
12342         }
12343 
12344         sx = x[i].unpack(cx, ex);
12345         sy = y[i].unpack(cy, ey);
12346         cxx = cx; cyy = cy;
12347         flags |= coefficientMul(cx, ex, sx, cy, ey, sy, mode);
12348         flags |= coefficientAdd(cr, er, sr, cx, ex, sx, mode);
12349         ++i;
12350         if (flags & ExceptionFlags.overflow)
12351             break;
12352     }
12353 
12354     while (i < len)
12355     {
12356         if (isSignaling(x[i]) || isSignaling(y[i]))
12357         {
12358             result = D.nan;
12359             return ExceptionFlags.invalidOperation;
12360         }
12361 
12362         if (isNaN(x[i]) || isNaN(y[i]))
12363         {
12364             result = D.nan;
12365             return ExceptionFlags.none;
12366         }
12367 
12368         if (isInfinity(x[i]))
12369         {
12370             if (isZero(y[i]))
12371             {
12372                 result = D.nan;
12373                 return ExceptionFlags.invalidOperation;
12374             }
12375 
12376             if (isInfinity(y[i]))
12377             {
12378                 if (signbit(x[i]) ^ signbit(y[i]))
12379                     hasNegativeInfinity = true;
12380                 else
12381                     hasPositiveInfinity = true;
12382 
12383             }
12384             else
12385             {
12386                 if (signbit(x[i]))
12387                     hasNegativeInfinity = true;
12388                 else
12389                     hasPositiveInfinity = true;
12390             }
12391         }
12392 
12393         if (isInfinity(y[i]))
12394         {
12395             if (isZero(x[i]))
12396             {
12397                 result = D.nan;
12398                 return ExceptionFlags.invalidOperation;
12399             }
12400 
12401 
12402             if (signbit(y[i]))
12403                 hasNegativeInfinity = true;
12404             else
12405                 hasPositiveInfinity = true;
12406         }
12407 
12408         ++i;
12409     }
12410 
12411     if (hasPositiveInfinity)
12412     {
12413         if (hasNegativeInfinity)
12414         {
12415             result = D.nan;
12416             return ExceptionFlags.invalidOperation;
12417         }
12418         result = D.infinity;
12419         return ExceptionFlags.none;
12420     }
12421 
12422     if (hasNegativeInfinity)
12423     {
12424         result = -D.infinity;
12425         return ExceptionFlags.none;
12426     }
12427 
12428     flags |= coefficientAdjust(cr, er, cvt!T(DataType!D.max), sr, mode);
12429     return result.adjustedPack(cvt!(DataType!D)(cr), er, sr, precision, mode, flags);
12430 }
12431 
12432 ExceptionFlags decimalProd(D)(const(D)[] x, out D result, out int scale, const int precision, const RoundingMode mode)
12433 if (isDecimal!D)
12434 {
12435     ExceptionFlags flags;
12436     alias T = MakeUnsigned!(D.sizeof * 16);
12437     DataType!D cx;
12438     T cxx, cr;
12439     int ex, er;
12440     bool sx, sr;
12441 
12442     result = 0;
12443     scale = 0;
12444     bool hasInfinity;
12445     bool hasZero;
12446     bool infinitySign;
12447     bool zeroSign;
12448     size_t i = 0;
12449     while (i < x.length)
12450     {
12451         if (isSignaling(x[i]))
12452         {
12453             result = D.nan;
12454             return ExceptionFlags.invalidOperation;
12455         }
12456 
12457         if (isNaN(x[i]))
12458         {
12459             result = D.nan;
12460             return ExceptionFlags.none;
12461         }
12462 
12463         if (isInfinity(x[i]))
12464         {
12465             hasInfinity = true;
12466             infinitySign = cast(bool)(signbit(x[i]));
12467             ++i;
12468             break;
12469         }
12470 
12471         if (isZero(x[i]))
12472         {
12473             hasZero = true;
12474             zeroSign = cast(bool)(signbit(x[i]));
12475             ++i;
12476             break;
12477         }
12478 
12479         sx = x.unpack(cx, ex);
12480         cxx = cx;
12481         flags |= coefficientMul(cr, er, sr, cxx, ex, sx, mode);
12482         er -= cappedAdd(scale, er);
12483         ++i;
12484 
12485         if (flags & ExceptionFlags.overflow)
12486             break;
12487     }
12488 
12489     while (i < x.length)
12490     {
12491         //infinity or overflow detected
12492         if (isSignaling(x[i]))
12493         {
12494             result = D.nan;
12495             return ExceptionFlags.invalidOperation;
12496         }
12497 
12498         if (isNaN(x[i]))
12499         {
12500             result = D.nan;
12501             return ExceptionFlags.none;
12502         }
12503 
12504         if (isInfinity(x[i]))
12505         {
12506             hasInfinity = true;
12507             infinitySign ^= cast(bool)(signbit(x[i]));
12508         }
12509         else if (isZero(x[i]))
12510         {
12511             hasZero = true;
12512             zeroSign ^= cast(bool)(signbit(x[i]));
12513         }
12514         else
12515         {
12516             zeroSign ^= cast(bool)(signbit(x[i]));
12517         }
12518 
12519 
12520         ++i;
12521     }
12522 
12523     if (hasInfinity & hasZero)
12524     {
12525         result = D.nan;
12526         return ExceptionFlags.invalidOperation;
12527     }
12528 
12529     if (hasInfinity)
12530     {
12531         result = infinitySign ? -D.infinity : D.infinity;
12532         return ExceptionFlags.none;
12533     }
12534 
12535     if (hasZero)
12536     {
12537         result = zeroSign ? -D.zero : D.zero;
12538         return ExceptionFlags.none;
12539     }
12540 
12541     flags |= coefficientAdjust(cr, er, cvt!T(DataType!D.max), sr, mode);
12542     return result.adjustedPack(cvt!(DataType!D)(cr), er, sr, precision, mode, flags);
12543 }
12544 
12545 ExceptionFlags decimalProdSum(D)(const(D)[] x, const(D)[] y, out D result, out int scale, const int precision, const RoundingMode mode)
12546 if (isDecimal!D)
12547 {
12548     size_t len = x.length;
12549     if (len > y.length)
12550         len = y.length;
12551 
12552     bool hasInfinity;
12553     bool hasZero;
12554 
12555     bool infinitySign;
12556 
12557     bool invalidSum;
12558 
12559     alias T = MakeUnsigned!(D.sizeof * 16);
12560     DataType!D cx, cy;
12561     T cxx, cyy, cr;
12562     int ex, ey, er;
12563     bool sx, sy, sr;
12564 
12565     size_t i = 0;
12566     while (i < len)
12567     {
12568         if (isSignaling(x[i]) || isSignaling(y[i]))
12569         {
12570             result = D.nan;
12571             return ExceptionFlags.invalidOperation;
12572         }
12573 
12574         if (isNaN(x[i]) || isNaN(y[i]))
12575         {
12576             result = D.nan;
12577             return ExceptionFlags.none;
12578         }
12579 
12580         if (isInfinity(x[i]))
12581         {
12582             if (isInfinity(y[i]) && signbit(x) != signbit(y))
12583             {
12584                 invalidSum = true;
12585                 ++i;
12586                 break;
12587             }
12588 
12589             hasInfinity = true;
12590             infinitySign = cast(bool)signbit(x[i]);
12591             ++i;
12592             break;
12593         }
12594 
12595         if (isInfinity(y[i]))
12596         {
12597             hasInfinity = true;
12598             infinitySign = cast(bool)signbit(x[i]);
12599             ++i;
12600             break;
12601         }
12602 
12603         if (x[i] == -y[i])
12604         {
12605             hasZero = true;
12606             ++i;
12607             break;
12608         }
12609         sx = x[i].unpack(cx, ex);
12610         sy = y[i].unpack(cy, ey);
12611         cxx = cx; cyy = cy;
12612         flags |= coefficientAdd(cx, ex, sx, cy, ey, sy, mode);
12613         flags |= coefficientMul(cr, er, sr, cx, ex, sx, mode);
12614         er -= cappedAdd(scale, er);
12615         ++i;
12616         if (flags & ExceptionFlags.overflow)
12617             break;
12618         if (flags & ExceptionFlags.underflow)
12619             break;
12620         
12621     }
12622 
12623     while (i < len)
12624     {
12625         //inf, zero or overflow, underflow, invalidSum;
12626         if (isSignaling(x[i]) || isSignaling(y[i]))
12627         {
12628             result = D.nan;
12629             return ExceptionFlags.invalidOperation;
12630         }
12631 
12632         if (isNaN(x[i]) || isNaN(y[i]))
12633         {
12634             result = D.nan;
12635             return ExceptionFlags.none;
12636         }
12637 
12638         if (isInfinity(x[i]))
12639         {
12640             if (isInfinity(y[i]) && signbit(x) != signbit(y))
12641                 invalidSum = true;
12642             else
12643             {
12644                 hasInfinity = true;
12645                 infinitySign ^= cast(bool)signbit(x[i]);
12646             }
12647         }
12648         else if (isInfinity(y[i]))
12649         {
12650             hasInfinity = true;
12651             infinitySign ^= cast(bool)signbit(y[i]);
12652         }
12653         else if (x[i] == -y[i])
12654             hasZero = true;
12655         ++i;
12656     }
12657 
12658     if (invalidSum)
12659     {
12660         result = D.nan;
12661         return ExceptionFlags.invalidOperation;
12662     }
12663 
12664     if (hasInfinity & hasZero)
12665     {
12666         result = D.nan;
12667         return ExceptionFlags.invalidOperation;
12668     }
12669 
12670     if (hasInfinity)
12671     {
12672         result = infinitySign ? -D.infinity : D.infinity;
12673         return ExceptionFlags.none;
12674     }
12675 
12676     if (hasZero)
12677     {
12678         result = D.zero;
12679         return ExceptionFlags.none;
12680     }
12681 
12682     flags |= coefficientAdjust(cr, er, cvt!T(DataType!D.max), sr, mode);
12683     return result.adjustedPack(cvt!(DataType!D)(cr), er, sr, precision, mode, flags);
12684 }
12685 
12686 ExceptionFlags decimalProdDiff(D)(const(D)[] x, const(D)[] y, out D result, out int scale, const int precision, const RoundingMode mode)
12687 if (isDecimal!D)
12688 {
12689     size_t len = x.length;
12690     if (len > y.length)
12691         len = y.length;
12692 
12693     bool hasInfinity;
12694     bool hasZero;
12695 
12696     bool infinitySign;
12697 
12698     bool invalidSum;
12699 
12700     alias T = MakeUnsigned!(D.sizeof * 16);
12701     DataType!D cx, cy;
12702     T cxx, cyy, cr;
12703     int ex, ey, er;
12704     bool sx, sy, sr;
12705 
12706     size_t i = 0;
12707     while (i < len)
12708     {
12709         if (isSignaling(x[i]) || isSignaling(y[i]))
12710         {
12711             result = D.nan;
12712             return ExceptionFlags.invalidOperation;
12713         }
12714 
12715         if (isNaN(x[i]) || isNaN(y[i]))
12716         {
12717             result = D.nan;
12718             return ExceptionFlags.none;
12719         }
12720 
12721         if (isInfinity(x[i]))
12722         {
12723             if (isInfinity(y[i]) && signbit(x) != signbit(y))
12724             {
12725                 invalidSum = true;
12726                 ++i;
12727                 break;
12728             }
12729 
12730             hasInfinity = true;
12731             infinitySign = cast(bool)signbit(x[i]);
12732             ++i;
12733             break;
12734         }
12735 
12736         if (isInfinity(y[i]))
12737         {
12738             hasInfinity = true;
12739             infinitySign = cast(bool)signbit(x[i]);
12740             ++i;
12741             break;
12742         }
12743 
12744         if (x[i] == y[i])
12745         {
12746             hasZero = true;
12747             ++i;
12748             break;
12749         }
12750         sx = x[i].unpack(cx, ex);
12751         sy = y[i].unpack(cy, ey);
12752         cxx = cx; cyy = cy;
12753         flags |= coefficientSub(cx, ex, sx, cy, ey, sy, mode);
12754         flags |= coefficientMul(cr, er, sr, cx, ex, sx, mode);
12755         er -= cappedAdd(scale, er);
12756         ++i;
12757         if (flags & ExceptionFlags.overflow)
12758             break;
12759         if (flags & ExceptionFlags.underflow)
12760             break;
12761 
12762     }
12763 
12764     while (i < len)
12765     {
12766         //inf, zero or overflow, underflow, invalidSum;
12767         if (isSignaling(x[i]) || isSignaling(y[i]))
12768         {
12769             result = D.nan;
12770             return ExceptionFlags.invalidOperation;
12771         }
12772 
12773         if (isNaN(x[i]) || isNaN(y[i]))
12774         {
12775             result = D.nan;
12776             return ExceptionFlags.none;
12777         }
12778 
12779         if (isInfinity(x[i]))
12780         {
12781             if (isInfinity(y[i]) && signbit(x) != signbit(y))
12782                 invalidSum = true;
12783             else
12784             {
12785                 hasInfinity = true;
12786                 infinitySign ^= cast(bool)signbit(x[i]);
12787             }
12788         }
12789         else if (isInfinity(y[i]))
12790         {
12791             hasInfinity = true;
12792             infinitySign ^= cast(bool)signbit(y[i]);
12793         }
12794         else if (x[i] == y[i])
12795             hasZero = true;
12796         ++i;
12797     }
12798 
12799     if (invalidSum)
12800     {
12801         result = D.nan;
12802         return ExceptionFlags.invalidOperation;
12803     }
12804 
12805     if (hasInfinity & hasZero)
12806     {
12807         result = D.nan;
12808         return ExceptionFlags.invalidOperation;
12809     }
12810 
12811     if (hasInfinity)
12812     {
12813         result = infinitySign ? -D.infinity : D.infinity;
12814         return ExceptionFlags.none;
12815     }
12816 
12817     if (hasZero)
12818     {
12819         result = D.zero;
12820         return ExceptionFlags.none;
12821     }
12822 
12823     flags |= coefficientAdjust(cr, er, cvt!T(DataType!D.max), sr, mode);
12824     return result.adjustedPack(cvt!(DataType!D)(cr), er, sr, precision, mode, flags);
12825 }
12826 
12827 ExceptionFlags decimalPoly(D1, D2, D)(auto const ref D1 x, const(D2)[] a, out D result)
12828 if (isDecimal!(D1, D2) && is(D: CommonDecimal!(D1, D2)))
12829 {
12830     if (!a.length)
12831     {
12832         result = 0;
12833         return ExceptionFlags.none;
12834     }
12835     ptrdiff_t i = a.length - 1;
12836     D result = a[i];
12837     ExceptionFlags flags;
12838     while (--i >= 0)
12839     {
12840         flags |= decimalMul(result, x);
12841         flags |= decimalAdd(result, a[i]);
12842     }
12843     return flags;    
12844 }
12845 
12846 /* ****************************************************************************************************************** */
12847 /* COEFFICIENT ARITHMETIC                                                                                            */       
12848 /* ****************************************************************************************************************** */
12849 //divPow10          - inexact
12850 //mulPow10          - overflow
12851 //coefficientAdjust - inexact, overflow, underflow
12852 //coefficientExpand - none
12853 //coefficientShrink - inexact
12854 //coefficientAdd    - inexact, overflow
12855 //coefficientMul    - inexact, overflow, underflow
12856 //coefficientDiv    - inexact, overflow, underflow, div0
12857 //coefficientMod    - inexact, overflow, underflow, invalid
12858 //coefficientFMA    - inexact, overflow, underflow
12859 //coefficientCmp    - none
12860 //coefficientEqu    - none
12861 //coefficientSqr    - inexact, overflow, underflow
12862 
12863 
12864 
12865 
12866 ExceptionFlags exp2to10(RoundingMode mode = RoundingMode.implicit, U)(ref U coefficient, ref int exponent, const bool isNegative)
12867 {
12868     enum maxMultiplicable = U.max / 5U;
12869 
12870     enum hibit = U(1U) << (U.sizeof * 8 - 1);
12871     ExceptionFlags flags;
12872     auto e5 = -exponent;
12873 
12874     if (e5 > 0)
12875     {
12876         auto tz = ctz(coefficient);
12877         if (tz)
12878         {
12879             auto shift = e5 > tz ? tz : e5;
12880             e5 -= shift;
12881             exponent += shift;
12882             coefficient >>= shift;
12883         }
12884 
12885         while (e5 > 0)
12886         {
12887             --e5;
12888             if (coefficient < maxMultiplicable)
12889                 coefficient *= 5U;
12890             else
12891             {
12892                 ++exponent;
12893                 bool mustRound = cast(bool)(coefficient & 1U);
12894                 coefficient >>= 1;
12895                 if (mustRound)
12896                 {
12897                     flags = ExceptionFlags.inexact;
12898                     static if (mode == RoundingMode.tiesToAway)
12899                     {
12900                         ++coefficient;
12901                     }
12902                     else static if (mode == RoundingMode.tiesToEven)
12903                     {
12904                         if ((coefficient & 1U))
12905                             ++coefficient;
12906                     }
12907                     else static if (mode == RoundingMode.towardNegative)
12908                     {
12909                         if (isNegative)
12910                             ++coefficient;
12911                     }
12912                     else static if (mode == RoundingMode.towardPositive)
12913                     {
12914                         if (!isNegative)
12915                             ++coefficient;
12916                     }
12917                 }           
12918             }
12919         }
12920     }
12921 
12922     if (e5 < 0)
12923     {
12924         auto lz = clz(coefficient);
12925         if (lz)
12926         {
12927             auto shift = -e5 > lz ? lz : -e5;
12928             exponent -= shift;
12929             e5 += shift;
12930             coefficient <<= shift;
12931         }
12932 
12933         while (e5 < 0)
12934         {
12935             ++e5;
12936             if (coefficient & hibit)
12937             {
12938                 auto r = divrem(coefficient, 5U);
12939                 if (r)
12940                 {
12941                     flags = ExceptionFlags.inexact;
12942                     static if (mode == RoundingMode.towardNegative)
12943                     {
12944                         if (isNegative)
12945                             ++coefficient;
12946                     }
12947                     else static if (mode == RoundingMode.towardPositive)
12948                     {
12949                         if (!isNegative)
12950                             ++coefficient;
12951                     }
12952                     else static if (mode == RoundingMode.tiesToAway || mode == RoundingMode.tiesToEven)
12953                     {
12954                         if (r >= 3U)
12955                             ++coefficient;
12956                     }
12957                 }
12958             }
12959             else
12960             {
12961                 coefficient <<= 1;
12962                 --exponent;
12963             }
12964         }
12965  
12966     }
12967 
12968     return flags;
12969 }
12970 
12971 ExceptionFlags exp10to2(RoundingMode mode = RoundingMode.implicit, U)(ref U coefficient, ref int exponent, const bool isNegative)
12972 {
12973     enum maxMultiplicable = U.max / 5U;
12974 
12975     enum hibit = U(1U) << (U.sizeof * 8 - 1);
12976     ExceptionFlags flags;
12977     auto e5 = exponent;
12978 
12979     if (e5 > 0)
12980     {
12981         while (e5 > 0)
12982         {
12983             
12984             if (coefficient < maxMultiplicable)
12985             {
12986                 --e5;
12987                 coefficient *= 5U;
12988             }
12989             else
12990             {
12991                 ++exponent;
12992                 bool mustRound = cast(bool)(coefficient & 1U);
12993                 coefficient >>= 1;
12994                 if (mustRound)
12995                 {
12996                     flags = ExceptionFlags.inexact;
12997                     static if (mode == RoundingMode.tiesToAway)
12998                     {
12999                         ++coefficient;
13000                     }
13001                     else static if (mode == RoundingMode.tiesToEven)
13002                     {
13003                         if ((coefficient & 1U))
13004                             ++coefficient;
13005                     }
13006                     else static if (mode == RoundingMode.towardNegative)
13007                     {
13008                         if (isNegative)
13009                             ++coefficient;
13010                     }
13011                     else static if (mode == RoundingMode.towardPositive)
13012                     {
13013                         if (!isNegative)
13014                             ++coefficient;
13015                     }
13016                 }           
13017             }
13018         }
13019     }
13020 
13021     if (e5 < 0)
13022     {
13023         while (e5 < 0)
13024         {
13025             
13026             if (coefficient & hibit)
13027             {          
13028                 ++e5;
13029                 auto r = divrem(coefficient, 5U);
13030                 if (r)
13031                 {
13032                     flags = ExceptionFlags.inexact;
13033                     static if (mode == RoundingMode.towardNegative)
13034                     {
13035                         if (isNegative)
13036                             ++coefficient;
13037                     }
13038                     else static if (mode == RoundingMode.towardPositive)
13039                     {
13040                         if (!isNegative)
13041                             ++coefficient;
13042                     }
13043                     else static if (mode == RoundingMode.tiesToAway || mode == RoundingMode.tiesToEven)
13044                     {
13045                         if (r >= 3U)
13046                             ++coefficient;
13047                     }
13048                 }
13049             }
13050             else
13051             {
13052                 coefficient <<= 1;
13053                 --exponent;
13054             }
13055         }
13056 
13057     }
13058 
13059     return flags;
13060 }
13061 
13062 unittest
13063 {
13064     uint cx = 3402823;
13065     int ex = 32;
13066 
13067    
13068     exp10to2!(RoundingMode.towardZero)(cx, ex, false);
13069 }
13070 
13071 //divides coefficient by 10^power
13072 //inexact
13073 @safe pure nothrow @nogc
13074 ExceptionFlags divpow10(T)(ref T coefficient, const int power, const bool isNegative, const RoundingMode mode)
13075 if (isAnyUnsigned!T)
13076 in
13077 {
13078     assert (power >= 0);
13079 }
13080 body
13081 {
13082     Unqual!T remainder;
13083 
13084     if (coefficient == 0U)
13085         return ExceptionFlags.none;
13086 
13087     if (power == 0)
13088         return ExceptionFlags.none;
13089 
13090     if (power >= pow10!T.length)
13091     {
13092         remainder = coefficient;
13093         coefficient = 0U;
13094     }
13095     else
13096         remainder = divrem(coefficient, pow10!T[power]);
13097 
13098     if (remainder == 0U)
13099         return ExceptionFlags.none;
13100 
13101     immutable half = power >= pow10!T.length ? T.max : pow10!T[power] >>> 1;
13102     final switch (mode)
13103     {
13104         case RoundingMode.tiesToEven:
13105             if (remainder > half)
13106                 ++coefficient;
13107             else if ((remainder == half) && ((coefficient & 1U) != 0U))
13108                 ++coefficient;
13109             break;
13110         case RoundingMode.tiesToAway:
13111             if (remainder >= half)
13112                 ++coefficient;
13113             break;
13114         case RoundingMode.towardNegative:
13115             if (isNegative)
13116                 ++coefficient;
13117             break;
13118         case RoundingMode.towardPositive:
13119             if (!isNegative)
13120                 ++coefficient;
13121             break;
13122         case RoundingMode.towardZero:
13123             break;
13124     } 
13125 
13126     return ExceptionFlags.inexact;
13127 }
13128 
13129 unittest
13130 {
13131     struct S {uint c; int p; bool n; RoundingMode r; uint outc; bool inexact; }
13132 
13133     S[] test = 
13134     [
13135         S (0, 0, false, RoundingMode.tiesToAway, 0, false),
13136         S (0, 0, false, RoundingMode.tiesToEven, 0, false),
13137         S (0, 0, false, RoundingMode.towardNegative, 0, false),
13138         S (0, 0, false, RoundingMode.towardPositive, 0, false),
13139         S (0, 0, false, RoundingMode.towardZero, 0, false),
13140 
13141         S (10, 1, false, RoundingMode.tiesToAway, 1, false),
13142         S (10, 1, false, RoundingMode.tiesToEven, 1, false),
13143         S (10, 1, false, RoundingMode.towardNegative, 1, false),
13144         S (10, 1, false, RoundingMode.towardPositive, 1, false),
13145         S (10, 1, false, RoundingMode.towardZero, 1, false),
13146 
13147         S (13, 1, false, RoundingMode.tiesToAway, 1, true),
13148         S (13, 1, false, RoundingMode.tiesToEven, 1, true),
13149         S (13, 1, false, RoundingMode.towardNegative, 1, true),
13150         S (13, 1, false, RoundingMode.towardPositive, 2, true),
13151         S (13, 1, false, RoundingMode.towardZero, 1, true),
13152 
13153         S (13, 1, true, RoundingMode.tiesToAway, 1, true),
13154         S (13, 1, true, RoundingMode.tiesToEven, 1, true),
13155         S (13, 1, true, RoundingMode.towardNegative, 2, true),
13156         S (13, 1, true, RoundingMode.towardPositive, 1, true),
13157         S (13, 1, true, RoundingMode.towardZero, 1, true),
13158 
13159 
13160         S (15, 1, false, RoundingMode.tiesToAway, 2, true),
13161         S (15, 1, false, RoundingMode.tiesToEven, 2, true),
13162         S (15, 1, false, RoundingMode.towardNegative, 1, true),
13163         S (15, 1, false, RoundingMode.towardPositive, 2, true),
13164         S (15, 1, false, RoundingMode.towardZero, 1, true),
13165 
13166         S (15, 1, true, RoundingMode.tiesToAway, 2, true),
13167         S (15, 1, true, RoundingMode.tiesToEven, 2, true),
13168         S (15, 1, true, RoundingMode.towardNegative, 2, true),
13169         S (15, 1, true, RoundingMode.towardPositive, 1, true),
13170         S (15, 1, true, RoundingMode.towardZero, 1, true),
13171 
13172 
13173         S (18, 1, false, RoundingMode.tiesToAway, 2, true),
13174         S (18, 1, false, RoundingMode.tiesToEven, 2, true),
13175         S (18, 1, false, RoundingMode.towardNegative, 1, true),
13176         S (18, 1, false, RoundingMode.towardPositive, 2, true),
13177         S (18, 1, false, RoundingMode.towardZero, 1, true),
13178 
13179         S (18, 1, true, RoundingMode.tiesToAway, 2, true),
13180         S (18, 1, true, RoundingMode.tiesToEven, 2, true),
13181         S (18, 1, true, RoundingMode.towardNegative, 2, true),
13182         S (18, 1, true, RoundingMode.towardPositive, 1, true),
13183         S (18, 1, true, RoundingMode.towardZero, 1, true),
13184 
13185         S (25, 1, false, RoundingMode.tiesToAway, 3, true),
13186         S (25, 1, false, RoundingMode.tiesToEven, 2, true),
13187         S (25, 1, false, RoundingMode.towardNegative, 2, true),
13188         S (25, 1, false, RoundingMode.towardPositive, 3, true),
13189         S (25, 1, false, RoundingMode.towardZero, 2, true),
13190 
13191         S (25, 1, true, RoundingMode.tiesToAway, 3, true),
13192         S (25, 1, true, RoundingMode.tiesToEven, 2, true),
13193         S (25, 1, true, RoundingMode.towardNegative, 3, true),
13194         S (25, 1, true, RoundingMode.towardPositive, 2, true),
13195         S (25, 1, true, RoundingMode.towardZero, 2, true),
13196     ];
13197 
13198     foreach (ref s; test)
13199     {
13200         auto flags = divpow10(s.c, s.p, s.n, s.r);
13201         assert (s.c == s.outc);
13202         assert (flags == ExceptionFlags.inexact ? s.inexact : !s.inexact);
13203 
13204     }
13205 
13206 }
13207 
13208 //multiplies coefficient by 10^^power, returns possible overflow
13209 //overflow
13210 @safe pure nothrow @nogc
13211 ExceptionFlags mulpow10(T)(ref T coefficient, const int power)
13212 if (isAnyUnsigned!T)
13213 in 
13214 {
13215     assert (power >= 0);
13216 }
13217 body
13218 {
13219     if (coefficient == 0U || power == 0)
13220         return ExceptionFlags.none;   
13221     if (power >= pow10!T.length || coefficient > maxmul10!T[power])
13222         return ExceptionFlags.overflow;
13223     coefficient *= pow10!T[power];
13224     return ExceptionFlags.none;   
13225 }
13226 
13227 
13228 //adjusts coefficient to fit minExponent <= exponent <= maxExponent and coefficient <= maxCoefficient
13229 //inexact, overflow, underflow
13230 @safe pure nothrow @nogc
13231 ExceptionFlags coefficientAdjust(T)(ref T coefficient, ref int exponent, const int minExponent, const int maxExponent, 
13232                                     const T maxCoefficient, const bool isNegative, const RoundingMode mode)
13233 if (isAnyUnsigned!T)
13234 in
13235 {
13236     assert (minExponent <= maxExponent);
13237     assert (maxCoefficient >= 1U);
13238 }
13239 body
13240 {
13241     bool overflow;
13242     ExceptionFlags flags;
13243 
13244     if (coefficient == 0U)
13245     {
13246         if (exponent < minExponent)
13247             exponent = minExponent;      
13248         if (exponent > maxExponent)
13249             exponent = maxExponent;
13250         return ExceptionFlags.none;
13251     }
13252 
13253     if (exponent < minExponent)
13254     {
13255         //increase exponent, divide coefficient 
13256         immutable dif = minExponent - exponent;
13257         flags = divpow10(coefficient, dif, isNegative, mode);
13258         if (coefficient == 0U)
13259             flags |= ExceptionFlags.underflow | ExceptionFlags.inexact;
13260         exponent += dif;
13261     }
13262     else if (exponent > maxExponent)
13263     {
13264         //decrease exponent, multiply coefficient
13265         immutable dif = exponent - maxExponent;
13266         flags = mulpow10(coefficient, dif);
13267         if (flags & ExceptionFlags.overflow)
13268             return flags | ExceptionFlags.inexact;
13269         else
13270             exponent -= dif;
13271     }
13272 
13273     if (coefficient > maxCoefficient)
13274     {
13275         //increase exponent, divide coefficient
13276         auto dif = prec(coefficient) - prec(maxCoefficient);
13277         if (!dif) 
13278             dif = 1;
13279         flags |= divpow10(coefficient, dif, isNegative, mode);
13280         if (coefficient > maxCoefficient)
13281         {
13282             //same precision but greater
13283             flags |= divpow10(coefficient, 1, isNegative, mode);         
13284             ++dif;
13285         }
13286         if (cappedAdd(exponent, dif) != dif)
13287         {
13288             if (coefficient != 0U)
13289                 return flags | ExceptionFlags.overflow | ExceptionFlags.inexact;
13290         }
13291     }
13292 
13293 
13294     //coefficient became 0, dont' bother with exponents;
13295     if (coefficient == 0U)
13296     {
13297         exponent = 0;
13298         if (exponent < minExponent)
13299             exponent = minExponent;      
13300         if (exponent > maxExponent)
13301             exponent = maxExponent;
13302         return flags;
13303     }
13304 
13305     if (exponent < minExponent)
13306         return flags | ExceptionFlags.underflow | ExceptionFlags.inexact;
13307     
13308     if (exponent > maxExponent)
13309         return flags | ExceptionFlags.overflow | ExceptionFlags.inexact;
13310 
13311 
13312     return flags;
13313 
13314 }
13315 
13316 
13317 //adjusts coefficient to fit minExponent <= exponent <= maxExponent
13318 //inexact, overflow, underflow
13319 @safe pure nothrow @nogc
13320 ExceptionFlags coefficientAdjust(T)(ref T coefficient, ref int exponent, const int minExponent, const int maxExponent, 
13321                                     const bool isNegative, const RoundingMode mode)
13322 if (isAnyUnsigned!T)
13323 in
13324 {
13325     assert (minExponent <= maxExponent);
13326 }
13327 body
13328 {
13329     return coefficientAdjust(coefficient, exponent, minExponent, maxExponent, T.max, isNegative, mode);
13330 }
13331 
13332 //adjusts coefficient to fit coefficient in maxCoefficient
13333 //inexact, overflow, underflow
13334 @safe pure nothrow @nogc
13335 ExceptionFlags coefficientAdjust(T)(ref T coefficient, ref int exponent, const T maxCoefficient, 
13336                                     const bool isNegative, const RoundingMode mode)
13337 if (isAnyUnsigned!T)
13338 in
13339 {
13340     assert (maxCoefficient >= 1U);
13341 }
13342 body
13343 {
13344     return coefficientAdjust(coefficient, exponent, int.min, int.max, maxCoefficient, isNegative, mode);
13345 }
13346 
13347 
13348 //adjusts coefficient to fit minExponent <= exponent <= maxExponent and to fit precision
13349 //inexact, overflow, underflow
13350 @safe pure nothrow @nogc
13351 ExceptionFlags coefficientAdjust(T)(ref T coefficient, ref int exponent, const int minExponent, const int maxExponent, 
13352                                   const int precision, const bool isNegative, const RoundingMode mode)
13353 if (isAnyUnsigned!T)
13354 in
13355 {
13356     assert (precision >= 1);
13357     assert (minExponent <= maxExponent);
13358 }
13359 body
13360 {
13361     immutable maxCoefficient = precision >= pow10!T.length ? T.max : pow10!T[precision] - 1U;
13362     auto flags = coefficientAdjust(coefficient, exponent, minExponent, maxExponent, maxCoefficient, isNegative, mode);
13363     if (flags & (ExceptionFlags.overflow | ExceptionFlags.underflow))
13364         return flags;
13365 
13366     immutable p = prec(coefficient);
13367     if (p > precision)
13368     {
13369         flags |= divpow10(coefficient, 1, isNegative, mode);
13370         if (coefficient == 0U)
13371         {
13372             exponent = 0;
13373             if (exponent < minExponent)
13374                 exponent = minExponent;      
13375             if (exponent > maxExponent)
13376                 exponent = maxExponent;
13377             return flags;
13378         }
13379         else
13380         {
13381             if (cappedAdd(exponent, 1) != 1)
13382                 return flags | ExceptionFlags.overflow;
13383             if (exponent > maxExponent)
13384                 return flags | ExceptionFlags.overflow;
13385         }
13386     }
13387     return flags;
13388 }
13389 
13390 //adjusts coefficient to fit precision
13391 //inexact, overflow, underflow
13392 @safe pure nothrow @nogc
13393 ExceptionFlags coefficientAdjust(T)(ref T coefficient, ref int exponent, 
13394                                     const int precision, const bool isNegative, const RoundingMode mode)
13395 if (isAnyUnsigned!T)
13396 in
13397 {
13398     assert (precision >= 1);
13399 }
13400 body
13401 {
13402     return coefficientAdjust(coefficient, exponent, int.min, int.max, precision, isNegative, mode);
13403 }
13404 
13405 //shrinks coefficient by cutting out terminating zeros and increasing exponent
13406 @safe pure nothrow @nogc
13407 void coefficientShrink(T)(ref T coefficient, ref int exponent)
13408 {
13409     if (coefficient > 9U && (coefficient & 1U) == 0U && exponent < int.max)
13410     {
13411         Unqual!T c = coefficient;
13412         Unqual!T r = divrem(c, 10U);
13413         int e = exponent + 1;
13414         while (r == 0U)
13415         {
13416             coefficient = c;
13417             exponent = e;
13418             if ((c & 1U) || e == int.max)
13419                 break;
13420             r = divrem(c, 10U);
13421             ++e;
13422         }
13423     }
13424 }
13425 
13426 //expands cx with 10^^target if possible
13427 @safe pure nothrow @nogc
13428 void coefficientExpand(T)(ref T cx, ref int ex, ref int target)
13429 in
13430 {
13431     assert (cx);
13432     assert (target > 0);
13433 }
13434 body
13435 {
13436     int px = prec(cx);
13437     int maxPow10 = cast(int)pow10!T.length - px;
13438     auto maxCoefficient = maxmul10!T[$ - px];
13439     if (cx > maxCoefficient)
13440         --maxPow10;
13441     auto pow = target > maxPow10 ? maxPow10 : target;    
13442     pow = cappedSub(ex, pow);
13443     if (pow)
13444     {
13445         cx *= pow10!T[pow];
13446         target -= pow;
13447     }
13448 }
13449 
13450 //expands cx to maximum available digits
13451 @safe pure nothrow @nogc
13452 void coefficientExpand(T)(ref T cx, ref int ex)
13453 {
13454     if (cx)
13455     {
13456         int px = prec(cx);
13457         int pow = cast(int)pow10!T.length - px;
13458         auto maxCoefficient = maxmul10!T[$ - px];
13459         if (cx > maxCoefficient)
13460             --pow;
13461         pow = cappedSub(ex, pow);
13462         if (pow)
13463         {
13464             cx *= pow10!T[pow];
13465         }
13466     }
13467 }
13468 
13469 unittest
13470 {
13471     struct S {uint x1; int ex1; int target1; uint x2; int ex2; int target2; }
13472     S[] tests =
13473     [
13474         S(1, 0, 4, 10000, -4, 0),
13475         S(429496729, 0, 1, 4294967290, -1, 0),
13476         S(429496739, 0, 1, 429496739, 0, 1),
13477         S(429496729, 0, 2, 4294967290, -1, 1),
13478         S(42949672, 0, 1, 429496720, -1, 0),
13479         S(42949672, 0, 2, 4294967200, -2, 0),
13480         S(42949672, 0, 3, 4294967200, -2, 1),
13481     ];
13482 
13483     foreach( s; tests)
13484     {
13485         coefficientExpand(s.x1, s.ex1, s.target1);
13486         assert (s.x1 == s.x2);
13487         assert (s.ex1 == s.ex2);
13488         assert (s.target1 == s.target2);
13489     }
13490 }
13491 
13492 //shrinks cx with 10^^target
13493 //inexact
13494 @safe pure nothrow @nogc
13495 ExceptionFlags coefficientShrink(T)(ref T cx, ref int ex, const bool sx, ref int target, const RoundingMode mode)
13496 in
13497 {
13498     assert (cx);
13499     assert (target > 0);
13500 }
13501 body
13502 {
13503     auto pow = cappedAdd(ex, target);
13504     if (pow)
13505     {
13506         auto flags = divpow10(cx, pow, sx, mode);
13507         target -= pow;
13508         return flags;
13509     }
13510     else
13511         return ExceptionFlags.none;
13512 }
13513 
13514 //inexact
13515 @safe pure nothrow @nogc
13516 ExceptionFlags exponentAlign(T)(ref T cx, ref int ex, const bool sx, ref T cy, ref int ey, const bool sy, const RoundingMode mode)
13517 out
13518 {
13519     assert (ex == ey);
13520 }
13521 body
13522 {
13523     if (ex == ey)
13524         return ExceptionFlags.none;
13525 
13526     if (!cx)
13527     {
13528         ex = ey;
13529         return ExceptionFlags.none;
13530     }
13531     
13532     if (!cy)
13533     {
13534         ey = ex;
13535         return ExceptionFlags.none;
13536     }
13537 
13538     ExceptionFlags flags;
13539     int dif = ex - ey;
13540     if (dif > 0) //ex > ey
13541     {
13542         coefficientExpand(cx, ex, dif);
13543         if (dif)
13544             flags = coefficientShrink(cy, ey, sy, dif, mode);
13545         assert(!dif);
13546     }
13547     else //ex < ey
13548     {
13549         dif = -dif;
13550         coefficientExpand(cy, ey, dif);
13551         if (dif)
13552             flags = coefficientShrink(cx, ex, sx, dif, mode);
13553         assert(!dif);
13554     }
13555     return flags;
13556 }
13557 
13558 //inexact, overflow, underflow
13559 @safe pure nothrow @nogc
13560 ExceptionFlags coefficientAdd(T)(ref T cx, ref int ex, ref bool sx, const T cy, const int ey, const bool sy, const RoundingMode mode)
13561 {
13562     if (!cy)
13563         return ExceptionFlags.none;
13564     
13565     if (!cx)
13566     {
13567         cx = cy;
13568         ex = ey;
13569         sx = sy;
13570         return ExceptionFlags.none;
13571     }
13572 
13573     Unqual!T cyy = cy;
13574     int eyy = ey;
13575 
13576     //if cx or cy underflowed, don't propagate
13577     auto flags = exponentAlign(cx, ex, sx, cyy, eyy, sy, mode) & ~ExceptionFlags.underflow;
13578 
13579     if (!cyy)
13580     {
13581         //cx is very big
13582         switch (mode)
13583         {
13584             case RoundingMode.towardPositive:
13585                 if (!sx && !sy)
13586                     ++cx;
13587                 else if (sx && !sy)
13588                     --cx;
13589                 break;
13590             case RoundingMode.towardNegative:
13591                 if (sx && sy)
13592                     ++cx;
13593                 else if (!sx && sy)
13594                     --cx;
13595                 break;
13596             case RoundingMode.towardZero:
13597                 if (sx != sy)
13598                     --cx;
13599                 break;
13600             default:
13601                 break;
13602         }
13603 
13604 
13605         //if (sx == sy)
13606         //{
13607         //    //cx + 0.0.....001 => cx0000.0....001
13608         //    if (sx && mode == RoundingMode.towardNegative)
13609         //        ++cx;
13610         //    else if (!sx && mode == RoundingMode.towardPositive)
13611         //        ++cx;
13612         //}
13613         //else
13614         //{
13615         //    //cx - 0.0.....001 => (cx-1)9999.9...999
13616         //    if (sx && mode == RoundingMode.towardZero)
13617         //        --cx;
13618         //    else if (!sx && mode == RoundingMode.towardNegative)
13619         //        --cx;
13620         //}
13621     }
13622     
13623     if (!cx)
13624     {
13625         //cy is very big, cx is tiny 
13626         switch (mode)
13627         {
13628             case RoundingMode.towardPositive:
13629                 if (!sx && !sy)
13630                     ++cyy;
13631                 else if (!sx && sy)
13632                     --cyy;
13633                 break;
13634             case RoundingMode.towardNegative:
13635                 if (sx && sy)
13636                     ++cyy;
13637                 else if (sx && !sy)
13638                     --cyy;
13639                 break;
13640             case RoundingMode.towardZero:
13641                 if (sx != sy)
13642                     --cyy;
13643                 break;
13644             default:
13645                 break;
13646         }
13647 
13648 
13649         //if (sx == sy)
13650         //{
13651         //    //0.0.....001 + cyy => cyy0000.0....001
13652         //    if (sy && mode == RoundingMode.towardNegative)
13653         //        ++cyy;
13654         //    else if (!sy && mode == RoundingMode.towardPositive)
13655         //        ++cyy;
13656         //}
13657         //else
13658         //{
13659         //    //0.0.....001 - cyy => -(cyy + 0.0.....001)
13660         //    if (sy && mode == RoundingMode.towardZero)
13661         //        --cyy;
13662         //    else if (!sy && mode == RoundingMode.towardNegative)
13663         //        --cyy;
13664         //}
13665     }
13666 
13667     if (sx == sy)
13668     {
13669         Unqual!T savecx = cx;
13670         auto carry = xadd(cx, cyy);
13671         if (carry)
13672         {
13673             if (!cappedAdd(ex, 1))
13674                 return flags | ExceptionFlags.overflow;
13675             flags |= divpow10(savecx, 1, sx, mode);
13676             flags |= divpow10(cyy, 1, sy, mode);
13677             cx = savecx + cyy;
13678         }
13679         return flags;
13680     }
13681     else
13682     {
13683         if (cx == cyy)
13684         {
13685             cx = T(0U);
13686             ex = 0;
13687             sx = false;
13688             return flags;
13689         }
13690 
13691         if (cx > cyy)
13692             cx -= cyy;
13693         else
13694         {
13695             cx = cyy - cx;
13696             sx = sy;
13697         }
13698         return flags;
13699     }
13700 }
13701 
13702 unittest
13703 {
13704     int x = 0;
13705 }
13706 
13707 //inexact, overflow, underflow
13708 @safe pure nothrow @nogc
13709 ExceptionFlags coefficientMul(T)(ref T cx, ref int ex, ref bool sx, const T cy, const int ey, const bool sy, const RoundingMode mode)
13710 {
13711     if (!cy || !cy)
13712     {
13713         cx = T(0U);
13714         sx ^= sy;
13715         return ExceptionFlags.none;
13716     }
13717 
13718     auto r = xmul(cx, cy);
13719     
13720     if (cappedAdd(ex, ey) != ey)
13721         return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow;
13722 
13723     sx ^= sy;
13724 
13725     if (r > T.max)
13726     {
13727         auto px = prec(r);
13728         auto pm = prec(T.max) - 1;
13729         auto flags = divpow10(r, px - pm, sx, mode);
13730         if (cappedAdd(ex, px - pm) != px - pm)
13731             return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow;
13732         cx = cvt!T(r);
13733         return flags;
13734     }
13735     else
13736     {
13737         cx = cvt!T(r);
13738         return ExceptionFlags.none;
13739     }
13740 }
13741 
13742 //div0, overflow, underflow
13743 @safe pure nothrow @nogc
13744 ExceptionFlags coefficientDiv(T)(ref T cx, ref int ex, ref bool sx, const T cy, const int ey, const bool sy, const RoundingMode mode)
13745 {
13746     if (!cy)
13747     {
13748         sx ^= sy;
13749         return ExceptionFlags.divisionByZero;
13750     }
13751 
13752     if (!cx)
13753     {
13754         ex = 0;
13755         sx ^= sy;
13756         return ExceptionFlags.none;
13757     }
13758 
13759     if (cy == 1U)
13760     {
13761         if (cappedSub(ex, ey) != ey)
13762             return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow;
13763         sx ^= sy;
13764         return ExceptionFlags.none;
13765     }
13766 
13767     Unqual!T savecx = cx;
13768     sx ^= sy;
13769     auto r = divrem(cx, cy);
13770     if (!r)
13771     {
13772         if (cappedSub(ex, ey) != ey)
13773            return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow; 
13774         return ExceptionFlags.none;
13775     }
13776 
13777     alias U = MakeUnsigned!(T.sizeof * 16);
13778     U cxx = savecx;
13779     auto px = prec(savecx);
13780     auto pm = prec(U.max) - 1;
13781     mulpow10(cxx, pm - px);
13782     auto scale = pm - px - cappedSub(ex, pm - px);
13783     auto s = divrem(cxx, cy);
13784     ExceptionFlags flags;
13785     if (s)
13786     {
13787         immutable half = cy >>> 1;
13788         final switch (mode)
13789         {
13790             case RoundingMode.tiesToEven:
13791                 if (s > half)
13792                     ++cxx;
13793                 else if ((s == half) && ((cxx & 1U) == 0U))
13794                     ++cxx;
13795                 break;
13796             case RoundingMode.tiesToAway:
13797                 if (s >= half)
13798                     ++cxx;
13799                 break;
13800             case RoundingMode.towardNegative:
13801                 if (sx)
13802                     ++cxx;
13803                 break;
13804             case RoundingMode.towardPositive:
13805                 if (!sx)
13806                     ++cxx;
13807                 break;
13808             case RoundingMode.towardZero:
13809                 break;
13810         }
13811         flags = ExceptionFlags.inexact;
13812     }
13813 
13814     flags |= coefficientAdjust(cxx, ex, U(T.max), sx, mode);
13815 
13816     if (flags & ExceptionFlags.underflow)
13817     {
13818         cx = 0U;
13819         ex = 0U;
13820         return flags;
13821     }
13822 
13823     if (flags & ExceptionFlags.overflow)
13824         return flags;
13825 
13826     
13827     cx = cast(T)cxx;
13828     if (cappedSub(ex, ey) != ey)
13829         flags |= ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow; 
13830     if (cappedSub(ex, scale) != scale)
13831         flags |= ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow; 
13832 
13833     return flags;
13834 }
13835 
13836 //inexact, overflow, underflow
13837 @safe pure nothrow @nogc
13838 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)
13839 {
13840     if (!cx || !cy)
13841     {
13842         cx = cz;
13843         ex = ez;
13844         sx = sz;
13845         return ExceptionFlags.none;
13846     }
13847 
13848     if (!cz)
13849         return coefficientMul(cx, ex, sx, cy, ey, sy, mode);
13850 
13851     
13852     if (cappedAdd(ex, ey) != ey)
13853         return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow;
13854     auto m = xmul(cx, cy);
13855     sx ^= sy;
13856 
13857     typeof(m) czz = cz;
13858     auto flags = coefficientAdd(m, ex, sx, czz, ez, sz, mode);
13859     auto pm = prec(m);
13860     auto pmax = prec(T.max) - 1;
13861     if (pm > pmax)
13862     {
13863         flags |= divpow10(m, pm - pmax, sx, mode);
13864         if (cappedAdd(ex, pm - pmax) != pm - pmax)
13865             return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow;
13866     }
13867     cx = cast(Unqual!T)m;
13868     return flags;
13869 }
13870 
13871 //inexact
13872 @safe pure nothrow @nogc
13873 ExceptionFlags coefficientRound(T)(ref T cx, ref int ex, const bool sx, const RoundingMode mode)
13874 {
13875     if (ex < 0)
13876     {
13877         auto flags = divpow10(cx, -ex, sx, mode);
13878         ex = 0;
13879         return flags;
13880     }
13881     return ExceptionFlags.none;
13882 }
13883 
13884 //inexact, overflow, underflow
13885 @safe pure nothrow @nogc
13886 ExceptionFlags coefficientMod(T)(ref T cx, ref int ex, ref bool sx, const T cy, const int ey, const bool sy, const RoundingMode mode)
13887 {
13888     if (!cy)
13889         return ExceptionFlags.invalidOperation;
13890     Unqual!T rcx = cx;
13891     int rex = ex;
13892     bool rsx = sx;
13893     coefficientDiv(rcx, rex, rsx, cy, ey, sy, mode);   //16
13894     coefficientRound(rcx, rex, rsx, mode);             //00
13895     coefficientMul(rcx, rex, rsx, cy, ey, sy, mode);   //16
13896     return coefficientAdd(cx, ex, sx, rcx, rex, !rsx, mode);  //0
13897 }
13898 
13899 unittest
13900 {
13901 
13902 }
13903 
13904 @safe pure nothrow @nogc
13905 int coefficientCmp(T)(const T cx, const int ex, const bool sx, const T cy, const int ey, const bool sy)
13906 {
13907     if (!cx)
13908         return cy ? (sy ? 1 : -1) : 0;
13909     if (!cy)
13910         return sx ? -1 : 1;
13911     
13912     if (sx && !sy)
13913         return -1;
13914     else if (!sx && sy)
13915         return 1;
13916     else
13917         return sx ? -coefficientCmp(cx, ex, cy, ey) : coefficientCmp(cx, ex, cy, ey);
13918 }
13919 
13920 @safe pure nothrow @nogc
13921 int coefficientCmp(T)(const T cx, const int ex, const T cy, const int ey)
13922 {
13923     if (!cx)
13924         return cy ? -1 : 0;
13925     if (!cy)
13926         return 1;
13927 
13928     int px = prec(cx);
13929     int py = prec(cy);
13930 
13931     if (px > py)
13932     {
13933         int eyy = ey - (px - py);
13934         if (ex > eyy)
13935             return 1;
13936         if (ex < eyy)
13937             return -1;
13938         Unqual!T cyy = cy;
13939         mulpow10(cyy, px - py);
13940         if (cx > cyy)
13941             return 1;
13942         if (cx < cyy)
13943             return -1;
13944         return 0;
13945     }
13946 
13947     if (px < py)
13948     {
13949         int exx = ex - (py - px);
13950         if (exx > ey)
13951             return 1;
13952         if (exx < ey)
13953             return -1;
13954         Unqual!T cxx = cx;
13955         mulpow10(cxx, py - px);       
13956         if (cxx > cy)
13957             return 1;
13958         if (cxx < cy)
13959             return -1;
13960         return 0;
13961     }
13962 
13963     if (ex > ey)
13964         return 1;
13965     if (ex < ey)
13966         return -1;
13967 
13968     if (cx > cy)
13969         return 1;
13970     else if (cx < cy)
13971         return -1;
13972     return 0;
13973     
13974 }
13975 
13976 @safe pure nothrow @nogc
13977 bool coefficientEqu(T)(const T cx, const int ex, const bool sx, const T cy, const int ey, const bool sy)
13978 {
13979     if (!cx)
13980         return cy == 0U;
13981 
13982     if (sx != sy)
13983         return false;
13984     else
13985     {
13986         int px = prec(cx);
13987         int py = prec(cy);
13988 
13989         if (px > py)
13990         {     
13991             int eyy = ey - (px - py);
13992             if (ex != eyy)
13993                 return false;
13994             Unqual!T cyy = cy;
13995             mulpow10(cyy, px - py);
13996             return cx == cyy;
13997         }
13998 
13999         if (px < py)
14000         {
14001             int exx = ex - (py - px);
14002             if (exx != ey)
14003                 return false;
14004             Unqual!T cxx = cx;
14005             mulpow10(cxx, py - px);       
14006             return cxx == cy;
14007         }
14008 
14009         return cx == cy && ex == ey;
14010     }
14011 }
14012 
14013 @safe pure nothrow @nogc
14014 bool coefficientApproxEqu(T)(const T cx, const int ex, const bool sx, const T cy, const int ey, const bool sy)
14015 {
14016     //same as coefficientEqu, but we ignore the last digit if coefficient > 10^max
14017     //this is useful in convergence loops to not become infinite
14018     if (!cx)
14019         return cy == 0U;
14020 
14021     if (sx != sy)
14022         return false;
14023     else
14024     {
14025         int px = prec(cx);
14026         int py = prec(cy);
14027 
14028         if (px > py)
14029         {     
14030             int eyy = ey - (px - py);
14031             if (ex != eyy)
14032                 return false;
14033             Unqual!T cyy = cy;
14034             mulpow10(cyy, px - py);
14035             if (cx > pow10!T[$ - 2])
14036                 return cx >= cy ? cx - cy < 10U : cy - cx < 10U;
14037             return cx == cy;
14038         }
14039 
14040         if (px < py)
14041         {
14042             int exx = ex - (py - px);
14043             if (exx != ey)
14044                 return false;
14045             Unqual!T cxx = cx;
14046             mulpow10(cxx, py - px);  
14047             if (cxx > pow10!T[$ - 2])
14048                 return cxx >= cy ? cxx - cy < 10U : cy - cxx < 10U;
14049             return cx == cy;
14050         }
14051 
14052         if (cx > pow10!T[$ - 2])
14053             return cx >= cy ? cx - cy < 10U : cy - cx < 10U;
14054 
14055         return cx == cy;
14056     }
14057 }
14058 
14059 //inexact, overflow, underflow
14060 @safe pure nothrow @nogc
14061 ExceptionFlags coefficientSqr(T)(ref T cx, ref int ex, const RoundingMode mode)
14062 {
14063     if (!cx)
14064     {
14065         cx = T(0U);
14066         ex = 0;
14067         return ExceptionFlags.none;
14068     }
14069 
14070     auto r = xsqr(cx);
14071 
14072     int ey = ex;
14073     if (cappedAdd(ex, ey) != ey)
14074         return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow;
14075 
14076 
14077     if (r > T.max)
14078     {
14079         auto px = prec(r);
14080         auto pm = prec(T.max) - 1;
14081         auto flags = divpow10(r, px - pm, false, mode);
14082         if (cappedAdd(ex, px - pm) != px - pm)
14083             return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow;
14084         cx = cvt!T(r);
14085         return flags;
14086     }
14087     else
14088     {
14089         cx = cvt!T(r);
14090         return ExceptionFlags.none;
14091     }
14092 }
14093 
14094 //inexact, underflow
14095 @safe pure nothrow @nogc
14096 ExceptionFlags coefficientSqrt(T)(ref T cx, ref int ex)
14097 {
14098     // Newton-Raphson: x = (x + n/x) / 2;
14099     if (!cx)
14100     {
14101         cx = 0U;
14102         ex = 0;
14103         return ExceptionFlags.none;
14104     }
14105 
14106     alias U = MakeUnsigned!(T.sizeof * 16);
14107 
14108     U cxx = cx;
14109     ExceptionFlags flags;
14110 
14111     //we need full precision
14112     coefficientExpand(cxx, ex);
14113 
14114     if (ex & 1)
14115     {
14116         //exponent is odd, make it even
14117         flags = divpow10(cxx, 1, false, RoundingMode.implicit);
14118         ++ex;
14119     }
14120 
14121     ex /= 2;
14122     bool inexact = decimal.integrals.sqrt(cxx);
14123     flags |= coefficientAdjust(cxx, ex, cvt!U(T.max), false, RoundingMode.implicit);
14124     cx = cast(T)cxx;
14125     return inexact ? flags | ExceptionFlags.inexact : flags;
14126 }
14127 
14128 //inexact, underflow
14129 @safe pure nothrow @nogc
14130 ExceptionFlags coefficientRSqrt(T)(ref T cx, ref int ex)
14131 {
14132     bool sx = false;
14133     if (!cx)
14134         return ExceptionFlags.divisionByZero;
14135     Unqual!T cy = cx; int ey = ex;
14136     auto flags = coefficientSqrt(cy, ey);
14137     if (flags & ExceptionFlags.underflow)
14138         return ExceptionFlags.overflow;
14139     cx = 1U;
14140     ex = 0;
14141     return flags | coefficientDiv(cx, ex, sx, cy, ey, false, RoundingMode.implicit);
14142 }
14143 
14144 @safe pure nothrow @nogc
14145 ExceptionFlags coefficientCbrt(T)(ref T cx, ref int ex)
14146 {
14147     // Newton-Raphson: x = (2x + N/x2)/3
14148 
14149     if (!cx)
14150     {
14151         cx = 0U;
14152         ex = 0;
14153         return ExceptionFlags.none;
14154     }
14155 
14156     alias U = MakeUnsigned!(T.sizeof * 16);
14157 
14158     U cxx = cx;
14159     ExceptionFlags flags;
14160 
14161     //we need full precision
14162     coefficientExpand(cxx, ex);
14163 
14164     auto r = ex % 3;
14165     if (r)
14166     {
14167         //exponent is not divisible by 3, make it
14168         flags = divpow10(cxx, 3 - r, false, RoundingMode.implicit);
14169         ex += 3 - r;
14170     }
14171 
14172     ex /= 3;
14173     bool inexact = decimal.integrals.cbrt(cxx);
14174     flags |= coefficientAdjust(cxx, ex, cvt!U(T.max), false, RoundingMode.implicit);
14175     cx = cast(T)cxx;
14176     return inexact ? flags | ExceptionFlags.inexact : flags; 
14177 }
14178 
14179 @safe pure nothrow @nogc
14180 ExceptionFlags coefficientHypot(T)(ref T cx, ref int ex, auto const ref T cy, const int ey)
14181 {
14182     Unqual!T cyy = cy;
14183     int eyy = ey;
14184     bool sx;
14185     auto flags = coefficientSqr(cx, ex, RoundingMode.implicit);
14186     flags |= coefficientSqr(cyy, eyy, RoundingMode.implicit);
14187     flags |= coefficientAdd(cx, ex, sx, cyy, eyy, false, RoundingMode.implicit);
14188     return flags | coefficientSqrt(cx, ex);
14189 }
14190 
14191 @safe pure nothrow @nogc
14192 ExceptionFlags coefficientExp(T)(ref T cx, ref int ex, ref bool sx)
14193 {
14194     //e^x = 1 + x + x2/2! + x3/3! + x4/4! ...
14195     //to avoid overflow and underflow:
14196     //x^n/n! = (x^(n-1)/(n-1)! * x/n
14197     
14198     ExceptionFlags flags;
14199 
14200     //save x for repeated multiplication
14201     immutable Unqual!T cxx = cx;
14202     immutable exx = ex;
14203     immutable sxx = sx;
14204 
14205     //shadow value
14206     Unqual!T cy;
14207     int ey = 0;
14208     bool sy = false;
14209 
14210     Unqual!T cf = cx;
14211     int ef = ex;
14212     bool sf = sx;
14213 
14214     if (coefficientAdd(cx, ex, sx, T(1U), 0, false, RoundingMode.implicit) & ExceptionFlags.overflow)
14215         return ExceptionFlags.overflow;
14216     
14217     
14218     Unqual!T n = 1U;
14219 
14220     do
14221     {
14222         cy = cx;
14223         ey = ex;
14224         sy = sx;
14225 
14226         Unqual!T cp = cxx;
14227         int ep = exx;
14228         bool sp = sxx;
14229 
14230         coefficientDiv(cp, ep, sp, ++n, 0, false, RoundingMode.implicit);
14231         coefficientMul(cf, ef, sf, cp, ep, sp, RoundingMode.implicit);
14232         coefficientAdd(cx, ex, sx, cf, ef, sf, RoundingMode.implicit);
14233 
14234     } 
14235     while (!coefficientApproxEqu(cx, ex, sx, cy, ey, sy));
14236 
14237     return ExceptionFlags.inexact;
14238     
14239 }
14240 
14241 @safe pure nothrow @nogc
14242 ExceptionFlags coefficientLog(T)(ref T cx, ref int ex, ref bool sx)
14243 {
14244     
14245     assert(!sx); //only positive
14246     assert(cx);
14247 
14248     //ln(coefficient * 10^exponent) = ln(coefficient) + exponent * ln(10);
14249 
14250     static if (is(T:uint))
14251     {
14252         immutable uint ce = 2718281828U;
14253         immutable int ee = -9;
14254         immutable uint cl = 2302585093U;
14255         immutable int el = -9;
14256 
14257     }
14258     else static if (is(T:ulong))
14259     {
14260         immutable ulong ce = 2718281828459045235UL;
14261         immutable int ee = -18;
14262         immutable ulong cl = 2302585092994045684UL;
14263         immutable int el = -18;
14264     }
14265     else static if (is(T:uint128))
14266     {
14267         immutable uint128 ce = uint128("271828182845904523536028747135266249776");
14268         immutable int ee = -38;
14269         immutable uint128 cl = uint128("230258509299404568401799145468436420760");
14270         immutable int el = -38;
14271     }
14272     else
14273         static assert(0);
14274 
14275     //ln(x) = ln(n*e) = ln(n) + ln(e);
14276     //we divide x by e to find out how many times (n) we must add ln(e) = 1
14277     //ln(x + 1) taylor series works in the interval (-1 .. 1]
14278     //so our taylor series is valid for x in (0 .. 2]
14279 
14280     //save exponent for later
14281     int exponent = ex;
14282     ex = 0;
14283     
14284     enum one = T(1U);
14285     enum two = T(2U);
14286 
14287     Unqual!T n = 0U;
14288     bool ss = false;
14289 
14290     immutable aaa = cx;
14291 
14292     while (coefficientCmp(cx, ex, false, two, 0, false) >= 0)
14293     {
14294         coefficientDiv(cx, ex, sx, ce, ee, false, RoundingMode.implicit);
14295         ++n;
14296     }
14297 
14298     coefficientDiv(cx, ex, sx, ce, ee, false, RoundingMode.implicit);
14299     ++n;
14300 
14301     //ln(x) = (x - 1) - [(x - 1)^2]/2 + [(x - 1)^3]/3 - ....
14302 
14303     //initialize our result to x - 1;
14304     coefficientAdd(cx, ex, sx, one, 0, true, RoundingMode.implicit);
14305      
14306     //store cx in cxm1, this will be used for repeated multiplication
14307     //we negate the sign to alternate between +/-
14308     Unqual!T cxm1 = cx;
14309     int exm1 = ex;
14310     bool sxm1 = !sx;
14311 
14312     //shadow
14313     Unqual!T cy;
14314     int ey;
14315     bool sy;
14316 
14317     Unqual!T cd = cxm1;
14318     int ed = exm1;
14319     bool sd = !sxm1;
14320 
14321     Unqual!T i = 2U;
14322 
14323     do
14324     {
14325         cy = cx;
14326         ey = ex;
14327         sy = sx;
14328 
14329         coefficientMul(cd, ed, sd, cxm1, exm1, sxm1, RoundingMode.implicit);
14330         
14331         Unqual!T cf = cd;
14332         int ef = ed;
14333         bool sf = sd;
14334 
14335         coefficientDiv(cf, ef, sf, i++, 0, false, RoundingMode.implicit);
14336         coefficientAdd(cx, ex, sx, cf, ef, sf, RoundingMode.implicit);
14337 
14338         //writefln("%10d %10d %10d %10d %10d %10d", cx, ex, cy, ey, cx - cy, i);
14339     }
14340     while (!coefficientApproxEqu(cx, ex, sx, cy, ey, sy));
14341    
14342 
14343 
14344     coefficientAdd(cx, ex, sx, n, 0, false, RoundingMode.implicit);
14345     
14346     if (exponent != 0)
14347     {
14348         sy = exponent < 0;
14349         cy = sy ? cast(uint)(-exponent) : cast(uint)(exponent);
14350         ey = 0;
14351         coefficientMul(cy, ey, sy, cl, el, false, RoundingMode.implicit);
14352         coefficientAdd(cx, ex, sx, cy, ey, sy, RoundingMode.implicit);
14353     }
14354 
14355     //iterations 
14356     //decimal32 min:         15, max:         48 avg:      30.03
14357     //decimal64 min:         30, max:        234 avg:     149.25    
14358 
14359 
14360     return ExceptionFlags.inexact;
14361 }
14362 
14363 @safe pure nothrow @nogc
14364 ExceptionFlags coefficientAtanh(T)(ref T cx, ref int ex, ref bool sx)
14365 {
14366     //1/2*ln[(1 + x)/(1 - x)]
14367 
14368     assert (coefficientCmp(cx, ex, sx, T(1U), 0, true) > 0);
14369     assert (coefficientCmp(cx, ex, sx, T(1U), 0, false) < 0);
14370 
14371     //1/2*ln[(1 + x)/(1 - x)]
14372 
14373     Unqual!T cm1 = cx;
14374     int em1 = ex;
14375     bool sm1 = !sx;
14376     coefficientAdd(cm1, em1, sm1, T(1U), 0, false, RoundingMode.implicit);
14377     coefficientAdd(cx, ex, sx, T(1U), 0, false, RoundingMode.implicit);
14378     coefficientDiv(cx, ex, sx, cm1, em1, sm1, RoundingMode.implicit);
14379     coefficientLog(cx, ex, sx);
14380     coefficientMul(cx, ex, sx, T(5U), -1, false, RoundingMode.implicit);
14381     return ExceptionFlags.inexact;
14382 }
14383 
14384 //caps angle to -2π ... +2π
14385 @safe pure nothrow @nogc
14386 ExceptionFlags coefficientCapAngle(T)(ref T cx, ref int ex, ref bool sx)
14387 {
14388     if (coefficientCmp(cx, ex, Constants!T.c2π, Constants!T.e2π) > 0)
14389     {
14390         alias U = MakeUnsigned!(T.sizeof* 16);
14391         U cxx = cx;
14392         auto flags = coefficientMod2PI(cxx, ex);
14393         flags |= coefficientAdjust(cxx, ex, cvt!U(T.max), sx, RoundingMode.implicit);
14394         cx = cvt!T(cxx);
14395     }
14396     return ExceptionFlags.none;
14397 }
14398 
14399 //caps angle to -π/2  .. +π/2 
14400 @safe pure nothrow @nogc
14401 ExceptionFlags coefficientCapAngle(T)(ref T cx, ref int ex, ref bool sx, out int quadrant)
14402 {
14403     quadrant = 1;
14404     if (coefficientCmp(cx, ex, Constants!T.cπ_2, Constants!T.eπ_2) > 0)
14405     {
14406         ExceptionFlags flags;
14407         if (coefficientCmp(cx, ex, Constants!T.c2π, Constants!T.e2π) > 0)
14408         {
14409             alias U = MakeUnsigned!(T.sizeof* 16);
14410             U cxx = cx;
14411             flags = coefficientMod2PI(cxx, ex);
14412             flags |= coefficientAdjust(cxx, ex, cvt!U(T.max), sx, RoundingMode.implicit);
14413             cx = cvt!T(cxx);
14414             if (coefficientCmp(cx, ex, Constants!T.cπ_2, Constants!T.eπ_2) <= 0)
14415                 return flags;
14416         }
14417         Unqual!T cy = cx;
14418         int ey = ex;
14419         bool sy = sx;
14420         flags |= coefficientMul(cy, ey, sy, Constants!T.c2_π, Constants!T.e2_π, false, RoundingMode.towardZero);
14421         flags |= coefficientRound(cy, ey, sy, RoundingMode.towardZero);
14422         quadrant = cast(uint)(cy % 4U) + 1;
14423         flags |= coefficientMul(cy, ey, sy, Constants!T.cπ_2, Constants!T.eπ_2, false, RoundingMode.implicit);
14424         flags |= coefficientAdd(cx, ex, sx, cy, ey, !sy, RoundingMode.implicit);
14425         return flags;
14426     }
14427     return ExceptionFlags.none;
14428 }
14429 
14430 @safe pure nothrow @nogc
14431 ExceptionFlags coefficientSinQ(T)(ref T cx, ref int ex, ref bool sx)
14432 {
14433     //taylor series: sin(x) = x - x^3/3! + x^5/5! - x^7/7! ...
14434     
14435     Unqual!T cx2 = cx; int ex2 = ex; bool sx2 = true;
14436     coefficientSqr(cx2, ex2, RoundingMode.implicit);
14437 
14438     Unqual!T cy; int ey; bool sy;
14439     Unqual!T cf = cx; int ef = ex; bool sf = sx;
14440 
14441     Unqual!T n = 2U;
14442 
14443     do
14444     {
14445         cy = cx;
14446         ey = ex;
14447         sy = sx;
14448         
14449         coefficientMul(cf, ef, sf, cx2, ex2, sx2, RoundingMode.implicit);
14450         coefficientDiv(cf, ef, sf, n++, 0, false, RoundingMode.implicit);
14451         coefficientDiv(cf, ef, sf, n++, 0, false, RoundingMode.implicit);
14452         coefficientAdd(cx, ex, sx, cf, ef, sf, RoundingMode.implicit);
14453         //writefln("%10d %10d %10d %10d", cx, ex, cy, ey);
14454        // writefln("%016x%016x %10d %016x%016x %10d", cx.hi, cx.lo, ex, cy.hi, cy.lo, ey);
14455     }
14456     while (!coefficientApproxEqu(cx, ex, sx, cy, ey, sy));
14457     return ExceptionFlags.inexact;
14458 }
14459 
14460 unittest
14461 {
14462     ulong cx = 11000000000000000855UL;
14463     int ex = -19;
14464     bool sx;
14465 
14466     coefficientSinQ(cx, ex, sx);
14467 
14468     //writefln("%35.34f", sin(decimal128("1.1000000000000000855000000000000000")));
14469     //writefln("%35.34f", decimal128(1.1));
14470 }
14471 
14472 @safe pure nothrow @nogc
14473 ExceptionFlags coefficientCosQ(T)(ref T cx, ref int ex, ref bool sx)
14474 {
14475     //taylor series: cos(x) = 1 - x^2/2! + x^4/4! - x^6/6! ...
14476 
14477     Unqual!T cx2 = cx; int ex2 = ex; bool sx2 = true;
14478     coefficientSqr(cx2, ex2, RoundingMode.implicit);
14479 
14480     cx = 1U;
14481     ex = 0;
14482     sx = false;
14483     Unqual!T cy; int ey; bool sy;
14484     Unqual!T cf = cx; int ef = ex; bool sf = sx;
14485 
14486     Unqual!T n = 1U;
14487 
14488     do
14489     {
14490         cy = cx;
14491         ey = ex;
14492         sy = sx;
14493 
14494         coefficientMul(cf, ef, sf, cx2, ex2, sx2, RoundingMode.implicit);
14495         coefficientDiv(cf, ef, sf, n++, 0, false, RoundingMode.implicit);
14496         coefficientDiv(cf, ef, sf, n++, 0, false, RoundingMode.implicit);
14497         coefficientAdd(cx, ex, sx, cf, ef, sf, RoundingMode.implicit);
14498         //writefln("%10d %10d %10d %10d", cx, ex, cy, ey);
14499     }
14500     while (!coefficientApproxEqu(cx, ex, sx, cy, ey, sy));
14501     return ExceptionFlags.inexact;
14502 }
14503 
14504 @safe pure nothrow @nogc
14505 ExceptionFlags coefficientSinCosQ(T)(const T cx, const int ex, const bool sx,
14506                                      out T csin, out int esin, out bool ssin,
14507                                      out T ccos, out int ecos, out bool scos)
14508 {
14509     csin = cx; esin = ex; ssin = sx;
14510     ccos = 1U; ecos = 0; scos = false;
14511     Unqual!T cs, cc; int es, ec; bool ss, sc;
14512 
14513     Unqual!T cf = cx; int ef = ex; bool sf = sx;
14514     Unqual!T n = 2U;
14515     do
14516     {
14517         cs = csin; es = esin; ss = ssin;
14518         cc = ccos; ec = ecos; sc = scos;
14519         coefficientMul(cf, ef, sf, cx, ex, !sx, RoundingMode.implicit);
14520         coefficientDiv(cf, ef, sf, n++, 0, false, RoundingMode.implicit);
14521         coefficientAdd(ccos, ecos, scos, cf, ef, sf, RoundingMode.implicit);
14522         coefficientMul(cf, ef, sf, cx, ex, sx, RoundingMode.implicit);
14523         coefficientDiv(cf, ef, sf, n++, 0, false, RoundingMode.implicit);
14524         coefficientAdd(csin, esin, ssin, cf, ef, sf, RoundingMode.implicit);
14525         //writefln("%10d %10d %10d %10d %10d %10d %10d %10d", csin, esin, cs, es, ccos, ecos, cc, ec);
14526     }
14527     while(!coefficientApproxEqu(csin, esin, ssin, cs, es, ss) &&
14528           !coefficientApproxEqu(ccos, ecos, scos, cc, ec, sc));
14529 
14530     return ExceptionFlags.inexact;
14531 }
14532 
14533 @safe pure nothrow @nogc
14534 ExceptionFlags coefficientCapAtan(T)(ref T cx, ref int ex, ref bool sx, out T reductions)
14535 {
14536     //half angle formula: atan(x/2) = 2 * atan(x/(1 + sqrt(1 +x^^2))))
14537     //reduce x = x / (sqrt(x * x + 1) + 1);
14538 
14539     reductions = 0U;
14540     while (coefficientCmp(cx, ex, T(1U), 0) >= 0)
14541     {
14542         Unqual!T cy = cx; int ey = ex; bool sy = false;
14543         coefficientSqr(cy, ey, RoundingMode.implicit);
14544         coefficientAdd(cy, ey, sy, T(1U), 0, false, RoundingMode.implicit);
14545         coefficientSqrt(cy, ey);
14546         coefficientAdd(cy, ey, sy, T(1U), 0, false, RoundingMode.implicit);
14547         coefficientDiv(cx, ex, sx, cy, ey, false, RoundingMode.implicit);
14548         ++reductions;
14549     }
14550 
14551     return ExceptionFlags.inexact;
14552 }
14553 
14554 @safe pure nothrow @nogc
14555 ExceptionFlags coefficientAtan(T)(ref T cx, ref int ex, bool sx)
14556 {
14557     //taylor series:
14558     //atan(x) = x - x^3/3 + x^5/5 - x^7/7 ...
14559 
14560     Unqual!T cx2 = cx; int ex2 = ex;
14561     coefficientSqr(cx2, ex2, RoundingMode.implicit);
14562 
14563     Unqual!T cy; int ey; bool sy;
14564 
14565     Unqual!T cxx = cx; int exx = ex; bool sxx = sx;
14566 
14567     Unqual!T n = 3U;
14568 
14569     do
14570     {
14571         cy = cx;
14572         ey = ex;
14573         sy = sx;
14574 
14575         coefficientMul(cxx, exx, sxx, cx2, ex2, true, RoundingMode.implicit);
14576         
14577         Unqual!T cf = cxx;
14578         int ef = exx;
14579         bool sf = sxx;
14580 
14581         coefficientDiv(cf, ef, sf, n, 0, false, RoundingMode.implicit);
14582         coefficientAdd(cx, ex, sx, cf, ef, sf, RoundingMode.implicit);
14583         n += 2U;
14584 
14585     }
14586     while (!coefficientApproxEqu(cx, ex, sx, cy, ey, sy));
14587     return ExceptionFlags.inexact;
14588 }
14589 
14590 ExceptionFlags coefficientFrac(T)(ref T cx, ref int ex)
14591 {
14592     if (ex >= 0)
14593     {
14594         cx = 0U;
14595         ex = 0;
14596         return ExceptionFlags.none;
14597     }
14598     auto p = prec(cx);
14599     if (ex < -p)
14600        return ExceptionFlags.none;
14601     cx %= pow10!T[-ex];    
14602     return ExceptionFlags.none;
14603 }
14604 
14605 ExceptionFlags coefficientMod2PI(T)(ref T cx, ref int ex)
14606 {
14607     ExceptionFlags flags;
14608     if (coefficientCmp(cx, ex, Constants!T.c2π, Constants!T.e2π) > 0)
14609     {
14610         bool sx = false;
14611         Unqual!T cy = cx;
14612         cx = get_mod2pi!T(ex);
14613         flags |= coefficientMul(cx, ex, sx, cy, 0, false, RoundingMode.implicit);
14614         flags |= coefficientFrac(cx, ex);
14615         flags |= coefficientMul(cx, ex, sx, Constants!T.c2π, Constants!T.e2π, false, RoundingMode.implicit);
14616     }
14617     return flags;
14618 }
14619 
14620 
14621 
14622 struct Constants(T)
14623 {
14624     
14625     
14626     static if (is(T:uint))
14627     {
14628         enum uint       c1_2π       = 1591549431U;
14629         enum int        e1_2π       = -10;
14630         enum uint       c2π         = 628318531U;
14631         enum int        e2π         = -8;
14632         enum uint       c2_π        = 636619772U;
14633         enum int        e2_π        = -9;
14634         enum uint       cπ_2        = 1570796327U;
14635         enum int        eπ_2        = -9;
14636         enum uint       chalf       = 5;
14637         enum int        ehalf       = -1;
14638         enum uint       cthird      = 3333333333;
14639         enum int        ethird      = -10;
14640         enum uint       ce          = 2718281828U;
14641         enum int        ee          = -9;
14642         enum uint       cln10       = 2302585093U;
14643         enum int        eln10       = -9;
14644     }
14645     else static if (is(T:ulong))
14646     {
14647         enum ulong      c1_2π       = 15915494309189533577UL;
14648         enum int        e1_2π       = -20;
14649         enum ulong      c2π         = 6283185307179586477UL;
14650         enum int        e2π         = -18;
14651         enum ulong      c2_π        = 6366197723675813431UL;
14652         enum int        e2_π        = -19;
14653         enum ulong      cπ_2        = 15707963267948966192UL;
14654         enum int        eπ_2        = -19;
14655         enum ulong      chalf       = 5;
14656         enum int        ehalf       = -1;
14657         enum ulong      cthird      = 3333333333333333333UL;
14658         enum int        ethird      = -19;
14659         enum ulong      ce          = 2718281828459045235UL;
14660         enum int        ee          = -18;
14661         enum ulong      cln10       = 2302585092994045684UL;
14662         enum int        eln10       = -18;
14663     }
14664     else static if (is(T:uint128))
14665     {
14666         enum uint128    c1_2π       = uint128("159154943091895335768883763372514362034");
14667         enum int        e1_2π       = -39;
14668         enum uint128    c2π         = uint128("62831853071795864769252867665590057684");
14669         enum int        e2π         = -37;
14670         enum uint128    c2_π        = uint128("63661977236758134307553505349005744814");
14671         enum int        e2_π        = -38;
14672         enum uint128    cπ_2        = uint128("157079632679489661923132169163975144210");
14673         enum int        eπ_2        = -38;
14674         enum uint128    chalf       = 5U;
14675         enum int        ehalf       = -1;
14676         enum uint128    cthird      = uint128("333333333333333333333333333333333333333");
14677         enum int        ethird      = -39;
14678         enum uint128    ce          = uint128("271828182845904523536028747135266249776");
14679         enum int        ee          = -38;
14680         enum uint128    cln10       = uint128("230258509299404568401799145468436420760");
14681         enum int        eln10       = -38;
14682     }
14683     else static if (is(T:uint256))
14684     {
14685         enum uint256    c1_2π       = uint256("15915494309189533576888376337251436203445964574045644874766734405889679763423");
14686         enum int        e1_2π       = -77;
14687         enum uint256    c2π         = uint256("62831853071795864769252867665590057683943387987502116419498891846156328125724");
14688         enum int        e2π         = -76;
14689         enum uint256    c2_π        = uint256("63661977236758134307553505349005744813783858296182579499066937623558719053691");
14690         enum int        e2_π        = -77;
14691         enum uint256    cπ_2        = uint256("15707963267948966192313216916397514420985846996875529104874722961539082031431");
14692         enum int        eπ_2        = -76;
14693         enum uint256    chalf       = 5U;
14694         enum int        ehalf       = -1;
14695         enum uint256    cthird      = uint256("33333333333333333333333333333333333333333333333333333333333333333333333333333");
14696         enum int        ethird      = -77;
14697         enum uint256    ce          = uint256("27182818284590452353602874713526624977572470936999595749669676277240766303536");
14698         enum int        ee          = -76;
14699         enum uint256    cln10       = uint256("23025850929940456840179914546843642076011014886287729760333279009675726096774");
14700         enum int        eln10       = -76;
14701     }
14702     else
14703         static assert(0);
14704 }
14705 
14706 enum
14707 {
14708     s_e             = "2.7182818284590452353602874713526625",
14709     s_pi            = "3.1415926535897932384626433832795029",
14710     s_pi_2          = "1.5707963267948966192313216916397514",
14711     s_pi_4          = "0.7853981633974483096156608458198757",
14712     s_m_1_pi        = "0.3183098861837906715377675267450287",
14713     s_m_2_pi        = "0.6366197723675813430755350534900574",
14714     s_m_2_sqrtpi    = "1.1283791670955125738961589031215452",
14715     s_sqrt2         = "1.4142135623730950488016887242096981",
14716     s_sqrt1_2       = "0.7071067811865475244008443621048490",
14717     s_ln10          = "2.3025850929940456840179914546843642",
14718     s_log2t         = "3.3219280948873623478703194294893902",
14719     s_log2e         = "1.4426950408889634073599246810018921",
14720     s_log2          = "0.3010299956639811952137388947244930",
14721     s_log10e        = "0.4342944819032518276511289189166051",
14722     s_ln2           = "0.6931471805599453094172321214581766",
14723 
14724     s_sqrt3         = "1.7320508075688772935274463415058723",
14725     s_m_sqrt3       = "0.5773502691896257645091487805019574",
14726     s_pi_3          = "1.0471975511965977461542144610931676",
14727     s_pi_6          = "0.5235987755982988730771072305465838",
14728 
14729     s_sqrt2_2       = "0.7071067811865475244008443621048490",
14730     s_sqrt3_2       = "0.8660254037844386467637231707529361",
14731     s_5pi_6         = "2.6179938779914943653855361527329190",
14732     s_3pi_4         = "2.3561944901923449288469825374596271",
14733     s_2pi_3         = "2.0943951023931954923084289221863352",
14734     s_onethird      = "0.3333333333333333333333333333333333",
14735     s_twothirds     = "0.6666666666666666666666666666666667",
14736     s_5_6           = "0.8333333333333333333333333333333333",
14737     s_1_6           = "0.1666666666666666666666666666666667",
14738     s_m_1_2pi       = "0.1591549430918953357688837633725144",
14739     s_pi2           = "6.2831853071795864769252867665590058",
14740 
14741     s_max_float     = "3.402823466385288598117041834845169e+0038",
14742     s_min_float     = "1.401298464324817070923729583289916e-0045",
14743     s_max_double    = "1.797693134862315708145274237317043e+0308",
14744     s_min_double    = "4.940656458412465441765687928682213e-0324",
14745     s_max_real      = "1.189731495357231765021263853030970e+4932",
14746     s_min_real      = "3.645199531882474602528405933619419e-4951",
14747     
14748 }
14749     //to find mod(10^n/2pi; 1): take digits[n .. n + precision], exponent -n 
14750     //example mod(10^3/2pi; 1): 1549430918953357688e-19, precision = 19
14751     //example mod(10^9/2pi; 1): 0918953357688837633e-19, precision = 19 = 918953357688837633[7]e-20
14752     //example mode(10^-8/2pi;1):0000000015915494309e-19, precision = 19 = 15915494309[18953357]e-27 
14753     //limit: 9866, that means nmax = 9866 - precision;
14754     //mod(c * 10^n mod 2pi) = frac(c * mod(10^n/2pi; 1)) * 2pi;
14755     //example for decimal32 -> mod(10^n/2pi; 1) => 19 digits
14756     //   c * mod(10^n/2pi; 1) => 19 + 7 = 26 digits => 
14757 
14758     immutable s_mod_1_2pi =  
14759         "15915494309189533576888376337251436203445964574045644874766734405889679763422653509011380276625308595607284" ~
14760         "27267579580368929118461145786528779674107316998392292399669374090775730777463969253076887173928962173976616" ~
14761         "93362390241723629011832380114222699755715940461890086902673956120489410936937844085528723099946443400248672" ~
14762         "34773945961089832309678307490616698646280469944865218788157478656696424103899587413934860998386809919996244" ~
14763         "28755851711788584311175187671605465475369880097394603647593337680593024944966353053271567755032203247778163" ~
14764         "97166022946748119598165840606016803035998133911987498832786654435279755070016240677564388849571310880122199" ~
14765         "37614768137776473789063306804645797848176131242731406996077502450029775985708905690279678513152521001631774" ~
14766         "60209248116062405614562031464840892484591914352115754075562008715266068022171591407574745827225977462853998" ~
14767         "75155329390813981772409358254797073328719040699975907657707849347039358982808717342564036689511662545705943" ~
14768         "32763126865002612271797115321125995043866794503762556083631711695259758128224941623334314510612353687856311" ~
14769         "36366921671420697469601292505783360531196085945098395567187099547465104316238155175808394429799709995052543" ~
14770         "87566129445883306846050785291515141040489298850638816077619699307341038999578691890598093737772061875432227" ~
14771         "18930136625526123878038753888110681406765434082827852693342679955607079038606035273899624512599574927629702" ~
14772         "35940955843011648296411855777124057544494570217897697924094903272947702166496035653181535440038406898747176" ~
14773         "91588763190966506964404776970687683656778104779795450353395758301881838687937766124814953059965580219083598" ~
14774         "75103512712904323158049871968687775946566346221034204440855497850379273869429353661937782928735937843470323" ~
14775         "02371458379235571186363419294601831822919641650087830793313534977909974586492902674506098936890945883050337" ~
14776         "03053805473123215809431976760322831314189809749822438335174356989847501039500683880039786723599608024002739" ~
14777         "01087495485478792356826113994890326899742708349611492082890377678474303550456845608367147930845672332703548" ~
14778         "53925562020868393240995622117533183940209707935707749654988086860663609686619670374745421028312192518462248" ~
14779         "34991161149566556037969676139931282996077608277990100783036002338272987908540238761557445430926011910054337" ~
14780         "99838904654921248295160707285300522721023601752331317317975931105032815510937391363964530579260718008361795" ~
14781         "48767246459804739772924481092009371257869183328958862839904358686666397567344514095036373271917431138806638" ~
14782         "30725923027597345060548212778037065337783032170987734966568490800326988506741791464683508281616853314336160" ~
14783         "73099514985311981973375844420984165595415225064339431286444038388356150879771645017064706751877456059160871" ~
14784         "68578579392262347563317111329986559415968907198506887442300575191977056900382183925622033874235362568083541" ~
14785         "56517297108811721795936832564885187499748708553116598306101392144544601614884527702511411070248521739745103" ~
14786         "86673640387286009967489317356181207117404788993688865569230784850230570571440636386320236852010741005748592" ~
14787         "28111572196800397824759530016695852212303464187736504354676464565659719011230847670993097085912836466691917" ~
14788         "76938791433315566506698132164152100895711728623842607067845176011134508006994768422356989624880515775980953" ~
14789         "39708085475059753626564903439445420581788643568304200031509559474343925254485067491429086475144230332133245" ~
14790         "69511634945677539394240360905438335528292434220349484366151466322860247766666049531406573435755301409082798" ~
14791         "80914786693434922737602634997829957018161964321233140475762897484082891174097478263789918169993948749771519" ~
14792         "89818726662946018305395832752092363506853889228468247259972528300766856937583659722919824429747406163818311" ~
14793         "39583067443485169285973832373926624024345019978099404021896134834273613676449913827154166063424829363741850" ~
14794         "61226108613211998633462847099418399427429559156283339904803821175011612116672051912579303552929241134403116" ~
14795         "13411249531838592695849044384680784909739828088552970451530539914009886988408836548366522246686240872540140" ~
14796         "40091178742122045230753347397253814940388419058684231159463227443390661251623931062831953238833921315345563" ~
14797         "81511752035108745955820112375435976815534018740739434036339780388172100453169182951948795917673954177879243" ~
14798         "52761740724605939160273228287946819364912894971495343255272359165929807247998580612690073321884452679433504" ~
14799         "55801952492566306204876616134365339920287545208555344144099051298272745465911813222328405116661565070983755" ~
14800         "74337295486312041121716380915606161165732000083306114606181280326258695951602463216613857661480471993270777" ~
14801         "13164412015949601106328305207595834850305079095584982982186740289838551383239570208076397550429225984764707" ~
14802         "10164269743845043091658645283603249336043546572375579161366324120457809969715663402215880545794313282780055" ~
14803         "24613208890187421210924489104100521549680971137207540057109634066431357454399159769435788920793425617783022" ~
14804         "23701148642492523924872871313202176673607566455982726095741566023437874362913210974858971507130739104072643" ~
14805         "54141797057222654798038151275957912400253446804822026173422990010204830624630337964746781905018118303751538" ~
14806         "02879523433419550213568977091290561431787879208620574499925789756901849210324206471385191138814756402097605" ~
14807         "54895793785141404145305151583964282326540602060331189158657027208625026991639375152788736060811455694842103" ~
14808         "22407772727421651364234366992716340309405307480652685093016589213692141431293713410615715371406203978476184" ~
14809         "26502978078606266969960809184223476335047746719017450451446166382846208240867359510237130290444377940853503" ~
14810         "44544263341306263074595138303102293146934466832851766328241515210179422644395718121717021756492196444939653" ~
14811         "22221876584882445119094013405044321398586286210831793939608443898019147873897723310286310131486955212620518" ~
14812         "27806349457118662778256598831005351552316659843940902218063144545212129789734471488741258268223860236027109" ~
14813         "98119152056882347239835801336606837863288679286197323672536066852168563201194897807339584191906659583867852" ~
14814         "94124187182172798750610394606481958574562006089212284163943738465495899320284812364334661197073243095458590" ~
14815         "73361878629063185016510626757685121635758869630745199922001077667683094698149756226824347936713108412102195" ~
14816         "20899481912444048751171059184413990788945577518462161904153093454380280893862807323757861526779711433232419" ~
14817         "69857805637630180884386640607175368321362629671224260942854011096321826276512011702255292928965559460820493" ~
14818         "84090690760692003954646191640021567336017909631872891998634341086903200579663710312861235698881764036425254" ~
14819         "08370981081483519031213186247228181050845123690190646632235938872454630737272808789830041018948591367374258" ~
14820         "94181240567291912380033063449982196315803863810542457893450084553280313511884341007373060595654437362488771" ~
14821         "29262898074235390740617869057844431052742626417678300582214864622893619296692992033046693328438158053564864" ~
14822         "07318444059954968935377318367266131301086235880212880432893445621404797894542337360585063270439981932635916" ~
14823         "68734194365678390128191220281622950033301223609185875592019590812241536794990954488810997589198908115811635" ~
14824         "38891633940292372204984837522423620910083409756679171008416795702233178971071029288848970130995339954244153" ~
14825         "35060625843921452433864640343244065731747755340540448100617761256908474646143297654390000838265211452101623" ~
14826         "66431119798731902751191441213616962045693602633610235596214046702901215679641873574683587317233100474596333" ~
14827         "97732477044918885134415363760091537564267438450166221393719306748706288159546481977519220771023674328906269" ~
14828         "07091179194127762122451172354677115640433357720616661564674474627305622913332030953340551384171819460532150" ~
14829         "14263280008795518132967549728467018836574253425016994231069156343106626043412205213831587971115075454063290" ~
14830         "65702484886486974028720372598692811493606274038423328749423321785787750735571857043787379693402336902911446" ~
14831         "96144864976971943452746744296030894371925405266588907106620625755099303799766583679361128137451104971506153" ~
14832         "78374357955586797212935876446309375720322132024605656611299713102758691128460432518434326915529284585734959" ~
14833         "71504256539930211218494723213238051654980290991967681511802248319251273721997921343310676421874844262159851" ~
14834         "21676396779352982985195854539210695788058685312327754543322916198905318905372539158222292325972781334278182" ~
14835         "56064882333760719681014481453198336237910767125501752882635183649210357258741035657389469487544469401817592" ~
14836         "30609370828146501857425324969212764624247832210765473750568198834564103545802726125228550315432503959184891" ~
14837         "89826304987591154063210354263890012837426155187877318375862355175378506956599570028011584125887015003017025" ~
14838         "91674630208424124491283923805257725147371412310230172563968305553583262840383638157686828464330456805994018" ~
14839         "70010719520929701779905832164175798681165865471477489647165479488312140431836079844314055731179349677763739" ~
14840         "89893022776560705853040837477526409474350703952145247016838840709087061471944372256502823145872995869738316" ~
14841         "89712685193904229711072135075697803726254581410950382703889873645162848201804682882058291353390138356491443" ~
14842         "00401570650988792671541745070668688878343805558350119674586234080595327247278438292593957715840368859409899" ~
14843         "39255241688378793572796795165407667392703125641876096219024304699348598919906001297774692145329704216778172" ~
14844         "61517850653008552559997940209969455431545274585670440368668042864840451288118230979349696272183649293551620" ~
14845         "29872469583299481932978335803459023227052612542114437084359584944338363838831775184116088171125127923337457" ~
14846         "72193398208190054063292937775306906607415304997682647124407768817248673421685881509913342207593094717385515" ~
14847         "93408089571244106347208931949128807835763115829400549708918023366596077070927599010527028150868897828549434" ~
14848         "03726427292621034870139928688535500620615143430786653960859950058714939141652065302070085265624074703660736" ~
14849         "60533380526376675720188394972770472221536338511354834636246198554259938719333674820422097449956672702505446" ~
14850         "42324395750686959133019374691914298099934242305501726652120924145596259605544275909519968243130842796937113" ~
14851         "2070210498232381957459";
14852 
14853 U get_mod2pi(U)(ref int power)
14854 {
14855     static if (is(U: uint))
14856         enum int digits = 9;
14857     else static if (is(U: ulong))
14858         enum int digits = 19;
14859     else static if (is(U: uint128))
14860         enum int digits = 38;
14861     else static if (is(U: uint256))
14862         enum digits = 77;
14863     else
14864         static assert (0, "Unsupported" ~ U.stringof);
14865 
14866     if (power >= 0)
14867     {
14868         auto p = power;
14869         while (s_mod_1_2pi[p] == '0')
14870             ++p;
14871         string s =  s_mod_1_2pi[p .. p + digits];
14872         
14873         U result = uparse!U(s);
14874         power = -digits - (p - power);
14875         return result;
14876     }
14877     else
14878     {
14879         string s = s_mod_1_2pi[0 .. digits];
14880         U result = uparse!U(s);
14881         power -= digits;
14882         return result;
14883     }   
14884 }
14885 
14886 
14887 struct IEEECompliant
14888 {
14889     string name;
14890     int page;
14891 }
14892 
14893 D parse(D, R)(ref R range)
14894 if (isInputRange!R && isSomeChar!(ElementType!R) && isDecimal!D)
14895 {
14896     Unqual!D result;
14897     auto flags = parse(range, result, D.realPrecision(DecimalControl.precision), DecimalControl.rounding);
14898     if (flags)
14899         DecimalControl.raiseFlags(flags);
14900 }
14901 
14902 //10 bit encoding
14903 @safe pure nothrow @nogc
14904 private uint packDPD(const uint d1, const uint d2, const uint d3)
14905 {
14906     uint x = ((d1 & 8) >>> 1) | ((d2 & 8) >>> 2) | ((d3 & 8) >>> 3);
14907 
14908     switch(x)
14909     {
14910         case 0: 
14911             return (d1 << 7) | (d2 << 4) | d3;
14912         case 1:
14913             return (d1 << 7) | (d2 << 4) | (d3 & 1) | 8;
14914         case 2:
14915             return (d1 << 7) | ((d3 & 6) << 4) | ((d2 & 1) << 4) | (d3 & 1) | 10;
14916         case 3:
14917             return (d1 << 7) | ((d2 & 1) << 4) | (d3 & 1) | 78;
14918         case 4:
14919             return ((d3 & 6) << 7) | ((d1 & 1) << 7) | (d2 << 4) | (d3 & 1) | 12;
14920         case 5:
14921             return ((d2 & 6) << 7) | ((d1 & 1) << 7) | ((d2 & 1) << 4) | (d3 & 1) | 46;
14922         case 6:
14923             return ((d3 & 6) << 7) | ((d1 & 1) << 7) | ((d2 & 1) << 4) | (d3 & 1) | 14;
14924         case 7:
14925             return ((d1 & 1) << 7) | ((d2 & 1) << 4) | (d3 & 1) | 110;
14926         default:
14927             assert(0);
14928     }
14929 }
14930 
14931 //10 bit decoding
14932 @safe pure nothrow @nogc
14933 private void unpackDPD(const uint declet, out uint d1, out uint d2, out uint d3)
14934 {
14935     uint x = declet & 14;
14936     uint decoded;
14937     switch (x)
14938     {
14939         case 0:
14940             decoded = ((declet & 896) << 1) | (declet & 119);
14941             break;
14942         case 1:
14943             decoded = ((declet & 128) << 1) | (declet & 113) | ((declet & 768) >> 7) | 2048;
14944             break;
14945         case 2: 
14946             decoded = ((declet & 896) << 1) | (declet & 17) | ((declet & 96) >> 4) | 128;
14947             break;
14948         case 3:
14949             decoded = ((declet & 896) << 1) | (declet & 113) | 8;
14950             break;
14951         case 4: 
14952             decoded = ((declet & 128) << 1) | (declet & 17) | ((declet & 768) >> 7) | 2176;
14953             break;
14954         case 5:
14955             decoded = ((declet & 128) << 1) | (declet & 17) | ((declet & 768) >> 3) | 2056;
14956             break;
14957         case 6:
14958             decoded = ((declet & 896) << 1) | (declet & 17) | 136;
14959             break;
14960         case 7: 
14961             decoded = ((declet & 128) << 1) | (declet & 17) | 2184;
14962             break;
14963         default:
14964             assert(0);
14965     }
14966 
14967     d1 = (decoded & 3840) >> 8;
14968     d2 = (decoded & 240) >> 4;
14969     d3 = (decoded & 15);
14970 }