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 }