1 // Written in the D programming language. 2 3 /** 4 5 IEEE 754-2008 implementation of _decimal floating point data types. 6 _Decimal values are represented in memory using an $(B integral coefficient) and a $(B 10-based exponent). 7 Implementation is based on 8 $(LINK2 https://en.wikipedia.org/wiki/Binary_Integer_Decimal, binary integer _decimal encoding), supported by Intel. 9 10 _Decimal data types use the same semantics as the built-in floating point data type (NaNs, infinities, etc.), 11 the main difference being that they use internally a 10 exponent instead of a 2 exponent. 12 13 The current implementation supports three _decimal data types, as specified by IEEE 754-2008 standard. 14 The supported types are: $(MYREF decimal32), $(MYREF decimal64) and $(MYREF decimal128), but they can be easily extended 15 to other bit widths if a underlying unsigned integral type is provided. 16 17 _Decimal data types are best used in financial applications because arithmetic operation results are exact. 18 19 $(SCRIPT inhibitQuickIndex = 1;) 20 $(DIVC quickindex, 21 $(BOOKTABLE , 22 $(TR $(TH Category) $(TH Members) ) 23 $(TR $(TDNW Classics) $(TD 24 $(MYREF copysign) $(MYREF fabs) $(MYREF fdim) 25 $(MYREF fmod) $(MYREF fma) $(MYREF getNaNPayload) 26 $(MYREF modf) $(MYREF NaN) 27 $(MYREF nextAfter) 28 $(MYREF nextDown) $(MYREF nextToward) $(MYREF nextUp) $(MYREF remainder) $(MYREF sgn) 29 )) 30 $(TR $(TDNW Comparison) $(TD 31 $(MYREF approxEqual) 32 $(MYREF cmp) 33 $(MYREF fmax) $(MYREF fmaxAbs) $(MYREF fmin) $(MYREF fminAbs) 34 $(MYREF isEqual) $(MYREF isGreater) $(MYREF isGreaterOrEqual) $(MYREF isGreaterOrUnordered) 35 $(MYREF isIdentical) 36 $(MYREF isLess) $(MYREF isLessOrEqual) $(MYREF isLessOrUnordered) 37 $(MYREF isNotEqual) 38 $(MYREF isUnordered) 39 $(MYREF sameQuantum) 40 $(MYREF totalOrder) $(MYREF totalOrderAbs) 41 )) 42 $(TR $(TDNW Conversion) $(TD 43 $(MYREF fromDPD) $(MYREF fromMsCurrency) $(MYREF fromMsDecimal) $(MYREF to) $(MYREF toDPD) $(MYREF toExact) 44 $(MYREF toMsCurrency) $(MYREF toMsDecimal) 45 )) 46 $(TR $(TDNW Data types) $(TD 47 $(MYREF Decimal) $(MYREF decimal32) $(MYREF decimal64) $(MYREF decimal128) 48 $(MYREF DecimalClass) $(MYREF DecimalControl) $(MYREF ExceptionFlags) $(MYREF Precision) 49 $(MYREF RoundingMode) 50 )) 51 $(TR $(TDNW Exceptions) $(TD 52 $(MYREF DecimalException) $(MYREF DivisionByZeroException) 53 $(MYREF InexactException) $(MYREF InvalidOperationException) 54 $(MYREF OverflowException) $(MYREF UnderflowException) 55 )) 56 $(TR $(TDNW Exponentiations & logarithms) $(TD 57 $(MYREF cbrt) $(MYREF compound) 58 $(MYREF exp) $(MYREF exp10) $(MYREF exp10m1) $(MYREF exp2) $(MYREF exp2m1) $(MYREF expm1) $(MYREF frexp) 59 $(MYREF ilogb) $(MYREF ldexp) $(MYREF log) $(MYREF log10) $(MYREF log10p1) $(MYREF log2) $(MYREF log2p1) 60 $(MYREF logp1) $(MYREF nextPow10) $(MYREF pow) $(MYREF quantexp) $(MYREF root) 61 $(MYREF rsqrt) $(MYREF scalbn) $(MYREF sqrt) 62 $(MYREF truncPow10) 63 )) 64 $(TR $(TDNW Introspection) $(TD 65 $(MYREF decimalClass) 66 $(MYREF isCanonical) $(MYREF isFinite) $(MYREF isInfinity) $(MYREF isNaN) $(MYREF isNormal) 67 $(MYREF isPowerOf10) $(MYREF isSignaling) $(MYREF isSubnormal) $(MYREF isZero) 68 $(MYREF signbit) 69 )) 70 $(TR $(TDNW Reduction) $(TD 71 $(MYREF dot) $(MYREF poly) $(MYREF scaledProd) $(MYREF scaledProdSum) $(MYREF scaledProdDiff) 72 $(MYREF sum) $(MYREF sumAbs) $(MYREF sumSquare) 73 )) 74 $(TR $(TDNW Rounding) $(TD 75 $(MYREF ceil) $(MYREF floor) $(MYREF lrint) $(MYREF lround) $(MYREF nearbyint) $(MYREF quantize) $(MYREF rint) 76 $(MYREF rndtonl) $(MYREF round) $(MYREF trunc) 77 )) 78 $(TR $(TDNW Trigonometry) $(TD 79 $(MYREF acos) $(MYREF acosh) $(MYREF asin) $(MYREF asinh) $(MYREF atan) $(MYREF atan2) $(MYREF atan2pi) 80 $(MYREF atanh) $(MYREF atanpi) $(MYREF cos) $(MYREF cosh) $(MYREF cospi) 81 $(MYREF hypot) $(MYREF sin) $(MYREF sinh) $(MYREF sinpi) $(MYREF tan) $(MYREF tanh) 82 )) 83 84 85 ) 86 ) 87 88 89 Context: 90 91 All arithmetic operations are performed using a $(U thread local context). The context is setting various 92 environment options: 93 $(UL 94 $(LI $(B precision) - number of digits used. Each _decimal data type has a default precision and all the calculations 95 are performed using this precision. Setting the precision to a custom value will affect 96 any subsequent operation and all the calculations will be performed using the specified 97 number of digits. See $(MYREF Precision) for details;) 98 $(LI $(B rounding) - rounding method used to adjust operation results. If a result will have more digits than the 99 current context precision, it will be rounded using the specified method. For available rounding 100 modes, see $(MYREF RoundingMode);) 101 $(LI $(B flags) - error flags. Every _decimal operation may signal an error. The context will gather these errors 102 for later introspection. See $(MYREF ExceptionFlags) for details;) 103 $(LI $(B traps) - exception traps. Any error flag which is set may trigger a $(MYREF DecimalException) if 104 the corresponding trap is installed. See $(MYREF ExceptionFlags) for details;) 105 ) 106 107 Operators: 108 109 All floating point operators are implemented. Binary operators accept as left or right side argument any _decimal, 110 integral, character or binary floating point value. 111 112 Initialization: 113 114 Creating _decimal floating point values can be done in several ways: 115 $(UL 116 $(LI by assigning a binary floating point, integral, char, bool, string or character range (including strings) value: 117 --- 118 decimal32 d = 123; 119 decimal64 e = 12.34; 120 decimal128 f = "24.9"; 121 decimal32 g = 'Y'; 122 decimal32 h = true; 123 --- 124 ) 125 $(LI by using one of the available contructors. 126 Suported type are binary floating point, integrals, chars, bool, strings or character ranges: 127 --- 128 auto d = decimal32(7500); 129 auto e = decimal64(52.16); 130 auto f - decimal128("199.4E-12"); 131 auto g = decimal32('a'); 132 auto h = decimal32(false); 133 --- 134 ) 135 $(LI using one of predefined constants: 136 --- 137 auto d = decimal32.nan; 138 auto e = decimal64.PI; 139 auto f - decimal128.infinity; 140 --- 141 ) 142 ) 143 144 Error_handling: 145 146 Errors occuring in arithmetic operations using _decimal values can be handled in two ways. By default, the thread local 147 context will throw exceptions for errors considered severe ($(MYREF InvalidOperationException), 148 $(MYREF DivisionByZeroException) or $(MYREF OverflowException)). 149 Any other error is considered silent and the context will only 150 set corresponding error flags ($(MYREF ExceptionFlags.inexact) or $(MYREF ExceptionFlags.underflow))<br/> 151 Most of the operations will throw $(MYREF InvalidOperationException) if a $(B signaling NaN) is encountered, 152 if not stated otherwise in the documentation. This behaviour is intended in order to avoid usage of unitialized variables 153 (_decimal values being by default always initialized to $(B signaling NaN)) 154 --- 155 //these will throw: 156 auto a = decimal32() + 12; //InvalidOperationException 157 auto b = decimal32.min / 0; //DivisionByZeroException 158 auto c = decimal32.max * 2; //OverflowException 159 160 //these will not throw: 161 auto d = decimal32(123456789); //inexact 162 auto e = decimal32.min_normal / decimal32.max; //underflow 163 --- 164 165 Default behaviour can be altered using $(MYREF DecimalControl) by setting or clearing corresponding traps: 166 --- 167 DecimalControl.disableExceptions(ExceptionFlags.overflow) 168 //from now on OverflowException will not be thrown; 169 170 DecimalControl.enableExceptions(ExceptionFlags.inexact) 171 //from now on InexactException will be thrown 172 --- 173 174 $(UL 175 $(LI Catching exceptions) 176 --- 177 try 178 { 179 auto a = decimal32.min / 0; 180 } 181 catch (DivisionByZeroException) 182 { 183 //error occured 184 } 185 --- 186 $(LI Checking for errors) 187 --- 188 DecimalControl.disableExceptions(ExceptionFlags.divisionByZero) 189 DecimalControl.resetFlags(); 190 auto a = decimal32.min / 0; 191 if (DecimalControl.divisionByZero) 192 { 193 //error occured 194 } 195 --- 196 ) 197 198 Exceptions_and_results: 199 200 Values returned after an exception is thrown or after an error flag is set, depend on the current $(MYREF RoundingMode). 201 202 $(BOOKTABLE, 203 $(TR $(TH Exception) $(TH tiesToEven) $(TH tiesToAway) $(TH towardPositive) $(TH towardNegative) $(TH towardZero)) 204 $(TR $(TD $(MYREF OverflowException)) $(TD +∞) $(TD +∞) $(TD +∞) $(TD $(B +max)) $(TD $(B +max)) ) 205 $(TR $(TD $(MYREF OverflowException)) $(TD -∞) $(TD -∞) $(TD $(B -max)) $(TD -∞) $(TD $(B -max)) ) 206 $(TR $(TD $(MYREF UnderflowException)) $(TD ±0.0) $(TD ±0.0) $(TD $(B +min_normal * epsilon)) $(TD $(B -min_normal * epsilon)) $(TD ±0.0) ) 207 $(TR $(TD $(MYREF DivisionByZeroException)) $(TD ±∞) $(TD ±∞) $(TD ±∞) $(TD ±∞) $(TD ±∞) ) 208 $(TR $(TD $(MYREF InvalidOperationException)) $(TD $(B NaN)) $(TD $(B NaN)) $(TD $(B NaN)) $(TD $(B NaN)) $(TD $(B NaN)) ) 209 ) 210 211 $(MYREF InexactException) does not have a specific value associated. 212 213 The subnormal exception is not implemented because it is not part of the IEEE-754-2008 standard. 214 If an operation results in a subnormal value (absolute value is smaller than $(B min_normal)), 215 $(MYREF UnderflowException) is always thrown or $(MYREF ExceptionFlag.underflow) is always set. It's better to avoid 216 subnormal values when performing calculations, the results of the operations involving such values are not exact. 217 218 219 Properties: 220 221 The following properties are defined for each _decimal type: 222 223 $(BOOKTABLE, 224 $(TR $(TH Constant) $(TH Name) $(TH decimal32) $(TH decimal64) $(TH decimal128)) 225 $(TR $(TD $(D init)) $(TD initial value) $(TD $(B signaling NaN)) $(TD $(B signaling NaN)) $(TD $(B signaling NaN))) 226 $(TR $(TD $(D nan)) $(TD Not a Number) $(TD $(B NaN)) $(TD $(B NaN)) $(TD $(B NaN))) 227 $(TR $(TD $(D infinity)) $(TD positive infinity) $(TD +∞) $(TD +∞) $(TD +∞)) 228 $(TR $(TD $(D dig)) $(TD precision) $(TD 7) $(TD 16) $(TD 34)) 229 $(TR $(TD $(D epsilon)) $(TD smallest increment to the value 1) $(TD 10$(SUPERSCRIPT-6)) $(TD 10$(SUPERSCRIPT-15)) $(TD 10$(SUPERSCRIPT-33))) 230 $(TR $(TD $(D mant_dig)) $(TD number of bits in mantissa) $(TD 24) $(TD 54) $(TD 114)) 231 $(TR $(TD $(D max_10_exp)) $(TD maximum int value such that 10$(SUPERSCRIPT max_10_exp) is representable) $(TD 96) $(TD 384) $(TD 6144)) 232 $(TR $(TD $(D min_10_exp)) $(TD minimum int value such that 10$(SUPERSCRIPT min_10_exp) is representable and normalized) $(TD -95) $(TD -383) $(TD -6143)) 233 $(TR $(TD $(D max_2_exp)) $(TD maximum int value such that 2$(SUPERSCRIPT max_2_exp) is representable) $(TD 318) $(TD 1275) $(TD 20409)) 234 $(TR $(TD $(D min_2_exp)) $(TD minimum int value such that 2$(SUPERSCRIPT min_2_exp) is representable and normalized) $(TD -315) $(TD -1272) $(TD -20406)) 235 $(TR $(TD $(D max)) $(TD largest representable value that's not infinity) $(TD 9.(9) * 10$(SUPERSCRIPT 96)) $(TD 9.(9) * 10$(SUPERSCRIPT 384)) $(TD 9.(9) * 10$(SUPERSCRIPT 6144))) 236 $(TR $(TD $(D min_normal)) $(TD smallest normalized value that's not 0) $(TD 10$(SUPERSCRIPT -95)) $(TD 10$(SUPERSCRIPT -383)) $(TD 10$(SUPERSCRIPT -6143))) 237 ) 238 239 240 Useful_constants: 241 242 There are common constants defined for each type. Values int the tablebelow have 34 digits of precision corresponding 243 to decimal128 data type; for decimal64 and decimal32, they are rounded away from 0 according to their respecive precision. 244 --- 245 auto a = decimal32.PI; 246 auto b = decimal64.LN2; 247 auto c = decimal128.E; 248 --- 249 250 $(BOOKTABLE, 251 $(TR $(TH Constant) $(TH Formula) $(TH Value)) 252 $(TR $(TD $(D E)) $(TD e) $(TD 2.7182818284590452353602874713526625)) 253 $(TR $(TD $(D PI)) $(TD π) $(TD 3.1415926535897932384626433832795029)) 254 $(TR $(TD $(D PI_2)) $(TD π/2) $(TD 1.5707963267948966192313216916397514)) 255 $(TR $(TD $(D PI_4)) $(TD π/4) $(TD 0.7853981633974483096156608458198757)) 256 $(TR $(TD $(D M_1_PI)) $(TD 1/π) $(TD 0.3183098861837906715377675267450287)) 257 $(TR $(TD $(D M_2_PI)) $(TD 2/π) $(TD 0.6366197723675813430755350534900574)) 258 $(TR $(TD $(D M_2_SQRTPI)) $(TD 2/√π) $(TD 1.1283791670955125738961589031215452)) 259 $(TR $(TD $(D SQRT2)) $(TD √2) $(TD 1.4142135623730950488016887242096981)) 260 $(TR $(TD $(D SQRT1_2)) $(TD √½) $(TD 0.7071067811865475244008443621048490)) 261 $(TR $(TD $(D LN10)) $(TD log$(SUBSCRIPT e)10) $(TD 2.3025850929940456840179914546843642)) 262 $(TR $(TD $(D LOG2T)) $(TD log$(SUBSCRIPT 2)10) $(TD 3.3219280948873623478703194294893902)) 263 $(TR $(TD $(D LOG2E)) $(TD log$(SUBSCRIPT 2)e) $(TD 1.4426950408889634073599246810018921)) 264 $(TR $(TD $(D LOG2)) $(TD log$(SUBSCRIPT 10)2) $(TD 0.3010299956639811952137388947244930)) 265 $(TR $(TD $(D LOG10E)) $(TD log$(SUBSCRIPT 10)e) $(TD 0.4342944819032518276511289189166051)) 266 $(TR $(TD $(D LN2)) $(TD log$(SUBSCRIPT e)2) $(TD 0.6931471805599453094172321214581766)) 267 ) 268 269 Interaction_with_binary_floating_point: 270 271 Even all _decimal operations allows the usage of binary floating point values, such mixing must be avoided; 272 Internally, binary floating point values are converted to _decimal counterparts before any operation: 273 --- 274 float f = 1.1; 275 decimal32 d = "2.5"; 276 decimal32 e = d + f; 277 //behind the scene this is roughly equivalent with e = d + decimal32(f); 278 --- 279 280 It is impossible to represent binary floating point values in full _decimal precision. 281 By default, $(B float) values are converted using 9 digits of precision, $(B double) values using 17 digits of precision and $(B real) values using 21 digits of precision; 282 --- 283 float f = 1.1; //internal representation is 1.10000002384185791015625; 284 decimal32 d1 = d; //1.100000, 9 digits from float, but decimal32 has a 7 digits precision 285 decimal64 d2 = d; //1.10000002000000, 9 digits from float 286 decimal128 d3 = d; //1.10000002000000000000000000000000, 9 digits from float; 287 --- 288 289 An exact conversion is possible only if the binary floating point value is an exact power of 2 290 and fits in the destination type precision or if it's a power of 5. 291 --- 292 float f = 4.0; //internally represented as 1.0 * 2^^2 293 decimal32 d = f; //internally represented as 0.4 * 10^^1 294 295 float f = 25.0; //internally represented as 1.5625 * 2^^4 296 decimal32 d = f; //internally represented as 0.25 * 10^^2 297 298 float f = 2147483648; //internally represented as 1.0 * 2^^31 299 decimal32 d = f; //inexact, internally represented as 0.2147484 * 10^^7 300 --- 301 302 Binary floating point conversion is dependent on the $(MYREF RoundingMode): 303 --- 304 double d = 2.7; //internal representation is 2.7000000476837158203125; 305 DecimalControl.rounding = RoundingMode.tiesToAway; 306 decimal64 d1 = d; //d1 will be 2.700000047683716; 307 DecimalControl.rounding = RoundingMode.towardZero; 308 decimal64 d2 = d; //d2 will be 2.700000047683715; 309 --- 310 311 Only Intel 80-bit $(B reals) are supported. Any other $(B real) type is cast to $(B double) before any conversion. 312 313 Special_remarks: 314 315 $(UL 316 $(LI As stated above, avoid mixing binary floating point values with _decimal values, binary foating point values cannot exactly represent 10-based exponents;) 317 $(LI There are many representations for the same number (IEEE calls them cohorts). Comparing bit by bit two _decimal values is error prone;) 318 $(LI The comparison operator will return float.nan for an unordered result; There is no operator overloading for unordered comparisons;) 319 $(LI Hexadecimal notation allows to define uncanonical coefficients (> 10 $(SUPERSCRIPT $(B dig)) - 1). According to IEEE standard, these values are considered equal to 0;) 320 $(LI All operations are available at compile time; Avoid exponential or trigonometry functions in CTFE, using them will significantly increase the compile time;) 321 $(LI Under CTFE, operations are performed in full precision, values are rounded to nearest. $(MYREF InexactException) and $(MYREF UnderflowException) are never thrown during CTFE;) 322 ) 323 324 Performance_tips: 325 326 $(UL 327 $(LI When performing _decimal calculations, avoid binary floating point; 328 conversion base-2 from/to base-10 is costly and error prone, especially if the exponents are very big or very small;) 329 $(LI Avoid custom precisions; rounding is expensive since most of the time will involve a division operation;) 330 $(LI Use $(MYREF decimal128) only if you truly need 34 digits of precision. $(MYREF decimal64) and $(MYREF decimal32) arithmetic is much faster;) 331 $(LI Avoid traps and check yourself for flags; throwing and catching exceptions is expensive;) 332 $(LI Contrary to usual approach, multiplication/division by 10 for _decimal values is faster than multiplication/division by 2;) 333 ) 334 335 336 Copyright: Copyright (c) Răzvan Ștefănescu 2018. 337 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 338 Authors: Răzvan Ștefănescu 339 Source: $(LINK2 https://github.com/rumbu13/decimal/blob/master/src/package.d, _decimal.d) 340 341 */ 342 module decimal.decimal; 343 344 public import std.traits: isIntegral, isFloatingPoint, isSomeChar, isSomeString; 345 public import std.format: FormatSpec, FormatException; 346 public import std.range.primitives: isInputRange, ElementType; 347 348 349 version(Windows) 350 { 351 public import core.sys.windows.wtypes: DECIMAL; 352 } 353 else 354 { 355 struct DECIMAL { 356 ushort wReserved; 357 struct { 358 ubyte scale; 359 ubyte sign; 360 enum ubyte DECIMAL_NEG = 0x80; 361 } 362 uint Hi32; 363 union { 364 struct { 365 uint Lo32; 366 uint Mid32; 367 } 368 ulong Lo64; 369 } 370 } 371 } 372 373 private import decimal.integrals; 374 private import decimal.floats; 375 private import decimal.ranges; 376 377 private alias fma = decimal.integrals.fma; 378 379 version(D_BetterC) 380 { 381 382 } 383 else 384 { 385 private import decimal.sinks; 386 } 387 388 private import std.traits: Unqual, isUnsigned, Unsigned, isSigned; 389 private import core.checkedint: adds, subs; 390 private import std.math: isNaN, isInfinity, signbit, ieeeFlags, FloatingPointControl, resetIeeeFlags, ldexp, getNaNPayload; 391 private import std.format: singleSpec; 392 393 394 395 396 version (unittest) 397 { 398 import std.typetuple; 399 import std.stdio; 400 import std.format; 401 } 402 403 /** 404 _Decimal floating-point computer numbering format that occupies 4, 8 or 16 bytes in computer memory. 405 */ 406 struct Decimal(int bits) if (bits == 32 || bits == 64 || bits == 128) 407 { 408 private: 409 alias D = typeof(this); 410 alias U = DataType!D; 411 412 U data = MASK_SNAN; 413 414 enum expBits = bits / 16 + 6; //8, 10, 14 415 enum trailingBits = bits - expBits - 1; //23, 53, 113 416 enum PRECISION = 9 * bits / 32 - 2; //7, 16, 34 417 enum EMAX = 3 * (2 ^^ (bits / 16 + 3)); //96, 384, 6144 418 419 enum SHIFT_EXP1 = trailingBits; //23, 53, 113 420 enum SHIFT_EXP2 = trailingBits - 2; //21, 51, 111 421 422 enum EXP_BIAS = EMAX + PRECISION - 2; //101, 398, 6176 423 enum EXP_MIN = -EXP_BIAS; 424 enum EXP_MAX = EMAX - PRECISION + 1; //90, 369, 6111 425 426 enum MASK_QNAN = U(0b01111100U) << (bits - 8); 427 enum MASK_SNAN = U(0b01111110U) << (bits - 8); 428 enum MASK_SNANBIT = U(0b00000010U) << (bits - 8); 429 enum MASK_INF = U(0b01111000U) << (bits - 8); 430 enum MASK_SGN = U(0b10000000U) << (bits - 8); 431 enum MASK_EXT = U(0b01100000U) << (bits - 8); 432 enum MASK_EXP1 = ((U(1U) << expBits) - 1U) << SHIFT_EXP1; 433 enum MASK_EXP2 = ((U(1U) << expBits) - 1U) << SHIFT_EXP2; 434 enum MASK_COE1 = ~(MASK_SGN | MASK_EXP1); 435 enum MASK_COE2 = ~(MASK_SGN | MASK_EXP2 | MASK_EXT); 436 enum MASK_COEX = U(1U) << trailingBits; 437 enum MASK_ZERO = U(cast(uint)EXP_BIAS) << SHIFT_EXP1; 438 enum MASK_PAYL = (U(1U) << (trailingBits - 3)) - 1U; 439 enum MASK_NONE = U(0U); 440 441 442 enum COEF_MAX = pow10!U[PRECISION] - 1U; 443 enum PAYL_MAX = pow10!U[PRECISION - 1] - 1U; 444 445 enum LOG10_2 = 0.30102999566398119521L; 446 447 @nogc nothrow pure @safe 448 this(const U signMask, const U expMask, const U coefMask) 449 { 450 this.data = signMask | expMask | coefMask; 451 } 452 453 @nogc nothrow pure @safe 454 this(const U coefficient, const int exponent, const bool isNegative) 455 { 456 pack(coefficient, exponent, isNegative); 457 } 458 459 //packs valid components 460 @nogc nothrow pure @safe 461 void pack(const U coefficient, const int exponent, const bool isNegative) 462 in 463 { 464 assert (coefficient <= (MASK_COE2 | MASK_COEX)); 465 assert (exponent >= EXP_MIN && exponent <= EXP_MAX); 466 } 467 out 468 { 469 assert ((this.data & MASK_INF) != MASK_INF); 470 } 471 body 472 { 473 U expMask = U(cast(uint)(exponent + EXP_BIAS)); 474 U sgnMask = isNegative ? MASK_SGN : MASK_NONE; 475 476 if (coefficient <= MASK_COE1) 477 this.data = sgnMask | (expMask << SHIFT_EXP1) | coefficient; 478 else 479 this.data = sgnMask | (expMask << SHIFT_EXP2) | (coefficient & MASK_COE2) | MASK_EXT; 480 } 481 482 //packs components, but checks the limits before 483 @nogc nothrow pure @safe 484 ExceptionFlags checkedPack(const U coefficient, const int exponent, const bool isNegative, 485 int precision, const RoundingMode mode, const bool acceptNonCanonical) 486 { 487 if (exponent > EXP_MAX) 488 return overflowPack(isNegative, precision, mode); 489 if (exponent < EXP_MIN) 490 return underflowPack(isNegative, mode); 491 if (coefficient > COEF_MAX && !acceptNonCanonical) 492 return overflowPack(isNegative, precision, mode); 493 if (coefficient > (MASK_COE2 | MASK_COEX) && acceptNonCanonical) 494 return overflowPack(isNegative, precision, mode); 495 496 U expMask = U(cast(uint)(exponent + EXP_BIAS)); 497 U sgnMask = isNegative ? MASK_SGN : MASK_NONE; 498 499 if (coefficient <= MASK_COE1) 500 this.data = sgnMask | (expMask << SHIFT_EXP1) | coefficient; 501 else 502 this.data = sgnMask | (expMask << SHIFT_EXP2) | (coefficient & MASK_COE2) | MASK_EXT; 503 504 if (expMask < cast(uint)(D.PRECISION - 1)) 505 if (prec(coefficient) < D.PRECISION - cast(uint)expMask) 506 return ExceptionFlags.underflow; 507 508 return ExceptionFlags.none; 509 } 510 511 512 //returns true if data was packed according to flags 513 @nogc nothrow pure @safe 514 bool errorPack(const bool isNegative, const ExceptionFlags flags, const int precision, const RoundingMode mode, const U payload = U(0U)) 515 { 516 if (flags & ExceptionFlags.invalidOperation) 517 invalidPack(isNegative, payload); 518 else if (flags & ExceptionFlags.divisionByZero) 519 div0Pack(isNegative); 520 else if (flags & ExceptionFlags.overflow) 521 overflowPack(isNegative, precision, mode); 522 else if (flags & ExceptionFlags.underflow) 523 underflowPack(isNegative, mode); 524 else 525 return false; 526 return true; 527 } 528 529 @nogc nothrow pure @safe 530 ExceptionFlags maxPack(const bool isNegative, const int precision) 531 { 532 data = isNegative ? MASK_SGN : MASK_NONE; 533 auto p = realPrecision(precision); 534 if (p >= PRECISION) 535 data |= max.data; 536 else 537 { 538 U coefficient = (COEF_MAX / pow10!U[PRECISION - p]) * pow10!U[PRECISION - p]; 539 int exponent = EXP_MAX; 540 pack(coefficient, exponent, isNegative); 541 return ExceptionFlags.inexact; 542 } 543 return ExceptionFlags.none; 544 } 545 546 @nogc nothrow pure @safe 547 ExceptionFlags minPack(const bool isNegative) 548 { 549 data = isNegative ? MASK_SGN : MASK_NONE; 550 data |= subn.data; 551 return ExceptionFlags.underflow; 552 } 553 554 //packs infinity or max, depending on the rounding mode 555 @nogc nothrow pure @safe 556 ExceptionFlags overflowPack(const bool isNegative, const int precision, const RoundingMode mode) 557 { 558 switch (mode) 559 { 560 case RoundingMode.towardZero: 561 return maxPack(isNegative, precision) | ExceptionFlags.overflow; 562 case RoundingMode.towardNegative: 563 if (!isNegative) 564 return maxPack(false, precision) | ExceptionFlags.overflow; 565 goto default; 566 case RoundingMode.towardPositive: 567 if (isNegative) 568 return maxPack(true, precision) | ExceptionFlags.overflow; 569 goto default; 570 default: 571 data = MASK_INF; 572 if (isNegative) 573 data |= D.MASK_SGN; 574 } 575 return ExceptionFlags.overflow; 576 } 577 578 //packs zero or min, depending on the rounding mode 579 @nogc nothrow pure @safe 580 ExceptionFlags underflowPack(const bool isNegative, const RoundingMode mode) 581 { 582 switch (mode) 583 { 584 case RoundingMode.towardPositive: 585 if (!isNegative) 586 return minPack(false); 587 goto default; 588 case RoundingMode.towardNegative: 589 if (isNegative) 590 return minPack(true); 591 goto default; 592 default: 593 data = MASK_ZERO; 594 if (isNegative) 595 data |= D.MASK_SGN; 596 } 597 return ExceptionFlags.underflow; 598 } 599 600 //packs $(B NaN) 601 @nogc nothrow pure @safe 602 ExceptionFlags invalidPack(const bool isNegative, const U payload) 603 { 604 data = MASK_QNAN; 605 data |= (payload & MASK_PAYL); 606 if (isNegative) 607 data |= MASK_SGN; 608 return ExceptionFlags.invalidOperation; 609 } 610 611 //packs infinity 612 @nogc nothrow pure @safe 613 ExceptionFlags div0Pack(const bool isNegative) 614 { 615 data = MASK_INF; 616 if (isNegative) 617 data |= MASK_SGN; 618 return ExceptionFlags.divisionByZero; 619 } 620 621 622 @nogc nothrow pure @safe 623 ExceptionFlags adjustedPack(T)(const T coefficient, const int exponent, const bool isNegative, 624 const int precision, const RoundingMode mode, 625 const ExceptionFlags previousFlags = ExceptionFlags.none) 626 { 627 if (!errorPack(isNegative, previousFlags, precision, mode, cvt!U(coefficient))) 628 { 629 bool stickyUnderflow = exponent < int.max - EXP_BIAS && exponent + EXP_BIAS < PRECISION - 1 && prec(coefficient) < PRECISION - (exponent + EXP_BIAS); 630 static if (T.sizeof <= U.sizeof) 631 U cx = coefficient; 632 else 633 Unqual!T cx = coefficient; 634 int ex = exponent; 635 ExceptionFlags flags = coefficientAdjust(cx, ex, EXP_MIN, EXP_MAX, realPrecision(precision), isNegative, mode) | previousFlags; 636 if (stickyUnderflow) 637 flags |= ExceptionFlags.underflow; 638 return checkedPack(cvt!U(cx), ex, isNegative, precision, mode, false) | flags; 639 } 640 return previousFlags; 641 } 642 643 @nogc nothrow pure @safe 644 bool unpack(out U coefficient, out int exponent) const 645 out 646 { 647 assert (exponent >= EXP_MIN && exponent <= EXP_MAX); 648 assert (coefficient <= (MASK_COE2 | MASK_COEX)); 649 } 650 body 651 { 652 uint e; 653 bool isNegative = unpackRaw(coefficient, e); 654 exponent = cast(int)(e - EXP_BIAS); 655 return isNegative; 656 } 657 658 @nogc nothrow pure @safe 659 bool unpackRaw(out U coefficient, out uint exponent) const 660 { 661 if ((data & MASK_EXT) == MASK_EXT) 662 { 663 coefficient = data & MASK_COE2 | MASK_COEX; 664 exponent = cast(uint)((data & MASK_EXP2) >>> SHIFT_EXP2); 665 } 666 else 667 { 668 coefficient = data & MASK_COE1; 669 exponent = cast(uint)((data & MASK_EXP1) >>> SHIFT_EXP1); 670 } 671 return (data & MASK_SGN) != 0U; 672 } 673 674 @nogc nothrow pure @safe 675 static int realPrecision(const int precision) 676 { 677 if (precision <= 0 || precision > PRECISION) 678 return PRECISION; 679 else 680 return precision; 681 } 682 683 ExceptionFlags packIntegral(T)(const T value, const int precision, const RoundingMode mode) 684 if (isIntegral!T) 685 { 686 alias V = CommonStorage!(D, T); 687 if (!value) 688 { 689 this.data = MASK_ZERO; 690 return ExceptionFlags.none; 691 } 692 else 693 { 694 static if (isSigned!T) 695 { 696 bool isNegative = void; 697 V coefficient = unsign!V(value, isNegative); 698 } 699 else 700 { 701 enum isNegative = false; 702 V coefficient = value; 703 } 704 int exponent = 0; 705 auto flags = coefficientAdjust(coefficient, exponent, cvt!V(COEF_MAX), isNegative, mode); 706 return adjustedPack(cvt!U(coefficient), exponent, isNegative, precision, mode, flags); 707 } 708 } 709 710 ExceptionFlags packFloatingPoint(T)(const T value, const int precision, const RoundingMode mode) 711 if (isFloatingPoint!T) 712 { 713 //float / decimal32 -> min(9, 7) = 7 714 //float / decimal64 -> min(9, 16) = 9 715 //float / decimal128 -> min(9, 34) = 9 716 717 //double / decimal32 -> min(16, 7) = 7 718 //double / decimal64 -> min(16, 16) = 16 719 //double / decimal128 -> min(16, 34) = 16 720 721 //real / decimal32 -> min(21, 7) = 7 722 //real / decimal64 -> min(21, 16) = 16 723 //real / decimal128 -> min(21, 34) = 21 724 725 ExceptionFlags flags; 726 DataType!D cx; int ex; bool sx; 727 switch (fastDecode(value, cx, ex, sx, mode, flags)) 728 { 729 case FastClass.quietNaN: 730 data = MASK_QNAN; 731 if (sx) 732 data |= MASK_SGN; 733 data |= cx & MASK_PAYL; 734 return ExceptionFlags.none; 735 case FastClass.infinite: 736 data = MASK_INF; 737 if (sx) 738 data |= MASK_SGN; 739 return ExceptionFlags.none; 740 case FastClass.zero: 741 data = MASK_ZERO; 742 if (sx) 743 data |= MASK_SGN; 744 return ExceptionFlags.none; 745 case FastClass.finite: 746 auto targetPrecision = realPrecision(precision); 747 static if (is(T == float)) 748 { 749 if (targetPrecision > 9) 750 targetPrecision = 9; 751 } 752 else static if (is(T == double)) 753 { 754 if (targetPrecision > 17) 755 targetPrecision = 17; 756 } 757 else 758 { 759 if (targetPrecision > 21) 760 targetPrecision = 21; 761 } 762 flags |= coefficientAdjust(cx, ex, targetPrecision, sx, mode); 763 return adjustedPack(cx, ex, sx, precision, mode, flags); 764 default: 765 assert(0); 766 } 767 } 768 769 770 ExceptionFlags packString(C)(const(C)[] value, const int precision, const RoundingMode mode) 771 if (isSomeChar!C) 772 { 773 U coefficient; 774 bool isinf, isnan, issnan, isnegative, wasHex; 775 int exponent; 776 const(C)[] ss = value; 777 auto flags = parseDecimal(ss, coefficient, exponent, isinf, isnan, issnan, isnegative, wasHex); 778 779 if (!ss.empty) 780 return invalidPack(isnegative, coefficient) | flags; 781 782 if (flags & ExceptionFlags.invalidOperation) 783 return invalidPack(isnegative, coefficient) | flags; 784 785 if (issnan) 786 data = MASK_SNAN | (coefficient & MASK_PAYL); 787 else if (isnan) 788 data = MASK_QNAN | (coefficient & MASK_PAYL); 789 else if (isinf) 790 data = MASK_INF; 791 else 792 { 793 if (!wasHex) 794 return adjustedPack(coefficient, exponent, isnegative, precision, mode, flags); 795 else 796 return flags | checkedPack(coefficient, exponent, isnegative, precision, mode, true); 797 } 798 799 if (isnegative) 800 data |= MASK_SGN; 801 802 return flags; 803 } 804 805 ExceptionFlags packRange(R)(ref R range, const int precision, const RoundingMode mode) 806 if (isInputRange!R && isSomeChar!(ElementType!R) && !isSomeString!range) 807 { 808 U coefficient; 809 bool isinf, isnan, issnan, isnegative, wasHex; 810 int exponent; 811 auto flags = parseDecimal(range, coefficient, exponent, isinf, isnan, issnan, isnegative, wasHex); 812 813 if (!ss.empty) 814 flags |= ExceptionFlags.invalidOperation; 815 816 if (flags & ExceptionFlags.invalidOperation) 817 { 818 packErrors(isnegative, flags, coefficient); 819 return flags; 820 } 821 822 if (issnan) 823 data = MASK_SNAN | (coefficient & MASK_PAYL); 824 else if (isnan) 825 data = MASK_QNAN | (coefficient & MASK_PAYL); 826 else if (isinf) 827 data = MASK_INF; 828 if (flags & ExceptionFlags.underflow) 829 data = MASK_ZERO; 830 else if (flags & ExceptionFlags.overflow) 831 data = MASK_INF; 832 else 833 { 834 flags |= adjustCoefficient(coefficient, exponent, EXP_MIN, EXP_MAX, COEF_MAX, isnegative, mode); 835 flags |= adjustPrecision(coefficient, exponent, EXP_MIN, EXP_MAX, precision, isnegative, mode); 836 } 837 838 if (flags & ExceptionFlags.underflow) 839 data = MASK_ZERO; 840 else if (flags & ExceptionFlags.overflow) 841 data = MASK_INF; 842 843 if (isnegative) 844 data |= MASK_SGN; 845 846 return flags; 847 } 848 849 850 enum zero = D(U(0U), 0, false); 851 enum minusZero = D(U(0U), 0, true); 852 enum one = D(U(1U), 0, false); 853 enum two = D(U(2U), 0, false); 854 enum three = D(U(3U), 0, false); 855 enum minusOne = D(U(1U), 0, true); 856 enum minusInfinity = -infinity; 857 enum ten = D(U(10U), 0, false); 858 enum minusTen = D(U(10U), 0, true); 859 enum qnan = nan; 860 enum snan = D(MASK_NONE, MASK_NONE, MASK_SNAN); 861 enum subn = D(U(1U), EXP_MIN, false); 862 enum minusSubn = D(U(1U), EXP_MIN, true); 863 enum min = D(COEF_MAX, EXP_MAX, true); 864 enum half = D(U(5U), -1, false); 865 enum threequarters = D(U(75U), -2, false); 866 enum quarter = D(U(25U), -2, false); 867 868 869 enum SQRT3 = fromString!D(s_sqrt3); 870 enum M_SQRT3 = fromString!D(s_m_sqrt3); 871 enum PI_3 = fromString!D(s_pi_3); 872 enum PI_6 = fromString!D(s_pi_6); 873 enum _5PI_6 = fromString!D(s_5pi_6); 874 enum _3PI_4 = fromString!D(s_3pi_4); 875 enum _2PI_3 = fromString!D(s_2pi_3); 876 enum SQRT3_2 = fromString!D(s_sqrt3_2); 877 enum SQRT2_2 = fromString!D(s_sqrt2_2); 878 enum onethird = fromString!D(s_onethird); 879 enum twothirds = fromString!D(s_twothirds); 880 enum _5_6 = fromString!D(s_5_6); 881 enum _1_6 = fromString!D(s_1_6); 882 enum M_1_2PI = fromString!D(s_m_1_2pi); 883 enum PI2 = fromString!D(s_pi2); 884 public: 885 886 887 enum dig = PRECISION; 888 enum epsilon = D(U(1U), -PRECISION + 1, false); 889 enum infinity = D(MASK_NONE, MASK_NONE, MASK_INF); 890 enum max = D(COEF_MAX, EXP_MAX, false); 891 enum max_10_exp = EMAX; 892 enum max_exp = cast(int)(max_10_exp / LOG10_2); 893 enum mant_dig = trailingBits; 894 enum min_10_exp = -(max_10_exp - 1); 895 enum min_exp = cast(int)(min_10_exp / LOG10_2); 896 enum min_normal = D(U(1U), min_10_exp, false); 897 enum nan = D(MASK_NONE, MASK_NONE, MASK_QNAN); 898 899 900 enum E = fromString!D(s_e); 901 enum PI = fromString!D(s_pi); 902 enum PI_2 = fromString!D(s_pi_2); 903 enum PI_4 = fromString!D(s_pi_4); 904 enum M_1_PI = fromString!D(s_m_1_pi); 905 enum M_2_PI = fromString!D(s_m_2_pi); 906 enum M_2_SQRTPI = fromString!D(s_m_2_sqrtpi); 907 enum SQRT2 = fromString!D(s_sqrt2); 908 enum SQRT1_2 = fromString!D(s_sqrt1_2); 909 enum LN10 = fromString!D(s_ln10); 910 enum LOG2T = fromString!D(s_log2t); 911 enum LOG2E = fromString!D(s_log2e); 912 enum LOG2 = fromString!D(s_log2); 913 enum LOG10E = fromString!D(s_log10e); 914 enum LN2 = fromString!D(s_ln2); 915 916 ///always 10 for _decimal data types 917 @IEEECompliant("radix", 25) 918 enum radix = 10; 919 920 /** 921 Constructs a Decimal data type using the specified _value 922 Params: 923 value = any integral, char, bool, floating point, decimal, string or character range _value 924 Exceptions: 925 $(BOOKTABLE, 926 $(TR $(TH Data type) $(TH Invalid) $(TH Overflow) $(TH Underflow) $(TH Inexact)) 927 $(TR $(TD integral) $(TD ) $(TD ) $(TD ) $(TD ✓ )) 928 $(TR $(TD char ) $(TD ) $(TD ) $(TD ) $(TD ✓ )) 929 $(TR $(TD float ) $(TD ) $(TD ✓ ) $(TD ✓ ) $(TD ✓ )) 930 $(TR $(TD bool ) $(TD ) $(TD ) $(TD ) $(TD )) 931 $(TR $(TD decimal ) $(TD ) $(TD ✓ ) $(TD ✓ ) $(TD ✓ )) 932 $(TR $(TD string ) $(TD ✓ ) $(TD ✓ ) $(TD ✓ ) $(TD ✓ )) 933 $(TR $(TD range ) $(TD ✓ ) $(TD ✓ ) $(TD ✓ ) $(TD ✓ )) 934 ) 935 Using_integral_values: 936 --- 937 auto a = decimal32(112); //represented as 112 x 10^^0; 938 auto b = decimal32(123456789); //inexact, represented as 1234568 * x 10^^2 939 --- 940 Using_floating_point_values: 941 --- 942 auto a = decimal32(1.23); 943 //inexact, represented as 123 x 10^^-2, 944 //because floating point data cannot exactly represent 1.23 945 //in fact 1.23 as float is 1.230000019073486328125 946 auto b = decimal64(float.nan); 947 --- 948 Using_other_decimal_values: 949 --- 950 auto a = decimal32(decimal64(10)); 951 auto b = decimal64(a); 952 auto c = decimal64(decimal128.nan); 953 --- 954 Using_strings_or_ranges: 955 A _decimal value can be defined based on _decimal, scientific or hexadecimal representation: 956 $(UL 957 $(LI values are rounded away from zero in case of precision overflow;) 958 --- 959 auto d = decimal32("2.3456789") 960 //internal representation will be 2.345679 961 //because decimal32 has a 7-digit precision 962 --- 963 $(LI the exponent in hexadecimal notation is 10-based;) 964 --- 965 auto d1 = decimal64("0x00003p+21"); 966 auto d2 = decimal64("3e+21"); 967 assert (d1 == d2); 968 --- 969 $(LI the hexadecimal notation doesn't have any _decimal point, 970 because there is no leading 1 as for binary floating point values;) 971 $(LI there is no octal notation, any leading zero before the decimal point is ignored;) 972 $(LI digits can be grouped using underscores;) 973 $(LI case insensitive special values are accepted: $(B nan, qnan, snan, inf, infinity);) 974 $(LI there is no digit count limit for _decimal representation, very large values are rounded and adjusted by 975 increasing the 10-exponent;) 976 --- 977 auto d1 = decimal32("123_456_789_123_456_789_123_456_789_123"); //30 digits 978 //internal representation will be 1.234568 x 10^^30 979 --- 980 $(LI $(B NaN) payloads can be defined betwen optional brackets ([], (), {}, <>). 981 The payload is unsigned and is accepted in decimal or hexadecimal format;) 982 ) 983 --- 984 auto d = decimal32("10"); //integral 985 auto e = decimal64("125.43") //floating point 986 auto f = decimal128("123.456E-32"); //scientific 987 auto g = decimal32("0xABCDEp+21"); //hexadecimal 0xABCD * 10^^21 988 auto h = decimal64("NaN1234"); //$(B NaN) with 1234 payload 989 auto i = decimal128("sNaN<0xABCD>") //signaling $(B NaN) with a 0xABCD payload 990 auto j = decimal32("inf"); //infinity 991 --- 992 Using_char_or_bool_values: 993 These constructors are provided only from convenience, and to 994 offer support for conversion function $(PHOBOS conv, to, to). 995 Char values are cast to unsigned int. 996 Bool values are converted to 0.0 (false) or 1.0 (true) 997 --- 998 auto a = decimal32(true); //1.0 999 auto b = decimal32('a'); //'a' ascii code (97) 1000 1001 auto c = to!decimal32(false); //phobos to!(bool, decimal32) 1002 auto d = to!decimal128('Z'); //phobos to!(char, decimal128) 1003 --- 1004 */ 1005 @IEEECompliant("convertFormat", 22) 1006 @IEEECompliant("convertFromDecimalCharacter", 22) 1007 @IEEECompliant("convertFromHexCharacter", 22) 1008 @IEEECompliant("convertFromInt", 21) 1009 @IEEECompliant("decodeBinary", 23) 1010 this(T)(auto const ref T value) 1011 { 1012 static if (isIntegral!T) 1013 { 1014 auto flags = packIntegral(value, 1015 __ctfe ? 0 : DecimalControl.precision, 1016 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1017 DecimalControl.raiseFlags(flags); 1018 } 1019 else static if (isSomeChar!T) 1020 { 1021 auto flags = packIntegral(cast(uint)value, 1022 __ctfe ? 0 : DecimalControl.precision, 1023 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1024 DecimalControl.raiseFlags(flags); 1025 } 1026 else static if (isFloatingPoint!T) 1027 { 1028 auto flags = packFloatingPoint(value, 1029 __ctfe ? 0 : DecimalControl.precision, 1030 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1031 DecimalControl.raiseFlags(flags); 1032 } 1033 else static if (isSomeString!T) 1034 { 1035 auto flags = packString(value, 1036 __ctfe ? 0 : DecimalControl.precision, 1037 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1038 DecimalControl.raiseFlags(flags); 1039 } 1040 else static if (isInputRange!T && isSomeChar!(ElementType!T) && !isSomeString!T) 1041 { 1042 auto flags = packRange(value, 1043 __ctfe ? 0 : DecimalControl.precision, 1044 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1045 DecimalControl.raiseFlags(flags); 1046 } 1047 else static if (is(T: D)) 1048 this.data = value.data; 1049 else static if (is(T: bool)) 1050 { 1051 this.data = value ? one.data : zero.data; 1052 } 1053 else static if (isDecimal!T) 1054 { 1055 auto flags = decimalToDecimal(value, this, 1056 __ctfe ? 0 : DecimalControl.precision, 1057 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1058 DecimalControl.raiseFlags(flags); 1059 } 1060 else 1061 static assert (0, "Cannot convert expression of type '" ~ 1062 Unqual!T.stringof ~ "' to '" ~ 1063 Unqual!D.stringof ~ "'"); 1064 } 1065 1066 1067 1068 /** 1069 Implementation of assignnment operator. It supports the same semantics as the constructor. 1070 */ 1071 @IEEECompliant("copy", 23) 1072 auto ref opAssign(T)(auto const ref T value) 1073 { 1074 auto result = Unqual!D(value); 1075 this.data = result.data; 1076 } 1077 1078 /** 1079 Implementation of cast operator. Supported casts: integral, floating point, _decimal, char, bool 1080 Exceptions: 1081 $(BOOKTABLE, 1082 $(TR $(TH Data type) $(TH Invalid) $(TH Overflow) $(TH Underflow) $(TH Inexact)) 1083 $(TR $(TD integral) $(TD ✓) $(TD ✓ ) $(TD ✓ ) $(TD ✓ )) 1084 $(TR $(TD char ) $(TD ✓) $(TD ✓ ) $(TD ✓ ) $(TD ✓ )) 1085 $(TR $(TD float ) $(TD ) $(TD ✓ ) $(TD ✓ ) $(TD ✓ )) 1086 $(TR $(TD bool ) $(TD ) $(TD ) $(TD ) $(TD )) 1087 $(TR $(TD decimal ) $(TD ) $(TD ✓ ) $(TD ✓ ) $(TD ✓ )) 1088 ) 1089 */ 1090 @IEEECompliant("convertFormat", 22) 1091 @IEEECompliant("encodeBinary", 23) 1092 T opCast(T)() const 1093 { 1094 Unqual!T result; 1095 static if (isUnsigned!T) 1096 { 1097 auto flags = decimalToUnsigned(this, result, 1098 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1099 DecimalControl.raiseFlags(flags); 1100 } 1101 else static if (isIntegral!T) 1102 { 1103 auto flags = decimalToSigned(this, result, 1104 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1105 DecimalControl.raiseFlags(flags); 1106 } 1107 else static if (is(T: D)) 1108 result = this; 1109 else static if (is(D: decimal32) && (is(T: decimal64) || is(T: decimal128))) 1110 decimalToDecimal(this, result, 0, RoundingMode.implicit); 1111 else static if (is(D: decimal64) && is(T: decimal128)) 1112 decimalToDecimal(this, result, 0, RoundingMode.implicit); 1113 else static if (isDecimal!T) 1114 { 1115 auto flags = decimalToDecimal(this, result, 1116 __ctfe ? 0 : DecimalControl.precision, 1117 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1118 DecimalControl.raiseFlags(flags); 1119 } 1120 else static if (isFloatingPoint!T) 1121 { 1122 auto flags = decimalToFloat(this, result, 1123 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1124 DecimalControl.raiseFlags(flags); 1125 } 1126 else static if (isSomeChar!T) 1127 { 1128 uint r; 1129 auto flags = decimalToUnsigned(this, r, 1130 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1131 result = cast(Unqual!T)r; 1132 DecimalControl.raiseFlags(flags); 1133 } 1134 else static if (is(T: bool)) 1135 result = !isZero(this); 1136 else 1137 static assert(0, "Cannot cast a value of type '" ~ 1138 Unqual!D.stringof ~ "' to '" ~ 1139 Unqual!T.stringof ~ "'"); 1140 1141 return result; 1142 } 1143 1144 1145 /** 1146 Implementation of +/- unary operators. These operations are silent, no exceptions are thrown 1147 */ 1148 @safe pure nothrow @nogc 1149 auto opUnary(string op: "+")() const 1150 { 1151 return this; 1152 } 1153 1154 ///ditto 1155 @IEEECompliant("negate", 23) 1156 @safe pure nothrow @nogc 1157 auto opUnary(string op: "-")() const 1158 { 1159 D result = this; 1160 static if (is(D: decimal128)) 1161 result.data.hi ^= D.MASK_SGN.hi; 1162 else 1163 result.data ^= D.MASK_SGN; 1164 return result; 1165 } 1166 1167 /** 1168 Implementation of ++/-- unary operators. 1169 Exceptions: 1170 $(BOOKTABLE, 1171 $(TR $(TH Value) $(TH ++/-- ) $(TH Invalid) $(TH Overflow) $(TH Inexact)) 1172 $(TR $(TD $(B NaN) ) $(TD $(B NaN) ) $(TD ✓ ) $(TD ) $(TD )) 1173 $(TR $(TD ±∞ ) $(TD ±∞ ) $(TD ) $(TD ) $(TD )) 1174 $(TR $(TD any ) $(TD any ) $(TD ) $(TD ✓ ) $(TD ✓ )) 1175 ) 1176 */ 1177 @safe 1178 auto ref opUnary(string op: "++")() 1179 { 1180 auto flags = decimalInc(this, 1181 __ctfe ? 0 : DecimalControl.precision, 1182 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1183 DecimalControl.raiseFlags(flags); 1184 return this; 1185 } 1186 1187 ///ditto 1188 @safe 1189 auto ref opUnary(string op: "--")() 1190 { 1191 auto flags = decimalDec(this, 1192 __ctfe ? 0 : DecimalControl.precision, 1193 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1194 DecimalControl.raiseFlags(flags); 1195 return this; 1196 } 1197 1198 1199 /** 1200 Implementation of == operator. This operation is silent, no exceptions are thrown. 1201 Supported types : _decimal, floating point, integral, char 1202 */ 1203 @IEEECompliant("compareQuietEqual", 24) 1204 @IEEECompliant("compareQuietNotEqual", 24) 1205 bool opEquals(T)(auto const ref T value) const 1206 { 1207 static if (isDecimal!T || isIntegral!T || isFloatingPoint!T) 1208 { 1209 int result = decimalEqu(this, value); 1210 if (result < -2) 1211 { 1212 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation); 1213 return false; 1214 } 1215 return result == 1; 1216 } 1217 else static if (isSomeChar!T) 1218 return opEquals(cast(uint)value); 1219 else 1220 static assert (0, "Cannot compare values of type '" ~ 1221 Unqual!D.stringof ~ "' and '" ~ 1222 Unqual!T.stringof ~ "'"); 1223 } 1224 1225 /** 1226 Implementation of comparison operator. 1227 Supported types : _decimal, floating point, integral, char 1228 $(BOOKTABLE, 1229 $(TR $(TH this) $(TH Value) $(TH Result) $(TH Invalid)) 1230 $(TR $(TD $(B NaN) ) $(TD any ) $(TD $(B NaN) ) $(TD ✓ )) 1231 $(TR $(TD any ) $(TD $(B NaN) ) $(TD $(B NaN) ) $(TD ✓ )) 1232 $(TR $(TD any ) $(TD any ) $(TD ±1.0, 0.0) $(TD )) 1233 ) 1234 */ 1235 @IEEECompliant("compareSignalingGreater", 24) 1236 @IEEECompliant("compareSignalingGreaterEqual", 24) 1237 @IEEECompliant("compareSignalingGreaterUnordered", 24) 1238 @IEEECompliant("compareSignalingLess", 24) 1239 @IEEECompliant("compareSignalingLessEqual", 24) 1240 @IEEECompliant("compareSignalingLessUnordered", 24) 1241 @IEEECompliant("compareSignalingNotGreater", 24) 1242 @IEEECompliant("compareSignalingNotLess", 24) 1243 float opCmp(T)(auto const ref T value) const 1244 { 1245 static if (isDecimal!T || isIntegral!T || isFloatingPoint!T) 1246 { 1247 int result = decimalCmp(this, value); 1248 if (result < -1) 1249 { 1250 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation); 1251 return float.nan; 1252 } 1253 else 1254 return cast(float)(result); 1255 } 1256 else static if (isSomeChar!T) 1257 { 1258 int result = decimalCmp(this, cast(uint)value); 1259 if (result < -1) 1260 { 1261 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation); 1262 return float.nan; 1263 } 1264 else 1265 return cast(float)(result); 1266 } 1267 else 1268 static assert (0, "Cannot compare values of type '" ~ 1269 Unqual!D.stringof ~ "' and '" ~ 1270 Unqual!T.stringof ~ "'"); 1271 } 1272 1273 1274 /** 1275 Implementation of binary and assignment operators (+, -, *, /, %, ^^). 1276 Returns: 1277 the widest _decimal value as result of the operation 1278 Supported_types: 1279 _decimal, floating point, integral, char 1280 Exceptions: 1281 $(BOOKTABLE, 1282 $(TR $(TH Left) $(TH Op) $(TH Right) $(TH Result) $(TH Invalid) $(TH Div0) $(TH Overflow) $(TH Underflow) $(TH Inexact)) 1283 $(TR $(TD $(B NaN)) $(TD any) $(TD any) $(TD $(B NaN)) $(TD ✓ ) $(TD ) $(TD ) $(TD ) $(TD )) 1284 $(TR $(TD any) $(TD any) $(TD $(B NaN)) $(TD $(B NaN)) $(TD ✓ ) $(TD ) $(TD ) $(TD ) $(TD )) 1285 $(TR $(TD +∞) $(TD +) $(TD -∞) $(TD $(B NaN)) $(TD ✓ ) $(TD ) $(TD ) $(TD ) $(TD )) 1286 $(TR $(TD +∞) $(TD +) $(TD any) $(TD +∞) $(TD ) $(TD ) $(TD ) $(TD ) $(TD )) 1287 $(TR $(TD any) $(TD +) $(TD +∞) $(TD +∞) $(TD ) $(TD ) $(TD ) $(TD ) $(TD )) 1288 $(TR $(TD -∞) $(TD +) $(TD +∞) $(TD $(B NaN)) $(TD ✓ ) $(TD ) $(TD ) $(TD ) $(TD )) 1289 $(TR $(TD -∞) $(TD +) $(TD any) $(TD -∞) $(TD ) $(TD ) $(TD ) $(TD ) $(TD )) 1290 $(TR $(TD any) $(TD +) $(TD -∞) $(TD -∞) $(TD ) $(TD ) $(TD ) $(TD ) $(TD )) 1291 $(TR $(TD any) $(TD +) $(TD any) $(TD any) $(TD ) $(TD ) $(TD ✓ ) $(TD ✓ ) $(TD ✓ )) 1292 $(TR $(TD +∞) $(TD -) $(TD +∞) $(TD $(B NaN)) $(TD ✓ ) $(TD ) $(TD ) $(TD ) $(TD )) 1293 $(TR $(TD +∞) $(TD -) $(TD any) $(TD +∞) $(TD ) $(TD ) $(TD ) $(TD ) $(TD )) 1294 $(TR $(TD any) $(TD -) $(TD +∞) $(TD -∞) $(TD ) $(TD ) $(TD ) $(TD ) $(TD )) 1295 $(TR $(TD -∞) $(TD -) $(TD -∞) $(TD $(B NaN)) $(TD ✓ ) $(TD ) $(TD ) $(TD ) $(TD )) 1296 $(TR $(TD -∞) $(TD -) $(TD any) $(TD -∞) $(TD ) $(TD ) $(TD ) $(TD ) $(TD )) 1297 $(TR $(TD any) $(TD -) $(TD -∞) $(TD -∞) $(TD ) $(TD ) $(TD ) $(TD ) $(TD )) 1298 $(TR $(TD any) $(TD -) $(TD any) $(TD any) $(TD ) $(TD ) $(TD ✓ ) $(TD ✓ ) $(TD ✓ )) 1299 $(TR $(TD ±∞) $(TD *) $(TD 0.0) $(TD $(B NaN)) $(TD ✓ ) $(TD ) $(TD ) $(TD ) $(TD )) 1300 $(TR $(TD ±∞) $(TD *) $(TD any) $(TD ±∞) $(TD ) $(TD ) $(TD ) $(TD ) $(TD )) 1301 $(TR $(TD any) $(TD *) $(TD any) $(TD any) $(TD ) $(TD ) $(TD ) $(TD ) $(TD )) 1302 $(TR $(TD ±∞) $(TD /) $(TD ±∞) $(TD $(B NaN)) $(TD ✓ ) $(TD ) $(TD ) $(TD ) $(TD )) 1303 $(TR $(TD 0.0) $(TD /) $(TD 0.0) $(TD $(B NaN)) $(TD ✓ ) $(TD ) $(TD ) $(TD ) $(TD )) 1304 $(TR $(TD ±∞) $(TD /) $(TD any) $(TD ±∞) $(TD ) $(TD ) $(TD ) $(TD ) $(TD )) 1305 $(TR $(TD any) $(TD /) $(TD 0.0) $(TD ±∞) $(TD ) $(TD ✓ ) $(TD ) $(TD ) $(TD )) 1306 $(TR $(TD any) $(TD /) $(TD any) $(TD any) $(TD ) $(TD ) $(TD ✓ ) $(TD ✓ ) $(TD ✓ )) 1307 $(TR $(TD ±∞) $(TD %) $(TD any) $(TD $(B NaN)) $(TD ✓ ) $(TD ) $(TD ) $(TD ) $(TD )) 1308 $(TR $(TD any) $(TD %) $(TD ±∞) $(TD $(B NaN)) $(TD ✓ ) $(TD ) $(TD ) $(TD ) $(TD )) 1309 $(TR $(TD any) $(TD %) $(TD 0.0) $(TD $(B NaN)) $(TD ✓ ) $(TD ) $(TD ) $(TD ) $(TD )) 1310 $(TR $(TD any) $(TD %) $(TD any) $(TD any) $(TD ) $(TD ) $(TD ✓ ) $(TD ✓ ) $(TD ✓ )) 1311 ) 1312 */ 1313 @IEEECompliant("addition", 21) 1314 @IEEECompliant("division", 21) 1315 @IEEECompliant("multiplication", 21) 1316 @IEEECompliant("pow", 42) 1317 @IEEECompliant("pown", 42) 1318 @IEEECompliant("powr", 42) 1319 @IEEECompliant("remainder", 25) 1320 @IEEECompliant("substraction", 21) 1321 auto opBinary(string op, T)(auto const ref T value) const 1322 if (op == "+" || op == "-" || op == "*" || op == "/" || op == "%" || op == "^^") 1323 { 1324 static if (isDecimal!T) 1325 CommonDecimal!(D, T) result = this; 1326 else 1327 Unqual!D result = this; 1328 1329 static if (op == "+") 1330 alias decimalOp = decimalAdd; 1331 else static if (op == "-") 1332 alias decimalOp = decimalSub; 1333 else static if (op == "*") 1334 alias decimalOp = decimalMul; 1335 else static if (op == "/") 1336 alias decimalOp = decimalDiv; 1337 else static if (op == "%") 1338 alias decimalOp = decimalMod; 1339 else static if (op == "^^") 1340 alias decimalOp = decimalPow; 1341 else 1342 static assert(0); 1343 1344 static if (isIntegral!T || isFloatingPoint!T || isDecimal!T) 1345 auto flags = decimalOp(result, value, 1346 __ctfe ? 0 : DecimalControl.precision, 1347 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1348 else static if (isSomeChar!T) 1349 auto flags = decimalOp(result, cast(uint)value, 1350 __ctfe ? 0 : DecimalControl.precision, 1351 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1352 else 1353 static assert (0, "Cannot perform binary operation: '" ~ 1354 Unqual!D.stringof ~ "' " ~ op ~" '" ~ 1355 Unqual!T.stringof ~ "'"); 1356 1357 DecimalControl.raiseFlags(flags); 1358 return result; 1359 } 1360 1361 ///ditto 1362 auto opBinaryRight(string op, T)(auto const ref T value) const 1363 if (op == "+" || op == "-" || op == "*" || op == "/" || op == "%" || op == "^^") 1364 { 1365 static if (isDecimal!T) 1366 CommonDecimal!(D, T) result = value; 1367 else 1368 Unqual!D result; 1369 static if (op == "+") 1370 alias decimalOp = decimalAdd; 1371 else static if (op == "-") 1372 alias decimalOp = decimalSub; 1373 else static if (op == "*") 1374 alias decimalOp = decimalMul; 1375 else static if (op == "/") 1376 alias decimalOp = decimalDiv; 1377 else static if (op == "%") 1378 alias decimalOp = decimalMod; 1379 else static if (op == "^^") 1380 alias decimalOp = decimalPow; 1381 else 1382 static assert(0); 1383 1384 static if (isDecimal!T) 1385 { 1386 1387 auto flags = decimalOp(result, this, 1388 __ctfe ? 0 : DecimalControl.precision, 1389 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1390 } 1391 else static if (isIntegral!T || isFloatingPoint!T) 1392 auto flags = decimalOp(value, this, result, 1393 __ctfe ? 0 : DecimalControl.precision, 1394 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1395 else static if (isSomeChar!T) 1396 auto flags = decimalOp(cast(uint)value, this, result, 1397 __ctfe ? 0 : DecimalControl.precision, 1398 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1399 else 1400 static assert (0, "Cannot perform binary operation: '" ~ 1401 Unqual!T.stringof ~ "' " ~ op ~" '" ~ 1402 Unqual!D.stringof ~ "'"); 1403 1404 DecimalControl.raiseFlags(flags); 1405 return result; 1406 } 1407 1408 ///ditto 1409 auto opOpAssign(string op, T)(auto const ref T value) 1410 if (op == "+" || op == "-" || op == "*" || op == "/" || op == "%" || op == "^^") 1411 { 1412 static if (op == "+") 1413 alias decimalOp = decimalAdd; 1414 else static if (op == "-") 1415 alias decimalOp = decimalSub; 1416 else static if (op == "*") 1417 alias decimalOp = decimalMul; 1418 else static if (op == "/") 1419 alias decimalOp = decimalDiv; 1420 else static if (op == "%") 1421 alias decimalOp = decimalMod; 1422 else static if (op == "^^") 1423 alias decimalOp = decimalPow; 1424 else 1425 static assert(0); 1426 1427 1428 1429 static if (isIntegral!T || isFloatingPoint!T || isDecimal!T) 1430 auto flags = decimalOp(this, value, 1431 __ctfe ? 0 : DecimalControl.precision, 1432 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1433 else static if (isSomeChar!T) 1434 auto flags = decimalOp(this, cast(uint)value, 1435 __ctfe ? 0 : DecimalControl.precision, 1436 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1437 else 1438 static assert (0, "Cannot perform assignment operation: '" ~ 1439 Unqual!D.stringof ~ "' " ~ op ~"= '" ~ 1440 Unqual!T.stringof ~ "'"); 1441 1442 DecimalControl.raiseFlags(flags); 1443 return this; 1444 } 1445 1446 version (D_BetterC) {} 1447 else { 1448 1449 /** 1450 Converts current value to string, passing it to the given sink using 1451 the specified format. 1452 Params: 1453 sink = a delegate used to sink character arrays; 1454 fmt = a format specification; 1455 Notes: 1456 This function is not intended to be used directly, it is used by the format, output or conversion 1457 family of functions from Phobos. All standard format options are supported, except digit grouping. 1458 Supported_formats: 1459 $(UL 1460 $(LI $(B f, F) - floating point notation) 1461 $(LI $(B e, E) - scientific notation) 1462 $(LI $(B a, A) - hexadecimal floating point notation) 1463 $(LI $(B g, G) - shortest representation between floating point and scientific notation) 1464 $(LI $(B s, S) - same as $(B g, G)) 1465 ) 1466 Throws: 1467 $(PHOBOS format, FormatException, FormatException) if the format specifier is not supported 1468 See_Also: 1469 $(PHOBOS format, FormatSpec, FormatSpec) 1470 $(PHOBOS format, format, format) 1471 $(PHOBOS conv, to, to) 1472 $(PHOBOS stdio, writef, writef) 1473 $(PHOBOS stdio, writefln, writefln) 1474 */ 1475 @IEEECompliant("convertToDecimalCharacter", 22) 1476 @IEEECompliant("convertToHexCharacter", 22) 1477 void toString(C)(scope void delegate(const(C)[]) sink, FormatSpec!C fmt) const 1478 if (isSomeChar!C) 1479 { 1480 if (__ctfe) 1481 sinkDecimal(fmt, sink, this, RoundingMode.tiesToAway); 1482 else 1483 sinkDecimal(fmt, sink, this, DecimalControl.rounding); 1484 } 1485 1486 ///ditto 1487 @IEEECompliant("convertToDecimalCharacter", 22) 1488 void toString(C)(scope void delegate(const(C)[]) sink) const 1489 if (isSomeChar!C) 1490 { 1491 sinkDecimal(singleSpec("%g"), sink, this, __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1492 } 1493 1494 ///Converts current value to string in floating point or scientific notation, 1495 ///which one is shorter. 1496 @IEEECompliant("convertToDecimalCharacter", 22) 1497 string toString() const 1498 { 1499 return decimalToString!char(this, __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1500 } 1501 1502 ///Converts current value to string according to the 1503 ///format specification 1504 @IEEECompliant("convertToDecimalCharacter", 22) 1505 @IEEECompliant("convertToHexCharacter", 22) 1506 string toString(C)(FormatSpec!C fmt) const 1507 { 1508 return decimalToString!C(fmt, this, __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1509 } 1510 1511 ///ditto 1512 @IEEECompliant("convertToDecimalCharacter", 22) 1513 @IEEECompliant("convertToHexCharacter", 22) 1514 string toString(C)(const(C)[] fmt) const 1515 { 1516 FormatSpec!C spec = singleSpec(fmt); 1517 return decimalToString!C(spec, this, __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 1518 } 1519 1520 } //!D_BetterC 1521 1522 /** 1523 Returns a unique hash of the _decimal value suitable for use in a hash table. 1524 Notes: 1525 This function is not intended for direct use, it's provided as support for associative arrays. 1526 */ 1527 @safe pure nothrow @nogc 1528 size_t toHash() 1529 { 1530 static if (bits == 32) 1531 return data; 1532 else static if (bits == 64) 1533 { 1534 static if (size_t.sizeof == uint.sizeof) 1535 return cast(uint)data ^ cast(uint)(data >>> 32); 1536 else 1537 return data; 1538 } 1539 else 1540 { 1541 static if (size_t.sizeof == uint.sizeof) 1542 return cast(uint)data.hi ^ cast(uint)(data.hi >>> 32) ^ 1543 cast(uint)data.lo ^ cast(uint)(data.lo >>> 32); 1544 else 1545 return data.hi ^ data.lo; 1546 } 1547 } 1548 } 1549 1550 @("Compilation tests") 1551 unittest 1552 { 1553 struct DumbRange(C) 1554 { 1555 bool empty; 1556 C front; 1557 void popFront() {} 1558 } 1559 1560 alias DecimalTypes = TypeTuple!(decimal32, decimal64, decimal128); 1561 alias IntegralTypes = TypeTuple!(byte, short, int, long, ubyte, ushort, uint, ulong); 1562 alias FloatTypes = TypeTuple!(float, double, real); 1563 alias CharTypes = TypeTuple!(char, wchar, dchar); 1564 alias StringTypes = TypeTuple!(string, wstring, dstring); 1565 alias RangeTypes = TypeTuple!(DumbRange!char, DumbRange!wchar, DumbRange!dchar); 1566 1567 auto x = decimal128(real.nan); 1568 1569 //constructors 1570 foreach (D; DecimalTypes) 1571 { 1572 foreach (T; DecimalTypes) 1573 static assert (is(typeof(D(T.init)) == D)); 1574 foreach (T; IntegralTypes) 1575 static assert (is(typeof(D(T.init)) == D)); 1576 foreach (T; FloatTypes) 1577 static assert (is(typeof(D(T.init)) == D)); 1578 foreach (T; CharTypes) 1579 static assert (is(typeof(D(T.init)) == D)); 1580 foreach (T; StringTypes) 1581 static assert (is(typeof(D(T.init)) == D)); 1582 static assert (is(typeof(D(true)) == D)); 1583 } 1584 1585 //assignment 1586 foreach (D; DecimalTypes) 1587 { 1588 foreach (T; DecimalTypes) 1589 static assert (__traits(compiles, { D d = T.init; })); 1590 foreach (T; IntegralTypes) 1591 static assert (__traits(compiles, { D d = T.init; })); 1592 foreach (T; FloatTypes) 1593 static assert (__traits(compiles, { D d = T.init; })); 1594 foreach (T; CharTypes) 1595 static assert (__traits(compiles, { D d = T.init; })); 1596 foreach (T; StringTypes) 1597 static assert (__traits(compiles, { D d = T.init; })); 1598 static assert (__traits(compiles, { D d = true; })); 1599 } 1600 1601 auto b = cast(float)decimal32(); 1602 //cast 1603 foreach (D; DecimalTypes) 1604 { 1605 foreach (T; DecimalTypes) 1606 static assert (is(typeof(cast(T)(D.init)) == T)); 1607 foreach (T; IntegralTypes) 1608 static assert (is(typeof(cast(T)(D.init)) == T)); 1609 foreach (T; FloatTypes) 1610 static assert (is(typeof(cast(T)(D.init)) == T)); 1611 foreach (T; CharTypes) 1612 static assert (is(typeof(cast(T)(D.init)) == T)); 1613 static assert (is(typeof(cast(bool)(D.init)) == bool)); 1614 } 1615 1616 1617 //unary ops 1618 foreach (D; DecimalTypes) 1619 { 1620 static assert(is(typeof(+D.init) == const D)); 1621 static assert(is(typeof(-D.init) == D)); 1622 static assert(is(typeof(++D.init) == D)); 1623 static assert(is(typeof(--D.init) == D)); 1624 } 1625 1626 1627 //equality 1628 foreach (D; DecimalTypes) 1629 { 1630 foreach (T; DecimalTypes) 1631 static assert (is(typeof(D.init == T.init) == bool)); 1632 foreach (T; IntegralTypes) 1633 static assert (is(typeof(D.init == T.init) == bool)); 1634 foreach (T; FloatTypes) 1635 static assert (is(typeof(D.init == T.init) == bool)); 1636 foreach (T; CharTypes) 1637 static assert (is(typeof(D.init == T.init) == bool)); 1638 } 1639 1640 auto c = decimal128() > 0.0; 1641 1642 //comparison 1643 foreach (D; DecimalTypes) 1644 { 1645 foreach (T; DecimalTypes) 1646 static assert (is(typeof(D.init > T.init) == bool)); 1647 foreach (T; IntegralTypes) 1648 static assert (is(typeof(D.init > T.init) == bool)); 1649 foreach (T; FloatTypes) 1650 static assert (is(typeof(D.init > T.init) == bool)); 1651 foreach (T; CharTypes) 1652 static assert (is(typeof(D.init > T.init) == bool)); 1653 } 1654 1655 //binary left 1656 foreach (D; DecimalTypes) 1657 { 1658 foreach (T; DecimalTypes) 1659 { 1660 static assert (is(typeof(D.init + T.init) == CommonDecimal!(D, T))); 1661 static assert (is(typeof(D.init - T.init) == CommonDecimal!(D, T))); 1662 static assert (is(typeof(D.init * T.init) == CommonDecimal!(D, T))); 1663 static assert (is(typeof(D.init / T.init) == CommonDecimal!(D, T))); 1664 static assert (is(typeof(D.init % T.init) == CommonDecimal!(D, T))); 1665 static assert (is(typeof(D.init ^^ T.init) == CommonDecimal!(D, T))); 1666 } 1667 1668 foreach (T; IntegralTypes) 1669 { 1670 static assert (is(typeof(D.init + T.init) == D)); 1671 static assert (is(typeof(D.init - T.init) == D)); 1672 static assert (is(typeof(D.init * T.init) == D)); 1673 static assert (is(typeof(D.init / T.init) == D)); 1674 static assert (is(typeof(D.init % T.init) == D)); 1675 static assert (is(typeof(D.init ^^ T.init) == D)); 1676 } 1677 1678 auto z = decimal32.nan + float.nan; 1679 1680 foreach (T; FloatTypes) 1681 { 1682 static assert (is(typeof(D.init + T.init) == D)); 1683 static assert (is(typeof(D.init - T.init) == D)); 1684 static assert (is(typeof(D.init * T.init) == D)); 1685 static assert (is(typeof(D.init / T.init) == D)); 1686 static assert (is(typeof(D.init % T.init) == D)); 1687 static assert (is(typeof(D.init ^^ T.init) == D)); 1688 } 1689 1690 foreach (T; CharTypes) 1691 { 1692 static assert (is(typeof(D.init + T.init) == D)); 1693 static assert (is(typeof(D.init - T.init) == D)); 1694 static assert (is(typeof(D.init * T.init) == D)); 1695 static assert (is(typeof(D.init / T.init) == D)); 1696 static assert (is(typeof(D.init % T.init) == D)); 1697 static assert (is(typeof(D.init ^^ T.init) == D)); 1698 } 1699 } 1700 1701 //binary right 1702 foreach (D; DecimalTypes) 1703 { 1704 foreach (T; DecimalTypes) 1705 { 1706 static assert (is(typeof(T.init + D.init) == CommonDecimal!(D, T))); 1707 static assert (is(typeof(T.init - D.init) == CommonDecimal!(D, T))); 1708 static assert (is(typeof(T.init * D.init) == CommonDecimal!(D, T))); 1709 static assert (is(typeof(T.init / D.init) == CommonDecimal!(D, T))); 1710 static assert (is(typeof(T.init % D.init) == CommonDecimal!(D, T))); 1711 static assert (is(typeof(T.init ^^ D.init) == CommonDecimal!(D, T))); 1712 } 1713 1714 1715 foreach (T; IntegralTypes) 1716 { 1717 static assert (is(typeof(T.init + D.init) == D)); 1718 static assert (is(typeof(T.init - D.init) == D)); 1719 static assert (is(typeof(T.init * D.init) == D)); 1720 static assert (is(typeof(T.init / D.init) == D)); 1721 static assert (is(typeof(T.init % D.init) == D)); 1722 static assert (is(typeof(T.init ^^ D.init) == D)); 1723 } 1724 1725 foreach (T; FloatTypes) 1726 { 1727 static assert (is(typeof(T.init + D.init) == D)); 1728 static assert (is(typeof(T.init - D.init) == D)); 1729 static assert (is(typeof(T.init * D.init) == D)); 1730 static assert (is(typeof(T.init / D.init) == D)); 1731 static assert (is(typeof(T.init % D.init) == D)); 1732 static assert (is(typeof(T.init ^^ D.init) == D)); 1733 } 1734 1735 foreach (T; CharTypes) 1736 { 1737 static assert (is(typeof(T.init + D.init) == D)); 1738 static assert (is(typeof(T.init - D.init) == D)); 1739 static assert (is(typeof(T.init * D.init) == D)); 1740 static assert (is(typeof(T.init / D.init) == D)); 1741 static assert (is(typeof(T.init % D.init) == D)); 1742 static assert (is(typeof(T.init ^^ D.init) == D)); 1743 } 1744 } 1745 1746 //op assignment 1747 foreach (D; DecimalTypes) 1748 { 1749 foreach (T; DecimalTypes) 1750 { 1751 static assert (is(typeof(D.init += T.init) == D)); 1752 static assert (is(typeof(D.init -= T.init) == D)); 1753 static assert (is(typeof(D.init *= T.init) == D)); 1754 static assert (is(typeof(D.init /= T.init) == D)); 1755 static assert (is(typeof(D.init %= T.init) == D)); 1756 static assert (is(typeof(D.init ^^= T.init) == D)); 1757 } 1758 1759 foreach (T; IntegralTypes) 1760 { 1761 static assert (is(typeof(D.init += T.init) == D)); 1762 static assert (is(typeof(D.init -= T.init) == D)); 1763 static assert (is(typeof(D.init *= T.init) == D)); 1764 static assert (is(typeof(D.init /= T.init) == D)); 1765 static assert (is(typeof(D.init %= T.init) == D)); 1766 static assert (is(typeof(D.init ^^= T.init) == D)); 1767 } 1768 1769 foreach (T; FloatTypes) 1770 { 1771 static assert (is(typeof(D.init += T.init) == D)); 1772 static assert (is(typeof(D.init -= T.init) == D)); 1773 static assert (is(typeof(D.init *= T.init) == D)); 1774 static assert (is(typeof(D.init /= T.init) == D)); 1775 static assert (is(typeof(D.init %= T.init) == D)); 1776 static assert (is(typeof(D.init ^^= T.init) == D)); 1777 } 1778 1779 foreach (T; CharTypes) 1780 { 1781 static assert (is(typeof(D.init += T.init) == D)); 1782 static assert (is(typeof(D.init -= T.init) == D)); 1783 static assert (is(typeof(D.init *= T.init) == D)); 1784 static assert (is(typeof(D.init /= T.init) == D)); 1785 static assert (is(typeof(D.init %= T.init) == D)); 1786 static assert (is(typeof(D.init ^^= T.init) == D)); 1787 } 1788 } 1789 1790 //expected constants 1791 foreach (D; DecimalTypes) 1792 { 1793 static assert (is(typeof(D.init) == D)); 1794 static assert (is(typeof(D.nan) == D)); 1795 static assert (is(typeof(D.infinity) == D)); 1796 static assert (is(typeof(D.max) == D)); 1797 static assert (is(typeof(D.min_normal) == D)); 1798 static assert (is(typeof(D.epsilon) == D)); 1799 static assert (is(typeof(D.dig) == int)); 1800 static assert (is(typeof(D.mant_dig) == int)); 1801 static assert (is(typeof(D.min_10_exp) == int)); 1802 static assert (is(typeof(D.max_10_exp) == int)); 1803 static assert (is(typeof(D.min_exp) == int)); 1804 static assert (is(typeof(D.max_exp) == int)); 1805 1806 static assert (is(typeof(D.E) == D)); 1807 static assert (is(typeof(D.PI) == D)); 1808 static assert (is(typeof(D.PI_2) == D)); 1809 static assert (is(typeof(D.PI_4) == D)); 1810 static assert (is(typeof(D.M_1_PI) == D)); 1811 static assert (is(typeof(D.M_2_PI) == D)); 1812 static assert (is(typeof(D.M_2_SQRTPI) == D)); 1813 static assert (is(typeof(D.LN10) == D)); 1814 static assert (is(typeof(D.LN2) == D)); 1815 static assert (is(typeof(D.LOG2) == D)); 1816 static assert (is(typeof(D.LOG2E) == D)); 1817 static assert (is(typeof(D.LOG2T) == D)); 1818 static assert (is(typeof(D.LOG10E) == D)); 1819 static assert (is(typeof(D.SQRT2) == D)); 1820 static assert (is(typeof(D.SQRT1_2) == D)); 1821 } 1822 1823 //expected members 1824 foreach (D; DecimalTypes) 1825 { 1826 static assert (is(typeof(D.init.toHash()) == size_t)); 1827 static assert (is(typeof(D.init.toString()) == string)); 1828 } 1829 } 1830 1831 1832 1833 @("Decimal should support decimal + float") 1834 unittest 1835 { 1836 immutable expected = decimal128("2"); 1837 1838 auto sut = decimal128("1"); 1839 auto result = sut + 1.0f; 1840 1841 assert(expected == result); 1842 } 1843 1844 @("Decimal should support decimal - float") 1845 unittest 1846 { 1847 immutable expected = decimal128("5"); 1848 1849 auto sut = decimal128("9"); 1850 auto result = sut - 4.0f; 1851 1852 assert(expected == result); 1853 } 1854 1855 @("Decimal should support decimal * float") 1856 unittest 1857 { 1858 immutable expected = decimal128("13.3"); 1859 1860 auto sut = decimal128("1.33"); 1861 auto result = sut * 10.0f; 1862 1863 assert(expected == result); 1864 } 1865 1866 @("Decimal should support decimal / float") 1867 unittest 1868 { 1869 immutable expected = decimal128("0.5"); 1870 1871 auto sut = decimal128("1"); 1872 auto result = sut / 2.0f; 1873 1874 assert(expected == result); 1875 } 1876 1877 @("Decimal should support decimal % float") 1878 unittest 1879 { 1880 immutable expected = decimal128("1"); 1881 1882 auto sut = decimal128("10"); 1883 auto result = sut % 3.0f; 1884 1885 assert(expected == result); 1886 } 1887 1888 1889 @("Decimal should support decimal + integral") 1890 unittest 1891 { 1892 immutable expected = decimal128("3"); 1893 1894 auto sut = decimal128("2"); 1895 auto result = sut + 1; 1896 1897 assert(expected == result); 1898 } 1899 1900 @("Decimal should support decimal - integral") 1901 unittest 1902 { 1903 immutable expected = decimal128("1"); 1904 1905 auto sut = decimal128("3"); 1906 auto result = sut - 2; 1907 1908 assert(expected == result); 1909 } 1910 1911 @("Decimal should support decimal * integral") 1912 unittest 1913 { 1914 immutable expected = decimal128("123.4"); 1915 1916 auto sut = decimal128("12.34"); 1917 auto result = sut * 10; 1918 1919 assert(expected == result); 1920 } 1921 1922 @("Decimal should support decimal / integral") 1923 unittest 1924 { 1925 immutable expected = decimal128("0.5"); 1926 1927 auto sut = decimal128("1"); 1928 auto result = sut / 2; 1929 1930 assert(expected == result); 1931 } 1932 1933 @("Decimal should support decimal % integral") 1934 unittest 1935 { 1936 immutable expected = decimal128("1"); 1937 1938 auto sut = decimal128("10"); 1939 auto result = sut % 3; 1940 1941 assert(expected == result); 1942 } 1943 1944 @("Decimal should support decimal % unsigned integral") 1945 unittest 1946 { 1947 immutable expected = decimal128("1"); 1948 1949 auto sut = decimal128("10"); 1950 auto result = sut % 3u; 1951 1952 assert(expected == result); 1953 } 1954 1955 ///Shorthand notations for $(MYREF Decimal) types 1956 alias decimal32 = Decimal!32; 1957 ///ditto 1958 alias decimal64 = Decimal!64; 1959 ///ditto 1960 alias decimal128 = Decimal!128; 1961 1962 1963 ///Returns true if all specified types are _decimal types. 1964 template isDecimal(D...) 1965 { 1966 static if (D.length == 0) 1967 enum isDecimal = false; 1968 static if (D.length == 1) 1969 enum isDecimal = is(D[0] == decimal32) || is(D[0] == decimal64) || is(D[0] == decimal128); 1970 else 1971 enum isDecimal = isDecimal!(D[0]) && isDecimal!(D[1 .. $]); 1972 } 1973 1974 /// 1975 unittest 1976 { 1977 static assert(isDecimal!decimal32); 1978 static assert(isDecimal!(decimal32, decimal64)); 1979 static assert(!isDecimal!int); 1980 static assert(!isDecimal!(decimal128, byte)); 1981 } 1982 1983 ///Returns the most wide _decimal type among the specified types 1984 template CommonDecimal(T...) if (isDecimal!T) 1985 { 1986 static if (T.length == 1) 1987 alias CommonDecimal = T[0]; 1988 else static if (is(T[0] == decimal128) || is(T[1] == decimal128)) 1989 alias CommonDecimal = decimal128; 1990 else static if (T.length == 2) 1991 { 1992 static if (is(T[0] == decimal32)) 1993 alias CommonDecimal = T[1]; 1994 else static if (is(T[1] == decimal32)) 1995 alias CommonDecimal = T[0]; 1996 else static if (is(T[0] == decimal64) && is(T[1] == decimal128)) 1997 alias CommonDecimal = decimal128; 1998 else static if (is(T[1] == decimal64) && is(T[0] == decimal128)) 1999 alias CommonDecimal = decimal128; 2000 else static if (is(T[1] == T[0])) 2001 alias CommonDecimal = T[0]; 2002 else 2003 static assert(false, "Never happen"); 2004 } 2005 else 2006 alias CommonDecimal = CommonDecimal!(CommonDecimal!(T[0 .. 1], CommonDecimal!(T[2 .. $]))); 2007 } 2008 2009 /// 2010 unittest 2011 { 2012 static assert(is(CommonDecimal!(decimal32, decimal64) == decimal64)); 2013 static assert(is(CommonDecimal!(decimal32, decimal128) == decimal128)); 2014 static assert(is(CommonDecimal!(decimal64, decimal128) == decimal128)); 2015 } 2016 2017 version(D_BetterC) 2018 { 2019 2020 } 2021 else 2022 { 2023 2024 ///Root object for all _decimal exceptions 2025 abstract class DecimalException : Exception 2026 { 2027 mixin ExceptionConstructors; 2028 } 2029 2030 ///Thrown if any operand of a _decimal operation is not a number or si not finite 2031 class InvalidOperationException : DecimalException 2032 { 2033 mixin ExceptionConstructors; 2034 } 2035 2036 ///Thrown if the denominator of a _decimal division operation is zero. 2037 class DivisionByZeroException : DecimalException 2038 { 2039 mixin ExceptionConstructors; 2040 } 2041 2042 ///Thrown if the result of a _decimal operation exceeds the largest finite number of the destination format. 2043 class OverflowException : DecimalException 2044 { 2045 mixin ExceptionConstructors; 2046 } 2047 2048 ///Thrown if the result of a _decimal operation is smaller the smallest finite number of the destination format. 2049 class UnderflowException : DecimalException 2050 { 2051 mixin ExceptionConstructors; 2052 } 2053 2054 ///Thrown if the result of a _decimal operation was rounded to fit in the destination format. 2055 class InexactException : DecimalException 2056 { 2057 mixin ExceptionConstructors; 2058 } 2059 } 2060 /** 2061 These flags indicate that an error has occurred. They indicate that a 0, $(B NaN) or an infinity value has been generated, 2062 that a result is inexact, or that a signalling $(B NaN) has been encountered. 2063 If the corresponding traps are set using $(MYREF DecimalControl), 2064 an exception will be thrown after setting these error flags. 2065 2066 By default the context will have all error flags lowered and exceptions are thrown only for severe errors. 2067 */ 2068 enum ExceptionFlags : uint 2069 { 2070 ///no error 2071 none = 0U, 2072 ///$(MYREF InvalidOperationException) is thrown if trap is set 2073 invalidOperation = 1U << 0, 2074 ///$(MYREF DivisionByZeroException) is thrown if trap is set 2075 divisionByZero = 1U << 1, 2076 ///$(MYREF OverflowException) is thrown if trap is set 2077 overflow = 1U << 2, 2078 ///$(MYREF UnderflowException) is thrown if trap is set 2079 underflow = 1U << 3, 2080 ///$(MYREF InexactException) is thrown if trap is set 2081 inexact = 1U << 4, 2082 ///group of errors considered severe: invalidOperation, divisionByZero, overflow 2083 severe = invalidOperation | divisionByZero | overflow, 2084 ///all errors 2085 all = severe | underflow | inexact 2086 } 2087 2088 /** 2089 * Rounding modes. To better understand how rounding is performed, consult the table below. 2090 * 2091 * $(BOOKTABLE, 2092 * $(TR $(TH Value) $(TH tiesToEven) $(TH tiesToAway) $(TH towardPositive) $(TH towardNegative) $(TH towardZero)) 2093 * $(TR $(TD +1.3) $(TD +1) $(TD +1) $(TD +2) $(TD +1) $(TD +1)) 2094 * $(TR $(TD +1.5) $(TD +2) $(TD +2) $(TD +2) $(TD +1) $(TD +1)) 2095 * $(TR $(TD +1.8) $(TD +2) $(TD +2) $(TD +2) $(TD +1) $(TD +1)) 2096 * $(TR $(TD -1.3) $(TD -1) $(TD -1) $(TD -1) $(TD -2) $(TD -1)) 2097 * $(TR $(TD -1.5) $(TD -2) $(TD -2) $(TD -1) $(TD -2) $(TD -1)) 2098 * $(TR $(TD -1.8) $(TD -2) $(TD -2) $(TD -1) $(TD -2) $(TD -1)) 2099 * $(TR $(TD +2.3) $(TD +2) $(TD +2) $(TD +3) $(TD +2) $(TD +2)) 2100 * $(TR $(TD +2.5) $(TD +2) $(TD +3) $(TD +3) $(TD +2) $(TD +2)) 2101 * $(TR $(TD +2.8) $(TD +3) $(TD +3) $(TD +3) $(TD +2) $(TD +2)) 2102 * $(TR $(TD -2.3) $(TD -2) $(TD -2) $(TD -2) $(TD -3) $(TD -2)) 2103 * $(TR $(TD -2.5) $(TD -2) $(TD -3) $(TD -2) $(TD -3) $(TD -2)) 2104 * $(TR $(TD -2.8) $(TD -3) $(TD -3) $(TD -2) $(TD -3) $(TD -2)) 2105 * ) 2106 */ 2107 enum RoundingMode 2108 { 2109 ///rounded away from zero; halfs are rounded to the nearest even number 2110 tiesToEven, 2111 ///rounded away from zero 2112 tiesToAway, 2113 ///truncated toward positive infinity 2114 towardPositive, 2115 ///truncated toward negative infinity 2116 towardNegative, 2117 ///truncated toward zero 2118 towardZero, 2119 2120 implicit = tiesToEven, 2121 } 2122 2123 /** 2124 _Precision used to round _decimal operation results. Every result will be adjusted 2125 to fit the specified precision. Use $(MYREF DecimalControl) to query or set the 2126 context precision 2127 */ 2128 alias Precision = uint; 2129 ///ditto 2130 enum : Precision 2131 { 2132 ///use the default precision of the current type 2133 ///(7 digits for decimal32, 16 digits for decimal64 or 34 digits for decimal128) 2134 precisionDefault = 0, 2135 ///use 32 bits precision (7 digits) 2136 precision32 = Decimal!32.PRECISION, 2137 ///use 64 bits precision (16 digits) 2138 precision64 = Decimal!64.PRECISION, 2139 ////use 128 bits precision (34 digits) 2140 precision128 = Decimal!128.PRECISION, 2141 } 2142 2143 /** 2144 Container for _decimal context control, provides methods to alter exception handling, 2145 manually edit error flags, adjust arithmetic precision and rounding mode 2146 */ 2147 struct DecimalControl 2148 { 2149 private: 2150 static ExceptionFlags flags; 2151 static ExceptionFlags traps; 2152 2153 @safe 2154 static void checkFlags(const ExceptionFlags group, const ExceptionFlags traps) 2155 { 2156 version(D_BetterC) 2157 { 2158 if (__ctfe) 2159 { 2160 if ((group & ExceptionFlags.invalidOperation) && (traps & ExceptionFlags.invalidOperation)) 2161 assert(0, "Invalid operation"); 2162 if ((group & ExceptionFlags.divisionByZero) && (traps & ExceptionFlags.divisionByZero)) 2163 assert(0, "Division by zero"); 2164 if ((group & ExceptionFlags.overflow) && (traps & ExceptionFlags.overflow)) 2165 assert(0, "Overflow"); 2166 } 2167 } 2168 else 2169 { 2170 if ((group & ExceptionFlags.invalidOperation) && (traps & ExceptionFlags.invalidOperation)) 2171 throw new InvalidOperationException("Invalid operation"); 2172 if ((group & ExceptionFlags.divisionByZero) && (traps & ExceptionFlags.divisionByZero)) 2173 throw new DivisionByZeroException("Division by zero"); 2174 if ((group & ExceptionFlags.overflow) && (traps & ExceptionFlags.overflow)) 2175 throw new OverflowException("Overflow"); 2176 if ((group & ExceptionFlags.underflow) && (traps & ExceptionFlags.underflow)) 2177 throw new UnderflowException("Underflow"); 2178 if ((group & ExceptionFlags.inexact) && (traps & ExceptionFlags.inexact)) 2179 throw new InexactException("Inexact"); 2180 } 2181 2182 } 2183 2184 public: 2185 2186 /** 2187 Gets or sets the rounding mode used when the result of an operation exceeds the _decimal precision. 2188 See $(MYREF RoundingMode) for details. 2189 --- 2190 DecimalControl.rounding = RoundingMode.tiesToEven; 2191 decimal32 d1 = 123456789; 2192 assert(d1 == 123456800); 2193 2194 DecimalControl.rounding = RoundingMode.towardNegative; 2195 decimal32 d2 = 123456789; 2196 assert(d2 == 123456700); 2197 --- 2198 */ 2199 @IEEECompliant("defaultModes", 46) 2200 @IEEECompliant("getDecimalRoundingDirection", 46) 2201 @IEEECompliant("restoreModes", 46) 2202 @IEEECompliant("saveModes", 46) 2203 @IEEECompliant("setDecimalRoundingDirection", 46) 2204 static RoundingMode rounding; 2205 2206 /** 2207 Gets or sets the precision applied to peration results. 2208 See $(MYREF Precision) for details. 2209 --- 2210 DecimalControl.precision = precisionDefault; 2211 decimal32 d1 = 12345; 2212 assert(d1 == 12345); 2213 2214 DecimalControl.precision = 4; 2215 decimal32 d2 = 12345; 2216 assert(d2 == 12350); 2217 --- 2218 */ 2219 static Precision precision; 2220 2221 /** 2222 Sets specified error flags. Multiple errors may be ORed together. 2223 --- 2224 DecimalControl.raiseFlags(ExceptionFlags.overflow | ExceptionFlags.underflow); 2225 assert (DecimalControl.overflow); 2226 assert (DecimalControl.underflow); 2227 --- 2228 */ 2229 @IEEECompliant("raiseFlags", 26) 2230 @safe 2231 static void raiseFlags(const ExceptionFlags group) 2232 { 2233 if (__ctfe) 2234 checkFlags(group, ExceptionFlags.severe); 2235 else 2236 { 2237 ExceptionFlags newFlags = flags ^ (group & ExceptionFlags.all); 2238 flags |= group & ExceptionFlags.all; 2239 checkFlags(newFlags, traps); 2240 } 2241 } 2242 2243 /** 2244 Unsets specified error flags. Multiple errors may be ORed together. 2245 --- 2246 DecimalControl.resetFlags(ExceptionFlags.inexact); 2247 assert(!DecimalControl.inexact); 2248 --- 2249 */ 2250 @IEEECompliant("lowerFlags", 26) 2251 @nogc @safe nothrow 2252 static void resetFlags(const ExceptionFlags group) 2253 { 2254 flags &= ~(group & ExceptionFlags.all); 2255 } 2256 2257 ///ditto 2258 @IEEECompliant("lowerFlags", 26) 2259 @nogc @safe nothrow 2260 static void resetFlags() 2261 { 2262 flags = ExceptionFlags.none; 2263 } 2264 2265 /** 2266 Enables specified error flags (group) without throwing corresponding exceptions. 2267 --- 2268 DecimalControl.restoreFlags(ExceptionFlags.underflow | ExceptionsFlags.inexact); 2269 assert (DecimalControl.testFlags(ExceptionFlags.underflow | ExceptionFlags.inexact)); 2270 --- 2271 */ 2272 @IEEECompliant("restoreFlags", 26) 2273 @nogc @safe nothrow 2274 static void restoreFlags(const ExceptionFlags group) 2275 { 2276 flags |= group & ExceptionFlags.all; 2277 } 2278 2279 /** 2280 Checks if the specified error flags are set. Multiple exceptions may be ORed together. 2281 --- 2282 DecimalControl.raiseFlags(ExceptionFlags.overflow | ExceptionFlags.underflow | ExceptionFlags.inexact); 2283 assert (DecimalControl.hasFlags(ExceptionFlags.overflow | ExceptionFlags.inexact)); 2284 --- 2285 */ 2286 @IEEECompliant("testFlags", 26) 2287 @IEEECompliant("testSavedFlags", 26) 2288 @nogc @safe nothrow 2289 static bool hasFlags(const ExceptionFlags group) 2290 { 2291 return (flags & (group & ExceptionFlags.all)) != 0; 2292 } 2293 2294 2295 /** 2296 Returns the current set flags. 2297 --- 2298 DecimalControl.restoreFlags(ExceptionFlags.inexact); 2299 assert (DecimalControl.saveFlags() & ExceptionFlags.inexact); 2300 --- 2301 */ 2302 @IEEECompliant("saveAllFlags", 26) 2303 @nogc @safe nothrow 2304 static ExceptionFlags saveFlags() 2305 { 2306 return flags; 2307 } 2308 2309 /** 2310 Disables specified exceptions. Multiple exceptions may be ORed together. 2311 --- 2312 DecimalControl.disableExceptions(ExceptionFlags.overflow); 2313 auto d = decimal64.max * decimal64.max; 2314 assert (DecimalControl.overflow); 2315 assert (isInfinity(d)); 2316 --- 2317 */ 2318 @nogc @safe nothrow 2319 static void disableExceptions(const ExceptionFlags group) 2320 { 2321 traps &= ~(group & ExceptionFlags.all); 2322 } 2323 2324 ///ditto 2325 @nogc @safe nothrow 2326 static void disableExceptions() 2327 { 2328 traps = ExceptionFlags.none; 2329 } 2330 2331 2332 2333 /** 2334 Enables specified exceptions. Multiple exceptions may be ORed together. 2335 --- 2336 DecimalControl.enableExceptions(ExceptionFlags.overflow); 2337 try 2338 { 2339 auto d = decimal64.max * 2; 2340 } 2341 catch (OverflowException) 2342 { 2343 writeln("Overflow error") 2344 } 2345 --- 2346 */ 2347 @nogc @safe nothrow 2348 static void enableExceptions(const ExceptionFlags group) 2349 { 2350 traps |= group & ExceptionFlags.all; 2351 } 2352 2353 /** 2354 Extracts current enabled exceptions. 2355 --- 2356 auto saved = DecimalControl.enabledExceptions; 2357 DecimalControl.disableExceptions(ExceptionFlags.all); 2358 DecimalControl.enableExceptions(saved); 2359 --- 2360 */ 2361 @nogc @safe nothrow 2362 static @property ExceptionFlags enabledExceptions() 2363 { 2364 return traps; 2365 } 2366 2367 /** 2368 IEEE _decimal context errors. By default, no error is set. 2369 --- 2370 DecimalControl.disableExceptions(ExceptionFlags.all); 2371 decimal32 uninitialized; 2372 decimal64 d = decimal64.max * 2; 2373 decimal32 e = uninitialized + 5.0; 2374 assert(DecimalControl.overflow); 2375 assert(DecimalControl.invalidOperation); 2376 --- 2377 */ 2378 @nogc @safe nothrow 2379 static @property bool invalidOperation() 2380 { 2381 return (flags & ExceptionFlags.invalidOperation) != 0; 2382 } 2383 2384 ///ditto 2385 @nogc @safe nothrow 2386 static @property bool divisionByZero() 2387 { 2388 return (flags & ExceptionFlags.divisionByZero) != 0; 2389 } 2390 2391 ///ditto 2392 @nogc @safe nothrow 2393 static @property bool overflow() 2394 { 2395 return (flags & ExceptionFlags.overflow) != 0; 2396 } 2397 2398 ///ditto 2399 @nogc @safe nothrow 2400 static @property bool underflow() 2401 { 2402 return (flags & ExceptionFlags.underflow) != 0; 2403 } 2404 2405 ///ditto 2406 @nogc @safe nothrow 2407 static @property bool inexact() 2408 { 2409 return (flags & ExceptionFlags.inexact) != 0; 2410 } 2411 2412 ///true if this programming environment conforms to IEEE 754-1985 2413 @IEEECompliant("is754version1985", 24) 2414 enum is754version1985 = true; 2415 2416 ///true if this programming environment conforms to IEEE 754-2008 2417 @IEEECompliant("is754version2008", 24) 2418 enum is754version2008 = true; 2419 } 2420 2421 2422 /** 2423 Calculates the arc cosine of x, returning a value ranging from 0 to π. 2424 Exceptions: 2425 $(BOOKTABLE, 2426 $(TR $(TD $(MYREF InvalidOperationException)) 2427 $(TD x is signaling $(B NaN) or |x| > 1.0)) 2428 $(TR $(TD $(MYREF InexactException)) 2429 $(TD the result is inexact)) 2430 ) 2431 Special_values: 2432 $(BOOKTABLE, 2433 $(TR $(TH x) $(TH acos(x))) 2434 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 2435 $(TR $(TD -1.0) $(TD π)) 2436 $(TR $(TD +1.0) $(TD +0.0)) 2437 $(TR $(TD < -1.0) $(TD $(B NaN))) 2438 $(TR $(TD > +1.0) $(TD $(B NaN))) 2439 ) 2440 */ 2441 @IEEECompliant("acos", 43) 2442 D acos(D)(auto const ref D x) 2443 if (isDecimal!D) 2444 { 2445 Unqual!D result = x; 2446 auto flags = decimalAcos(result, 2447 __ctfe ? D.PRECISION : DecimalControl.precision, 2448 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 2449 flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation); 2450 DecimalControl.raiseFlags(flags); 2451 return result; 2452 } 2453 2454 /// 2455 unittest 2456 { 2457 decimal32 x = 0; 2458 assert(acos(x) == decimal32.PI_2); 2459 } 2460 2461 unittest 2462 { 2463 foreach(T; TypeTuple!(decimal32, decimal64, decimal128)) 2464 { 2465 assert (acos(-T.one) == T.PI); 2466 assert (acos(T.one) == 0); 2467 assert (acos(T.zero) == T.PI_2); 2468 assert (isNaN(acos(T.nan))); 2469 } 2470 } 2471 2472 /** 2473 Calculates the inverse hyperbolic cosine of x 2474 Exceptions: 2475 $(BOOKTABLE, 2476 $(TR $(TD $(MYREF InvalidOperationException)) 2477 $(TD x is signaling $(B NaN) or x < 1.0)) 2478 $(TR $(TD $(MYREF InexactException)) 2479 $(TD the result is inexact)) 2480 ) 2481 Special_values: 2482 $(BOOKTABLE, 2483 $(TR $(TH x) $(TH acosh(x))) 2484 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 2485 $(TR $(TD +1.0) $(TD +0.0)) 2486 $(TR $(TD +∞) $(TD +∞)) 2487 $(TR $(TD < 1.0) $(TD $(B NaN))) 2488 ) 2489 */ 2490 @IEEECompliant("acosh", 43) 2491 D acosh(D)(auto const ref D x) 2492 if (isDecimal!D) 2493 { 2494 Unqual!D result = x; 2495 auto flags = decimalAcosh(result, 2496 __ctfe ? D.PRECISION : DecimalControl.precision, 2497 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 2498 flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation); 2499 DecimalControl.raiseFlags(flags); 2500 return result; 2501 } 2502 2503 /// 2504 unittest 2505 { 2506 decimal32 x = 1; 2507 assert (acosh(x) == 0); 2508 } 2509 2510 unittest 2511 { 2512 foreach(T; TypeTuple!(decimal32, decimal64, decimal128)) 2513 { 2514 assert (acosh(T.one) == T.zero); 2515 assert (acosh(T.infinity) == T.infinity); 2516 assert (isNaN(acosh(T.nan))); 2517 } 2518 } 2519 2520 2521 /** 2522 Computes whether two values are approximately equal, admitting a maximum relative difference, 2523 or a maximum absolute difference. 2524 Params: 2525 x = First item to compare 2526 y = Second item to compare 2527 maxRelDiff = Maximum allowable relative difference (defaults to 1e-5) 2528 maxAbsDiff = Maximum allowable absolute difference (defaults to 1e-2) 2529 Returns: 2530 true if the two items are approximately equal under either criterium. 2531 Notes: 2532 This operation is silent, does not throw any exceptions and it doesn't set any error flags. 2533 */ 2534 bool approxEqual(D1, D2, D3, D4)(auto const ref D1 x, auto const ref D2 y, 2535 auto const ref D3 maxRelDiff, 2536 auto const ref D4 maxAbsDiff) 2537 if (isDecimal!(D1, D2, D3, D4)) 2538 { 2539 if (isInfinity(x) && isInfinity(y)) 2540 return signbit(x) == signbit(y); 2541 else 2542 { 2543 alias D = CommonDecimal!(D1, D2, D3, D4); 2544 D d; 2545 decimalToDecimal(x, d, D.PRECISION, __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 2546 decimalSub(d, y, D.PRECISION, __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 2547 d = fabs(d); 2548 if (decimalCmp(maxAbsDiff, d) >= 0) 2549 return true; 2550 decimalDiv(d, y, D.PRECISION, __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 2551 if (decimalCmp(maxRelDiff, d) >= 0) 2552 return true; 2553 } 2554 return false; 2555 } 2556 2557 ///ditto 2558 bool approxEqual(D1, D2, D3)(auto const ref D1 x, auto const ref D2 y, 2559 auto const ref D3 maxRelDiff) 2560 if (isDecimal!(D1, D2, D3)) 2561 { 2562 enum maxAbsDiff = CommonDecimal!(D1, D2, D3)("1e-5"); 2563 return approxEqual(x, y, maxRelDiff, maxAbsDiff); 2564 } 2565 2566 ///ditto 2567 bool approxEqual(D1, D2)(auto const ref D1 x, auto const ref D2 y) 2568 if (isDecimal!(D1, D2)) 2569 { 2570 enum maxAbsDiff = CommonDecimal!(D1, D2)("1e-5"); 2571 enum maxRelDiff = CommonDecimal!(D1, D2)("1e-2"); 2572 return approxEqual(x, y, maxRelDiff, maxAbsDiff); 2573 } 2574 2575 2576 2577 /** 2578 Calculates the arc sine of x, returning a value ranging from -π/2 to +π/2. 2579 Exceptions: 2580 $(BOOKTABLE, 2581 $(TR $(TD $(MYREF InvalidOperationException)) 2582 $(TD x is signaling $(B NaN) or |x| > 1.0)) 2583 $(TR $(TD $(MYREF InexactException)) 2584 $(TD the result is inexact)) 2585 ) 2586 Special_values: 2587 $(BOOKTABLE, 2588 $(TR $(TH x) $(TH asin(x))) 2589 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 2590 $(TR $(TD -1.0) $(TD -π/2)) 2591 $(TR $(TD +1.0) $(TD +π/2)) 2592 $(TR $(TD < -1.0) $(TD $(B NaN))) 2593 $(TR $(TD > +1.0) $(TD $(B NaN))) 2594 ) 2595 */ 2596 @IEEECompliant("asin", 43) 2597 D asin(D)(auto const ref D x) 2598 if (isDecimal!D) 2599 { 2600 Unqual!D result = x; 2601 auto flags = decimalAsin(result, 2602 __ctfe ? D.PRECISION : DecimalControl.precision, 2603 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 2604 flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation); 2605 DecimalControl.raiseFlags(flags); 2606 return result; 2607 } 2608 2609 /// 2610 unittest 2611 { 2612 decimal32 x = 1; 2613 assert(asin(x) == decimal32.PI_2); 2614 assert(asin(-x) == -decimal32.PI_2); 2615 } 2616 2617 unittest 2618 { 2619 foreach(T; TypeTuple!(decimal32, decimal64, decimal128)) 2620 { 2621 assert (asin(-T.one) == -T.PI_2); 2622 assert (asin(T.zero) == 0); 2623 assert (asin(T.one) == T.PI_2); 2624 assert (isNaN(asin(T.nan))); 2625 } 2626 } 2627 2628 2629 /** 2630 Calculates the inverse hyperbolic sine of x 2631 Exceptions: 2632 $(BOOKTABLE, 2633 $(TR $(TD $(MYREF InvalidOperationException)) 2634 $(TD x is signaling $(B NaN))) 2635 $(TR $(TD $(MYREF UnderflowException)) 2636 $(TD the result is too small to be represented)) 2637 $(TR $(TD $(MYREF InexactException)) 2638 $(TD the result is inexact)) 2639 ) 2640 Special_values: 2641 $(BOOKTABLE, 2642 $(TR $(TH x) $(TH asinh(x))) 2643 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 2644 $(TR $(TD ±0.0) $(TD ±0.0)) 2645 $(TR $(TD ±∞) $(TD ±∞)) 2646 ) 2647 */ 2648 @IEEECompliant("asinh", 43) 2649 D asinh(D)(auto const ref D x) 2650 if (isDecimal!D) 2651 { 2652 Unqual!D result = x; 2653 auto flags = decimalAsinh(result, 2654 __ctfe ? D.PRECISION : DecimalControl.precision, 2655 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 2656 flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.underflow); 2657 DecimalControl.raiseFlags(flags); 2658 return result; 2659 } 2660 2661 /// 2662 unittest 2663 { 2664 decimal32 x = 0; 2665 assert (asinh(x) == 0); 2666 } 2667 2668 unittest 2669 { 2670 foreach(T; TypeTuple!(decimal32, decimal64, decimal128)) 2671 { 2672 assert (asinh(T.zero) == T.zero); 2673 assert (asinh(T.infinity) == T.infinity); 2674 assert (isNaN(asinh(T.nan))); 2675 } 2676 } 2677 2678 2679 2680 /** 2681 Calculates the arc tangent of x, returning a value ranging from -π/2 to π/2. 2682 Exceptions: 2683 $(BOOKTABLE, 2684 $(TR $(TD $(MYREF InvalidOperationException)) 2685 $(TD x is signaling $(B NaN))) 2686 $(TR $(TD $(MYREF InexactException)) 2687 $(TD the result is inexact)) 2688 $(TR $(TD $(MYREF UnderflowException)) 2689 $(TD the result is too small to be represented)) 2690 ) 2691 Special_values: 2692 $(BOOKTABLE, 2693 $(TR $(TH x) $(TH atan(x))) 2694 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 2695 $(TR $(TD ±0.0) $(TD ±0.0)) 2696 $(TR $(TD ±∞) $(TD ±π/2)) 2697 ) 2698 */ 2699 @IEEECompliant("atan", 43) 2700 D atan(D)(auto const ref D x) 2701 if (isDecimal!D) 2702 { 2703 Unqual!D result = x; 2704 auto flags = decimalAtan(result, 2705 __ctfe ? D.PRECISION : DecimalControl.precision, 2706 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 2707 flags &= ExceptionFlags.invalidOperation | ExceptionFlags.underflow | ExceptionFlags.inexact; 2708 DecimalControl.raiseFlags(flags); 2709 return result; 2710 } 2711 2712 /// 2713 unittest 2714 { 2715 decimal32 radians = 1; 2716 assert(atan(radians) == decimal32.PI_4); 2717 } 2718 2719 2720 unittest 2721 { 2722 foreach(T; TypeTuple!(decimal32, decimal64, decimal128)) 2723 { 2724 assert (isIdentical(atan(T.zero), T.zero)); 2725 assert (isIdentical(atan(-T.zero), -T.zero)); 2726 assert (isIdentical(atan(T.infinity), T.PI_2)); 2727 assert (isIdentical(atan(-T.infinity), -T.PI_2)); 2728 assert (isNaN(atan(T.nan))); 2729 } 2730 } 2731 2732 /** 2733 Calculates the arc tangent of y / x, returning a value ranging from -π to π. 2734 Exceptions: 2735 $(BOOKTABLE, 2736 $(TR $(TD $(MYREF InvalidOperationException)) 2737 $(TD x or y is signaling $(B NaN))) 2738 $(TR $(TD $(MYREF InexactException)) 2739 $(TD the result is inexact)) 2740 $(TR $(TD $(MYREF UnderflowException)) 2741 $(TD the result is too small to be represented)) 2742 ) 2743 Special_values: 2744 $(BOOKTABLE, 2745 $(TR $(TH y) $(TH x) $(TH atan2(y, x))) 2746 $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN))) 2747 $(TR $(TD any) $(TD $(B NaN)) $(TD $(B NaN))) 2748 $(TR $(TD ±0.0) $(TD -0.0) $(TD ±π)) 2749 $(TR $(TD ±0.0) $(TD +0.0) $(TD ±0.0)) 2750 $(TR $(TD ±0.0) $(TD <0.0) $(TD ±π)) 2751 $(TR $(TD ±0.0) $(TD >0.0) $(TD ±0.0)) 2752 $(TR $(TD ±∞) $(TD -∞) $(TD ±3π/4)) 2753 $(TR $(TD ±∞) $(TD +∞) $(TD ±π/4)) 2754 $(TR $(TD ±∞) $(TD any) $(TD ±π/2)) 2755 $(TR $(TD any) $(TD -∞) $(TD ±π)) 2756 $(TR $(TD any) $(TD +∞) $(TD ±0.0)) 2757 ) 2758 */ 2759 @IEEECompliant("atan2", 43) 2760 auto atan2(D1, D2)(auto const ref D1 y, auto const ref D2 x) 2761 if (isDecimal!(D1, D2)) 2762 { 2763 alias D = CommonDecimal!(D1, D2); 2764 D result; 2765 auto flags = decimalAtan2(y, x, result, 2766 __ctfe ? D.PRECISION : DecimalControl.precision, 2767 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 2768 flags &= ExceptionFlags.invalidOperation | ExceptionFlags.underflow | ExceptionFlags.inexact; 2769 DecimalControl.raiseFlags(flags); 2770 return result; 2771 } 2772 2773 /// 2774 unittest 2775 { 2776 decimal32 y = 10; 2777 decimal32 x = 0; 2778 assert (atan2(y, x) == decimal32.PI_2); 2779 } 2780 2781 unittest 2782 { 2783 2784 foreach(T; TypeTuple!(decimal32, decimal64, decimal128)) 2785 { 2786 assert (isNaN(atan2(T.nan, T.zero))); 2787 assert (isNaN(atan2(T.one, T.nan))); 2788 assert (atan2(T.zero, -T.zero) == T.PI); 2789 assert (atan2(-T.zero, -T.zero) == -T.PI); 2790 assert (atan2(T.zero, T.zero) == T.zero); 2791 assert (atan2(-T.zero, T.zero) == -T.zero); 2792 assert (atan2(T.zero, -T.one) == T.PI); 2793 assert (atan2(-T.zero, -T.one) == -T.PI); 2794 assert (atan2(T.zero, T.one) == T.zero); 2795 assert (atan2(-T.zero, T.one) == -T.zero); 2796 assert (atan2(-T.one, T.zero) == -T.PI_2); 2797 assert (atan2(T.one, T.zero) == T.PI_2); 2798 assert (atan2(T.one, -T.infinity) == T.PI); 2799 assert (atan2(-T.one, -T.infinity) == -T.PI); 2800 assert (atan2(T.one, T.infinity) == T.zero); 2801 assert (atan2(-T.one, T.infinity) == -T.zero); 2802 assert (atan2(-T.infinity, T.one) == -T.PI_2); 2803 assert (atan2(T.infinity, T.one) == T.PI_2); 2804 assert (atan2(-T.infinity, -T.infinity) == -T._3PI_4); 2805 assert (atan2(T.infinity, -T.infinity) == T._3PI_4); 2806 assert (atan2(-T.infinity, T.infinity) == -T.PI_4); 2807 assert (atan2(T.infinity, T.infinity) == T.PI_4); 2808 } 2809 } 2810 2811 /** 2812 Calculates the arc tangent of y / x divided by π, returning a value ranging from -1 to 1. 2813 Exceptions: 2814 $(BOOKTABLE, 2815 $(TR $(TD $(MYREF InvalidOperationException)) 2816 $(TD x or y is signaling $(B NaN))) 2817 $(TR $(TD $(MYREF InexactException)) 2818 $(TD the result is inexact)) 2819 $(TR $(TD $(MYREF UnderflowException)) 2820 $(TD the result is too small to be represented)) 2821 ) 2822 Special_values: 2823 $(BOOKTABLE, 2824 $(TR $(TH y) $(TH x) $(TH atan2pi(y, x))) 2825 $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN))) 2826 $(TR $(TD any) $(TD $(B NaN)) $(TD $(B NaN))) 2827 $(TR $(TD ±0.0) $(TD -0.0) $(TD ±1.0)) 2828 $(TR $(TD ±0.0) $(TD +0.0) $(TD ±0.0)) 2829 $(TR $(TD ±0.0) $(TD <0.0) $(TD ±1.0)) 2830 $(TR $(TD ±0.0) $(TD >0.0) $(TD ±0.0)) 2831 $(TR $(TD ±∞) $(TD -∞) $(TD ±3/4)) 2832 $(TR $(TD ±∞) $(TD +∞) $(TD ±1/4)) 2833 $(TR $(TD ±∞) $(TD any) $(TD ±1/2)) 2834 $(TR $(TD any) $(TD -∞) $(TD ±1.0)) 2835 $(TR $(TD any) $(TD +∞) $(TD ±0.0)) 2836 ) 2837 */ 2838 @IEEECompliant("atan2Pi", 43) 2839 auto atan2pi(D1, D2)(auto const ref D1 y, auto const ref D2 x) 2840 if (isDecimal!(D1, D2)) 2841 { 2842 alias D = CommonDecimal!(D1, D2); 2843 D result; 2844 auto flags = decimalAtan2Pi(y, x, result, 2845 __ctfe ? D.PRECISION : DecimalControl.precision, 2846 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 2847 flags &= ExceptionFlags.invalidOperation | ExceptionFlags.underflow | ExceptionFlags.inexact; 2848 DecimalControl.raiseFlags(flags); 2849 return result; 2850 } 2851 2852 /// 2853 unittest 2854 { 2855 decimal32 y = 10; 2856 decimal32 x = 0; 2857 assert (atan2pi(y, x) == decimal32("0.5")); 2858 } 2859 2860 unittest 2861 { 2862 2863 foreach(T; TypeTuple!(decimal32, decimal64, decimal128)) 2864 { 2865 assert (isNaN(atan2(T.nan, T.zero))); 2866 assert (isNaN(atan2(T.one, T.nan))); 2867 assert (atan2pi(T.zero, -T.zero) == T.one); 2868 assert (atan2pi(-T.zero, -T.zero) == -T.one); 2869 assert (atan2pi(T.zero, T.zero) == T.zero); 2870 assert (atan2pi(-T.zero, T.zero) == -T.zero); 2871 assert (atan2pi(T.zero, -T.one) == T.one); 2872 assert (atan2pi(-T.zero, -T.one) == -T.one); 2873 assert (atan2pi(T.zero, T.one) == T.zero); 2874 assert (atan2pi(-T.zero, T.one) == -T.zero); 2875 assert (atan2pi(-T.one, T.zero) == -T.half); 2876 assert (atan2pi(T.one, T.zero) == T.half); 2877 assert (atan2pi(T.one, -T.infinity) == T.one); 2878 assert (atan2pi(-T.one, -T.infinity) == -T.one); 2879 assert (atan2pi(T.one, T.infinity) == T.zero); 2880 assert (atan2pi(-T.one, T.infinity) == -T.zero); 2881 assert (atan2pi(-T.infinity, T.one) == -T.half); 2882 assert (atan2pi(T.infinity, T.one) == T.half); 2883 assert (atan2pi(-T.infinity, -T.infinity) == -T.threequarters); 2884 assert (atan2pi(T.infinity, -T.infinity) == T.threequarters); 2885 assert (atan2pi(-T.infinity, T.infinity) == -T.quarter); 2886 assert (atan2pi(T.infinity, T.infinity) == T.quarter); 2887 } 2888 } 2889 2890 /** 2891 Calculates the inverse hyperbolic tangent of x 2892 Exceptions: 2893 $(BOOKTABLE, 2894 $(TR $(TD $(MYREF InvalidOperationException)) 2895 $(TD x is signaling $(B NaN) or |x| > 1.0)) 2896 $(TR $(TD $(MYREF DivisionByZeroException)) 2897 $(TD |x| = 1.0)) 2898 $(TR $(TD $(MYREF UnderflowException)) 2899 $(TD the result is too small to be represented)) 2900 $(TR $(TD $(MYREF InexactException)) 2901 $(TD the result is inexact)) 2902 ) 2903 Special_values: 2904 $(BOOKTABLE, 2905 $(TR $(TH x) $(TH atanh(x))) 2906 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 2907 $(TR $(TD ±0.0) $(TD ±0.0)) 2908 $(TR $(TD ±1.0) $(TD ±∞)) 2909 $(TR $(TD >1.0) $(TD $(B NaN))) 2910 $(TR $(TD <1.0) $(TD $(B NaN))) 2911 ) 2912 */ 2913 @IEEECompliant("atanh", 43) 2914 D atanh(D)(auto const ref D x) 2915 if (isDecimal!D) 2916 { 2917 Unqual!D result = x; 2918 auto flags = decimalAtanh(result, 2919 __ctfe ? D.PRECISION : DecimalControl.precision, 2920 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 2921 flags &= ExceptionFlags.invalidOperation | ExceptionFlags.underflow | 2922 ExceptionFlags.inexact | ExceptionFlags.divisionByZero; 2923 DecimalControl.raiseFlags(flags); 2924 return result; 2925 } 2926 2927 /// 2928 unittest 2929 { 2930 decimal32 x = 0; 2931 assert (atanh(x) == 0); 2932 } 2933 2934 /** 2935 Calculates the arc tangent of x divided by π, returning a value ranging from -1/2 to 1/2. 2936 Exceptions: 2937 $(BOOKTABLE, 2938 $(TR $(TD $(MYREF InvalidOperationException)) 2939 $(TD x is signaling $(B NaN))) 2940 $(TR $(TD $(MYREF InexactException)) 2941 $(TD the result is inexact)) 2942 $(TR $(TD $(MYREF UnderflowException)) 2943 $(TD the result is too small to be represented)) 2944 ) 2945 Special_values: 2946 $(BOOKTABLE, 2947 $(TR $(TH x) $(TH atan(x))) 2948 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 2949 $(TR $(TD ±0.0) $(TD ±0.0)) 2950 $(TR $(TD ±∞) $(TD ±1/2)) 2951 ) 2952 */ 2953 @IEEECompliant("atanPi", 43) 2954 D atanpi(D)(auto const ref D x) 2955 if (isDecimal!D) 2956 { 2957 Unqual!D result = x; 2958 auto flags = decimalAtanPi(result, 2959 __ctfe ? D.PRECISION : DecimalControl.precision, 2960 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 2961 flags &= ExceptionFlags.invalidOperation | ExceptionFlags.underflow | ExceptionFlags.inexact; 2962 DecimalControl.raiseFlags(flags); 2963 return result; 2964 } 2965 2966 /// 2967 unittest 2968 { 2969 decimal32 radians = 1; 2970 assert (atanpi(radians) == decimal32("0.25")); 2971 } 2972 2973 2974 unittest 2975 { 2976 foreach(T; TypeTuple!(decimal32, decimal64, decimal128)) 2977 { 2978 assert (isIdentical(atanpi(T.zero), T.zero)); 2979 assert (isIdentical(atanpi(-T.zero), -T.zero)); 2980 assert (isIdentical(atanpi(T.infinity), T.half)); 2981 assert (isIdentical(atanpi(-T.infinity), -T.half)); 2982 assert (isNaN(atanpi(T.nan))); 2983 } 2984 } 2985 2986 /** 2987 Computes the cubic root of x 2988 Throws: 2989 $(BOOKTABLE, 2990 $(TR $(TD $(MYREF InvalidOperationException)) 2991 $(TD x is signaling $(B NaN))) 2992 $(TR $(TD $(MYREF UnderflowException)) 2993 $(TD cubic root of x is too small to be represented)) 2994 $(TR $(TD $(MYREF InexactException)) 2995 $(TD the result is inexact)) 2996 ) 2997 Special_values: 2998 $(BOOKTABLE, 2999 $(TR $(TH x) $(TH cbrt(x))) 3000 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 3001 $(TR $(TD ±0.0) $(TD ±0.0)) 3002 $(TR $(TD ±∞) $(TD ±∞)) 3003 ) 3004 */ 3005 D cbrt(D)(auto const ref D x) 3006 if (isDecimal!D) 3007 { 3008 Unqual!D result = x; 3009 auto flags = decimalCbrt(result, 3010 __ctfe ? D.PRECISION : DecimalControl.precision, 3011 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 3012 DecimalControl.raiseFlags(flags); 3013 return result; 3014 } 3015 3016 /// 3017 unittest 3018 { 3019 decimal32 x = 27; 3020 assert (cbrt(x) == 3); 3021 } 3022 3023 /** 3024 Returns the value of x rounded upward to the next integer (toward positive infinity). 3025 This operation is silent, doesn't throw any exception. 3026 Special_values: 3027 $(BOOKTABLE, 3028 $(TR $(TH x) $(TH ceil(x))) 3029 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 3030 $(TR $(TD ±0.0) $(TD ±0.0)) 3031 $(TR $(TD ±∞) $(TD ±∞)) 3032 ) 3033 */ 3034 D ceil(D)(auto const ref D x) 3035 if (isDecimal!D) 3036 { 3037 Unqual!D result = x; 3038 decimalRound(result, 0, RoundingMode.towardPositive); 3039 return result; 3040 } 3041 3042 /// 3043 unittest 3044 { 3045 assert (ceil(decimal32("123.456")) == 124); 3046 assert (ceil(decimal32("-123.456")) == -123); 3047 } 3048 3049 /** 3050 Defines a total order on all _decimal values. 3051 Params: 3052 x = a _decimal value 3053 y = a _decimal value 3054 Returns: 3055 -1 if x precedes y, 0 if x is equal to y, +1 if x follows y 3056 Notes: 3057 The total order is defined as:<br/> 3058 - -sNaN < -$(B NaN) < -infinity < -finite < -0.0 < +0.0 < +finite < +infinity < +$(B NaN) < +sNaN<br/> 3059 - for two $(B NaN) values the total order is defined based on the payload 3060 */ 3061 int cmp(D1, D2)(auto const ref D1 x, auto const ref D2 y) 3062 if (isDecimal!(D1, D2)) 3063 { 3064 static if (is(D1 : D2)) 3065 { 3066 if (x.data == y.data) 3067 return 0; 3068 } 3069 alias U = CommonStorage!(D1, D2); 3070 U cx, cy; int ex, ey; bool sx, sy; 3071 auto fx = fastDecode(x, cx, ex, sx); 3072 auto fy = fastDecode(y, cy, ey, sy); 3073 3074 if (sx != sy) 3075 return sx ? -1 : 1; 3076 3077 if (fx == FastClass.quietNaN) 3078 { 3079 if (fy == FastClass.quietNaN) 3080 { 3081 if (cx > cy) 3082 return sx ? -1 : 1; 3083 else if (cx < cy) 3084 return sx ? 1 : -1; 3085 return 0; 3086 } 3087 return sx ? -1 : 1; 3088 } 3089 3090 if (fy == FastClass.quietNaN) 3091 return sx ? 1 : -1; 3092 3093 if (fx == FastClass.signalingNaN) 3094 { 3095 if (fy == FastClass.signalingNaN) 3096 { 3097 if (cx > cy) 3098 return sx ? -1 : 1; 3099 else if (cx < cy) 3100 return sx ? 1 : -1; 3101 return 0; 3102 } 3103 return sx ? -1 : 1; 3104 } 3105 3106 if (fy == FastClass.signalingNaN) 3107 return sx ? 1 : -1; 3108 3109 3110 3111 if (fx == FastClass.infinite) 3112 { 3113 if (fy == FastClass.infinite) 3114 return 0; 3115 return sx ? -1 : 1; 3116 } 3117 3118 if (fy == FastClass.infinite) 3119 return sx ? 1 : -1; 3120 3121 //if (fx == FastClass.zero) 3122 //{ 3123 // if (fy == FastClass.zero) 3124 // return 0; 3125 // return sx ? 1 : -1; 3126 //} 3127 // 3128 //if (fy == FastClass.zero) 3129 // return sx ? -1 : 1; 3130 3131 int c = coefficientCmp(cx, ex, cy, ey); 3132 3133 if (c == 0) 3134 { 3135 if (ex > ey) 3136 c = sx ? -1 : 1; 3137 else if (ex < ey) 3138 c = sx ? 1 : -1; 3139 } 3140 else if (sx) 3141 c = -c; 3142 3143 return c; 3144 3145 } 3146 3147 /// 3148 unittest 3149 { 3150 assert (cmp(-decimal32.nan, decimal64.max) == -1); 3151 assert (cmp(decimal32.max, decimal128.min_normal) == 1); 3152 assert (cmp(decimal64(0), -decimal64(0)) == 1); 3153 } 3154 /** 3155 Computes (1 + x)$(SUPERSCRIPT n) where n is an integer 3156 Throws: 3157 $(BOOKTABLE, 3158 $(TR $(TD $(MYREF InvalidOperationException)) 3159 $(TD x is signaling $(B NaN) or x < -1.0)) 3160 $(TR $(TD $(MYREF DivisionByZeroException)) 3161 $(TD x = -1.0 and n < 0)) 3162 $(TR $(TD $(MYREF OverflowException)) 3163 $(TD result is too big to be represented)) 3164 $(TR $(TD $(MYREF UnderflowException)) 3165 $(TD result is too small to be represented)) 3166 $(TR $(TD $(MYREF InexactException)) 3167 $(TD the result is inexact)) 3168 ) 3169 Special_values: 3170 $(BOOKTABLE, 3171 $(TR $(TH x) $(TH n) $(TH compound(x, n))) 3172 $(TR $(TD sNaN) $(TD any) $(TD $(B NaN))) 3173 $(TR $(TD any) $(TD 0) $(TD +1.0)) 3174 $(TR $(TD -1.0) $(TD <0) $(TD +∞)) 3175 $(TR $(TD -1.0) $(TD >0) $(TD +0.0)) 3176 $(TR $(TD +∞) $(TD any) $(TD +∞)) 3177 ) 3178 */ 3179 @IEEECompliant("compound", 42) 3180 auto compound(D)(auto const ref D x, const int n) 3181 if (isDecimal!D) 3182 { 3183 Unqual!D result = x; 3184 auto flags = decimalCompound(result, n, 3185 __ctfe ? D.PRECISION : DecimalControl.precision, 3186 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 3187 DecimalControl.raiseFlags(flags); 3188 return result; 3189 } 3190 3191 unittest 3192 { 3193 foreach(T; TypeTuple!(decimal32, decimal64, decimal128)) 3194 { 3195 assert (compound(T.ten, 0) == 1); 3196 assert (compound(T.infinity, 0) == 1); 3197 assert (compound(-T.one, 0) == 1); 3198 assert (compound(T.zero, 0) == 1); 3199 assert (compound(-T.one, 5) == 0); 3200 assert (compound(T.infinity, 5) == T.infinity); 3201 } 3202 } 3203 3204 /// 3205 unittest 3206 { 3207 decimal32 x = "0.2"; 3208 assert (compound(x, 2) == decimal32("1.44")); 3209 } 3210 3211 /** 3212 Copies the sign of a _decimal value _to another. 3213 This operation is silent, no error flags are set and no exceptions are thrown. 3214 Params: 3215 to = a _decimal value to copy 3216 from = a _decimal value from which the sign is copied 3217 Returns: 3218 to with the sign of from 3219 */ 3220 @IEEECompliant("copySign", 23) 3221 D1 copysign(D1, D2)(auto const ref D1 to, auto const ref D2 from) 3222 if (isDecimal!(D1, D2)) 3223 { 3224 Unqual!D1 result = to; 3225 static if (is(D2: decimal32) || is(D2: decimal64)) 3226 { 3227 bool sx = cast(bool)((from.data & D2.MASK_SGN) == D2.MASK_SGN); 3228 if (sx) 3229 result.data |= D1.MASK_SGN; 3230 else 3231 result.data &= ~D1.MASK_SGN; 3232 } 3233 else 3234 { 3235 bool sx = cast(bool)((from.data.hi & D2.MASK_SGN.hi) == D2.MASK_SGN.hi); 3236 if (sx) 3237 result.data.hi |= D1.MASK_SGN.hi; 3238 else 3239 result.data.hi &= ~D1.MASK_SGN.hi; 3240 } 3241 3242 return result; 3243 } 3244 3245 /// 3246 unittest 3247 { 3248 decimal32 negative = -decimal32.min_normal; 3249 decimal64 test = decimal64.max; 3250 assert(copysign(test, negative) == -decimal64.max); 3251 3252 } 3253 3254 /** 3255 Returns cosine of x. 3256 Throws: 3257 $(BOOKTABLE, 3258 $(TR $(TD $(MYREF InvalidOperationException)) 3259 $(TD x is signaling $(B NaN) or ±∞)) 3260 $(TR $(TD $(MYREF UnderflowException)) 3261 $(TD result is too small to be represented)) 3262 $(TR $(TD $(MYREF InexactException)) 3263 $(TD the result is inexact)) 3264 ) 3265 Special_values: 3266 $(BOOKTABLE, 3267 $(TR $(TH x) $(TH cos(x))) 3268 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 3269 $(TR $(TD ±∞) $(TD $(B NaN))) 3270 $(TR $(TD ±0.0) $(TD +1.0)) 3271 $(TR $(TD π/6) $(TD +√3/2)) 3272 $(TR $(TD π/4) $(TD +√2/2)) 3273 $(TR $(TD π/3) $(TD +0.5)) 3274 $(TR $(TD π/2) $(TD +0.0)) 3275 $(TR $(TD 2π/3) $(TD -0.5)) 3276 $(TR $(TD 3π/4) $(TD -√2/2)) 3277 $(TR $(TD 5π/6) $(TD -√3/2)) 3278 $(TR $(TD π) $(TD -1.0)) 3279 ) 3280 */ 3281 @IEEECompliant("cos", 42) 3282 D cos(D)(auto const ref D x) 3283 if (isDecimal!D) 3284 { 3285 Unqual!D result = x; 3286 auto flags = decimalCos(result, 3287 __ctfe ? D.PRECISION : DecimalControl.precision, 3288 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 3289 DecimalControl.raiseFlags(flags); 3290 return result; 3291 } 3292 3293 3294 /** 3295 Calculates the hyperbolic cosine of x. 3296 Throws: 3297 $(BOOKTABLE, 3298 $(TR $(TD $(MYREF InvalidOperationException)) 3299 $(TD x is signaling $(B NaN))) 3300 $(TR $(TD $(MYREF OverflowException)) 3301 $(TD result is too big to be represented)) 3302 $(TR $(TD $(MYREF InexactException)) 3303 $(TD the result is inexact)) 3304 ) 3305 Special_values: 3306 $(BOOKTABLE, 3307 $(TR $(TH x) $(TH cosh(x))) 3308 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 3309 $(TR $(TD ±∞) $(TD +∞)) 3310 $(TR $(TD ±0.0) $(TD +1.0)) 3311 ) 3312 */ 3313 @IEEECompliant("cosh", 42) 3314 D cosh(D)(auto const ref D x) 3315 if (isDecimal!D) 3316 { 3317 Unqual!D result = x; 3318 auto flags = decimalCosh(result, 3319 __ctfe ? D.PRECISION : DecimalControl.precision, 3320 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 3321 DecimalControl.raiseFlags(flags); 3322 return result; 3323 } 3324 3325 //unittest 3326 //{ 3327 // import std.stdio; 3328 // import std.math; 3329 // for(int i = 1; i < 10; ++i) 3330 // { 3331 // writefln("+%3.2f %35.34f %35.34f", i/10.0, cosh(decimal128(i)/10), std.math.cosh(i/10.0)); 3332 // } 3333 //} 3334 3335 /** 3336 Returns cosine of xπ. 3337 Throws: 3338 $(BOOKTABLE, 3339 $(TR $(TD $(MYREF InvalidOperationException)) 3340 $(TD x is signaling $(B NaN) or ±∞)) 3341 $(TR $(TD $(MYREF UnderflowException)) 3342 $(TD result is too small to be represented)) 3343 $(TR $(TD $(MYREF InexactException)) 3344 $(TD the result is inexact)) 3345 ) 3346 Special_values: 3347 $(BOOKTABLE, 3348 $(TR $(TH x) $(TH cospi(x))) 3349 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 3350 $(TR $(TD ±∞) $(TD $(B NaN))) 3351 $(TR $(TD ±0.0) $(TD +1.0)) 3352 $(TR $(TD 1/6) $(TD +√3/2)) 3353 $(TR $(TD 1/4) $(TD +√2/2)) 3354 $(TR $(TD 1/3) $(TD +0.5)) 3355 $(TR $(TD 1/2) $(TD +0.0)) 3356 $(TR $(TD 2/3) $(TD -0.5)) 3357 $(TR $(TD 3/4) $(TD -√2/2)) 3358 $(TR $(TD 5/6) $(TD -√3/2)) 3359 $(TR $(TD 1.0) $(TD -1.0)) 3360 ) 3361 */ 3362 @IEEECompliant("cosPi", 42) 3363 D cospi(D)(auto const ref D x) 3364 if (isDecimal!D) 3365 { 3366 Unqual!D result = x; 3367 auto flags = decimalCosPi(result, 3368 __ctfe ? D.PRECISION : DecimalControl.precision, 3369 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 3370 DecimalControl.raiseFlags(flags); 3371 return result; 3372 } 3373 3374 ///IEEE-754-2008 floating point categories 3375 enum DecimalClass 3376 { 3377 ///a signalling $(B NaN) represents most of the time an uninitialized variable; 3378 ///a quiet $(B NaN) represents the result of an invalid operation 3379 signalingNaN, 3380 ///ditto 3381 quietNaN, 3382 ///value represents infinity 3383 negativeInfinity, 3384 ///ditto 3385 positiveInfinity, 3386 ///value represents a normalized _decimal value 3387 negativeNormal, 3388 ///ditto 3389 positiveNormal, 3390 ///value represents a subnormal _decimal value 3391 negativeSubnormal, 3392 ///ditto 3393 positiveSubnormal, 3394 ///value is 0 3395 negativeZero, 3396 ///ditto 3397 positiveZero, 3398 } 3399 3400 /** 3401 Returns the decimal class where x falls into. 3402 This operation is silent, no exception flags are set and no exceptions are thrown. 3403 Params: 3404 x = a _decimal value 3405 Returns: 3406 One of the members of $(MYREF DecimalClass) enumeration 3407 */ 3408 @IEEECompliant("class", 25) 3409 DecimalClass decimalClass(D)(auto const ref D x) 3410 if (isDecimal!D) 3411 { 3412 DataType!D coefficient; 3413 uint exponent; 3414 3415 static if (is(D: decimal32) || is(D: decimal64)) 3416 { 3417 if ((x.data & D.MASK_INF) == D.MASK_INF) 3418 if ((x.data & D.MASK_QNAN) == D.MASK_QNAN) 3419 if ((x.data & D.MASK_SNAN) == D.MASK_SNAN) 3420 return DecimalClass.signalingNaN; 3421 else 3422 return DecimalClass.quietNaN; 3423 else 3424 return x.data & D.MASK_SGN ? DecimalClass.negativeInfinity : DecimalClass.positiveInfinity; 3425 else if ((x.data & D.MASK_EXT) == D.MASK_EXT) 3426 { 3427 coefficient = (x.data & D.MASK_COE2) | D.MASK_COEX; 3428 if (coefficient > D.COEF_MAX) 3429 return x.data & D.MASK_SGN ? DecimalClass.negativeZero : DecimalClass.positiveZero; 3430 exponent = cast(uint)((x.data & D.MASK_EXP2) >>> D.SHIFT_EXP2); 3431 } 3432 else 3433 { 3434 coefficient = x.data & D.MASK_COE1; 3435 if (coefficient == 0U) 3436 return (x.data & D.MASK_SGN) == D.MASK_SGN ? DecimalClass.negativeZero : DecimalClass.positiveZero; 3437 exponent = cast(uint)((x.data & D.MASK_EXP1) >>> D.SHIFT_EXP1); 3438 } 3439 bool sx = (x.data & D.MASK_SGN) == D.MASK_SGN; 3440 } 3441 else 3442 { 3443 if ((x.data.hi & D.MASK_INF.hi) == D.MASK_INF.hi) 3444 if ((x.data.hi & D.MASK_QNAN.hi) == D.MASK_QNAN.hi) 3445 if ((x.data.hi & D.MASK_SNAN.hi) == D.MASK_SNAN.hi) 3446 return DecimalClass.signalingNaN; 3447 else 3448 return DecimalClass.quietNaN; 3449 else 3450 return x.data.hi & D.MASK_SGN.hi ? DecimalClass.negativeInfinity : DecimalClass.positiveInfinity; 3451 else if ((x.data.hi & D.MASK_EXT.hi) == D.MASK_EXT.hi) 3452 return (x.data.hi & D.MASK_SGN.hi) == D.MASK_SGN.hi ? DecimalClass.negativeZero : DecimalClass.positiveZero; 3453 else 3454 { 3455 coefficient = x.data & D.MASK_COE1; 3456 if (coefficient == 0U || coefficient > D.COEF_MAX) 3457 return (x.data.hi & D.MASK_SGN.hi) == D.MASK_SGN.hi ? DecimalClass.negativeZero : DecimalClass.positiveZero; 3458 exponent = cast(uint)((x.data & D.MASK_EXP1) >>> D.SHIFT_EXP1); 3459 } 3460 bool sx = (x.data.hi & D.MASK_SGN.hi) == D.MASK_SGN.hi; 3461 } 3462 3463 if (exponent < D.PRECISION - 1) 3464 { 3465 if (prec(coefficient) < D.PRECISION - exponent) 3466 return sx ? DecimalClass.negativeSubnormal : DecimalClass.positiveSubnormal; 3467 } 3468 return sx ? DecimalClass.negativeNormal : DecimalClass.positiveNormal; 3469 } 3470 3471 /// 3472 unittest 3473 { 3474 assert(decimalClass(decimal32.nan) == DecimalClass.quietNaN); 3475 assert(decimalClass(decimal64.infinity) == DecimalClass.positiveInfinity); 3476 assert(decimalClass(decimal128.max) == DecimalClass.positiveNormal); 3477 assert(decimalClass(-decimal32.max) == DecimalClass.negativeNormal); 3478 assert(decimalClass(decimal128.epsilon) == DecimalClass.positiveNormal); 3479 } 3480 3481 unittest 3482 { 3483 foreach(T; TypeTuple!(decimal32, decimal64, decimal128)) 3484 { 3485 assert(decimalClass(T.snan) == DecimalClass.signalingNaN); 3486 assert(decimalClass(T.qnan) == DecimalClass.quietNaN); 3487 assert(decimalClass(T.minusInfinity) == DecimalClass.negativeInfinity); 3488 assert(decimalClass(T.infinity) == DecimalClass.positiveInfinity); 3489 assert(decimalClass(T.zero) == DecimalClass.positiveZero); 3490 assert(decimalClass(T.minusZero) == DecimalClass.negativeZero); 3491 assert(decimalClass(T.subn) == DecimalClass.positiveSubnormal); 3492 assert(decimalClass(T.minusSubn) == DecimalClass.negativeSubnormal); 3493 assert(decimalClass(T.ten) == DecimalClass.positiveNormal); 3494 assert(decimalClass(T.minusTen) == DecimalClass.negativeNormal); 3495 assert(decimalClass(T.max) == DecimalClass.positiveNormal); 3496 assert(decimalClass(-T.max) == DecimalClass.negativeNormal); 3497 assert(decimalClass(T.min_normal) == DecimalClass.positiveNormal); 3498 assert(decimalClass(T.epsilon) == DecimalClass.positiveNormal); 3499 } 3500 } 3501 3502 3503 3504 /** 3505 Sums x$(SUBSCRIPT i) * y$(SUBSCRIPT i) using a higher precision, rounding only once at the end. 3506 Returns: 3507 x$(SUBSCRIPT 0) * y$(SUBSCRIPT 0) + x$(SUBSCRIPT 1) * y$(SUBSCRIPT 1) + ... + x$(SUBSCRIPT n) * y$(SUBSCRIPT n) 3508 Notes: 3509 If x and y arrays are not of the same length, operation is performed for min(x.length, y.length); 3510 Throws: 3511 $(BOOKTABLE, 3512 $(TR $(TD $(MYREF InvalidOperationException)) 3513 $(TD any x is signaling $(B NaN))) 3514 $(TR $(TD $(MYREF InvalidOperationException)) 3515 $(TD any combination of elements is (±∞, ±0.0) or (±0.0, ±∞))) 3516 $(TR $(TD $(MYREF InvalidOperationException)) 3517 $(TD there are two products resulting in infinities of different sign)) 3518 $(TR $(TD $(MYREF OverflowException)) 3519 $(TD result is too big to be represented)) 3520 $(TR $(TD $(MYREF UnderflowException)) 3521 $(TD result is too small to be represented)) 3522 $(TR $(TD $(MYREF InexactException)) 3523 $(TD result is inexact)) 3524 ) 3525 */ 3526 @IEEECompliant("dot", 47) 3527 D dot(D)(const(D)[] x, const(D)[] y) 3528 if (isDecimal!D) 3529 { 3530 Unqual!D result = x; 3531 auto flags = decimalDot(x, y, result, 3532 __ctfe ? D.PRECISION : DecimalControl.precision, 3533 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 3534 flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.overflow | ExceptionFlags.underflow); 3535 DecimalControl.raiseFlags(flags); 3536 return result; 3537 } 3538 3539 /** 3540 Calculates e$(SUPERSCRIPT x) 3541 Throws: 3542 $(BOOKTABLE, 3543 $(TR $(TD $(MYREF InvalidOperationException)) 3544 $(TD x is signaling $(B NaN))) 3545 $(TR $(TD $(MYREF UnderflowException)) 3546 $(TD e$(SUPERSCRIPT x) is too small to be represented)) 3547 $(TR $(TD $(MYREF OverflowException)) 3548 $(TD e$(SUPERSCRIPT x) is too big to be represented)) 3549 $(TR $(TD $(MYREF InexactException)) 3550 $(TD the result is inexact)) 3551 ) 3552 Special_values: 3553 $(BOOKTABLE, 3554 $(TR $(TH x) $(TH exp(x))) 3555 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 3556 $(TR $(TD ±0.0) $(TD +1.0)) 3557 $(TR $(TD -∞) $(TD 0)) 3558 $(TR $(TD +∞) $(TD +∞)) 3559 ) 3560 */ 3561 @IEEECompliant("exp", 42) 3562 D exp(D)(auto const ref D x) 3563 if (isDecimal!D) 3564 { 3565 Unqual!D result = x; 3566 auto flags = decimalExp(result, 3567 __ctfe ? D.PRECISION : DecimalControl.precision, 3568 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 3569 flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.overflow | ExceptionFlags.underflow); 3570 DecimalControl.raiseFlags(flags); 3571 return result; 3572 } 3573 3574 /// 3575 unittest 3576 { 3577 decimal32 power = 1; 3578 assert (exp(power) == decimal32.E); 3579 } 3580 3581 unittest 3582 { 3583 foreach(T; TypeTuple!(decimal32, decimal64, decimal128)) 3584 { 3585 assert (exp(T.zero) == T.one); 3586 assert (exp(-T.infinity) == T.zero); 3587 assert (exp(T.infinity) == T.infinity); 3588 assert (isNaN(exp(T.nan))); 3589 } 3590 } 3591 3592 /** 3593 Calculates 10$(SUPERSCRIPT x) 3594 Throws: 3595 $(BOOKTABLE, 3596 $(TR $(TD $(MYREF InvalidOperationException)) 3597 $(TD x is signaling $(B NaN))) 3598 $(TR $(TD $(MYREF UnderflowException)) 3599 $(TD 10$(SUPERSCRIPT x) is too small to be represented)) 3600 $(TR $(TD $(MYREF OverflowException)) 3601 $(TD 10$(SUPERSCRIPT x) is too big to be represented)) 3602 $(TR $(TD $(MYREF InexactException)) 3603 $(TD the result is inexact)) 3604 ) 3605 Special_values: 3606 $(BOOKTABLE, 3607 $(TR $(TH x) $(TH exp10(x))) 3608 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 3609 $(TR $(TD ±0.0) $(TD +1.0)) 3610 $(TR $(TD -∞) $(TD +0.0)) 3611 $(TR $(TD +∞) $(TD +∞)) 3612 ) 3613 */ 3614 @IEEECompliant("exp10", 42) 3615 D exp10(D)(auto const ref D x) 3616 if (isDecimal!D) 3617 { 3618 Unqual!D result = x; 3619 auto flags = decimalExp10(result, 3620 __ctfe ? D.PRECISION : DecimalControl.precision, 3621 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 3622 flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.overflow | ExceptionFlags.underflow); 3623 DecimalControl.raiseFlags(flags); 3624 return result; 3625 } 3626 3627 /// 3628 unittest 3629 { 3630 decimal32 x = 3; 3631 assert(exp10(x) == 1000); 3632 } 3633 3634 3635 /** 3636 Calculates 10$(SUPERSCRIPT x) - 1 3637 Throws: 3638 $(BOOKTABLE, 3639 $(TR $(TD $(MYREF InvalidOperationException)) 3640 $(TD x is signaling $(B NaN))) 3641 $(TR $(TD $(MYREF UnderflowException)) 3642 $(TD 10$(SUPERSCRIPT x) - 1 is too small to be represented)) 3643 $(TR $(TD $(MYREF OverflowException)) 3644 $(TD 10$(SUPERSCRIPT x) - 1 is too big to be represented)) 3645 $(TR $(TD $(MYREF InexactException)) 3646 $(TD the result is inexact)) 3647 ) 3648 Special_values: 3649 $(BOOKTABLE, 3650 $(TR $(TH x) $(TH exp10m1(x))) 3651 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 3652 $(TR $(TD ±0.0) $(TD ±0.0)) 3653 $(TR $(TD -∞) $(TD -1.0)) 3654 $(TR $(TD +∞) $(TD +∞)) 3655 ) 3656 */ 3657 @IEEECompliant("exp10m1", 42) 3658 D exp10m1(D)(auto const ref D x) 3659 if (isDecimal!D) 3660 { 3661 Unqual!D result = x; 3662 auto flags = decimalExp10m1(result, 3663 __ctfe ? D.PRECISION : DecimalControl.precision, 3664 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 3665 flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.overflow | ExceptionFlags.underflow); 3666 DecimalControl.raiseFlags(flags); 3667 return result; 3668 } 3669 3670 /// 3671 unittest 3672 { 3673 decimal32 x = 3; 3674 assert(exp10m1(x) == 999); 3675 } 3676 3677 /** 3678 Calculates 2$(SUPERSCRIPT x) 3679 Throws: 3680 $(BOOKTABLE, 3681 $(TR $(TD $(MYREF InvalidOperationException)) 3682 $(TD x is signaling $(B NaN))) 3683 $(TR $(TD $(MYREF UnderflowException)) 3684 $(TD 2$(SUPERSCRIPT x) is too small to be represented)) 3685 $(TR $(TD $(MYREF OverflowException)) 3686 $(TD 2$(SUPERSCRIPT x) is too big to be represented)) 3687 $(TR $(TD $(MYREF InexactException)) 3688 $(TD the result is inexact)) 3689 ) 3690 Special_values: 3691 $(BOOKTABLE, 3692 $(TR $(TH x) $(TH exp2(x))) 3693 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 3694 $(TR $(TD ±0.0) $(TD +1.0)) 3695 $(TR $(TD -∞) $(TD +0.0)) 3696 $(TR $(TD +∞) $(TD +∞)) 3697 ) 3698 */ 3699 @IEEECompliant("exp2", 42) 3700 D exp2(D)(auto const ref D x) 3701 if (isDecimal!D) 3702 { 3703 Unqual!D result = x; 3704 auto flags = decimalExp2(result, 3705 __ctfe ? D.PRECISION : DecimalControl.precision, 3706 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 3707 flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.overflow | ExceptionFlags.underflow); 3708 DecimalControl.raiseFlags(flags); 3709 return result; 3710 } 3711 3712 /// 3713 unittest 3714 { 3715 decimal32 x = 3; 3716 assert(exp2(x) == 8); 3717 } 3718 3719 /** 3720 Calculates 2$(SUPERSCRIPT x) - 1 3721 Throws: 3722 $(BOOKTABLE, 3723 $(TR $(TD $(MYREF InvalidOperationException)) 3724 $(TD x is signaling $(B NaN))) 3725 $(TR $(TD $(MYREF UnderflowException)) 3726 $(TD 2$(SUPERSCRIPT x) - 1 is too small to be represented)) 3727 $(TR $(TD $(MYREF OverflowException)) 3728 $(TD 2$(SUPERSCRIPT x) - 1 is too big to be represented)) 3729 $(TR $(TD $(MYREF InexactException)) 3730 $(TD the result is inexact)) 3731 ) 3732 Special_values: 3733 $(BOOKTABLE, 3734 $(TR $(TH x) $(TH exp2m1(x))) 3735 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 3736 $(TR $(TD ±0.0) $(TD ±0.0)) 3737 $(TR $(TD -∞) $(TD -1.0)) 3738 $(TR $(TD +∞) $(TD +∞)) 3739 ) 3740 */ 3741 @IEEECompliant("exp2m1", 42) 3742 D exp2m1(D)(auto const ref D x) 3743 if (isDecimal!D) 3744 { 3745 Unqual!D result = x; 3746 auto flags = decimalExp2m1(result, 3747 __ctfe ? D.PRECISION : DecimalControl.precision, 3748 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 3749 flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.overflow | ExceptionFlags.underflow); 3750 DecimalControl.raiseFlags(flags); 3751 return result; 3752 } 3753 3754 /// 3755 unittest 3756 { 3757 decimal32 x = 3; 3758 assert(exp2m1(x) == 7); 3759 } 3760 3761 /** 3762 Calculates e$(SUPERSCRIPT x) - 1 3763 Throws: 3764 $(BOOKTABLE, 3765 $(TR $(TD $(MYREF InvalidOperationException)) 3766 $(TD x is signaling $(B NaN))) 3767 $(TR $(TD $(MYREF UnderflowException)) 3768 $(TD e$(SUPERSCRIPT x) - 1 is too small to be represented)) 3769 $(TR $(TD $(MYREF OverflowException)) 3770 $(TD e$(SUPERSCRIPT x) - 1 is too big to be represented)) 3771 $(TR $(TD $(MYREF InexactException)) 3772 $(TD the result is inexact)) 3773 ) 3774 Special_values: 3775 $(BOOKTABLE, 3776 $(TR $(TH x) $(TH expm1(x))) 3777 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 3778 $(TR $(TD ±0.0) $(TD ±0.0)) 3779 $(TR $(TD -∞) $(TD -1.0)) 3780 $(TR $(TD +∞) $(TD +∞)) 3781 ) 3782 */ 3783 @IEEECompliant("expm1", 42) 3784 D expm1(D)(auto const ref D x) 3785 if (isDecimal!D) 3786 { 3787 Unqual!D result = x; 3788 auto flags = decimalExpm1(result, 3789 __ctfe ? D.PRECISION : DecimalControl.precision, 3790 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 3791 flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.overflow | ExceptionFlags.underflow); 3792 DecimalControl.raiseFlags(flags); 3793 return result; 3794 } 3795 3796 /** 3797 Calculates |x|. 3798 This operation is silent, no error flags are set and no exceptions are thrown. 3799 */ 3800 @IEEECompliant("abs", 23) 3801 D fabs(D)(auto const ref D x) 3802 if (isDecimal!D) 3803 { 3804 Unqual!D result = x; 3805 static if (is(D: decimal128)) 3806 result.data.hi &= ~D.MASK_SGN.hi; 3807 else 3808 result.data &= ~D.MASK_SGN; 3809 return result; 3810 } 3811 3812 /// 3813 unittest 3814 { 3815 assert(fabs(-decimal32.max) == decimal32.max); 3816 assert(fabs(decimal64.infinity) == decimal64.infinity); 3817 } 3818 3819 3820 /** 3821 Returns the positive difference between x and y. If x ≤ y, retuns 0.0 3822 Throws: 3823 $(BOOKTABLE, 3824 $(TR $(TD $(MYREF InvalidOperationException)) 3825 $(TD either x or y is $(B signaling NaN))) 3826 $(TR $(TD $(MYREF UnderflowException)) 3827 $(TD result is subnormal)) 3828 $(TR $(TD $(MYREF InexactException)) 3829 $(TD result is inexact)) 3830 ) 3831 Special_values: 3832 $(BOOKTABLE, 3833 $(TR $(TH x) $(TH y) $(TH fdim(x, y))) 3834 $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN))) 3835 $(TR $(TD any) $(TD $(B NaN)) $(TD $(B NaN))) 3836 $(TR $(TD x > y) $(TD) $(TD x - y)) 3837 $(TR $(TD x ≤ y) $(TD) $(TD 0.0)) 3838 ) 3839 */ 3840 auto fdim(D1, D2)(auto const ref D1 x, auto const ref D2 y) 3841 { 3842 alias D = CommonDecimal!(D1, D2); 3843 D result = x; 3844 3845 if (isInfinity(x) && isInfinity(y)) 3846 { 3847 if (signbit(x) == signbit(y)) 3848 return D.zero; 3849 else 3850 return result; 3851 } 3852 3853 if (decimalCmp(y, x) >= 0) 3854 return D.zero; 3855 3856 auto flags = decimalSub(result, y, 3857 __ctfe ? 0 : DecimalControl.precision, 3858 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 3859 if (!isNaN(result) && signbit(result)) 3860 result = D.zero; 3861 DecimalControl.raiseFlags(flags); 3862 return result; 3863 } 3864 3865 /// 3866 unittest 3867 { 3868 decimal32 x = "10.4"; 3869 decimal32 y = "7.3"; 3870 3871 assert (fdim(x, y) == decimal32("3.1")); 3872 assert (fdim(y, x) == 0); 3873 } 3874 3875 /** 3876 Returns the value of x rounded downward to the previous integer (toward negative infinity). 3877 This operation is silent, doesn't throw any exception. 3878 Special_values: 3879 $(BOOKTABLE, 3880 $(TR $(TH x) $(TH floor(x))) 3881 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 3882 $(TR $(TD ±0.0) $(TD ±0.0)) 3883 $(TR $(TD ±∞) $(TD ±∞)) 3884 ) 3885 */ 3886 D floor(D)(auto const ref D x) 3887 if (isDecimal!D) 3888 { 3889 Unqual!D result = x; 3890 decimalRound(result, 0, RoundingMode.towardNegative); 3891 return result; 3892 } 3893 3894 /// 3895 unittest 3896 { 3897 assert (floor(decimal32("123.456")) == 123); 3898 assert (floor(decimal32("-123.456")) == -124); 3899 } 3900 3901 /** 3902 Returns (x * y) + z, rounding only once according to the current precision and rounding mode 3903 Throws: 3904 $(BOOKTABLE, 3905 $(TR $(TD $(MYREF InvalidOperationException)) 3906 $(TD x, y or z is signaling $(B NaN))) 3907 $(TR $(TD $(MYREF InvalidOperationException)) 3908 $(TD (x, y) = (±∞, ±0.0) or (±0.0, ±∞))) 3909 $(TR $(TD $(MYREF InvalidOperationException)) 3910 $(TD x or y is infinite, z is infinite but has opposing sign)) 3911 $(TR $(TD $(MYREF UnderflowException)) 3912 $(TD result is too small to be represented)) 3913 $(TR $(TD $(MYREF OverflowException)) 3914 $(TD result is too big to be represented)) 3915 $(TR $(TD $(MYREF InexactException)) 3916 $(TD the result is inexact)) 3917 ) 3918 Special_values: 3919 $(BOOKTABLE, 3920 $(TR $(TH x) $(TH y) $(TH z) $(TH fma(x, y, z))) 3921 $(TR $(TD $(B NaN)) $(TD any) $(TD any) $(TD $(B NaN))) 3922 $(TR $(TD any) $(TD $(B NaN)) $(TD any) $(TD $(B NaN))) 3923 $(TR $(TD any) $(TD any) $(TD $(B NaN)) $(TD $(B NaN))) 3924 $(TR $(TD ±∞) $(TD ±0.0) $(TD any) $(TD $(B NaN))) 3925 $(TR $(TD ±0.0) $(TD ±∞) $(TD any) $(TD $(B NaN))) 3926 $(TR $(TD +∞) $(TD >0.0) $(TD -∞) $(TD $(B NaN))) 3927 $(TR $(TD -∞) $(TD <0.0) $(TD -∞) $(TD $(B NaN))) 3928 $(TR $(TD -∞) $(TD <0.0) $(TD -∞) $(TD $(B NaN))) 3929 $(TR $(TD +∞) $(TD >0.0) $(TD -∞) $(TD $(B NaN))) 3930 $(TR $(TD -∞) $(TD >0.0) $(TD +∞) $(TD $(B NaN))) 3931 $(TR $(TD +∞) $(TD <0.0) $(TD +∞) $(TD $(B NaN))) 3932 $(TR $(TD +∞) $(TD <0.0) $(TD +∞) $(TD $(B NaN))) 3933 $(TR $(TD -∞) $(TD >0.0) $(TD +∞) $(TD $(B NaN))) 3934 $(TR $(TD >0.0) $(TD +∞) $(TD -∞) $(TD $(B NaN))) 3935 $(TR $(TD <0.0) $(TD -∞) $(TD -∞) $(TD $(B NaN))) 3936 $(TR $(TD <0.0) $(TD -∞) $(TD -∞) $(TD $(B NaN))) 3937 $(TR $(TD >0.0) $(TD +∞) $(TD -∞) $(TD $(B NaN))) 3938 $(TR $(TD >0.0) $(TD -∞) $(TD +∞) $(TD $(B NaN))) 3939 $(TR $(TD <0.0) $(TD +∞) $(TD +∞) $(TD $(B NaN))) 3940 $(TR $(TD <0.0) $(TD +∞) $(TD +∞) $(TD $(B NaN))) 3941 $(TR $(TD >0.0) $(TD -∞) $(TD +∞) $(TD $(B NaN))) 3942 $(TR $(TD +∞) $(TD >0.0) $(TD +∞) $(TD +∞)) 3943 $(TR $(TD -∞) $(TD <0.0) $(TD +∞) $(TD +∞)) 3944 $(TR $(TD +∞) $(TD <0.0) $(TD -∞) $(TD -∞)) 3945 $(TR $(TD -∞) $(TD >0.0) $(TD -∞) $(TD -∞)) 3946 $(TR $(TD >0.0) $(TD +∞) $(TD +∞) $(TD +∞)) 3947 $(TR $(TD <0.0) $(TD -∞) $(TD +∞) $(TD +∞)) 3948 $(TR $(TD <0.0) $(TD +∞) $(TD -∞) $(TD -∞)) 3949 $(TR $(TD >0.0) $(TD -∞) $(TD -∞) $(TD -∞)) 3950 $(TR $(TD +∞) $(TD >0.0) $(TD any) $(TD +∞)) 3951 $(TR $(TD -∞) $(TD <0.0) $(TD any) $(TD +∞)) 3952 $(TR $(TD +∞) $(TD <0.0) $(TD any) $(TD -∞)) 3953 $(TR $(TD -∞) $(TD >0.0) $(TD any) $(TD -∞)) 3954 $(TR $(TD >0.0) $(TD +∞) $(TD any) $(TD +∞)) 3955 $(TR $(TD <0.0) $(TD -∞) $(TD any) $(TD +∞)) 3956 $(TR $(TD <0.0) $(TD +∞) $(TD any) $(TD -∞)) 3957 $(TR $(TD >0.0) $(TD -∞) $(TD any) $(TD -∞)) 3958 ) 3959 */ 3960 @IEEECompliant("fusedMultiplyAdd", 4) 3961 auto fma(D1, D2, D3)(auto const ref D1 x, auto const ref D2 y, auto const ref D3 z) 3962 if (isDecimal!(D1, D2, D3)) 3963 { 3964 alias D = CommonDecimal!(D1, D2, D3); 3965 D result; 3966 auto flags = decimalFMA!(D1, D2, D3)(x, y, z, result, 3967 __ctfe ? D.PRECISION : DecimalControl.precision, 3968 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 3969 DecimalControl.raiseFlags(flags); 3970 return result; 3971 } 3972 3973 /// 3974 unittest 3975 { 3976 decimal32 x = 2; 3977 decimal64 y = 3; 3978 decimal128 z = 5; 3979 assert (fma(x, y, z) == 11); 3980 } 3981 3982 /** 3983 Returns the larger _decimal value between x and y 3984 Throws: 3985 $(MYREF InvalidOperationException) if x or y is signaling $(B NaN) 3986 Special_values: 3987 $(BOOKTABLE, 3988 $(TR $(TH x) $(TH y) $(TH fmax(x, y))) 3989 $(TR $(TD $(B NaN)) $(TD any) $(TD y)) 3990 $(TR $(TD any) $(TD $(B NaN)) $(TD x)) 3991 ) 3992 */ 3993 @IEEECompliant("maxNum", 19) 3994 auto fmax(D1, D2)(auto const ref D1 x, auto const ref D2 y) 3995 if (isDecimal!D1 && isDecimal!D2) 3996 { 3997 CommonDecimal!(D1, D2) result; 3998 auto flags = decimalMax(x, y, result); 3999 DecimalControl.raiseFlags(flags); 4000 return result; 4001 } 4002 4003 /// 4004 unittest 4005 { 4006 decimal32 x = 3; 4007 decimal64 y = -4; 4008 assert (fmax(x, y) == 3); 4009 } 4010 4011 /** 4012 Returns the larger _decimal value between absolutes of x and y 4013 Throws: 4014 $(MYREF InvalidOperationException) if x or y is signaling $(B NaN) 4015 Special_values: 4016 $(BOOKTABLE, 4017 $(TR $(TH x) $(TH y) $(TH fmaxAbs(x, y))) 4018 $(TR $(TD $(B NaN)) $(TD any) $(TD y)) 4019 $(TR $(TD any) $(TD $(B NaN)) $(TD x)) 4020 ) 4021 */ 4022 @IEEECompliant("maxNumMag", 19) 4023 auto fmaxAbs(D1, D2)(auto const ref D1 x, auto const ref D2 y) 4024 if (isDecimal!D1 && isDecimal!D2) 4025 { 4026 CommonDecimal!(D1, D2) result; 4027 auto flags = decimalMaxAbs(x, y, result) & ExceptionFlags.invalidOperation; 4028 DecimalControl.raiseFlags(flags); 4029 return result; 4030 } 4031 4032 /// 4033 unittest 4034 { 4035 decimal32 x = 3; 4036 decimal64 y = -4; 4037 assert (fmaxAbs(x, y) == -4); 4038 } 4039 4040 /** 4041 Returns the smaller _decimal value between x and y 4042 Throws: 4043 $(MYREF InvalidOperationException) if x or y is signaling $(B NaN) 4044 Special_values: 4045 $(BOOKTABLE, 4046 $(TR $(TH x) $(TH y) $(TH fmin(x, y))) 4047 $(TR $(TD $(B NaN)) $(TD any) $(TD y)) 4048 $(TR $(TD any) $(TD $(B NaN)) $(TD x)) 4049 ) 4050 */ 4051 @IEEECompliant("minNum", 19) 4052 auto fmin(D1, D2)(auto const ref D1 x, auto const ref D2 y) 4053 if (isDecimal!D1 && isDecimal!D2) 4054 { 4055 CommonDecimal!(D1, D2) result; 4056 auto flags = decimalMin(x, y, result) & ExceptionFlags.invalidOperation; 4057 DecimalControl.raiseFlags(flags); 4058 return result; 4059 } 4060 4061 /// 4062 unittest 4063 { 4064 decimal32 x = 3; 4065 decimal64 y = -4; 4066 assert (fmin(x, y) == -4); 4067 } 4068 4069 /** 4070 Returns the smaller _decimal value between absolutes of x and y 4071 Throws: 4072 $(MYREF InvalidOperationException) if x or y is signaling $(B NaN) 4073 Special_values: 4074 $(BOOKTABLE, 4075 $(TR $(TH x) $(TH y) $(TH fminAbs(x, y))) 4076 $(TR $(TD $(B NaN)) $(TD any) $(TD y)) 4077 $(TR $(TD any) $(TD $(B NaN)) $(TD x)) 4078 ) 4079 */ 4080 @IEEECompliant("minNumMag", 19) 4081 auto fminAbs(D1, D2)(auto const ref D1 x, auto const ref D2 y) 4082 if (isDecimal!D1 && isDecimal!D2) 4083 { 4084 CommonDecimal!(D1, D2) result; 4085 auto flags = decimalMinAbs(x, y, result) & ExceptionFlags.invalidOperation; 4086 DecimalControl.raiseFlags(flags); 4087 return result; 4088 } 4089 4090 /// 4091 unittest 4092 { 4093 decimal32 x = 3; 4094 decimal64 y = -4; 4095 assert (fminAbs(x, y) == 3); 4096 } 4097 4098 /** 4099 Calculates the remainder of the division x / y 4100 Params: 4101 x = dividend 4102 y = divisor 4103 Returns: 4104 The value of x - n * y, where n is the quotient rounded toward zero of the division x / y 4105 Throws: 4106 $(BOOKTABLE, 4107 $(TR $(TD $(MYREF InvalidOperationException)) 4108 $(TD x or y is signaling $(B NaN), x = ±∞, y = ±0.0)) 4109 $(TR $(TD $(MYREF UnderflowException)) 4110 $(TD result is too small to be represented)) 4111 $(TR $(TD $(MYREF DivisionByZeroException)) 4112 $(TD y = 0.0)) 4113 $(TR $(TD $(MYREF InexactException)) 4114 $(TD the result is inexact)) 4115 ) 4116 Special_values: 4117 $(BOOKTABLE, 4118 $(TR $(TH x) $(TH y) $(TH fmod(x, y))) 4119 $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN))) 4120 $(TR $(TD any) $(TD $(B NaN)) $(TD $(B NaN))) 4121 $(TR $(TD ±∞) $(TD any) $(TD $(B NaN))) 4122 $(TR $(TD any) $(TD 0.0) $(TD $(B NaN))) 4123 $(TR $(TD any) $(TD ±∞) $(TD $(B NaN))) 4124 ) 4125 */ 4126 auto fmod(D1, D2)(auto const ref D1 x, auto const ref D2 y) 4127 { 4128 alias D = CommonDecimal!(D1, D2); 4129 D result = x; 4130 auto flags = decimalMod(result, y, 4131 __ctfe ? D.PRECISION : DecimalControl.precision, 4132 RoundingMode.towardZero); 4133 DecimalControl.raiseFlags(flags & ~ExceptionFlags.underflow); 4134 return result; 4135 } 4136 4137 /// 4138 unittest 4139 { 4140 decimal32 x = "18.5"; 4141 decimal32 y = "4.2"; 4142 assert (fmod(x, y) == decimal32("1.7")); 4143 } 4144 4145 4146 /** 4147 Separates _decimal _value into coefficient and exponent. 4148 This operation is silent, doesn't throw any exception. 4149 Returns: 4150 a result such as x = result * 10$(SUPERSCRIPT y) and |result| < 1.0 4151 Special_values: 4152 $(BOOKTABLE, 4153 $(TR $(TH x) $(TH y) $(TH frexp(x, y))) 4154 $(TR $(TD $(B NaN)) $(TD 0) $(TD $(B NaN))) 4155 $(TR $(TD +∞) $(TD 0) $(TD +∞)) 4156 $(TR $(TD -∞) $(TD 0) $(TD -∞)) 4157 $(TR $(TD ±0.0) $(TD 0) $(TD ±0.0)) 4158 ) 4159 Notes: 4160 This operation is silent, doesn't throw any exceptions and doesn't set any error flags. 4161 Signaling NaNs are quieted by this operation 4162 4163 */ 4164 D frexp(D)(auto const ref D x, out int y) 4165 { 4166 DataType!D cx; int ex; bool sx; 4167 Unqual!D result; 4168 final switch(fastDecode(x, cx, ex, sx)) 4169 { 4170 case FastClass.signalingNaN: 4171 result.invalidPack(sx, cx); 4172 return result; 4173 case FastClass.quietNaN: 4174 y = 0; 4175 return x; 4176 case FastClass.infinite: 4177 y = 0; 4178 return x; 4179 case FastClass.zero: 4180 y = 0; 4181 return sx ? -D.zero : D.zero; 4182 case FastClass.finite: 4183 auto targetPower = -prec(cx); 4184 y = ex - targetPower; 4185 result.adjustedPack(cx, targetPower, sx, 0, RoundingMode.implicit); 4186 return result; 4187 } 4188 } 4189 /** 4190 Extracts the current payload from a $(B NaN) value 4191 Note: 4192 These functions do not check if x is truly a $(B NaN) value 4193 before extracting the payload. Using them on finite values will extract a part of the coefficient 4194 */ 4195 @nogc nothrow pure @safe 4196 uint getNaNPayload(const decimal32 x) 4197 { 4198 return x.data & decimal32.MASK_PAYL; 4199 } 4200 4201 ///ditto 4202 @nogc nothrow pure @safe 4203 ulong getNaNPayload(const decimal64 x) 4204 { 4205 return x.data & decimal64.MASK_PAYL; 4206 } 4207 4208 ///ditto 4209 @nogc nothrow pure @safe 4210 ulong getNaNPayload(const decimal128 x, out ulong payloadHi) 4211 { 4212 auto payload = x.data & decimal128.MASK_PAYL; 4213 payloadHi = payload.hi; 4214 return payload.lo; 4215 } 4216 4217 /// 4218 unittest 4219 { 4220 decimal32 x = decimal32("nan(123)"); 4221 decimal64 y = decimal64("nan(456)"); 4222 decimal128 z = decimal128("nan(789)"); 4223 4224 assert (getNaNPayload(x) == 123); 4225 assert (getNaNPayload(y) == 456); 4226 ulong hi; 4227 assert (getNaNPayload(z, hi) == 789 && hi == 0); 4228 4229 } 4230 4231 4232 /** 4233 Calculates the length of the hypotenuse of a right-angled triangle with sides 4234 of length x and y. The hypotenuse is the value of the square root of the sums 4235 of the squares of x and y. 4236 Throws: 4237 $(BOOKTABLE, 4238 $(TR $(TD $(MYREF InvalidOperationException)) 4239 $(TD x, y is signaling $(B NaN))) 4240 $(TR $(TD $(MYREF OverflowException)) 4241 $(TD result is too big to be represented)) 4242 $(TR $(TD $(MYREF InexactException)) 4243 $(TD the result is inexact)) 4244 ) 4245 Special_values: 4246 $(BOOKTABLE, 4247 $(TR $(TH x) $(TH y) $(TH hypot(x, y))) 4248 $(TR $(TD $(B NaN)) $(TD $(B NaN)) $(TD nan)) 4249 $(TR $(TD ±∞) $(TD any) $(TD +∞)) 4250 $(TR $(TD any) $(TD ±∞) $(TD +∞)) 4251 $(TR $(TD $(B NaN)) $(TD any) $(TD nan)) 4252 $(TR $(TD any) $(TD $(B NaN)) $(TD nan)) 4253 $(TR $(TD 0.0) $(TD any) $(TD y)) 4254 $(TR $(TD any) $(TD 0.0) $(TD x)) 4255 ) 4256 */ 4257 @IEEECompliant("hypot", 42) 4258 auto hypot(D1, D2)(auto const ref D1 x, auto const ref D2 y) 4259 if (isDecimal!D1 && isDecimal!D2) 4260 { 4261 alias D = CommonDecimal!(D1, D2); 4262 D result; 4263 auto flags = decimalHypot(x, y, result, 4264 __ctfe ? D.PRECISION : DecimalControl.precision, 4265 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 4266 DecimalControl.raiseFlags(flags); 4267 return result; 4268 } 4269 4270 /// 4271 unittest 4272 { 4273 decimal32 x = 3; 4274 decimal32 y = 4; 4275 assert (hypot(x, y) == 5); 4276 } 4277 4278 /** 4279 Returns the 10-exponent of x as a signed integral value.. 4280 Throws: 4281 $(MYREF InvalidOperationException) if x is $(B NaN), infinity or 0 4282 Special_values: 4283 $(BOOKTABLE, 4284 $(TR $(TH x) $(TH ilogb(x))) 4285 $(TR $(TD $(B NaN)) $(TD int.min)) 4286 $(TR $(TD ±∞) $(TD int min + 1)) 4287 $(TR $(TD ±0.0) $(TD int.min + 2)) 4288 $(TR $(TD ±1.0) $(TD 0)) 4289 ) 4290 */ 4291 @IEEECompliant("logB", 17) 4292 int ilogb(D)(auto const ref D x) 4293 if (isDecimal!D) 4294 { 4295 int result; 4296 auto flags = decimalLog(x, result); 4297 DecimalControl.raiseFlags(flags); 4298 return result; 4299 } 4300 4301 /// 4302 unittest 4303 { 4304 assert (ilogb(decimal32(1234)) == 3); 4305 } 4306 4307 /** 4308 Determines if x is canonical. 4309 This operation is silent, no error flags are set and no exceptions are thrown. 4310 Params: 4311 x = a _decimal value 4312 Returns: 4313 true if x is canonical, false otherwise 4314 Notes: 4315 A _decimal value is considered canonical:<br/> 4316 - if the value is $(B NaN), the payload must be less than 10 $(SUPERSCRIPT precision - 1);<br/> 4317 - if the value is infinity, no trailing bits are accepted;<br/> 4318 - if the value is finite, the coefficient must be less than 10 $(SUPERSCRIPT precision). 4319 */ 4320 @IEEECompliant("isCanonical", 25) 4321 bool isCanonical(D)(auto const ref D x) 4322 if (isDecimal!D) 4323 { 4324 static if (is(D: decimal32) || is(D: decimal64)) 4325 { 4326 if ((x.data & D.MASK_QNAN) == D.MASK_QNAN) 4327 return (x.data & D.MASK_PAYL) <= D.PAYL_MAX && (x.data & ~(D.MASK_SNAN | D.MASK_SGN | D.MASK_PAYL)) == 0U; 4328 if ((x.data & D.MASK_INF) == D.MASK_INF) 4329 return (x.data & ~(D.MASK_INF | D.MASK_SGN)) == 0U; 4330 if ((x.data & D.MASK_EXT) == D.MASK_EXT) 4331 return ((x.data & D.MASK_COE2) | D.MASK_COEX) <= D.COEF_MAX; 4332 else 4333 return ((x.data & D.MASK_COE1) <= D.COEF_MAX); 4334 } 4335 else 4336 { 4337 if ((x.data.hi & D.MASK_QNAN.hi) == D.MASK_QNAN.hi) 4338 return (x.data & D.MASK_PAYL) <= D.PAYL_MAX && (x.data & ~(D.MASK_SNAN | D.MASK_SGN | D.MASK_PAYL)) == 0U; 4339 if ((x.data.hi & D.MASK_INF.hi) == D.MASK_INF.hi) 4340 return (x.data.hi & ~(D.MASK_INF.hi | D.MASK_SGN.hi)) == 0U && x.data.lo == 0U; 4341 if ((x.data.hi & D.MASK_EXT.hi) == D.MASK_EXT.hi) 4342 return false; 4343 else 4344 return ((x.data & D.MASK_COE1) <= D.COEF_MAX); 4345 } 4346 4347 4348 } 4349 4350 /// 4351 unittest 4352 { 4353 assert(isCanonical(decimal32.max)); 4354 assert(isCanonical(decimal64.max)); 4355 assert(!isCanonical(decimal32("nan(0x3fffff)"))); 4356 4357 } 4358 4359 unittest 4360 { 4361 4362 foreach(T; TypeTuple!(decimal32, decimal64, decimal128)) 4363 { 4364 assert(isCanonical(T.zero)); 4365 assert(isCanonical(T.max)); 4366 assert(isCanonical(T.nan)); 4367 assert(isCanonical(T.snan)); 4368 assert(isCanonical(T.infinity)); 4369 } 4370 } 4371 4372 /** 4373 Determines if x is a finite value. 4374 This operation is silent, no error flags are set and no exceptions are thrown. 4375 Params: 4376 x = a _decimal value 4377 Returns: 4378 true if x is finite, false otherwise ($(B NaN) or infinity) 4379 */ 4380 @IEEECompliant("isFinite", 25) 4381 bool isFinite(D: Decimal!bits, int bits)(auto const ref D x) 4382 { 4383 static if (is(D: decimal32) || is(D: decimal64)) 4384 { 4385 return (x.data & D.MASK_INF) != D.MASK_INF; 4386 } 4387 else 4388 { 4389 return (x.data.hi & D.MASK_INF.hi) != D.MASK_INF.hi; 4390 } 4391 } 4392 4393 /// 4394 unittest 4395 { 4396 assert(isFinite(decimal32.max)); 4397 assert(!isFinite(decimal64.nan)); 4398 assert(!isFinite(decimal128.infinity)); 4399 } 4400 4401 unittest 4402 { 4403 foreach(T; TypeTuple!(decimal32, decimal64, decimal128)) 4404 { 4405 assert(isFinite(T.max)); 4406 assert(!isFinite(T.infinity)); 4407 assert(!isFinite(T.snan)); 4408 assert(!isFinite(T.qnan)); 4409 } 4410 } 4411 4412 /** 4413 Checks if two _decimal values are identical 4414 Params: 4415 x = a _decimal value 4416 y = a _decimal value 4417 Returns: 4418 true if x has the same internal representation as y 4419 Notes: 4420 Even if two _decimal values are equal, their internal representation can be different:<br/> 4421 - $(B NaN) values must have the same sign and the same payload to be considered identical; 4422 $(B NaN)(12) is not identical to $(B NaN)(13)<br/> 4423 - Zero values must have the same sign and the same exponent to be considered identical; 4424 0 * 10$(SUPERSCRIPT 3) is not identical to 0 * 10$(SUPERSCRIPT 5)<br/> 4425 - Finite _values must be represented based on same exponent to be considered identical; 4426 123 * 10$(SUPERSCRIPT -3) is not identical to 1.23 * 10$(SUPERSCRIPT -1) 4427 */ 4428 bool isIdentical(D)(auto const ref D x, auto const ref D y) 4429 if (isDecimal!D) 4430 { 4431 return x.data == y.data; 4432 } 4433 4434 /// 4435 unittest 4436 { 4437 assert (isIdentical(decimal32.min_normal, decimal32.min_normal)); 4438 assert (!isIdentical(decimal64("nan"), decimal64("nan<200>"))); 4439 } 4440 4441 /** 4442 Determines if x represents infinity. 4443 This operation is silent, no error flags are set and no exceptions are thrown. 4444 Params: 4445 x = a _decimal value 4446 Returns: 4447 true if x is infinite, false otherwise ($(B NaN) or any finite value) 4448 */ 4449 @IEEECompliant("isInfinite", 25) 4450 bool isInfinity(D)(auto const ref D x) 4451 if (isDecimal!D) 4452 { 4453 static if (is(D: decimal32) || is(D: decimal64)) 4454 { 4455 return (x.data & D.MASK_QNAN) == D.MASK_INF; 4456 } 4457 else 4458 { 4459 return (x.data.hi & D.MASK_QNAN.hi) == D.MASK_INF.hi; 4460 } 4461 } 4462 4463 /// 4464 unittest 4465 { 4466 assert(isInfinity(decimal32.infinity)); 4467 assert(isInfinity(-decimal64.infinity)); 4468 assert(!isInfinity(decimal128.nan)); 4469 } 4470 4471 unittest 4472 { 4473 foreach(T; TypeTuple!(decimal32, decimal64, decimal128)) 4474 { 4475 assert(isInfinity(T.infinity)); 4476 assert(isInfinity(-T.infinity)); 4477 assert(!isInfinity(T.ten)); 4478 assert(!isInfinity(T.snan)); 4479 assert(!isInfinity(T.qnan)); 4480 } 4481 } 4482 4483 /** 4484 Determines if x represents a $(B NaN). 4485 This operation is silent, no error flags are set and no exceptions are thrown. 4486 Params: 4487 x = a _decimal value 4488 Returns: 4489 true if x is $(B NaN) (quiet or signaling), false otherwise (any other value than $(B NaN)) 4490 */ 4491 @IEEECompliant("isNaN", 25) 4492 bool isNaN(D)(auto const ref D x) 4493 if (isDecimal!D) 4494 { 4495 static if (is(D: decimal32) || is(D: decimal64)) 4496 { 4497 return (x.data & D.MASK_QNAN) == D.MASK_QNAN; 4498 } 4499 else 4500 { 4501 return (x.data.hi & D.MASK_QNAN.hi) == D.MASK_QNAN.hi; 4502 } 4503 } 4504 4505 /// 4506 unittest 4507 { 4508 assert(isNaN(decimal32())); 4509 assert(isNaN(decimal64.nan)); 4510 assert(!isNaN(decimal128.max)); 4511 } 4512 4513 unittest 4514 { 4515 foreach(T; TypeTuple!(decimal32, decimal64, decimal128)) 4516 { 4517 assert(isNaN(T.snan)); 4518 assert(isNaN(T())); 4519 assert(!isSignaling(T.ten)); 4520 assert(!isSignaling(T.min_normal)); 4521 assert(isNaN(T.qnan)); 4522 } 4523 } 4524 4525 /** 4526 Determines if x is normalized. 4527 This operation is silent, no error flags are set and no exceptions are thrown. 4528 Params: 4529 x = a _decimal value 4530 Returns: 4531 true if x is normal, false otherwise ($(B NaN), infinity, zero, subnormal) 4532 */ 4533 @IEEECompliant("isNormal", 25) 4534 bool isNormal(D)(auto const ref D x) 4535 if (isDecimal!D) 4536 { 4537 DataType!D coefficient; 4538 uint exponent; 4539 4540 static if (is(D: decimal32) || is(D: decimal64)) 4541 { 4542 if ((x.data & D.MASK_INF) == D.MASK_INF) 4543 return false; 4544 if ((x.data & D.MASK_EXT) == D.MASK_EXT) 4545 { 4546 coefficient = (x.data & D.MASK_COE2) | D.MASK_COEX; 4547 if (coefficient > D.COEF_MAX) 4548 return false; 4549 exponent = cast(uint)((x.data & D.MASK_EXP2) >>> D.SHIFT_EXP2); 4550 } 4551 else 4552 { 4553 coefficient = x.data & D.MASK_COE1; 4554 if (coefficient == 0U) 4555 return false; 4556 exponent = cast(uint)((x.data & D.MASK_EXP1) >>> D.SHIFT_EXP1); 4557 } 4558 } 4559 else 4560 { 4561 if ((x.data.hi & D.MASK_INF.hi) == D.MASK_INF.hi) 4562 return false; 4563 if ((x.data.hi & D.MASK_EXT.hi) == D.MASK_EXT.hi) 4564 return false; 4565 coefficient = x.data & D.MASK_COE1; 4566 if (coefficient == 0U || coefficient > D.COEF_MAX) 4567 return false; 4568 exponent = cast(uint)((x.data.hi & D.MASK_EXP1.hi) >>> (D.SHIFT_EXP1 - 64)); 4569 } 4570 4571 if (exponent < D.PRECISION - 1) 4572 return prec(coefficient) >= D.PRECISION - exponent; 4573 4574 return true; 4575 } 4576 4577 /// 4578 unittest 4579 { 4580 assert(isNormal(decimal32.max)); 4581 assert(!isNormal(decimal64.nan)); 4582 assert(!isNormal(decimal32("0x1p-101"))); 4583 } 4584 4585 unittest 4586 { 4587 4588 foreach(T; TypeTuple!(decimal32, decimal64, decimal128)) 4589 { 4590 assert(!isNormal(T.zero)); 4591 assert(isNormal(T.ten)); 4592 assert(!isNormal(T.nan)); 4593 assert(isNormal(T.min_normal)); 4594 assert(!isNormal(T.subn)); 4595 } 4596 } 4597 4598 /** 4599 Checks whether a _decimal value is a power of ten. This operation is silent, 4600 no exception flags are set and no exceptions are thrown. 4601 Params: 4602 x = any _decimal value 4603 Returns: 4604 true if x is power of ten, false otherwise ($(B NaN), infinity, 0, negative) 4605 */ 4606 bool isPowerOf10(D)(auto const ref D x) 4607 if (isDecimal!D) 4608 { 4609 if (isNaN(x) || isInfinity(x) || isZero(x) || signbit(x) != 0U) 4610 return false; 4611 4612 alias U = DataType!D; 4613 U c; 4614 int e; 4615 x.unpack(c, e); 4616 coefficientShrink(c, e); 4617 return c == 1U; 4618 } 4619 4620 /// 4621 unittest 4622 { 4623 assert (isPowerOf10(decimal32("1000"))); 4624 assert (isPowerOf10(decimal32("0.001"))); 4625 } 4626 4627 /** 4628 Determines if x represents a signaling $(B NaN). 4629 This operation is silent, no error flags are set and no exceptions are thrown. 4630 Params: 4631 x = a _decimal value 4632 Returns: 4633 true if x is $(B NaN) and is signaling, false otherwise (quiet $(B NaN), any other value) 4634 */ 4635 @IEEECompliant("isSignaling", 25) 4636 bool isSignaling(D)(auto const ref D x) 4637 if (isDecimal!D) 4638 { 4639 static if (is(D: decimal32) || is(D: decimal64)) 4640 { 4641 return (x.data & D.MASK_SNAN) == D.MASK_SNAN; 4642 } 4643 else 4644 { 4645 return (x.data.hi & D.MASK_SNAN.hi) == D.MASK_SNAN.hi; 4646 } 4647 } 4648 4649 /// 4650 unittest 4651 { 4652 assert(isSignaling(decimal32())); 4653 assert(!isSignaling(decimal64.nan)); 4654 assert(!isSignaling(decimal128.max)); 4655 } 4656 4657 unittest 4658 { 4659 foreach(T; TypeTuple!(decimal32, decimal64, decimal128)) 4660 { 4661 assert(isSignaling(T.snan)); 4662 assert(isSignaling(T())); 4663 assert(!isSignaling(T.ten)); 4664 assert(!isSignaling(T.min_normal)); 4665 assert(!isSignaling(T.qnan)); 4666 } 4667 } 4668 4669 /** 4670 Determines if x is subnormal (denormalized). 4671 This operation is silent, no error flags are set and no exceptions are thrown. 4672 Params: 4673 x = a _decimal value 4674 Returns: 4675 true if x is subnormal, false otherwise ($(B NaN), infinity, zero, normal) 4676 */ 4677 @IEEECompliant("isSubnormal", 25) 4678 bool isSubnormal(D)(auto const ref D x) 4679 if (isDecimal!D) 4680 { 4681 DataType!D coefficient; 4682 uint exponent; 4683 4684 static if (is(D: decimal32) || is(D: decimal64)) 4685 { 4686 if ((x.data & D.MASK_INF) == D.MASK_INF) 4687 return false; 4688 if ((x.data & D.MASK_EXT) == D.MASK_EXT) 4689 { 4690 coefficient = (x.data & D.MASK_COE2) | D.MASK_COEX; 4691 if (coefficient > D.COEF_MAX) 4692 return false; 4693 exponent = cast(uint)((x.data & D.MASK_EXP2) >>> D.SHIFT_EXP2); 4694 } 4695 else 4696 { 4697 coefficient = x.data & D.MASK_COE1; 4698 if (coefficient == 0U) 4699 return false; 4700 exponent = cast(uint)((x.data & D.MASK_EXP1) >>> D.SHIFT_EXP1); 4701 } 4702 } 4703 else 4704 { 4705 if ((x.data.hi & D.MASK_INF.hi) == D.MASK_INF.hi) 4706 return false; 4707 if ((x.data.hi & D.MASK_EXT.hi) == D.MASK_EXT.hi) 4708 return false; 4709 coefficient = x.data & D.MASK_COE1; 4710 if (coefficient == 0U || coefficient > D.COEF_MAX) 4711 return false; 4712 exponent = cast(uint)((x.data.hi & D.MASK_EXP1.hi) >>> (D.SHIFT_EXP1 - 64)); 4713 } 4714 4715 if (exponent < D.PRECISION - 1) 4716 return prec(coefficient) < D.PRECISION - exponent; 4717 4718 return false; 4719 } 4720 4721 /// 4722 unittest 4723 { 4724 assert(isSubnormal(decimal32("0x1p-101"))); 4725 assert(!isSubnormal(decimal32.max)); 4726 assert(!isSubnormal(decimal64.nan)); 4727 4728 } 4729 4730 unittest 4731 { 4732 4733 foreach(T; TypeTuple!(decimal32, decimal64, decimal128)) 4734 { 4735 assert(!isSubnormal(T.zero)); 4736 assert(!isSubnormal(T.ten)); 4737 assert(!isSubnormal(T.nan)); 4738 assert(!isSubnormal(T.min_normal)); 4739 assert(isSubnormal(T.subn)); 4740 assert(isSubnormal(-T.subn)); 4741 } 4742 } 4743 4744 4745 4746 /** 4747 Determines if x represents the value zero. 4748 This operation is silent, no error flags are set and no exceptions are thrown. 4749 Params: 4750 x = a _decimal value 4751 Returns: 4752 true if x is zero, false otherwise (any other value than zero) 4753 Standards: 4754 If the internal representation of the _decimal data type has a coefficient 4755 greater that 10$(SUPERSCRIPT precision) - 1, is considered 0 according to 4756 IEEE standard. 4757 */ 4758 @("this must be fast") 4759 @IEEECompliant("isZero", 25) 4760 bool isZero(D)(auto const ref D x) 4761 if (isDecimal!D) 4762 { 4763 static if (is(D: decimal32) || is(D: decimal64)) 4764 { 4765 if ((x.data & D.MASK_INF) != D.MASK_INF) 4766 { 4767 if ((x.data & D.MASK_EXT) == D.MASK_EXT) 4768 return ((x.data & D.MASK_COE2) | D.MASK_COEX) > D.COEF_MAX; 4769 else 4770 return (x.data & D.MASK_COE1) == 0; 4771 } 4772 else 4773 return false; 4774 } 4775 else 4776 { 4777 if ((x.data.hi & D.MASK_INF.hi) != D.MASK_INF.hi) 4778 { 4779 if ((x.data.hi & D.MASK_EXT.hi) == D.MASK_EXT.hi) 4780 return true; 4781 else 4782 { 4783 auto cx = x.data & D.MASK_COE1; 4784 return !cx || cx > D.COEF_MAX; 4785 } 4786 } 4787 else 4788 return false; 4789 } 4790 4791 } 4792 4793 /// 4794 unittest 4795 { 4796 assert(isZero(decimal32(0))); 4797 assert(!isZero(decimal64.nan)); 4798 assert(isZero(decimal32("0x9FFFFFp+10"))); 4799 } 4800 4801 unittest 4802 { 4803 foreach(T; TypeTuple!(decimal32, decimal64, decimal128)) 4804 { 4805 assert(isZero(T.zero)); 4806 assert(isZero(T.minusZero)); 4807 assert(!isZero(T.ten)); 4808 assert(isZero(T(T.MASK_NONE, T.MASK_EXT, T.MASK_COE2 | T.MASK_COEX))); 4809 } 4810 } 4811 4812 4813 4814 /** 4815 Compares two _decimal operands. 4816 This operation is silent, no exception flags are set and no exceptions are thrown. 4817 Returns: 4818 true if the specified condition is satisfied 4819 Notes: 4820 By default, comparison operators will throw $(MYREF InvalidOperationException) or will 4821 set the $(MYREF ExceptionFlags.invalidOperation) context flag if a trap is not set. 4822 The equivalent functions are silent and will not throw any exception (or will not set any flag) 4823 if a $(B NaN) value is encountered. 4824 */ 4825 @IEEECompliant("compareQuietGreater", 24) 4826 bool isGreater(D1, D2)(auto const ref D1 x, auto const ref D2 y) 4827 if (isDecimal!(D1, D2)) 4828 { 4829 auto c = decimalCmp(x, y); 4830 if (c == -3) 4831 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation); 4832 return c > 0; 4833 } 4834 4835 ///ditto 4836 @IEEECompliant("compareQuietGreaterEqual", 24) 4837 bool isGreaterOrEqual(D1, D2)(auto const ref D1 x, auto const ref D2 y) 4838 if (isDecimal!(D1, D2)) 4839 { 4840 auto c = decimalCmp(x, y); 4841 if (c == -3) 4842 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation); 4843 return c >= 0; 4844 } 4845 4846 ///ditto 4847 @IEEECompliant("compareQuietGreaterUnordered", 24) 4848 bool isGreaterOrUnordered(D1, D2)(auto const ref D1 x, auto const ref D2 y) 4849 if (isDecimal!(D1, D2)) 4850 { 4851 auto c = decimalCmp(x, y); 4852 if (c == -3) 4853 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation); 4854 return c > 0 || c < -1; 4855 } 4856 4857 ///ditto 4858 @IEEECompliant("compareQuietLess", 24) 4859 @IEEECompliant("compareQuietNotLess", 24) 4860 bool isLess(D1, D2)(auto const ref D1 x, auto const ref D2 y) 4861 if (isDecimal!(D1, D2)) 4862 { 4863 auto c = decimalCmp(x, y); 4864 if (c == -3) 4865 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation); 4866 return c == -1; 4867 } 4868 4869 ///ditto 4870 @IEEECompliant("compareQuietLessEqual", 24) 4871 bool isLessOrEqual(D1, D2)(auto const ref D1 x, auto const ref D2 y) 4872 if (isDecimal!(D1, D2)) 4873 { 4874 auto c = decimalCmp(x, y); 4875 if (c == -3) 4876 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation); 4877 return c <= 0 && c > -2; 4878 } 4879 4880 ///ditto 4881 @IEEECompliant("compareQuietLessUnordered", 24) 4882 bool isLessOrUnordered(D1, D2)(auto const ref D1 x, auto const ref D2 y) 4883 if (isDecimal!(D1, D2)) 4884 { 4885 auto c = decimalCmp(x, y); 4886 if (c == -3) 4887 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation); 4888 return c < 0; 4889 } 4890 4891 ///ditto 4892 @IEEECompliant("compareQuietOrdered", 24) 4893 @IEEECompliant("compareQuietUnordered", 24) 4894 bool isUnordered(D1, D2)(auto const ref D1 x, auto const ref D2 y) 4895 if (isDecimal!(D1, D2)) 4896 { 4897 auto c = decimalCmp(x, y); 4898 if (c == -3) 4899 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation); 4900 return c < -1; 4901 } 4902 4903 /// 4904 unittest 4905 { 4906 assert(isUnordered(decimal32.nan, decimal64.max)); 4907 assert(isGreater(decimal32.infinity, decimal128.max)); 4908 assert(isGreaterOrEqual(decimal32.infinity, decimal64.infinity)); 4909 assert(isLess(decimal64.max, decimal128.max)); 4910 assert(isLessOrEqual(decimal32.min_normal, decimal32.min_normal)); 4911 } 4912 4913 unittest 4914 { 4915 4916 4917 foreach(T; TypeTuple!(decimal32, decimal64, decimal128)) 4918 { 4919 assert(isUnordered(T.nan, T.one)); 4920 assert(isUnordered(T.one, T.nan)); 4921 assert(isUnordered(T.nan, T.nan)); 4922 4923 assert(isGreater(T.max, T.ten)); 4924 assert(isGreater(T.ten, T.one)); 4925 assert(isGreater(-T.ten, -T.max)); 4926 assert(isGreater(T.zero, -T.max)); 4927 assert(isGreater(T.max, T.zero)); 4928 4929 assert(isLess(T.one, T.ten), T.stringof); 4930 assert(isLess(T.ten, T.max)); 4931 assert(isLess(-T.max, -T.one)); 4932 assert(isLess(T.zero, T.max)); 4933 assert(isLess(T.max, T.infinity)); 4934 } 4935 } 4936 4937 /** 4938 Compares two _decimal operands for equality 4939 Returns: 4940 true if the specified condition is satisfied, false otherwise or if any of the operands is $(B NaN). 4941 Notes: 4942 By default, $(MYREF Decimal.opEquals) is silent, returning false if a $(B NaN) value is encountered. 4943 isEqual and isNotEqual will throw $(MYREF InvalidOperationException) or will 4944 set the $(MYREF ExceptionFlags.invalidOperation) context flag if a trap is not set. 4945 */ 4946 4947 @IEEECompliant("compareSignalingEqual", 24) 4948 bool isEqual(D1, D2)(auto const ref D1 x, auto const ref D2 y) 4949 if (isDecimal!(D1, D2)) 4950 { 4951 auto c = decimalEqu(x, y); 4952 if (c < 0) 4953 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation); 4954 return c == 1; 4955 } 4956 4957 ///ditto 4958 @IEEECompliant("compareSignalingNotEqual", 24) 4959 bool isNotEqual(D1, D2)(auto const ref D1 x, auto const ref D2 y) 4960 if (isDecimal!(D1, D2)) 4961 { 4962 auto c = decimalEqu(x, y); 4963 if (c < 0) 4964 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation); 4965 return c != 1; 4966 } 4967 4968 /// 4969 unittest 4970 { 4971 assert (isEqual(decimal32.max, decimal32.max)); 4972 assert (isNotEqual(decimal32.max, decimal32.min_normal)); 4973 } 4974 4975 /** 4976 Efficiently calculates 2 * 10$(SUPERSCRIPT n). 4977 $(BOOKTABLE, 4978 $(TR $(TD $(MYREF InvalidOperationException)) 4979 $(TD x is $(B signaling NaN))) 4980 $(TR $(TD $(MYREF UnderflowException)) 4981 $(TD result is subnormal or too small to be represented) 4982 $(TR $(TD $(MYREF OverflowException)) 4983 $(TD result is too big to be represented) 4984 $(TR $(TD $(MYREF InexactException)) 4985 $(TD result is inexact) 4986 ) 4987 Special_values: 4988 $(BOOKTABLE, 4989 $(TR $(TH x) $(TH n) $(TH ldexp(x, n))) 4990 $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN))) 4991 $(TR $(TD ±∞) $(TD any) $(TD ±∞)) 4992 $(TR $(TD ±0) $(TD any) $(TD ±0)) 4993 $(TR $(TD any) $(TD 0) $(TD x)) 4994 ) 4995 */ 4996 D ldexp(D)(auto const ref D x, const int n) 4997 if (isDecimal!D) 4998 { 4999 Unqual!D result = x; 5000 auto flags = decimalMulPow2(result, n, 5001 __ctfe ? D.PRECISION : DecimalControl.precision, 5002 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 5003 DecimalControl.raiseFlags(flags); 5004 return result; 5005 } 5006 5007 /// 5008 unittest 5009 { 5010 decimal32 d = "1.0"; 5011 assert (ldexp(d, 3) == 8); 5012 } 5013 5014 /** 5015 Calculates the natural logarithm of log$(SUBSCRIPT e)x. 5016 Throws: 5017 $(BOOKTABLE, 5018 $(TR $(TD $(MYREF InvalidOperationException)) 5019 $(TD x is signaling $(B NaN) or x < 0)) 5020 $(TR $(TD $(MYREF DivisionByZero)) 5021 $(TD x is ±0.0)) 5022 $(TR $(TD $(MYREF Underflow)) 5023 $(TD result is too small to be represented)) 5024 $(TR $(TD $(MYREF InexactException)) 5025 $(TD the result is inexact)) 5026 ) 5027 Special_values: 5028 $(BOOKTABLE, 5029 $(TR $(TH x) $(TH log(x))) 5030 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 5031 $(TR $(TD ±0.0) $(TD -∞)) 5032 $(TR $(TD -∞) $(TD $(B NaN))) 5033 $(TR $(TD +∞) $(TD +∞)) 5034 $(TR $(TD e) $(TD +1.0)) 5035 $(TR $(TD < 0.0) $(TD $(B NaN))) 5036 ) 5037 */ 5038 @IEEECompliant("log", 42) 5039 D log(D)(auto const ref D x) 5040 if (isDecimal!D) 5041 { 5042 Unqual!D result = x; 5043 auto flags = decimalLog(result, 5044 __ctfe ? D.PRECISION : DecimalControl.precision, 5045 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 5046 flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero); 5047 DecimalControl.raiseFlags(flags); 5048 return result; 5049 } 5050 5051 /// 5052 unittest 5053 { 5054 assert (log(decimal32.E) == 1); 5055 } 5056 5057 5058 /** 5059 Calculates log$(SUBSCRIPT 10)x. 5060 Throws: 5061 $(BOOKTABLE, 5062 $(TR $(TD $(MYREF InvalidOperationException)) 5063 $(TD x is signaling $(B NaN) or x < 0.0)) 5064 $(TR $(TD $(MYREF DivisionByZero)) 5065 $(TD x is ±0.0)) 5066 $(TR $(TD $(MYREF Underflow)) 5067 $(TD result is too small to be represented)) 5068 $(TR $(TD $(MYREF InexactException)) 5069 $(TD the result is inexact)) 5070 ) 5071 Special_values: 5072 $(BOOKTABLE, 5073 $(TR $(TH x) $(TH log(x))) 5074 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 5075 $(TR $(TD ±0.0) $(TD -∞)) 5076 $(TR $(TD -∞) $(TD $(B NaN))) 5077 $(TR $(TD +∞) $(TD +∞)) 5078 $(TR $(TD +10.0) $(TD +1.0)) 5079 $(TR $(TD < 0.0) $(TD $(B NaN))) 5080 ) 5081 */ 5082 @IEEECompliant("log10", 42) 5083 D log10(D)(auto const ref D x) 5084 if (isDecimal!D) 5085 { 5086 Unqual!D result = x; 5087 auto flags = decimalLog10(result, 5088 __ctfe ? D.PRECISION : DecimalControl.precision, 5089 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 5090 flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero); 5091 DecimalControl.raiseFlags(flags); 5092 return result; 5093 } 5094 5095 /** 5096 Calculates log$(SUBSCRIPT 10)(x + 1). 5097 Throws: 5098 $(BOOKTABLE, 5099 $(TR $(TD $(MYREF InvalidOperationException)) 5100 $(TD x is signaling $(B NaN) or x < 1.0)) 5101 $(TR $(TD $(MYREF DivisionByZero)) 5102 $(TD x is -1.0)) 5103 $(TR $(TD $(MYREF Underflow)) 5104 $(TD result is too small to be represented)) 5105 $(TR $(TD $(MYREF InexactException)) 5106 $(TD the result is inexact)) 5107 ) 5108 Special_values: 5109 $(BOOKTABLE, 5110 $(TR $(TH x) $(TH log(x))) 5111 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 5112 $(TR $(TD -1.0) $(TD -∞)) 5113 $(TR $(TD -∞) $(TD $(B NaN))) 5114 $(TR $(TD +∞) $(TD +∞)) 5115 $(TR $(TD +9.0) $(TD +1.0)) 5116 $(TR $(TD < -1.0) $(TD $(B NaN))) 5117 ) 5118 */ 5119 @IEEECompliant("log10p1", 42) 5120 D log10p1(D)(auto const ref D x) 5121 if (isDecimal!D) 5122 { 5123 Unqual!D result = x; 5124 auto flags = decimalLog10p1(result, 5125 __ctfe ? D.PRECISION : DecimalControl.precision, 5126 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 5127 flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero); 5128 DecimalControl.raiseFlags(flags); 5129 return result; 5130 } 5131 5132 /** 5133 Calculates log$(SUBSCRIPT 2)x. 5134 Throws: 5135 $(BOOKTABLE, 5136 $(TR $(TD $(MYREF InvalidOperationException)) 5137 $(TD x is signaling $(B NaN) or x < 0)) 5138 $(TR $(TD $(MYREF DivisionByZero)) 5139 $(TD x is ±0.0)) 5140 $(TR $(TD $(MYREF Underflow)) 5141 $(TD result is too small to be represented)) 5142 $(TR $(TD $(MYREF InexactException)) 5143 $(TD the result is inexact)) 5144 ) 5145 Special_values: 5146 $(BOOKTABLE, 5147 $(TR $(TH x) $(TH log(x))) 5148 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 5149 $(TR $(TD ±0.0) $(TD -∞)) 5150 $(TR $(TD -∞) $(TD $(B NaN))) 5151 $(TR $(TD +∞) $(TD +∞)) 5152 $(TR $(TD +2.0) $(TD +1.0)) 5153 $(TR $(TD < 0.0) $(TD $(B NaN))) 5154 ) 5155 */ 5156 @IEEECompliant("log2", 42) 5157 D log2(D)(auto const ref D x) 5158 if (isDecimal!D) 5159 { 5160 Unqual!D result = x; 5161 auto flags = decimalLog2(result, 5162 __ctfe ? D.PRECISION : DecimalControl.precision, 5163 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 5164 flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero); 5165 DecimalControl.raiseFlags(flags); 5166 return result; 5167 } 5168 5169 /** 5170 Calculates log$(SUBSCRIPT 2)(x + 1). 5171 Throws: 5172 $(BOOKTABLE, 5173 $(TR $(TD $(MYREF InvalidOperationException)) 5174 $(TD x is signaling $(B NaN) or x < 0)) 5175 $(TR $(TD $(MYREF DivisionByZero)) 5176 $(TD x is -1.0)) 5177 $(TR $(TD $(MYREF Underflow)) 5178 $(TD result is too small to be represented)) 5179 $(TR $(TD $(MYREF InexactException)) 5180 $(TD the result is inexact)) 5181 ) 5182 Special_values: 5183 $(BOOKTABLE, 5184 $(TR $(TH x) $(TH log(x))) 5185 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 5186 $(TR $(TD ±0.0) $(TD -∞)) 5187 $(TR $(TD -∞) $(TD $(B NaN))) 5188 $(TR $(TD +∞) $(TD +∞)) 5189 $(TR $(TD +1.0) $(TD +1.0)) 5190 $(TR $(TD < -1.0) $(TD $(B NaN))) 5191 ) 5192 */ 5193 @IEEECompliant("log2p1", 42) 5194 D log2p1(D)(auto const ref D x) 5195 if (isDecimal!D) 5196 { 5197 Unqual!D result = x; 5198 auto flags = decimalLog2p1(result, 5199 __ctfe ? D.PRECISION : DecimalControl.precision, 5200 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 5201 flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero); 5202 DecimalControl.raiseFlags(flags); 5203 return result; 5204 } 5205 5206 /** 5207 Calculates log$(SUBSCRIPT e)(x + 1). 5208 Throws: 5209 $(BOOKTABLE, 5210 $(TR $(TD $(MYREF InvalidOperationException)) 5211 $(TD x is signaling $(B NaN) or x < 0)) 5212 $(TR $(TD $(MYREF DivisionByZero)) 5213 $(TD x is -1.0)) 5214 $(TR $(TD $(MYREF Underflow)) 5215 $(TD result is too small to be represented)) 5216 $(TR $(TD $(MYREF InexactException)) 5217 $(TD the result is inexact)) 5218 ) 5219 Special_values: 5220 $(BOOKTABLE, 5221 $(TR $(TH x) $(TH log(x))) 5222 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 5223 $(TR $(TD ±0.0) $(TD -∞)) 5224 $(TR $(TD -∞) $(TD $(B NaN))) 5225 $(TR $(TD +∞) $(TD +∞)) 5226 $(TR $(TD e - 1) $(TD +1.0)) 5227 $(TR $(TD < -1.0) $(TD $(B NaN))) 5228 ) 5229 */ 5230 @IEEECompliant("logp1", 42) 5231 D logp1(D)(auto const ref D x) 5232 if (isDecimal!D) 5233 { 5234 Unqual!D result = x; 5235 auto flags = decimalLogp1(result, 5236 __ctfe ? D.PRECISION : DecimalControl.precision, 5237 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 5238 flags &= (ExceptionFlags.inexact | ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero); 5239 DecimalControl.raiseFlags(flags); 5240 return result; 5241 } 5242 5243 /** 5244 Returns the value of x rounded using the specified rounding _mode. 5245 If no rounding _mode is specified the default context rounding _mode is used instead. 5246 Throws: 5247 $(BOOKTABLE, 5248 $(TR $(TD $(MYREF InvalidOperationException)) 5249 $(TD x is $(B NaN) or ±∞)) 5250 $(TR $(TD $(MYREF OverflowException)) 5251 $(TD result is too big to be represented)) 5252 $(TR $(TD $(MYREF InexactException)) 5253 $(TD the result is inexact)) 5254 ) 5255 Special_values: 5256 $(BOOKTABLE, 5257 $(TR $(TH x) $(TH lrint(x))) 5258 $(TR $(TD $(B NaN)) $(TD 0)) 5259 $(TR $(TD -∞) $(TD long.min)) 5260 $(TR $(TD +∞) $(TD long.max)) 5261 ) 5262 */ 5263 long lrint(D)(auto const ref D x, const RoundingMode mode) 5264 if (isDecimal!D) 5265 { 5266 long result; 5267 auto flags = decimalToSigned(x, result, mode); 5268 DecimalControl.raiseFlags(flags & (ExceptionFlags.invalidOperation | ExceptionFlags.inexact)); 5269 return result; 5270 } 5271 5272 ///ditto 5273 long lrint(D)(auto const ref D x) 5274 if (isDecimal!D) 5275 { 5276 return lrint(x, __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 5277 } 5278 5279 /** 5280 Returns the value of x rounded away from zero. 5281 Throws: 5282 $(BOOKTABLE, 5283 $(TR $(TD $(MYREF InvalidOperationException)) 5284 $(TD x is $(B NaN) or ±∞)) 5285 $(TR $(TD $(MYREF OverflowException)) 5286 $(TD result is too big to be represented)) 5287 ) 5288 Special_values: 5289 $(BOOKTABLE, 5290 $(TR $(TH x) $(TH lround(x))) 5291 $(TR $(TD $(B NaN)) $(TD 0)) 5292 $(TR $(TD -∞) $(TD long.min)) 5293 $(TR $(TD +∞) $(TD long.max)) 5294 ) 5295 */ 5296 long lround(D)(auto const ref D x) 5297 { 5298 long result; 5299 auto flags = decimalToSigned(x, result, RoundingMode.tiesToAway); 5300 DecimalControl.raiseFlags(flags & ExceptionFlags.invalidOperation); 5301 //todo: intel does not set ovf, is that correct? 5302 return result; 5303 } 5304 5305 /** 5306 Splits x in integral and fractional part. 5307 Params: 5308 x = value to split 5309 y = value of x truncated toward zero 5310 Returns: 5311 Fractional part of x. 5312 Throws: 5313 $(BOOKTABLE, 5314 $(TR $(TD $(MYREF InvalidOperationException)) 5315 $(TD x is $(B signaling NaN))) 5316 Special_values: 5317 $(BOOKTABLE, 5318 $(TR $(TH x) $(TH modf(x)) $(TH y)) 5319 $(TR $(TD $(B NaN)) $(TD $(B NaN)) $(TD $(B NaN))) 5320 $(TR $(TD 0.0) $(TD 0.0) $(TD 0.0)) 5321 $(TR $(TD ±∞) $(TD 0.0) $(TD ±∞)) 5322 ) 5323 */ 5324 D modf(D)(auto const ref D x, ref D y) 5325 if (isDecimal!D) 5326 { 5327 if (isSignaling(x)) 5328 { 5329 y = copysign(D.nan, x); 5330 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation); 5331 return y; 5332 } 5333 else if (isNaN(x)) 5334 { 5335 y = copysign(D.nan, x); 5336 return y; 5337 } 5338 else if (isZero(x)) 5339 { 5340 y = copysign(D.zero, x); 5341 return y; 5342 } 5343 else if (isInfinity(x)) 5344 { 5345 y = x; 5346 return copysign(D.zero, x); 5347 } 5348 else 5349 { 5350 Unqual!D fractional = x; 5351 y = x; 5352 decimalRound(y, 0, RoundingMode.towardZero); 5353 decimalSub(fractional, y, 0, RoundingMode.tiesToAway); 5354 return copysign(fractional, x); 5355 } 5356 } 5357 5358 /** 5359 Creates a quiet $(B NaN) value using the specified payload 5360 Notes: 5361 Payloads are masked to fit the current representation, having a limited bit width of to $(B mant_dig) - 2; 5362 */ 5363 D NaN(D, T)(const T payload) 5364 if (isDecimal!D && isUnsigned!T) 5365 { 5366 D result = void; 5367 result.data = D.MASK_QNAN | (cast(DataType!D)payload & D.MASK_PAYL); 5368 return result; 5369 } 5370 5371 ///ditto 5372 decimal128 NaN(T)(const T payloadHi, const T payloadLo) 5373 if (isUnsigned!T) 5374 { 5375 decimal128 result = void; 5376 result.data = decimal128.MASK_QNAN | (uint128(payloadHi, payloadLo) & decimal128.MASK_PAYL); 5377 return result; 5378 } 5379 5380 /// 5381 unittest 5382 { 5383 auto a = NaN!decimal32(12345U); 5384 auto b = NaN!decimal64(12345UL); 5385 decimal128 c = NaN(123U, 456U); 5386 } 5387 5388 /** 5389 Returns the value of x rounded using the specified rounding _mode. 5390 If no rounding _mode is specified the default context rounding _mode is used instead. 5391 Throws: 5392 $(MYREF InvalidOperationException) if x is signaling $(B NaN) 5393 Special_values: 5394 $(BOOKTABLE, 5395 $(TR $(TH x) $(TH nearbyint(x))) 5396 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 5397 $(TR $(TD ±∞) $(TD ±∞)) 5398 $(TR $(TD ±0.0) $(TD ±0.0)) 5399 ) 5400 */ 5401 @IEEECompliant("roundToIntegralTiesToAway", 19) 5402 @IEEECompliant("roundToIntegralTiesToEven", 19) 5403 @IEEECompliant("roundToIntegralTowardNegative", 19) 5404 @IEEECompliant("roundToIntegralTowardPositive", 19) 5405 @IEEECompliant("roundToIntegralTowardZero", 19) 5406 D nearbyint(D)(auto const ref D x, const RoundingMode mode) 5407 if (isDecimal!D) 5408 { 5409 Unqual!D result = x; 5410 auto flags = decimalRound(result, __ctfe ? D.PRECISION : DecimalControl.precision, mode); 5411 flags &= ExceptionFlags.invalidOperation; 5412 DecimalControl.raiseFlags(flags); 5413 return result; 5414 } 5415 5416 ///ditto 5417 D nearbyint(D)(auto const ref D x) 5418 if (isDecimal!D) 5419 { 5420 return nearbyint(x, __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 5421 } 5422 5423 /// 5424 unittest 5425 { 5426 assert(nearbyint(decimal32("1.2"), RoundingMode.tiesToEven) == 1); 5427 assert(nearbyint(decimal64("2.7"), RoundingMode.tiesToAway) == 3); 5428 assert(nearbyint(decimal128("-7.9"), RoundingMode.towardZero) == -7); 5429 assert(nearbyint(decimal128("6.66")) == 7); 5430 } 5431 5432 5433 /** 5434 Returns the previous _decimal value before x. 5435 Throws: 5436 $(MYREF InvalidOperationException) if x is signaling $(B NaN) 5437 Special_values: 5438 $(BOOKTABLE, 5439 $(TR $(TH x) $(TH nextDown(x))) 5440 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 5441 $(TR $(TD -∞) $(TD -∞)) 5442 $(TR $(TD -max) $(TD -∞)) 5443 $(TR $(TD ±0.0) $(TD -min_normal * epsilon)) 5444 $(TR $(TD +∞) $(TD D.max)) 5445 ) 5446 */ 5447 @IEEECompliant("nextDown", 19) 5448 D nextDown(D)(auto const ref D x) 5449 if (isDecimal!D) 5450 { 5451 Unqual!D result = x; 5452 auto flags = decimalNextDown(result) & ExceptionFlags.invalidOperation; 5453 DecimalControl.raiseFlags(flags); 5454 return result; 5455 } 5456 5457 /** 5458 Gives the next power of 10 after x. 5459 Throws: 5460 $(BOOKTABLE, 5461 $(TR $(TD $(MYREF InvalidOperationException)) 5462 $(TD x is signaling $(B NaN))) 5463 $(TR $(TD $(MYREF OverflowException)) 5464 $(TD result is too big to be represented)) 5465 ) 5466 Special_values: 5467 $(BOOKTABLE, 5468 $(TR $(TH x) $(TH nextPow10(x))) 5469 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 5470 $(TR $(TD ±∞) $(TD ±∞)) 5471 $(TR $(TD ±0.0) $(TD +1.0)) 5472 ) 5473 */ 5474 D nextPow10(D)(auto const ref D x) 5475 if (isDecimal!D) 5476 { 5477 ExceptionFlags flags; 5478 Unqual!D result; 5479 5480 if (isSignaling(x)) 5481 { 5482 result = D.nan; 5483 flags = ExceptionFlags.invalidOperation; 5484 } 5485 else if (isNaN(x) || isInfinity(x)) 5486 result = x; 5487 else if (isZero(x)) 5488 result = D.one; 5489 else 5490 { 5491 alias U = DataType!D; 5492 U c; 5493 int e; 5494 bool s = x.unpack(c, e); 5495 for (size_t i = 0; i < pow10!U.length; ++i) 5496 { 5497 if (c == pow10!U[i]) 5498 { 5499 ++e; 5500 break; 5501 } 5502 else if (c < pow10!U[i]) 5503 { 5504 c = pow10!U[i]; 5505 break; 5506 } 5507 } 5508 if (i == pow10!U.length) 5509 { 5510 c = pow10!U[$ - 1]; 5511 ++e; 5512 } 5513 5514 flags = result.adjustedPack(c, e, s, RoundingMode.towardZero, ExceptionFlags.none); 5515 } 5516 5517 DecimalControl.raiseFlags(flags); 5518 return result; 5519 } 5520 5521 /** 5522 Returns the next value after or before x, toward y. 5523 Throws: 5524 $(BOOKTABLE, 5525 $(TR $(TD $(MYREF InvalidOperationException)) 5526 $(TD either x or y is $(B signaling NaN))) 5527 $(TR $(TD $(MYREF OverflowException)) 5528 $(TD result is ±∞)) 5529 $(TR $(TD $(MYREF UnderflowException)) 5530 $(TD result is subnormal or ±0.0)) 5531 $(TR $(TD $(MYREF InexactException)) 5532 $(TD result is ±∞, subnormal or ±0.0)) 5533 ) 5534 Special_values: 5535 $(BOOKTABLE, 5536 $(TR $(TH x) $(TH y) $(TH nextAfter(x, y))) 5537 $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN)) ) 5538 $(TR $(TD any) $(TD $(B NaN)) $(TD $(B NaN)) ) 5539 $(TR $(TD x = y) $(TD) $(TD x) ) 5540 $(TR $(TD x < y) $(TD) $(TD $(MYREF nextUp)(x)) ) 5541 $(TR $(TD x > y) $(TD) $(TD $(MYREF nextDown)(x)) ) 5542 ) 5543 */ 5544 D1 nextAfter(D1, D2)(auto const ref D1 x, auto const ref D2 y) 5545 if (isDecimal!(D1, D2)) 5546 { 5547 if (isSignaling(x)) 5548 { 5549 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation); 5550 return copysign(D1.nan, x); 5551 } 5552 5553 if (isSignaling(y)) 5554 { 5555 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation); 5556 return copysign(D1.nan, y); 5557 } 5558 5559 if (isNaN(x)) 5560 return copysign(D1.nan, x); 5561 5562 if (isNaN(y)) 5563 return copysign(D1.nan, y); 5564 5565 Unqual!D result = x; 5566 ExceptionFlags flags; 5567 int c = decimalCmp(x, y); 5568 if (c != 0) 5569 flags = c < 0 ? decimalNextUp(result) : decimalNextDown(result); 5570 if (isInfinity(result)) 5571 flags |= ExceptionFlags.overflow | ExceptionFlags.inexact; 5572 else if (isZero(result) || isSubnormal(result)) 5573 flags |= ExceptionFlags.underflow | ExceptionFlags.inexact; 5574 DecimalControl.raiseFlags(flags); 5575 return result; 5576 } 5577 5578 ///ditto 5579 alias nextToward = nextAfter; 5580 5581 /** 5582 Returns the next representable _decimal value after x. 5583 Throws: 5584 $(MYREF InvalidOperationException) if x is signaling $(B NaN) 5585 Special_values: 5586 $(BOOKTABLE, 5587 $(TR $(TH x) $(TH nextUp(x))) 5588 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 5589 $(TR $(TD -∞) $(TD -D.max)) 5590 $(TR $(TD ±0.0) $(TD D.min_normal * epsilon)) 5591 $(TR $(TD D.max) $(TD +∞)) 5592 $(TR $(TD +∞) $(TD +∞)) 5593 ) 5594 */ 5595 @IEEECompliant("nextUp", 19) 5596 D nextUp(D)(auto const ref D x) 5597 if (isDecimal!D) 5598 { 5599 Unqual!D result = x; 5600 auto flags = decimalNextUp(result) & ExceptionFlags.invalidOperation; 5601 DecimalControl.raiseFlags(flags); 5602 return result; 5603 } 5604 5605 5606 5607 5608 /** 5609 Calculates a$(SUBSCRIPT 0) + a$(SUBSCRIPT 1)x + a$(SUBSCRIPT 2)x$(SUPERSCRIPT 2) + .. + a$(SUBSCRIPT n)x$(SUPERSCRIPT n) 5610 Throws: 5611 $(BOOKTABLE, 5612 $(TR $(TD $(MYREF InvalidOperationException)) 5613 $(TD x is signaling $(B NaN) or any a$(SUBSCRIPT i) is signaling $(B NaN))) 5614 $(TR $(TD $(MYREF InvalidOperationException)) 5615 $(TD x is ±∞ and any a$(SUBSCRIPT i) is ±0.0)) 5616 $(TR $(TD $(MYREF InvalidOperationException)) 5617 $(TD x is ±0.0 and any a$(SUBSCRIPT i) is ±∞)) 5618 $(TR $(TD $(MYREF OverflowException)) 5619 $(TD result is too big to be represented)) 5620 $(TR $(TD $(MYREF UnderflowException)) 5621 $(TD result is too small to be represented)) 5622 $(TR $(TD $(MYREF InexactException)) 5623 $(TD result is inexact)) 5624 ) 5625 */ 5626 auto poly(D1, D2)(auto const ref D1 x, const(D2)[] a) 5627 if (isDecimal!(D1, D2)) 5628 { 5629 ExceptionFlags flags; 5630 alias D = CommonDecimal!(D1, D2); 5631 D result; 5632 auto flags = decimalPoly(x, a, result, 5633 __ctfe ? D.PRECISION : DecimalControl.precision, 5634 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 5635 DecimalControl.raiseFlags(flags); 5636 return result; 5637 } 5638 5639 /** 5640 Compute the value of x$(SUPERSCRIPT n), where n is integral 5641 Throws: 5642 $(BOOKTABLE, 5643 $(TR $(TD $(MYREF InvalidOperationException)) 5644 $(TD x is signaling $(B NaN))) 5645 $(TR $(TD $(MYREF DivisionByZeroException)) 5646 $(TD x = ±0.0 and n < 0)) 5647 $(TR $(TD $(MYREF OverflowException)) 5648 $(TD result is too big to be represented)) 5649 $(TR $(TD $(MYREF UnderflowException)) 5650 $(TD result is too small to be represented)) 5651 $(TR $(TD $(MYREF InexactException)) 5652 $(TD result is inexact)) 5653 ) 5654 Special_values: 5655 $(BOOKTABLE, 5656 $(TR $(TH x) $(TH n) $(TH pow(x, n)) ) 5657 $(TR $(TD sNaN) $(TD any) $(TD $(B NaN)) ) 5658 $(TR $(TD any) $(TD 0) $(TD +1.0) ) 5659 $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN))) 5660 $(TR $(TD ±∞) $(TD any) $(TD ±∞) ) 5661 $(TR $(TD ±0.0) $(TD odd n < 0) $(TD ±∞)) 5662 $(TR $(TD ±0.0) $(TD even n < 0) $(TD +∞) ) 5663 $(TR $(TD ±0.0) $(TD odd n > 0) $(TD ±0.0) ) 5664 $(TR $(TD ±0.0) $(TD even n > 0) $(TD +0.0) ) 5665 ) 5666 */ 5667 @IEEECompliant("pown", 42) 5668 D pow(D, T)(auto const ref D x, const T n) 5669 if (isDecimal!D && isIntegral!T) 5670 { 5671 ExceptionFlags flags; 5672 Unqual!D result = x; 5673 auto flags = decimalPow(result, n, 5674 __ctfe ? D.PRECISION : DecimalControl.precision, 5675 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 5676 DecimalControl.raiseFlags(flags); 5677 return result; 5678 } 5679 5680 /** 5681 Compute the value of x$(SUPERSCRIPT y) 5682 Throws: 5683 $(BOOKTABLE, 5684 $(TR $(TD $(MYREF InvalidOperationException)) 5685 $(TD x is signaling $(B NaN))) 5686 $(TR $(TD $(MYREF DivisionByZeroException)) 5687 $(TD x = ±0.0 and y < 0.0)) 5688 $(TR $(TD $(MYREF OverflowException)) 5689 $(TD result is too big to be represented)) 5690 $(TR $(TD $(MYREF UnderflowException)) 5691 $(TD result is too small to be represented)) 5692 $(TR $(TD $(MYREF InexactException)) 5693 $(TD result is inexact)) 5694 ) 5695 Special_values: 5696 $(BOOKTABLE, 5697 $(TR $(TH x) $(TH y) $(TH pow(x, y)) ) 5698 $(TR $(TD sNaN) $(TD any) $(TD $(B NaN)) ) 5699 $(TR $(TD any) $(TD 0) $(TD +1.0) ) 5700 $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN))) 5701 $(TR $(TD ±∞) $(TD any) $(TD ±∞) ) 5702 $(TR $(TD ±0.0) $(TD odd n < 0) $(TD ±∞)) 5703 $(TR $(TD ±0.0) $(TD even n < 0) $(TD +∞) ) 5704 $(TR $(TD ±0.0) $(TD odd n > 0) $(TD ±0.0) ) 5705 $(TR $(TD ±0.0) $(TD even n > 0) $(TD +0.0) ) 5706 ) 5707 */ 5708 @IEEECompliant("pow", 42) 5709 @IEEECompliant("powr", 42) 5710 auto pow(D1, D2)(auto const ref D1 x, auto const ref D2 x) 5711 { 5712 ExceptionFlags flags; 5713 Unqual!D1 result = x; 5714 auto flags = decimalPow(result, y, 5715 __ctfe ? D.PRECISION : DecimalControl.precision, 5716 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 5717 DecimalControl.raiseFlags(flags); 5718 return result; 5719 } 5720 5721 5722 5723 5724 /** 5725 Express a value using another value exponent 5726 Params: 5727 x = source value 5728 y = value used as exponent source 5729 Returns: 5730 a value with the same numerical value as x but with the exponent of y 5731 Throws: 5732 $(BOOKTABLE, 5733 $(TR $(TD $(MYREF InvalidOperationException)) 5734 $(TD x is signaling $(B NaN))) 5735 $(TR $(TD $(MYREF InvalidOperationException)) 5736 $(TD only one of x or y is ±∞)) 5737 $(TR $(TD $(MYREF InexactException)) 5738 $(TD result is inexact)) 5739 ) 5740 Special_values: 5741 $(BOOKTABLE, 5742 $(TR $(TH x) $(TH y) $(TH quantize(x, y))) 5743 $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN))) 5744 $(TR $(TD any) $(TD $(B NaN)) $(TD $(B NaN))) 5745 $(TR $(TD ±∞) $(TD ±∞) $(TD ±∞)) 5746 $(TR $(TD ±∞) $(TD any) $(TD $(B NaN))) 5747 $(TR $(TD any) $(TD ±∞) $(TD $(B NaN))) 5748 ) 5749 */ 5750 @IEEECompliant("quantize", 18) 5751 D1 quantize(D1, D2)(auto const ref D1 x, auto const ref D2 y) 5752 if (isDecimal!(D1, D2)) 5753 { 5754 D1 result = x; 5755 auto flags = decimalQuantize(result, y, 5756 __ctfe ? D1.PRECISION : DecimalControl.precision, 5757 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 5758 flags &= ExceptionFlags.invalidOperation | ExceptionFlags.inexact; 5759 DecimalControl.raiseFlags(flags); 5760 return result; 5761 } 5762 5763 /** 5764 Returns the exponent encoded into the specified _decimal value; 5765 Throws: 5766 $(BOOKTABLE, 5767 $(TR $(TD $(MYREF InvalidOperationException)) 5768 $(TD x is $(B NaN) or ±∞)) 5769 ) 5770 Special_values: 5771 $(BOOKTABLE, 5772 $(TR $(TH x) $(TH quantexp(x))) 5773 $(TR $(TD $(B NaN)) $(TD int.min) ) 5774 $(TR $(TD ±∞) $(TD int.min) ) 5775 ) 5776 Notes: 5777 Unlike $(MYREF frexp) where the exponent is calculated for a |coefficient| < 1.0, this 5778 functions returns the raw encoded exponent. 5779 */ 5780 int quantexp(D)(auto const ref D x) 5781 if (isDecimal!D) 5782 { 5783 DataType!D cx; int ex; bool sx; 5784 switch (fastDecode(x, cx, ex, sx)) 5785 { 5786 case FastClass.finite: 5787 case FastClass.zero: 5788 return ex; 5789 default: 5790 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation); 5791 return int.min; 5792 } 5793 } 5794 5795 /// 5796 unittest 5797 { 5798 auto d = decimal32("0x0001p+12"); //1 * 10^^12 5799 auto z = decimal64("0x0000p-3"); //0 * 10^^-3 5800 5801 int calculatedExponent, rawExponent; 5802 5803 //d is 0.1 * 10^^13 5804 frexp(d, calculatedExponent); 5805 rawExponent = quantexp(d); 5806 assert (calculatedExponent == 13 && rawExponent == 12); 5807 5808 //z is 0.0 5809 frexp(z, calculatedExponent); 5810 rawExponent = quantexp(z); 5811 assert (calculatedExponent == 0 && rawExponent == -3); 5812 } 5813 5814 /** 5815 Calculates the _remainder of the division x / y 5816 Params: 5817 x = dividend 5818 y = divisor 5819 Returns: 5820 The value of x - n * y, where n is the quotient rounded to nearest even of the division x / y 5821 Throws: 5822 $(BOOKTABLE, 5823 $(TR $(TD $(MYREF InvalidOperationException)) 5824 $(TD x or y is signaling $(B NaN), x = ±∞, y = ±0.0)) 5825 $(TR $(TD $(MYREF UnderflowException)) 5826 $(TD result is too small to be represented)) 5827 $(TR $(TD $(MYREF DivisionByZeroException)) 5828 $(TD y = 0.0)) 5829 $(TR $(TD $(MYREF InexactException)) 5830 $(TD the result is inexact)) 5831 ) 5832 Special_values: 5833 $(BOOKTABLE, 5834 $(TR $(TH x) $(TH y) $(TH remainder(x, y))) 5835 $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN))) 5836 $(TR $(TD any) $(TD $(B NaN)) $(TD $(B NaN))) 5837 $(TR $(TD ±∞) $(TD any) $(TD $(B NaN))) 5838 $(TR $(TD any) $(TD 0.0) $(TD $(B NaN))) 5839 $(TR $(TD any) $(TD ±∞) $(TD $(B NaN))) 5840 ) 5841 */ 5842 @IEEECompliant("remainder", 25) 5843 auto remainder(D1, D2)(auto const ref D1 x, auto const ref D2 y) 5844 { 5845 CommonDecimal!(D1, D2) result = x; 5846 auto flags = decimalMod(result, y, 5847 __ctfe ? D1.PRECISION : DecimalControl.precision, 5848 RoundingMode.tiesToEven); 5849 DecimalControl.raiseFlags(flags); 5850 return result; 5851 } 5852 5853 5854 5855 /** 5856 Returns the value of x rounded using the specified rounding _mode. 5857 If no rounding _mode is specified the default context rounding _mode is used instead. 5858 This function is similar to $(MYREF nearbyint), but if the rounded value is not exact it will throw 5859 $(MYREF InexactException) 5860 Throws: 5861 $(BOOKTABLE, 5862 $(TR $(TD $(MYREF InvalidOperationException)) 5863 $(TD x is signaling $(B NaN))) 5864 $(TR $(TD $(MYREF InexactException)) 5865 $(TD the result is inexact)) 5866 ) 5867 Special_values: 5868 $(BOOKTABLE, 5869 $(TR $(TH x) $(TH rint(x))) 5870 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 5871 $(TR $(TD ±∞) $(TD ±∞)) 5872 $(TR $(TD ±0.0) $(TD ±0.0)) 5873 ) 5874 */ 5875 @IEEECompliant("roundToIntegralExact", 25) 5876 D rint(D)(auto const ref D x, const RoundingMode mode) 5877 if (isDecimal!D) 5878 { 5879 Unqual!D result = x; 5880 auto flags = decimalRound(result, __ctfe ? D.PRECISION : DecimalControl.precision, mode); 5881 flags &= ExceptionFlags.invalidOperation | ExceptionFlags.inexact; 5882 DecimalControl.raiseFlags(flags); 5883 return result; 5884 } 5885 5886 ///ditto 5887 @IEEECompliant("roundToIntegralExact", 25) 5888 D rint(D)(auto const ref D x) 5889 if (isDecimal!D) 5890 { 5891 return rint(x, __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 5892 } 5893 5894 /// 5895 unittest 5896 { 5897 DecimalControl.resetFlags(ExceptionFlags.inexact); 5898 assert(rint(decimal32("9.9")) == 10); 5899 assert(DecimalControl.inexact); 5900 5901 DecimalControl.resetFlags(ExceptionFlags.inexact); 5902 assert(rint(decimal32("9.0")) == 9); 5903 assert(!DecimalControl.inexact); 5904 } 5905 5906 /** 5907 Returns the value of x rounded using the specified rounding _mode. 5908 If no rounding _mode is specified the default context rounding _mode is used instead. 5909 If the value doesn't fit in a long data type $(MYREF OverflowException) is thrown. 5910 Throws: 5911 $(BOOKTABLE, 5912 $(TR $(TD $(MYREF InvalidOperationException)) 5913 $(TD x is $(B NaN))) 5914 $(TR $(TD $(MYREF OverflowException)) 5915 $(TD result does not fit in a long data type)) 5916 $(TR $(TD $(MYREF InexactException)) 5917 $(TD the result is inexact)) 5918 ) 5919 Special_values: 5920 $(BOOKTABLE, 5921 $(TR $(TH x) $(TH rndtonl(x))) 5922 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 5923 $(TR $(TD ±∞) $(TD ±∞)) 5924 $(TR $(TD ±0.0) $(TD ±0.0)) 5925 ) 5926 */ 5927 D rndtonl(D)(auto const ref D x, const RoundingMode mode) 5928 if (isDecimal!D) 5929 { 5930 Unqual!D result = x; 5931 ExceptionFlags flags; 5932 long l; 5933 if (isNaN(x)) 5934 { 5935 flags = ExceptionFlags.invalidOperation; 5936 result = signbit(x) ? -D.nan : D.nan; 5937 } 5938 else if (isInfinity(x)) 5939 flags = ExceptionFlags.overflow; 5940 else 5941 { 5942 flags = decimalToSigned(x, l, mode); 5943 result.packIntegral(l, 0, mode); 5944 } 5945 DecimalControl.raiseFlags(flags); 5946 return result; 5947 } 5948 5949 ///ditto 5950 @safe 5951 D rndtonl(D)(auto const ref D x) 5952 if (isDecimal!D) 5953 { 5954 return rndtonl(x, __ctfe ? RoundingMode.tiesToAway : DecimalControl.rounding); 5955 } 5956 5957 /** 5958 Compute the value of x$(SUPERSCRIPT 1/n), where n is an integer 5959 Throws: 5960 $(BOOKTABLE, 5961 $(TR $(TD $(MYREF InvalidOperationException)) 5962 $(TD x is signaling $(B NaN))) 5963 $(TR $(TD $(MYREF DivisionByZeroException)) 5964 $(TD x = ±0.0 and n < 0.0)) 5965 $(TR $(TD $(MYREF OverflowException)) 5966 $(TD result is too big to be represented or n = -1)) 5967 $(TR $(TD $(MYREF UnderflowException)) 5968 $(TD result is too small to be represented or n = -1)) 5969 $(TR $(TD $(MYREF InexactException)) 5970 $(TD result is inexact)) 5971 ) 5972 Special_values: 5973 $(BOOKTABLE, 5974 $(TR $(TH x) $(TH y) $(TH root(x, n)) ) 5975 $(TR $(TD sNaN) $(TD any) $(TD $(B NaN)) ) 5976 $(TR $(TD any) $(TD 0) $(TD $(B NaN)) ) 5977 $(TR $(TD any) $(TD -1) $(TD $(B NaN)) ) 5978 $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN))) 5979 $(TR $(TD ±∞) $(TD any) $(TD ±∞) ) 5980 $(TR $(TD ±0.0) $(TD odd n < 0) $(TD ±∞)) 5981 $(TR $(TD ±0.0) $(TD even n < 0) $(TD +∞) ) 5982 $(TR $(TD ±0.0) $(TD odd n > 0) $(TD ±0.0) ) 5983 $(TR $(TD ±0.0) $(TD even n > 0) $(TD +0.0) ) 5984 ) 5985 */ 5986 @IEEECompliant("rootn", 42) 5987 D root(D)(auto const ref D x, const T n) 5988 if (isDecimal!D & isIntegral!T) 5989 { 5990 ExceptionFlags flags; 5991 Unqual!D1 result = x; 5992 auto flags = decimalRoot(result, n, 5993 __ctfe ? D.PRECISION : DecimalControl.precision, 5994 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 5995 DecimalControl.raiseFlags(flags); 5996 return result; 5997 } 5998 5999 /** 6000 Returns the value of x rounded away from zero. 6001 This operation is silent, doesn't throw any exception. 6002 Special_values: 6003 $(BOOKTABLE, 6004 $(TR $(TH x) $(TH round(x))) 6005 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 6006 $(TR $(TD ±0.0) $(TD ±0.0)) 6007 $(TR $(TD ±∞) $(TD ±∞)) 6008 ) 6009 */ 6010 D round(D)(auto const ref D x) 6011 if (isDecimal!D) 6012 { 6013 Unqual!D result = x; 6014 decimalRound(result, 0, RoundingMode.tiesToAway); 6015 return result; 6016 } 6017 6018 /** 6019 Computes the inverse square root of x 6020 Throws: 6021 $(MYREF InvalidOperationException) if x is signaling $(B NaN) or negative, 6022 $(MYREF InexactException), $(MYREF UnderflowException), 6023 $(MYREF DivisionByZeroException) 6024 Special_values: 6025 $(BOOKTABLE, 6026 $(TR $(TH x) $(TH rsqrt(x))) 6027 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 6028 $(TR $(TD < 0.0) $(TD $(B NaN))) 6029 $(TR $(TD ±0.0) $(TD $(B NaN))) 6030 $(TR $(TD +∞) $(TD +∞)) 6031 ) 6032 */ 6033 @IEEECompliant("rSqrt", 42) 6034 D rsqrt(D)(auto const ref D x) 6035 if (isDecimal!D) 6036 { 6037 ExceptionFlags flags; 6038 6039 Unqual!D result = x; 6040 6041 flags = decimalRSqrt(result, 6042 __ctfe ? D.PRECISION : DecimalControl.precision, 6043 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 6044 DecimalControl.raiseFlags(flags); 6045 return result; 6046 } 6047 6048 /** 6049 Compares the exponents of two _decimal values 6050 Params: 6051 x = a _decimal value 6052 y = a _decimal value 6053 Returns: 6054 true if the internal representation of x and y use the same exponent, false otherwise 6055 Notes: 6056 Returns also true if both operands are $(B NaN) or both operands are infinite. 6057 */ 6058 @IEEECompliant("sameQuantum", 26) 6059 bool sameQuantum(D1, D2)(auto const ref D1 x, auto const ref D2 y) 6060 if (isDecimal!(D1, D2)) 6061 { 6062 if ((x.data & D1.MASK_INF) == D1.MASK_INF) 6063 { 6064 if ((x.data & D1.MASK_QNAN) == D1.MASK_QNAN) 6065 return (y.data & D2.MASK_QNAN) == D2.MASK_QNAN; 6066 return (y.data & D2.MASK_SNAN) == D2.MASK_INF; 6067 } 6068 6069 if ((y.data & D2.MASK_INF) == D2.MASK_INF) 6070 return false; 6071 6072 auto expx = (x.data & D1.MASK_EXT) == D1.MASK_EXT ? 6073 (x.data & D1.MASK_EXP2) >>> D1.SHIFT_EXP2 : 6074 (x.data & D1.MASK_EXP1) >>> D1.SHIFT_EXP1; 6075 auto expy = (x.data & D2.MASK_EXT) == D2.MASK_EXT ? 6076 (y.data & D2.MASK_EXP2) >>> D2.SHIFT_EXP2 : 6077 (y.data & D2.MASK_EXP1) >>> D2.SHIFT_EXP1; 6078 6079 int ex = cast(int)cast(uint)expx; 6080 int ey = cast(int)cast(uint)expy; 6081 return ex - D1.EXP_BIAS == ey - D2.EXP_BIAS; 6082 } 6083 6084 /// 6085 unittest 6086 { 6087 assert(sameQuantum(decimal32.infinity, -decimal64.infinity)); 6088 6089 auto x = decimal32("123456e+23"); 6090 auto y = decimal64("911911e+23"); 6091 assert(sameQuantum(x, y)); 6092 6093 } 6094 6095 /** 6096 Returns: 6097 x efficiently multiplied by 10$(SUPERSCRIPT n) 6098 Throws: 6099 $(MYREF InvalidOperationException) if x is signaling $(B NaN), $(MYREF OverflowException), 6100 $(MYREF UnderflowException), $(MYREF InexactException) 6101 Special_values: 6102 $(BOOKTABLE, 6103 $(TR $(TH x) $(TH n) $(TH scalbn(x, n))) 6104 $(TR $(TD $(B NaN)) $(TD any) $(TD $(B NaN))) 6105 $(TR $(TD ±∞) $(TD any) $(TD ±∞)) 6106 $(TR $(TD ±0) $(TD any) $(TD ±0)) 6107 $(TR $(TD any) $(TD 0) $(TD x)) 6108 ) 6109 */ 6110 @IEEECompliant("scaleB", 17) 6111 D scalbn(D)(auto const ref D x, const int n) 6112 if (isDecimal!D) 6113 { 6114 Unqual!D result = x; 6115 auto flags = decimalScale(result, n, 6116 __ctfe ? D.PRECISION : DecimalControl.precision, 6117 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 6118 DecimalControl.raiseFlags(flags); 6119 return result; 6120 } 6121 6122 /** 6123 Multiplies elements of x using a higher precision, rounding only once at the end. 6124 Returns: 6125 x$(SUBSCRIPT 0) * x$(SUBSCRIPT 1) * ... * x$(SUBSCRIPT n) 6126 Notes: 6127 To avoid overflow, an additional scale is provided that the final result is to be multiplied py 10$(SUPERSCRIPT scale) 6128 Throws: 6129 $(BOOKTABLE, 6130 $(TR $(TD $(MYREF InvalidOperationException)) 6131 $(TD any x is signaling $(B NaN))) 6132 $(TR $(TD $(MYREF InvalidOperationException)) 6133 $(TD there is one infinite element and one 0.0 element)) 6134 $(TR $(TD $(MYREF OverflowException)) 6135 $(TD result is too big to be represented)) 6136 $(TR $(TD $(MYREF UnderflowException)) 6137 $(TD result is too small to be represented)) 6138 $(TR $(TD $(MYREF InexactException)) 6139 $(TD result is inexact)) 6140 ) 6141 */ 6142 @IEEECompliant("scaledProd", 47) 6143 D scaledProd(D)(const(D)[] x, out int scale) 6144 if (isDecimal!D) 6145 { 6146 Unqual!D result; 6147 flags = decimalProd(x, result, scale, 6148 __ctfe ? D.PRECISION : DecimalControl.precision, 6149 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 6150 DecimalControl.raiseFlags(flags); 6151 return result; 6152 } 6153 6154 /** 6155 Multiplies results of x$(SUBSCRIPT i) + y$(SUBSCRIPT i) using a higher precision, rounding only once at the end. 6156 Returns: 6157 (x$(SUBSCRIPT 0) + y$(SUBSCRIPT 0)) * (x$(SUBSCRIPT 1) + y$(SUBSCRIPT 1)) * ... * (x$(SUBSCRIPT n) + y$(SUBSCRIPT n)) 6158 Notes: 6159 To avoid overflow, an additional scale is provided that the final result is to be multiplied py 10$(SUPERSCRIPT scale).<br/> 6160 If x and y arrays are not of the same length, operation is performed for min(x.length, y.length); 6161 Throws: 6162 $(BOOKTABLE, 6163 $(TR $(TD $(MYREF InvalidOperationException)) 6164 $(TD any x is signaling $(B NaN))) 6165 $(TR $(TD $(MYREF InvalidOperationException)) 6166 $(TD any x[i] and y[i] are infinite and with different sign)) 6167 $(TR $(TD $(MYREF InvalidOperationException)) 6168 $(TD there is one infinite element and one x$(SUBSCRIPT i) + y$(SUBSCRIPT i) == 0.0)) 6169 $(TR $(TD $(MYREF OverflowException)) 6170 $(TD result is too big to be represented)) 6171 $(TR $(TD $(MYREF UnderflowException)) 6172 $(TD result is too small to be represented)) 6173 $(TR $(TD $(MYREF InexactException)) 6174 $(TD result is inexact)) 6175 ) 6176 */ 6177 @IEEECompliant("scaledProdSum", 47) 6178 D scaledProdSum(D)(const(D)[] x, const(D)[] y, out int scale) 6179 if (isDecimal!D) 6180 { 6181 Unqual!D result; 6182 flags = decimalProdSum(x, y, result, scale, 6183 __ctfe ? D.PRECISION : DecimalControl.precision, 6184 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 6185 DecimalControl.raiseFlags(flags); 6186 return result; 6187 } 6188 6189 /** 6190 Multiplies results of x$(SUBSCRIPT i) - y$(SUBSCRIPT i) using a higher precision, rounding only once at the end. 6191 Returns: 6192 (x$(SUBSCRIPT 0) - y$(SUBSCRIPT 0)) * (x$(SUBSCRIPT 1) - y$(SUBSCRIPT 1)) * ... * (x$(SUBSCRIPT n) - y$(SUBSCRIPT n)) 6193 Notes: 6194 To avoid overflow, an additional scale is provided that the final result is to be multiplied py 10$(SUPERSCRIPT scale)</br> 6195 If x and y arrays are not of the same length, operation is performed for min(x.length, y.length); 6196 Throws: 6197 $(BOOKTABLE, 6198 $(TR $(TD $(MYREF InvalidOperationException)) 6199 $(TD any x is signaling $(B NaN))) 6200 $(TR $(TD $(MYREF InvalidOperationException)) 6201 $(TD any x$(SUBSCRIPT i) and y$(SUBSCRIPT i) are infinite and with different sign)) 6202 $(TR $(TD $(MYREF InvalidOperationException)) 6203 $(TD there is one infinite element and one x$(SUBSCRIPT i) - y$(SUBSCRIPT i) == 0.0)) 6204 $(TR $(TD $(MYREF OverflowException)) 6205 $(TD result is too big to be represented)) 6206 $(TR $(TD $(MYREF UnderflowException)) 6207 $(TD result is too small to be represented)) 6208 $(TR $(TD $(MYREF InexactException)) 6209 $(TD result is inexact)) 6210 ) 6211 */ 6212 @IEEECompliant("scaledProdDiff", 47) 6213 D scaledProdDiff(D)(const(D)[] x, const(D)[] y, out int scale) 6214 if (isDecimal!D) 6215 { 6216 Unqual!D result; 6217 flags = decimalProdDiff(x, y, result, scale, 6218 __ctfe ? D.PRECISION : DecimalControl.precision, 6219 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 6220 DecimalControl.raiseFlags(flags); 6221 return result; 6222 } 6223 6224 /** 6225 Determines if x is negative 6226 This operation is silent, no error flags are set and no exceptions are thrown. 6227 Params: 6228 x = a _decimal value 6229 Returns: 6230 -1.0 if x is negative, 0.0 if x is zero, 1.0 if x is positive 6231 */ 6232 @safe pure nothrow @nogc 6233 D sgn(D: Decimal!bits, int bits)(auto const ref D x) 6234 { 6235 if (isZero(x)) 6236 return D.zero; 6237 return (x.data & D.MASK_SGN) ? D.minusOne : D.one; 6238 } 6239 6240 6241 6242 /// 6243 unittest 6244 { 6245 assert(sgn(decimal32.max) == 1); 6246 assert(sgn(-decimal32.max) == -1); 6247 assert(sgn(decimal64(0)) == 0); 6248 } 6249 6250 unittest 6251 { 6252 6253 foreach(T; TypeTuple!(decimal32, decimal64, decimal128)) 6254 { 6255 assert(sgn(T.nan) == 1); 6256 assert(sgn(T.infinity) == 1); 6257 assert(sgn(T.minusInfinity) == -1); 6258 } 6259 } 6260 6261 /** 6262 Returns the sign bit of the specified value. 6263 This operation is silent, no error flags are set and no exceptions are thrown. 6264 Params: 6265 x = a _decimal value 6266 Returns: 6267 1 if the sign bit is set, 0 otherwise 6268 */ 6269 @IEEECompliant("isSignMinus", 25) 6270 int signbit(D: Decimal!bits, int bits)(auto const ref D x) 6271 { 6272 static if (is(D: decimal32) || is(D: decimal64)) 6273 { 6274 return cast(uint)((x.data & D.MASK_SGN) >>> ((D.sizeof * 8) - 1)); 6275 } 6276 else 6277 { 6278 return cast(uint)((x.data.hi & D.MASK_SGN.hi) >>> ((D.sizeof * 4) - 1)); 6279 } 6280 } 6281 6282 /// 6283 unittest 6284 { 6285 assert(signbit(-decimal32.infinity) == 1); 6286 assert(signbit(decimal64.min_normal) == 0); 6287 assert(signbit(-decimal128.max) == 1); 6288 } 6289 6290 unittest 6291 { 6292 foreach(T; TypeTuple!(decimal32, decimal64, decimal128)) 6293 { 6294 assert(signbit(T.snan) == 0); 6295 assert(signbit(T.minusInfinity) == 1); 6296 assert(signbit(T.zero) == 0); 6297 assert(signbit(T.minusZero) == 1); 6298 } 6299 } 6300 6301 /** 6302 Returns sine of x. 6303 Throws: 6304 $(BOOKTABLE, 6305 $(TR $(TD $(MYREF InvalidOperationException)) 6306 $(TD x is signaling $(B NaN) or ±∞)) 6307 $(TR $(TD $(MYREF UnderflowException)) 6308 $(TD result is too small to be represented)) 6309 $(TR $(TD $(MYREF InexactException)) 6310 $(TD the result is inexact)) 6311 ) 6312 Special_values: 6313 $(BOOKTABLE, 6314 $(TR $(TH x) $(TH sin(x))) 6315 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 6316 $(TR $(TD ±∞) $(TD $(B NaN))) 6317 $(TR $(TD -π/2) $(TD -1.0)) 6318 $(TR $(TD -π/3) $(TD -√3/2)) 6319 $(TR $(TD -π/4) $(TD -√2/2)) 6320 $(TR $(TD -π/6) $(TD -0.5)) 6321 $(TR $(TD ±0.0) $(TD +0.0)) 6322 $(TR $(TD +π/6) $(TD +0.5)) 6323 $(TR $(TD +π/4) $(TD +√2/2)) 6324 $(TR $(TD +π/3) $(TD +√3/2)) 6325 $(TR $(TD +π/2) $(TD +1.0)) 6326 ) 6327 */ 6328 @IEEECompliant("sin", 42) 6329 D sin(D)(auto const ref D x) 6330 if (isDecimal!D) 6331 { 6332 Unqual!D result = x; 6333 auto flags = decimalSin(result, 6334 __ctfe ? D.PRECISION : DecimalControl.precision, 6335 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 6336 6337 DecimalControl.raiseFlags(flags); 6338 return result; 6339 } 6340 6341 /** 6342 Calculates the hyperbolic sine of x. 6343 Throws: 6344 $(BOOKTABLE, 6345 $(TR $(TD $(MYREF InvalidOperationException)) 6346 $(TD x is signaling $(B NaN))) 6347 $(TR $(TD $(MYREF OverflowException)) 6348 $(TD result is too big to be represented)) 6349 $(TR $(TD $(MYREF InexactException)) 6350 $(TD the result is inexact)) 6351 ) 6352 Special_values: 6353 $(BOOKTABLE, 6354 $(TR $(TH x) $(TH sinh(x))) 6355 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 6356 $(TR $(TD ±∞) $(TD +∞)) 6357 $(TR $(TD ±0.0) $(TD +0.0)) 6358 ) 6359 */ 6360 @IEEECompliant("sinh", 42) 6361 D sinh(D)(auto const ref D x) 6362 if (isDecimal!D) 6363 { 6364 Unqual!D result = x; 6365 auto flags = decimalSinh(result, 6366 __ctfe ? D.PRECISION : DecimalControl.precision, 6367 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 6368 6369 DecimalControl.raiseFlags(flags); 6370 return result; 6371 } 6372 6373 /** 6374 Returns sine of x*π. 6375 Throws: 6376 $(BOOKTABLE, 6377 $(TR $(TD $(MYREF InvalidOperationException)) 6378 $(TD x is signaling $(B NaN) or ±∞)) 6379 $(TR $(TD $(MYREF UnderflowException)) 6380 $(TD result is too small to be represented)) 6381 $(TR $(TD $(MYREF InexactException)) 6382 $(TD the result is inexact)) 6383 ) 6384 Special_values: 6385 $(BOOKTABLE, 6386 $(TR $(TH x) $(TH sin(x))) 6387 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 6388 $(TR $(TD ±∞) $(TD $(B NaN))) 6389 $(TR $(TD -1/2) $(TD -1.0)) 6390 $(TR $(TD -1/3) $(TD -√3/2)) 6391 $(TR $(TD -1/4) $(TD -√2/2)) 6392 $(TR $(TD -1/6) $(TD -0.5)) 6393 $(TR $(TD ±0.0) $(TD +0.0)) 6394 $(TR $(TD +1/6) $(TD +0.5)) 6395 $(TR $(TD +1/4) $(TD +√2/2)) 6396 $(TR $(TD +1/3) $(TD +√3/2)) 6397 $(TR $(TD +1/2) $(TD +1.0)) 6398 ) 6399 */ 6400 @IEEECompliant("sinPi", 42) 6401 D sinPi(D)(auto const ref D x) 6402 if (isDecimal!D) 6403 { 6404 Unqual!D result = x; 6405 auto flags = decimalSinPi(result, 6406 __ctfe ? D.PRECISION : DecimalControl.precision, 6407 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 6408 6409 DecimalControl.raiseFlags(flags); 6410 return result; 6411 } 6412 6413 6414 /** 6415 Computes the square root of x 6416 Throws: 6417 $(MYREF InvalidOperationException) if x is signaling $(B NaN) or negative, 6418 $(MYREF InexactException), $(MYREF UnderflowException) 6419 Special_values: 6420 $(BOOKTABLE, 6421 $(TR $(TH x) $(TH sqrt(x))) 6422 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 6423 $(TR $(TD < 0.0) $(TD $(B NaN))) 6424 $(TR $(TD ±0.0) $(TD ±0.0)) 6425 $(TR $(TD +∞) $(TD +∞)) 6426 ) 6427 */ 6428 @IEEECompliant("squareRoot", 42) 6429 D sqrt(D)(auto const ref D x) 6430 if (isDecimal!D) 6431 { 6432 6433 Unqual!D result = x; 6434 auto flags = decimalSqrt(result, 6435 __ctfe ? D.PRECISION : DecimalControl.precision, 6436 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 6437 6438 DecimalControl.raiseFlags(flags); 6439 return result; 6440 } 6441 6442 /** 6443 Sums elements of x using a higher precision, rounding only once at the end.</br> 6444 Returns: 6445 x$(SUBSCRIPT 0) + x$(SUBSCRIPT 1) + ... + x$(SUBSCRIPT n) 6446 Throws: 6447 $(BOOKTABLE, 6448 $(TR $(TD $(MYREF InvalidOperationException)) 6449 $(TD any x is signaling $(B NaN))) 6450 $(TR $(TD $(MYREF InvalidOperationException)) 6451 $(TD there are two infinite elements with different sign)) 6452 $(TR $(TD $(MYREF OverflowException)) 6453 $(TD result is too big to be represented)) 6454 $(TR $(TD $(MYREF UnderflowException)) 6455 $(TD result is too small to be represented)) 6456 $(TR $(TD $(MYREF InexactException)) 6457 $(TD result is inexact)) 6458 ) 6459 */ 6460 @IEEECompliant("sum", 47) 6461 D sum(D)(const(D)[] x) 6462 if (isDecimal!D) 6463 { 6464 Unqual!D result; 6465 auto flags = decimalSum(x, result, 6466 __ctfe ? D.PRECISION : DecimalControl.precision, 6467 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 6468 6469 DecimalControl.raiseFlags(flags); 6470 return result; 6471 } 6472 6473 /** 6474 Sums absolute elements of x using a higher precision, rounding only once at the end. 6475 Returns: 6476 |x$(SUBSCRIPT 0)| + |x$(SUBSCRIPT 1)| + ... + |x$(SUBSCRIPT n)| 6477 Throws: 6478 $(BOOKTABLE, 6479 $(TR $(TD $(MYREF InvalidOperationException)) 6480 $(TD any x is signaling $(B NaN))) 6481 $(TR $(TD $(MYREF OverflowException)) 6482 $(TD result is too big to be represented)) 6483 $(TR $(TD $(MYREF UnderflowException)) 6484 $(TD result is too small to be represented)) 6485 $(TR $(TD $(MYREF InexactException)) 6486 $(TD result is inexact)) 6487 ) 6488 */ 6489 @IEEECompliant("sumAbs", 47) 6490 D sumAbs(D)(const(D)[] x) 6491 if (isDecimal!D) 6492 { 6493 Unqual!D result; 6494 auto flags = decimalSumAbs(x, result, 6495 __ctfe ? D.PRECISION : DecimalControl.precision, 6496 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 6497 6498 DecimalControl.raiseFlags(flags); 6499 return result; 6500 } 6501 6502 /** 6503 Sums squares of elements of x using a higher precision, rounding only once at the end. 6504 Returns: 6505 x$(SUBSCRIPT 0)$(SUPERSCRIPT 2) + x$(SUBSCRIPT 1)$(SUPERSCRIPT 2) + ... + x$(SUBSCRIPT n)$(SUPERSCRIPT 2) 6506 Throws: 6507 $(BOOKTABLE, 6508 $(TR $(TD $(MYREF InvalidOperationException)) 6509 $(TD any x is signaling $(B NaN))) 6510 $(TR $(TD $(MYREF OverflowException)) 6511 $(TD result is too big to be represented)) 6512 $(TR $(TD $(MYREF UnderflowException)) 6513 $(TD result is too small to be represented)) 6514 $(TR $(TD $(MYREF InexactException)) 6515 $(TD result is inexact)) 6516 ) 6517 */ 6518 @IEEECompliant("sumSquare", 47) 6519 D sumSquare(D)(const(D)[] x) 6520 if (isDecimal!D) 6521 { 6522 Unqual!D result; 6523 auto flags = decimalSumSquare(x, result, 6524 __ctfe ? D.PRECISION : DecimalControl.precision, 6525 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 6526 6527 DecimalControl.raiseFlags(flags); 6528 return result; 6529 } 6530 6531 /** 6532 Returns tangent of x. 6533 Throws: 6534 $(BOOKTABLE, 6535 $(TR $(TD $(MYREF InvalidOperationException)) 6536 $(TD x is signaling $(B NaN) or ±∞)) 6537 $(TR $(TD $(MYREF UnderflowException)) 6538 $(TD result is too small to be represented)) 6539 $(TR $(TD $(MYREF OverflowException)) 6540 $(TD result is too big to be represented)) 6541 $(TR $(TD $(MYREF InexactException)) 6542 $(TD the result is inexact)) 6543 ) 6544 Special_values: 6545 $(BOOKTABLE, 6546 $(TR $(TH x) $(TH tan(x))) 6547 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 6548 $(TR $(TD ±∞) $(TD $(B NaN))) 6549 $(TR $(TD -π/2) $(TD -∞)) 6550 $(TR $(TD -π/3) $(TD -√3)) 6551 $(TR $(TD -π/4) $(TD -1.0)) 6552 $(TR $(TD -π/6) $(TD -1/√3)) 6553 $(TR $(TD ±0.0) $(TD +0.0)) 6554 $(TR $(TD +π/6) $(TD +1/√3)) 6555 $(TR $(TD +π/4) $(TD +1.0)) 6556 $(TR $(TD +π/3) $(TD +√3)) 6557 $(TR $(TD +π/2) $(TD +∞)) 6558 ) 6559 */ 6560 @IEEECompliant("tan", 42) 6561 D tan(D)(auto const ref D x) 6562 if (isDecimal!D) 6563 { 6564 Unqual!D result = x; 6565 auto flags = decimalTan(result, 6566 __ctfe ? D.PRECISION : DecimalControl.precision, 6567 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 6568 6569 DecimalControl.raiseFlags(flags); 6570 return result; 6571 } 6572 6573 /** 6574 Returns tangent of x. 6575 Throws: 6576 $(BOOKTABLE, 6577 $(TR $(TD $(MYREF InvalidOperationException)) 6578 $(TD x is signaling $(B NaN) )) 6579 $(TR $(TD $(MYREF UnderflowException)) 6580 $(TD result is too small to be represented)) 6581 $(TR $(TD $(MYREF OverflowException)) 6582 $(TD result is too big to be represented)) 6583 $(TR $(TD $(MYREF InexactException)) 6584 $(TD the result is inexact)) 6585 ) 6586 Special_values: 6587 $(BOOKTABLE, 6588 $(TR $(TH x) $(TH tanh(x))) 6589 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 6590 $(TR $(TD ±∞) $(TD ±1.0)) 6591 $(TR $(TD ±0.0) $(TD ±0.0)) 6592 ) 6593 */ 6594 @IEEECompliant("tanh", 42) 6595 D tanh(D)(auto const ref D x) 6596 if (isDecimal!D) 6597 { 6598 Unqual!D result = x; 6599 auto flags = decimalTanh(result, 6600 __ctfe ? D.PRECISION : DecimalControl.precision, 6601 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 6602 6603 DecimalControl.raiseFlags(flags); 6604 return result; 6605 } 6606 6607 6608 /** 6609 Converts x to the specified integral type rounded if necessary by mode 6610 Throws: 6611 $(MYREF InvalidOperationException) if x is $(B NaN), 6612 $(MYREF UnderflowException), $(MYREF OverflowException) 6613 Special_values: 6614 $(BOOKTABLE, 6615 $(TR $(TH x) $(TH to!T(x))) 6616 $(TR $(TD $(B NaN)) $(TD 0)) 6617 $(TR $(TD +∞) $(TD T.max)) 6618 $(TR $(TD -∞) $(TD T.min)) 6619 $(TR $(TD ±0.0) $(TD 0)) 6620 ) 6621 */ 6622 @IEEECompliant("convertToIntegerTiesToAway", 22) 6623 @IEEECompliant("convertToIntegerTiesToEven", 22) 6624 @IEEECompliant("convertToIntegerTowardNegative", 22) 6625 @IEEECompliant("convertToIntegerTowardPositive", 22) 6626 @IEEECompliant("convertToIntegerTowardZero", 22) 6627 T to(T, D)(auto const ref D x, const RoundingMode mode) 6628 if (isIntegral!T && isDecimal!D) 6629 { 6630 Unqual!T result; 6631 static if (isUnsigned!T) 6632 auto flags = decimalToUnsigned(x, result, mode); 6633 else 6634 auto flags = decimalToSigned(x, result, mode); 6635 DecimalControl.raiseFlags(flags & ExceptionFlags.invalidOperation); 6636 return result; 6637 } 6638 6639 6640 /** 6641 Converts x to the specified binary floating point type rounded if necessary by mode 6642 Throws: 6643 $(MYREF UnderflowException), $(MYREF OverflowException) 6644 */ 6645 F to(F, D)(auto const ref D x, const RoundingMode mode) 6646 if (isFloatingPoint!F && isDecimal!D) 6647 { 6648 Unqual!F result; 6649 flags = decimalToFloat(x, result, mode); 6650 flags &= ~ExceptionFlags.inexact; 6651 if (__ctfe) 6652 DecimalControl.checkFlags(flags, ExceptionFlags.severe); 6653 else 6654 { 6655 if (flags) 6656 DecimalControl.raiseFlags(flags); 6657 } 6658 return result; 6659 } 6660 6661 /** 6662 Converts the specified value from internal encoding from/to densely packed decimal encoding 6663 Notes: 6664 _Decimal values are represented internaly using 6665 $(LINK2 https://en.wikipedia.org/wiki/Binary_Integer_Decimal, binary integer _decimal encoding), 6666 supported by Intel (BID). 6667 This function converts the specified value to/from 6668 $(LINK2 https://en.wikipedia.org/wiki/Densely_Packed_Decimal, densely packed _decimal encoding), 6669 supported by IBM (DPD). 6670 Please note that a DPD encoded _decimal cannot be passed to a function from this module, there is no way 6671 to determine if a _decimal value is BID-encoded or DPD-encoded, all functions will assume a BID-encoding. 6672 */ 6673 @IEEECompliant("encodeDecimal", 23) 6674 @safe pure nothrow @nogc 6675 decimal32 toDPD(const decimal32 x) 6676 { 6677 if (isNaN(x) || isInfinity(x) || isZero(x)) 6678 return canonical(x); 6679 6680 uint cx; 6681 int ex; 6682 bool sx = x.unpack(cx, ex); 6683 6684 uint[7] digits; 6685 size_t index = digits.length; 6686 while (cx) 6687 digits[--index] = divrem(cx, 10U); 6688 6689 cx = packDPD(digits[$ - 3], digits[$ - 2], digits[$ - 1]); 6690 cx |= packDPD(digits[$ - 6], digits[$ - 5], digits[$ - 4]) << 10; 6691 cx |= cast(uint)digits[0] << 20; 6692 6693 decimal32 result; 6694 result.pack(cx, ex, sx); 6695 return result; 6696 } 6697 6698 ///ditto 6699 @IEEECompliant("encodeDecimal", 23) 6700 @safe pure nothrow @nogc 6701 decimal64 toDPD(const decimal64 x) 6702 { 6703 if (isNaN(x) || isInfinity(x) || isZero(x)) 6704 return canonical(x); 6705 6706 ulong cx; 6707 int ex; 6708 bool sx = x.unpack(cx, ex); 6709 6710 uint[16] digits; 6711 size_t index = digits.length; 6712 while (cx) 6713 digits[--index] = cast(uint)(divrem(cx, 10U)); 6714 6715 cx = cast(ulong)(packDPD(digits[$ - 3], digits[$ - 2], digits[$ - 1])); 6716 cx |= cast(ulong)packDPD(digits[$ - 6], digits[$ - 5], digits[$ - 4]) << 10; 6717 cx |= cast(ulong)packDPD(digits[$ - 9], digits[$ - 8], digits[$ - 7]) << 20; 6718 cx |= cast(ulong)packDPD(digits[$ - 12], digits[$ - 11], digits[$ - 10]) << 30; 6719 cx |= cast(ulong)packDPD(digits[$ - 15], digits[$ - 14], digits[$ - 13]) << 40; 6720 cx |= cast(ulong)digits[0] << 50; 6721 6722 decimal64 result; 6723 result.pack(cx, ex, sx); 6724 return result; 6725 } 6726 6727 ///ditto 6728 @IEEECompliant("encodeDecimal", 23) 6729 @safe pure nothrow @nogc 6730 decimal128 toDPD(const decimal128 x) 6731 { 6732 if (isNaN(x) || isInfinity(x) || isZero(x)) 6733 return canonical(x); 6734 6735 uint128 cx; 6736 int ex; 6737 bool sx = x.unpack(cx, ex); 6738 6739 uint[34] digits; 6740 size_t index = digits.length; 6741 while (cx) 6742 digits[--index] = cast(uint)(divrem(cx, 10U)); 6743 6744 cx = uint128(packDPD(digits[$ - 3], digits[$ - 2], digits[$ - 1])); 6745 cx |= uint128(packDPD(digits[$ - 6], digits[$ - 5], digits[$ - 4])) << 10; 6746 cx |= uint128(packDPD(digits[$ - 9], digits[$ - 8], digits[$ - 7])) << 20; 6747 cx |= uint128(packDPD(digits[$ - 12], digits[$ - 11], digits[$ - 10])) << 30; 6748 cx |= uint128(packDPD(digits[$ - 15], digits[$ - 14], digits[$ - 13])) << 40; 6749 cx |= uint128(packDPD(digits[$ - 18], digits[$ - 17], digits[$ - 16])) << 50; 6750 cx |= uint128(packDPD(digits[$ - 21], digits[$ - 20], digits[$ - 19])) << 60; 6751 cx |= uint128(packDPD(digits[$ - 24], digits[$ - 23], digits[$ - 22])) << 70; 6752 cx |= uint128(packDPD(digits[$ - 27], digits[$ - 26], digits[$ - 25])) << 80; 6753 cx |= uint128(packDPD(digits[$ - 30], digits[$ - 29], digits[$ - 28])) << 90; 6754 cx |= uint128(packDPD(digits[$ - 33], digits[$ - 32], digits[$ - 31])) << 100; 6755 cx |= uint128(digits[0]) << 110; 6756 6757 decimal128 result; 6758 result.pack(cx, ex, sx); 6759 return result; 6760 } 6761 6762 ///ditto 6763 @IEEECompliant("decodeDecimal", 23) 6764 @safe pure nothrow @nogc 6765 decimal32 fromDPD(const decimal32 x) 6766 { 6767 if (isNaN(x) || isInfinity(x) || isZero(x)) 6768 return canonical(x); 6769 6770 uint[7] digits; 6771 uint cx; 6772 int ex; 6773 bool sx = x.unpack(cx, ex); 6774 6775 unpackDPD(cx & 1023, digits[$ - 1], digits[$ - 2], digits[$ - 3]); 6776 unpackDPD((cx >>> 10) & 1023, digits[$ - 4], digits[$ - 5], digits[$ - 6]); 6777 digits[0] = (cx >>> 20) & 15; 6778 6779 cx = 0U; 6780 for (size_t i = 0; i < digits.length; ++i) 6781 cx += digits[i] * pow10!uint[6 - i]; 6782 6783 decimal32 result; 6784 result.pack(cx, ex, sx); 6785 return result; 6786 } 6787 6788 ///ditto 6789 @IEEECompliant("decodeDecimal", 23) 6790 @safe pure nothrow @nogc 6791 decimal64 fromDPD(const decimal64 x) 6792 { 6793 if (isNaN(x) || isInfinity(x) || isZero(x)) 6794 return canonical(x); 6795 6796 uint[16] digits; 6797 ulong cx; 6798 int ex; 6799 bool sx = x.unpack(cx, ex); 6800 6801 unpackDPD(cast(uint)cx & 1023, digits[$ - 1], digits[$ - 2], digits[$ - 3]); 6802 unpackDPD(cast(uint)(cx >>> 10) & 1023, digits[$ - 4], digits[$ - 5], digits[$ - 6]); 6803 unpackDPD(cast(uint)(cx >>> 20) & 1023, digits[$ - 7], digits[$ - 8], digits[$ - 9]); 6804 unpackDPD(cast(uint)(cx >>> 30) & 1023, digits[$ - 10], digits[$ - 11], digits[$ - 12]); 6805 unpackDPD(cast(uint)(cx >>> 40) & 1023, digits[$ - 13], digits[$ - 14], digits[$ - 15]); 6806 digits[0] = cast(uint)(cx >>> 50) & 15; 6807 6808 cx = 0U; 6809 for (size_t i = 0; i < digits.length; ++i) 6810 cx += digits[i] * pow10!ulong[15 - i]; 6811 6812 decimal64 result; 6813 result.pack(cx, ex, sx); 6814 return result; 6815 } 6816 6817 ///ditto 6818 @safe pure nothrow @nogc 6819 @IEEECompliant("decodeDecimal", 23) 6820 decimal128 fromDPD(const decimal128 x) 6821 { 6822 if (isNaN(x) || isInfinity(x) || isZero(x)) 6823 return canonical(x); 6824 6825 uint[34] digits; 6826 uint128 cx; 6827 int ex; 6828 bool sx = x.unpack(cx, ex); 6829 6830 unpackDPD(cast(uint)cx & 1023U, digits[$ - 1], digits[$ - 2], digits[$ - 3]); 6831 unpackDPD(cast(uint)(cx >>> 10) & 1023, digits[$ - 4], digits[$ - 5], digits[$ - 6]); 6832 unpackDPD(cast(uint)(cx >>> 20) & 1023, digits[$ - 7], digits[$ - 8], digits[$ - 9]); 6833 unpackDPD(cast(uint)(cx >>> 30) & 1023, digits[$ - 10], digits[$ - 11], digits[$ - 12]); 6834 unpackDPD(cast(uint)(cx >>> 40) & 1023, digits[$ - 13], digits[$ - 14], digits[$ - 15]); 6835 unpackDPD(cast(uint)(cx >>> 50) & 1023, digits[$ - 16], digits[$ - 17], digits[$ - 18]); 6836 unpackDPD(cast(uint)(cx >>> 60) & 1023, digits[$ - 19], digits[$ - 20], digits[$ - 21]); 6837 unpackDPD(cast(uint)(cx >>> 70) & 1023, digits[$ - 22], digits[$ - 23], digits[$ - 24]); 6838 unpackDPD(cast(uint)(cx >>> 80) & 1023, digits[$ - 25], digits[$ - 26], digits[$ - 27]); 6839 unpackDPD(cast(uint)(cx >>> 90) & 1023, digits[$ - 28], digits[$ - 29], digits[$ - 30]); 6840 unpackDPD(cast(uint)(cx >>> 100) & 1023, digits[$ - 31], digits[$ - 32], digits[$ - 33]); 6841 digits[0] = cast(uint)(cx >>> 110) & 15; 6842 6843 cx = 0U; 6844 for (size_t i = 0; i < digits.length; ++i) 6845 cx += pow10!uint128[34 - i] * digits[i]; 6846 6847 decimal128 result; 6848 result.pack(cx, ex, sx); 6849 return result; 6850 } 6851 6852 /** 6853 Converts x to the specified integral type rounded if necessary by mode 6854 Throws: 6855 $(MYREF InvalidOperationException) if x is $(B NaN), 6856 $(MYREF InexactException) 6857 $(MYREF UnderflowException), $(MYREF OverflowException) 6858 Special_values: 6859 $(BOOKTABLE, 6860 $(TR $(TH x) $(TH toExact!T(x))) 6861 $(TR $(TD $(B NaN)) $(TD 0)) 6862 $(TR $(TD +∞) $(TD T.max)) 6863 $(TR $(TD -∞) $(TD T.min)) 6864 $(TR $(TD ±0.0) $(TD 0)) 6865 ) 6866 */ 6867 @IEEECompliant("convertToIntegerExactTiesToAway", 22) 6868 @IEEECompliant("convertToIntegerExactTiesToEven", 22) 6869 @IEEECompliant("convertToIntegerExactTowardNegative", 22) 6870 @IEEECompliant("convertToIntegerExactTowardPositive", 22) 6871 @IEEECompliant("convertToIntegerExactTowardZero", 22) 6872 T toExact(T, D)(auto const ref D x, const RoundingMode mode) 6873 if (isIntegral!T && isDecimal!D) 6874 { 6875 Unqual!T result; 6876 static if (isUnsigned!T) 6877 auto flags = decimalToUnsigned(x, result, mode); 6878 else 6879 auto flags = decimalToSigned(x, result, mode); 6880 DecimalControl.raiseFlags(flags & (ExceptionFlags.invalidOperation | ExceptionFlags.inexact)); 6881 return result; 6882 } 6883 6884 /** 6885 Converts x to the specified binary floating point type rounded if necessary by mode 6886 Throws: 6887 $(MYREF UnderflowException), $(MYREF OverflowException), 6888 $(MYREF InexactException) 6889 */ 6890 F toExact(F, D)(auto const ref D x, const RoundingMode mode) 6891 if (isFloatingPoint!F && isDecimal!D) 6892 { 6893 Unqual!F result; 6894 flags = decimalToFloat(x, result, __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 6895 DecimalControl.raiseFlags(flags); 6896 return result; 6897 } 6898 6899 /** 6900 Converts the specified value to/from Microsoft currency data type; 6901 Throws: 6902 $(BOOKTABLE, 6903 $(TR $(TD $(MYREF InvalidOperationException)) 6904 $(TD x is $(B NaN))) 6905 $(TR $(TD $(MYREF OverflowException)) 6906 $(TD x is infinite or outside the Currency limits)) 6907 $(TR $(TD $(MYREF UnderflowException)) 6908 $(TD x is too small to be represented as Currency)) 6909 $(TR $(TD $(MYREF InexactException)) 6910 $(TD x cannot be represented exactly)) 6911 ) 6912 Notes: 6913 The Microsoft currency data type is stored as long 6914 always scaled by 10$(SUPERSCRIPT -4) 6915 */ 6916 long toMsCurrency(D)(auto const ref D x) 6917 if (isDecimal!D) 6918 { 6919 ExceptionFlags flags; 6920 6921 if (isNaN(x)) 6922 { 6923 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation); 6924 return 0; 6925 } 6926 6927 if (isInfinity(x)) 6928 { 6929 DecimalControl.raiseFlags(ExceptionFlags.overflow); 6930 return signbit(x) ? long.max : long.min; 6931 } 6932 6933 if (isZero(x)) 6934 return 0; 6935 6936 ex +=4; 6937 6938 long result; 6939 flags = decimalToSigned!long(x, result, 6940 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 6941 DecimalControl.raiseFlags(flags); 6942 return result; 6943 } 6944 6945 ///ditto 6946 D fromMsCurrency(D)(const ulong x) 6947 if (isDecimal!D) 6948 { 6949 ExceptionFlags flags; 6950 Unqual!D result; 6951 flags = result.packIntegral(result, D.PRECISION, RoundingMode.implicit); 6952 flags |= decimalDiv(result, 100, 6953 __ctfe ? D.PRECISION : DecimalControl.precision, 6954 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 6955 DecimalControl.raiseFlags(flags); 6956 return result; 6957 } 6958 6959 /** 6960 Converts the specified value to/from Microsoft _decimal data type; 6961 Throws: 6962 $(BOOKTABLE, 6963 $(TR $(TD $(MYREF InvalidOperationException)) 6964 $(TD x is $(B NaN))) 6965 $(TR $(TD $(MYREF OverflowException)) 6966 $(TD x is infinite or outside the DECIMAL limits)) 6967 $(TR $(TD $(MYREF UnderflowException)) 6968 $(TD x is too small to be represented as DECIMAL)) 6969 $(TR $(TD $(MYREF InexactException)) 6970 $(TD x cannot be represented exactly)) 6971 ) 6972 Notes: 6973 The Microsoft _decimal data type is stored as a 96 bit integral 6974 scaled by a variable exponent between 10$(SUPERSCRIPT -28) and 10$(SUPERSCRIPT 0). 6975 */ 6976 DECIMAL toMsDecimal(D)(auto const ref D x) 6977 { 6978 ExceptionFlags flags; 6979 DECIMAL result; 6980 6981 if (isNaN(x)) 6982 { 6983 if (__ctfe) 6984 DecimalControl.checkFlags(ExceptionFlags.invalidOperation, ExceptionFlags.severe); 6985 else 6986 { 6987 DecimalControl.raiseFlags(ExceptionFlags.invalidOperation); 6988 } 6989 return result; 6990 } 6991 6992 if (isInfinity(x)) 6993 { 6994 if (__ctfe) 6995 DecimalControl.checkFlags(ExceptionFlags.overflow, ExceptionFlags.severe); 6996 else 6997 { 6998 DecimalControl.raiseFlags(ExceptionFlags.overflow); 6999 } 7000 result.Lo64 = ulong.max; 7001 result.Hi32 = uint.max; 7002 if (signbit(x)) 7003 result.sign = DECIMAL.DECIMAL_NEG; 7004 return result; 7005 } 7006 7007 if (isZero(x)) 7008 return result; 7009 7010 DataType!D cx; 7011 int ex; 7012 bool sx = x.unpack(cx, ex); 7013 7014 7015 static if (is(D == decimal128)) 7016 alias cxx = cx; 7017 else 7018 uint128 cxx = cx; 7019 7020 enum cmax = uint128(cast(ulong)(uint.max), ulong.max); 7021 7022 flags = coefficientAdjust(cxx, ex, -28, 0, cmax, sx, 7023 __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 7024 7025 if (flags & ExceptionFlags.overflow) 7026 { 7027 result.Lo64 = ulong.max; 7028 result.Hi32 = uint.max; 7029 if (signbit(x)) 7030 result.sign = DECIMAL.DECIMAL_NEG; 7031 } 7032 else if (flags & ExceptionFlags.underflow) 7033 { 7034 result.Lo64 = 0; 7035 result.Hi32 = 0; 7036 if (sx) 7037 result.sign = DECIMAL.DECIMAL_NEG; 7038 } 7039 else 7040 { 7041 result.Lo64 = cxx.lo; 7042 result.Hi32 = cast(uint)(cxx.hi); 7043 result.scale = -ex; 7044 if (sx) 7045 result.sign = DECIMAL.DECIMAL_NEG; 7046 } 7047 7048 DecimalControl.raiseFlags(flags); 7049 return result; 7050 } 7051 7052 7053 ///ditto 7054 D fromMsDecimal(D)(auto const ref DECIMAL x) 7055 { 7056 ExceptionFlags flags; 7057 Unqual!D result; 7058 7059 uint128 cx = uint128(cast(ulong)(x.Hi32), x.Lo64); 7060 int ex = -x.scale; 7061 bool sx = (x.sign & DECIMAL.DECIMAL_NEG) == DECIMAL.DECIMAL_NEG; 7062 7063 flags = coefficientAdjust(cx, ex, cvt!uint128(D.COEF_MAX), RoundingMode.implicit); 7064 7065 flags |= result.adjustedPack(cvt!(DataType!D)(cx), ex, sx, 7066 __ctfe ? D.PRECISION : DecimalControl.precision, 7067 __ctfe ? RoundingMode.implicit : DecimalControl.rounding, 7068 flags); 7069 DecimalControl.raiseFlags(flags); 7070 return result; 7071 } 7072 7073 7074 7075 /** 7076 Checks the order between two _decimal values 7077 Params: 7078 x = a _decimal value 7079 y = a _decimal value 7080 Returns: 7081 true if x precedes y, false otherwise 7082 Notes: 7083 totalOrderAbs checks the order between |x| and |y| 7084 See_Also: 7085 $(MYREF cmp) 7086 */ 7087 @IEEECompliant("totalOrder", 25) 7088 bool totalOrder(D1, D2)(auto const ref D1 x, auto const ref D2 y) 7089 if (isDecimal!(D1, D2)) 7090 { 7091 return cmp(x, y) <= 0; 7092 } 7093 7094 ///ditto 7095 @IEEECompliant("totalOrderAbs", 25) 7096 bool totalOrderAbs(D1, D2)(auto const ref D1 x, auto const ref D2 y) 7097 if (isDecimal!(D1, D2)) 7098 { 7099 return cmp(fabs(x), fabs(y)) <= 0; 7100 } 7101 7102 /// 7103 unittest 7104 { 7105 assert (totalOrder(decimal32.min_normal, decimal64.max)); 7106 assert (!totalOrder(decimal32.max, decimal128.min_normal)); 7107 assert (totalOrder(-decimal64(0), decimal64(0))); 7108 assert (totalOrderAbs(decimal64(0), -decimal64(0))); 7109 } 7110 7111 /** 7112 Returns the value of x rounded up or down, depending on sign (toward zero). 7113 This operation is silent, doesn't throw any exception. 7114 Special_values: 7115 $(BOOKTABLE, 7116 $(TR $(TH x) $(TH trunc(x))) 7117 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 7118 $(TR $(TD ±0.0) $(TD ±0.0)) 7119 $(TR $(TD ±∞) $(TD ±∞)) 7120 ) 7121 */ 7122 @safe pure nothrow @nogc 7123 D trunc(D)(auto const ref D x) 7124 if (isDecimal!D) 7125 { 7126 Unqual!D result = x; 7127 decimalRound(result, 0, RoundingMode.towardZero); 7128 return result; 7129 } 7130 7131 /** 7132 Gives the previous power of 10 before x. 7133 Throws: 7134 $(MYREF InvalidOperationException), 7135 $(MYREF OverflowException), 7136 $(MYREF UnderflowException), 7137 $(MYREF InexactException) 7138 Special_values: 7139 $(BOOKTABLE, 7140 $(TR $(TH x) $(TH truncPow10(x))) 7141 $(TR $(TD $(B NaN)) $(TD $(B NaN))) 7142 $(TR $(TD ±∞) $(TD ±∞)) 7143 $(TR $(TD ±0.0) $(TD ±0.0)) 7144 ) 7145 */ 7146 D truncPow10(D)(auto const ref D x) 7147 if (isDecimal!D) 7148 { 7149 ExceptionFlags flags; 7150 Unqual!D result; 7151 7152 if (isSignaling(x)) 7153 { 7154 result = D.nan; 7155 flags = ExceptionFlags.invalidOperation; 7156 } 7157 else if (isNaN(x) || isInfinity(x) || isZero(x)) 7158 result = x; 7159 else 7160 { 7161 alias U = DataType!D; 7162 U c; 7163 int e; 7164 bool s = x.unpack(c, e); 7165 for (size_t i = 0; i < pow10!U.length; ++i) 7166 { 7167 if (c == pow10!U[i]) 7168 break; 7169 else if (c < pow10!U[i]) 7170 { 7171 c = pow10!U[i - 1]; 7172 break; 7173 } 7174 } 7175 if (i == pow10!U.length) 7176 c = pow10!U[$ - 1]; 7177 flags = adjustCoefficient(c, e, D.EXP_MIN, D.EXP_MAX, D.COEF_MAX, s, RoundingMode.towardZero); 7178 flags |= result.pack(c, e, s, flags); 7179 } 7180 7181 if (__ctfe) 7182 DecimalControl.checkFlags(flags, ExceptionFlags.severe); 7183 else 7184 { 7185 if (flags) 7186 DecimalControl.raiseFlags(flags); 7187 } 7188 return result; 7189 } 7190 7191 7192 private: 7193 7194 template DataType(D) 7195 { 7196 static if (is(Unqual!D == decimal32)) 7197 alias DataType = uint; 7198 else static if (is(Unqual!D == decimal64)) 7199 alias DataType = ulong; 7200 else static if (is(Unqual!D == decimal128)) 7201 alias DataType = uint128; 7202 else 7203 static assert(0); 7204 } 7205 7206 mixin template ExceptionConstructors() 7207 { 7208 @nogc @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) 7209 { 7210 super(msg, file, line, next); 7211 } 7212 7213 @nogc @safe pure nothrow this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__) 7214 { 7215 super(msg, file, line, next); 7216 } 7217 } 7218 7219 7220 /* ****************************************************************************************************************** */ 7221 /* DECIMAL STRING CONVERSION */ 7222 /* ****************************************************************************************************************** */ 7223 7224 7225 //sinks %a 7226 void sinkHexadecimal(C, T)(auto const ref FormatSpec!C spec, scope void delegate(const(C)[]) sink, 7227 auto const ref T coefficient, const int exponent, const bool signed) 7228 if (isSomeChar!C && isAnyUnsigned!T) 7229 { 7230 int w = 4; //0x, p, exponent sign 7231 if (spec.flPlus || spec.flSpace || signed) 7232 ++w; 7233 7234 int p = prec(coefficient); 7235 if (p == 0) 7236 p = 1; 7237 7238 int precision = spec.precision == spec.UNSPECIFIED || spec.precision <= 0 ? p : spec.precision; 7239 7240 Unqual!T c = coefficient; 7241 int e = exponent; 7242 7243 coefficientAdjust(c, e, precision, signed, __ctfe ? RoundingMode.implicit : DecimalControl.rounding); 7244 7245 7246 Unqual!C[T.sizeof / 2] buffer; 7247 Unqual!C[prec(uint.max)] exponentBuffer; 7248 7249 int digits = dumpUnsignedHex(buffer, c, spec.spec <= 'Z'); 7250 7251 bool signedExponent = e < 0; 7252 uint ex = signedExponent ? -e : e; 7253 int exponentDigits = dumpUnsigned(exponentBuffer, ex); 7254 7255 w += digits; 7256 w += exponentDigits; 7257 7258 int pad = spec.width - w; 7259 sinkPadLeft(spec, sink, pad); 7260 sinkSign(spec, sink, signed); 7261 sink("0"); 7262 sink(spec.spec <= 'Z' ? "X" : "x"); 7263 sinkPadZero(spec, sink, pad); 7264 sink(buffer[$ - digits .. $]); 7265 sink(spec.spec < 'Z' ? "P" : "p"); 7266 sink(signedExponent ? "-" : "+"); 7267 sink(exponentBuffer[$ - exponentDigits .. $]); 7268 sinkPadRight(sink, pad); 7269 } 7270 7271 7272 //sinks %f 7273 void sinkFloat(C, T)(auto const ref FormatSpec!C spec, scope void delegate(const(C)[]) sink, const T coefficient, 7274 const int exponent, const bool signed, const RoundingMode mode, const bool skipTrailingZeros = false) 7275 if (isSomeChar!C) 7276 { 7277 if (coefficient == 0U) 7278 sinkZero(spec, sink, signed, skipTrailingZeros); 7279 else 7280 { 7281 Unqual!T c = coefficient; 7282 int e = exponent; 7283 coefficientShrink(c, e); 7284 7285 Unqual!C[40] buffer; 7286 int w = spec.flPlus || spec.flSpace || signed ? 1 : 0; 7287 7288 if (e >= 0) //coefficient[0...].[0...] 7289 { 7290 ptrdiff_t digits = dumpUnsigned(buffer, c); 7291 w += digits; 7292 w += e; 7293 int requestedDecimals = spec.precision == spec.UNSPECIFIED ? 6 : spec.precision; 7294 if (skipTrailingZeros) 7295 requestedDecimals = 0; 7296 if (requestedDecimals || spec.flHash) 7297 w += requestedDecimals + 1; 7298 int pad = spec.width - w; 7299 sinkPadLeft(spec, sink, pad); 7300 sinkSign(spec, sink, signed); 7301 sinkPadZero(spec, sink, pad); 7302 sink(buffer[$ - digits .. $]); 7303 sinkRepeat(sink, '0', e); 7304 if (requestedDecimals || spec.flHash) 7305 { 7306 sink("."); 7307 sinkRepeat(sink, '0', requestedDecimals); 7308 } 7309 sinkPadRight(sink, pad); 7310 } 7311 else 7312 { 7313 int digits = prec(c); 7314 int requestedDecimals = spec.precision == spec.UNSPECIFIED ? 6 : spec.precision; 7315 7316 if (-e < digits) //coef.ficient[0...] 7317 { 7318 int integralDigits = digits + e; 7319 int fractionalDigits = digits - integralDigits; 7320 if (fractionalDigits > requestedDecimals) 7321 { 7322 divpow10(c, fractionalDigits - requestedDecimals, signed, mode); 7323 digits = prec(c); 7324 fractionalDigits = digits - integralDigits; 7325 if (fractionalDigits > requestedDecimals) 7326 { 7327 c /= 10U; 7328 --fractionalDigits; 7329 } 7330 } 7331 if (requestedDecimals > fractionalDigits && skipTrailingZeros) 7332 requestedDecimals = fractionalDigits; 7333 w += integralDigits; 7334 if (requestedDecimals || spec.flHash) 7335 w += requestedDecimals + 1; 7336 int pad = spec.width - w; 7337 sinkPadLeft(spec, sink, pad); 7338 sinkSign(spec, sink, signed); 7339 sinkPadZero(spec, sink, pad); 7340 dumpUnsigned(buffer, c); 7341 sink(buffer[$ - digits .. $ - fractionalDigits]); 7342 if (requestedDecimals || spec.flHash) 7343 { 7344 sink("."); 7345 if (fractionalDigits) 7346 sink(buffer[$ - fractionalDigits .. $]); 7347 sinkRepeat(sink, '0', requestedDecimals - fractionalDigits); 7348 } 7349 sinkPadRight(sink, pad); 7350 } 7351 else if (-e == digits) //0.coefficient[0...] 7352 { 7353 if (skipTrailingZeros && requestedDecimals > digits) 7354 requestedDecimals = digits; 7355 if (requestedDecimals == 0) //special case, no decimals, round 7356 { 7357 divpow10(c, digits - 1, signed, mode); 7358 divpow10(c, 1, signed, mode); 7359 w += 1; 7360 if (spec.flHash) 7361 ++w; 7362 int pad = spec.width - w; 7363 sinkPadLeft(spec, sink, pad); 7364 sinkSign(spec, sink, signed); 7365 sinkPadZero(spec, sink, pad); 7366 sink(c != 0U ? "1": "0"); 7367 if (spec.flHash) 7368 sink("."); 7369 sinkPadRight(sink, pad); 7370 } 7371 else 7372 { 7373 w += 2; 7374 w += requestedDecimals; 7375 if (digits > requestedDecimals) 7376 { 7377 divpow10(c, digits - requestedDecimals, signed, mode); 7378 digits = prec(c); 7379 if (digits > requestedDecimals) 7380 { 7381 c /= 10U; 7382 --digits; 7383 } 7384 } 7385 int pad = spec.width - w; 7386 sinkPadLeft(spec, sink, pad); 7387 sinkSign(spec, sink, signed); 7388 sinkPadZero(spec, sink, pad); 7389 sink("0."); 7390 dumpUnsigned(buffer, c); 7391 sink(buffer[$ - digits .. $]); 7392 sinkRepeat(sink, '0', requestedDecimals - digits); 7393 sinkPadRight(sink, pad); 7394 } 7395 } 7396 else //-e > 0.[0...][coefficient] 7397 { 7398 int zeros = -e - digits; 7399 7400 if (requestedDecimals > digits - e && skipTrailingZeros) 7401 requestedDecimals = digits - e - 1; 7402 7403 if (requestedDecimals <= zeros) //special case, coefficient does not fit 7404 { 7405 divpow10(c, digits - 1, signed, mode); 7406 divpow10(c, 1, signed, mode); 7407 if (requestedDecimals == 0) //special case, 0 or 1 7408 { 7409 w += 1; 7410 int pad = spec.width - w; 7411 sinkPadLeft(spec, sink, pad); 7412 sinkSign(spec, sink, signed); 7413 sinkPadZero(spec, sink, pad); 7414 sink(c != 0U ? "1": "0"); 7415 sinkPadRight(sink, pad); 7416 } 7417 else //special case 0.[0..][0/1] 7418 { 7419 w += 2; 7420 w += requestedDecimals; 7421 int pad = spec.width - w; 7422 sinkPadLeft(spec, sink, pad); 7423 sinkSign(spec, sink, signed); 7424 sinkPadZero(spec, sink, pad); 7425 sink("0."); 7426 sinkRepeat(sink, '0', requestedDecimals - 1); 7427 sink(c != 0U ? "1": "0"); 7428 sinkPadRight(sink, pad); 7429 } 7430 } 7431 else //0.[0...]coef 7432 { 7433 if (digits > requestedDecimals - zeros) 7434 { 7435 divpow10(c, digits - (requestedDecimals - zeros), signed, mode); 7436 digits = prec(c); 7437 if (digits > requestedDecimals - zeros) 7438 c /= 10U; 7439 digits = prec(c); 7440 } 7441 w += 2; 7442 w += requestedDecimals; 7443 int pad = spec.width - w; 7444 sinkPadLeft(spec, sink, pad); 7445 sinkSign(spec, sink, signed); 7446 sinkPadZero(spec, sink, pad); 7447 sink("0."); 7448 sinkRepeat(sink, '0', zeros); 7449 digits = dumpUnsigned(buffer, c); 7450 sink(buffer[$ - digits .. $]); 7451 sinkRepeat(sink, '0', requestedDecimals - digits - zeros); 7452 sinkPadRight(sink, pad); 7453 } 7454 } 7455 } 7456 } 7457 } 7458 7459 //sinks %e 7460 void sinkExponential(C, T)(auto const ref FormatSpec!C spec, scope void delegate(const(C)[]) sink, const T coefficient, 7461 const int exponent, const bool signed, const RoundingMode mode, const bool skipTrailingZeros = false) 7462 if (isSomeChar!C) 7463 { 7464 int w = 3; /// N e +/- 7465 if (spec.flPlus || spec.flSpace || signed) 7466 ++w; 7467 Unqual!C[T.sizeof * 8 / 3 + 1] buffer; 7468 Unqual!C[10] exponentBuffer; 7469 Unqual!T c = coefficient; 7470 int ex = exponent; 7471 coefficientShrink(c, ex); 7472 int digits = prec(c); 7473 int e = digits == 0 ? 0 : ex + (digits - 1); 7474 int requestedDecimals = spec.precision == spec.UNSPECIFIED ? 6 : spec.precision; 7475 7476 int targetPrecision = requestedDecimals + 1; 7477 7478 if (digits > targetPrecision) 7479 { 7480 divpow10(c, digits - targetPrecision, signed, mode); 7481 digits = prec(c); 7482 if (digits > targetPrecision) 7483 c /= 10U; 7484 --digits; 7485 } 7486 7487 7488 bool signedExponent = e < 0; 7489 uint ue = signedExponent ? -e : e; 7490 int exponentDigits = dumpUnsigned(exponentBuffer, ue); 7491 w += exponentDigits <= 2 ? 2 : exponentDigits; 7492 digits = dumpUnsigned(buffer, c); 7493 7494 if (skipTrailingZeros && requestedDecimals > digits - 1) 7495 requestedDecimals = digits - 1; 7496 7497 if (requestedDecimals || spec.flHash) 7498 w += requestedDecimals + 1; 7499 7500 int pad = spec.width - w; 7501 sinkPadLeft(spec, sink, pad); 7502 sinkSign(spec, sink, signed); 7503 sinkPadZero(spec, sink, pad); 7504 sink(buffer[$ - digits .. $ - digits + 1]); 7505 if (requestedDecimals || spec.flHash) 7506 { 7507 sink("."); 7508 if (digits > 1) 7509 sink(buffer[$ - digits + 1 .. $]); 7510 sinkRepeat(sink, '0', requestedDecimals - (digits - 1)); 7511 } 7512 sink(spec.spec <= 'Z' ? "E" : "e"); 7513 sink(signedExponent ? "-" : "+"); 7514 if (exponentDigits < 2) 7515 sink("0"); 7516 sink(exponentBuffer[$ - exponentDigits .. $]); 7517 sinkPadRight(sink, pad); 7518 } 7519 7520 //sinks %g 7521 void sinkGeneral(C, T)(auto const ref FormatSpec!C spec, scope void delegate(const(C)[]) sink, const T coefficient, 7522 const int exponent, const bool signed, const RoundingMode mode) 7523 if (isSomeChar!C) 7524 { 7525 int precision = spec.precision == spec.UNSPECIFIED ? 6 : (spec.precision <= 0 ? 1 : spec.precision); 7526 Unqual!T c = coefficient; 7527 int e = exponent; 7528 coefficientShrink(c, e); 7529 coefficientAdjust(c, e, precision, signed, mode); 7530 if (c == 0U) 7531 e = 0; 7532 int cp = prec(c); 7533 7534 int expe = cp > 0 ? e + cp - 1 : 0; 7535 7536 if (precision > expe && expe >= -4) 7537 { 7538 FormatSpec!C fspec = spec; 7539 fspec.precision = precision - 1 - expe; 7540 sinkFloat(fspec, sink, coefficient, exponent, signed, mode, !fspec.flHash); 7541 } 7542 else 7543 { 7544 FormatSpec!C espec = spec; 7545 espec.precision = precision - 1; 7546 sinkExponential(espec, sink, coefficient, exponent, signed, mode, !espec.flHash); 7547 } 7548 7549 } 7550 7551 //sinks a decimal value 7552 void sinkDecimal(C, D)(auto const ref FormatSpec!C spec, scope void delegate(const(C)[]) sink, auto const ref D decimal, 7553 const RoundingMode mode) 7554 if (isDecimal!D && isSomeChar!C) 7555 { 7556 DataType!D coefficient; int exponent; bool isNegative; 7557 auto fx = fastDecode(decimal, coefficient, exponent, isNegative); 7558 if (fx == FastClass.signalingNaN) 7559 sinkNaN(spec, sink, isNegative, true, coefficient, spec.spec == 'a' || spec.spec == 'A'); 7560 else if (fx == FastClass.quietNaN) 7561 sinkNaN(spec, sink, isNegative, false, coefficient, spec.spec == 'a' || spec.spec == 'A'); 7562 else if (fx == FastClass.infinite) 7563 sinkInfinity(spec, sink, signbit(decimal) != 0); 7564 else 7565 { 7566 switch (spec.spec) 7567 { 7568 case 'f': 7569 case 'F': 7570 sinkFloat(spec, sink, coefficient, exponent, isNegative, mode); 7571 break; 7572 case 'e': 7573 case 'E': 7574 sinkExponential(spec, sink, coefficient, exponent, isNegative, mode); 7575 break; 7576 case 'g': 7577 case 'G': 7578 case 's': 7579 case 'S': 7580 sinkGeneral(spec, sink, coefficient, exponent, isNegative, mode); 7581 break; 7582 case 'a': 7583 case 'A': 7584 sinkHexadecimal(spec, sink, coefficient, exponent, isNegative); 7585 break; 7586 default: 7587 throw new FormatException("Unsupported format specifier"); 7588 } 7589 } 7590 } 7591 7592 //converts decimal to string using %g 7593 immutable(C)[] decimalToString(C, D)(auto const ref D decimal, const RoundingMode mode) 7594 if (isDecimal!D && isSomeChar!C) 7595 { 7596 immutable(C)[] result; 7597 void localSink(const(C)[] s) 7598 { 7599 result ~= s; 7600 } 7601 7602 sinkDecimal(FormatSpec!C("%g"), &localSink, decimal, mode); 7603 7604 return result; 7605 } 7606 7607 //converts decimal to string 7608 immutable(C)[] decimalToString(C, D)(auto const ref FormatSpec!C spec, auto const ref D decimal, const RoundingMode mode) 7609 if (isDecimal!D && isSomeChar!C) 7610 { 7611 immutable(C)[] result; 7612 void localSink(const(C)[] s) 7613 { 7614 result ~= s; 7615 } 7616 7617 sinkDecimal(spec, &localSink, decimal, mode); 7618 7619 return result; 7620 } 7621 7622 unittest 7623 { 7624 import std.format; 7625 decimal32 x = "1.234567"; 7626 assert (format("%0.7f", x) == "1.2345670"); 7627 assert (format("%0.6f", x) == "1.234567"); 7628 assert (format("%0.5f", x) == "1.23457"); 7629 assert (format("%0.4f", x) == "1.2346"); 7630 assert (format("%0.3f", x) == "1.235"); 7631 assert (format("%0.2f", x) == "1.23"); 7632 assert (format("%0.1f", x) == "1.2"); 7633 assert (format("%0.0f", x) == "1"); 7634 assert (format("%+0.1f", x) == "+1.2"); 7635 assert (format("%+0.1f", -x) == "-1.2"); 7636 assert (format("% 0.1f", x) == " 1.2"); 7637 assert (format("% 0.1f", -x) == "-1.2"); 7638 assert (format("%8.2f", x) == " 1.23"); 7639 assert (format("%+8.2f", x) == " +1.23"); 7640 assert (format("%+8.2f", -x) == " -1.23"); 7641 assert (format("% 8.2f", x) == " 1.23"); 7642 assert (format("%-8.2f", x) == "1.23 "); 7643 assert (format("%-8.2f", -x) == "-1.23 "); 7644 7645 struct S 7646 { 7647 string fmt; 7648 string v; 7649 string expected; 7650 } 7651 7652 S[] tests = 7653 [ 7654 S("%+.3e","0.0","+0.000e+00"), 7655 S("%+.3e","1.0","+1.000e+00"), 7656 S("%+.3f","-1.0","-1.000"), 7657 S("%+.3F","-1.0","-1.000"), 7658 S("%+07.2f","1.0","+001.00"), 7659 S("%+07.2f","-1.0","-001.00"), 7660 S("%-07.2f","1.0","1.00 "), 7661 S("%-07.2f","-1.0","-1.00 "), 7662 S("%+-07.2f","1.0","+1.00 "), 7663 S("%+-07.2f","-1.0","-1.00 "), 7664 S("%-+07.2f","1.0","+1.00 "), 7665 S("%-+07.2f","-1.0","-1.00 "), 7666 S("%+10.2f","+1.0"," +1.00"), 7667 S("%+10.2f","-1.0"," -1.00"), 7668 S("% .3E","-1.0","-1.000E+00"), 7669 S("% .3e","1.0"," 1.000e+00"), 7670 S("%+.3g","0.0","+0"), 7671 S("%+.3g","1.0","+1"), 7672 S("%+.3g","-1.0","-1"), 7673 S("% .3g","-1.0","-1"), 7674 S("% .3g","1.0"," 1"), 7675 S("%a","1","0x1p+0"), 7676 S("%#g","1e-32","1.00000e-32"), 7677 S("%#g","-1.0","-1.00000"), 7678 S("%#g","1.1","1.10000"), 7679 S("%#g","123456.0","123456."), 7680 S("%#g","1234567.0","1.23457e+06"), 7681 S("%#g","1230000.0","1.23000e+06"), 7682 S("%#g","1000000.0","1.00000e+06"), 7683 S("%#.0f","1.0","1."), 7684 S("%#.0e","1.0","1.e+00"), 7685 S("%#.0g","1.0","1."), 7686 S("%#.0g","1100000.0","1.e+06"), 7687 S("%#.4f","1.0","1.0000"), 7688 S("%#.4e","1.0","1.0000e+00"), 7689 S("%#.4g","1.0","1.000"), 7690 S("%#.4g","100000.0","1.000e+05"), 7691 S("%#.0f","123.0","123."), 7692 S("%#.0e","123.0","1.e+02"), 7693 S("%#.0g","123.0","1.e+02"), 7694 S("%#.4f","123.0","123.0000"), 7695 S("%#.4e","123.0","1.2300e+02"), 7696 S("%#.4g","123.0","123.0"), 7697 S("%#.4g","123000.0","1.230e+05"), 7698 S("%#9.4g","1.0"," 1.000"), 7699 S("%.4a","1","0x1p+0"), 7700 S("%.4a","-1","-0x1p+0"), 7701 S("%f","+inf","inf"), 7702 S("%.1f","-inf","-inf"), 7703 S("% f","$(B NaN)"," nan"), 7704 S("%20f","+inf"," inf"), 7705 S("% 20F","+inf"," INF"), 7706 S("% 20e","-inf"," -inf"), 7707 S("%+20E","-inf"," -INF"), 7708 S("% +20g","-Inf"," -inf"), 7709 S("%+-20G","+inf","+INF "), 7710 S("%20e","$(B NaN)"," nan"), 7711 S("% +20E","$(B NaN)"," +NAN"), 7712 S("% -20g","$(B NaN)"," nan "), 7713 S("%+-20G","$(B NaN)","+NAN "), 7714 S("%+020e","+inf"," +inf"), 7715 S("%-020f","-inf","-inf "), 7716 S("%-020E","$(B NaN)","NAN "), 7717 S("%e","1.0","1.000000e+00"), 7718 S("%e","1234.5678e3","1.234568e+06"), 7719 S("%e","1234.5678e-8","1.234568e-05"), 7720 S("%e","-7.0","-7.000000e+00"), 7721 S("%e","-1e-9","-1.000000e-09"), 7722 S("%f","1234.567e2","123456.700000"), 7723 S("%f","1234.5678e-8","0.000012"), 7724 S("%f","-7.0","-7.000000"), 7725 S("%f","-1e-9","-0.000000"), 7726 S("%g","1234.5678e3","1.23457e+06"), 7727 S("%g","1234.5678e-8","1.23457e-05"), 7728 S("%g","-7.0","-7"), 7729 S("%g","-1e-9","-1e-09"), 7730 S("%E","1.0","1.000000E+00"), 7731 S("%E","1234.5678e3","1.234568E+06"), 7732 S("%E","1234.5678e-8","1.234568E-05"), 7733 S("%E","-7.0","-7.000000E+00"), 7734 S("%E","-1e-9","-1.000000E-09"), 7735 S("%G","1234.5678e3","1.23457E+06"), 7736 S("%G","1234.5678e-8","1.23457E-05"), 7737 S("%G","-7.0","-7"), 7738 S("%G","-1e-9","-1E-09"), 7739 S("%20.6e","1.2345e3"," 1.234500e+03"), 7740 S("%20.6e","1.2345e-3"," 1.234500e-03"), 7741 S("%20e","1.2345e3"," 1.234500e+03"), 7742 S("%20e","1.2345e-3"," 1.234500e-03"), 7743 S("%20.8e","1.2345e3"," 1.23450000e+03"), 7744 S("%20f","1.23456789e3"," 1234.568000"), 7745 S("%20f","1.23456789e-3"," 0.001235"), 7746 S("%20f","12345678901.23456789"," 12345680000.000000"), 7747 S("%-20f","1.23456789e3","1234.568000 "), 7748 S("%20.8f","1.23456789e3"," 1234.56800000"), 7749 S("%20.8f","1.23456789e-3"," 0.00123457"), 7750 S("%g","1.23456789e3","1234.57"), 7751 S("%g","1.23456789e-3","0.00123457"), 7752 S("%g","1.23456789e20","1.23457e+20"), 7753 S("%.2f","1.0","1.00"), 7754 S("%.2f","-1.0","-1.00"), 7755 S("% .2f","1.0"," 1.00"), 7756 S("% .2f","-1.0","-1.00"), 7757 S("%+.2f","1.0","+1.00"), 7758 S("%+.2f","-1.0","-1.00"), 7759 S("%7.2f","1.0"," 1.00"), 7760 S("%7.2f","-1.0"," -1.00"), 7761 S("% 7.2f","1.0"," 1.00"), 7762 S("% 7.2f","-1.0"," -1.00"), 7763 S("%+7.2f","1.0"," +1.00"), 7764 S("%+7.2f","-1.0"," -1.00"), 7765 S("% +7.2f","1.0"," +1.00"), 7766 S("% +7.2f","-1.0"," -1.00"), 7767 S("%07.2f","1.0","0001.00"), 7768 S("%07.2f","-1.0","-001.00"), 7769 S("% 07.2f","1.0"," 001.00"), 7770 S("% 07.2f","-1.0","-001.00"), 7771 S("%+07.2f","1.0","+001.00"), 7772 S("%+07.2f","-1.0","-001.00"), 7773 S("% +07.2f","1.0","+001.00"), 7774 S("% +07.2f","-1.0","-001.00"), 7775 7776 7777 ]; 7778 7779 foreach(s; tests) 7780 { 7781 string result = format(s.fmt, decimal32(s.v)); 7782 assert(result == s.expected, "value: '" ~ s.v ~ "', format: '" ~ s.fmt ~ "', result :'" ~ result ~ "', expected: '" ~ s.expected ~ "'"); 7783 } 7784 } 7785 7786 7787 //returns true if a decimal number can be read in value, stops if doesn't fit in value 7788 ExceptionFlags parseNumberAndExponent(R, T)(ref R range, out T value, out int exponent, bool zeroPrefix) 7789 if (isInputRange!R && isSomeChar!(ElementType!R)) 7790 { 7791 bool afterDecimalPoint = false; 7792 bool atLeastOneDigit = parseZeroes(range) > 0 || zeroPrefix; 7793 bool atLeastOneFractionalDigit = false; 7794 ExceptionFlags flags = ExceptionFlags.none; 7795 while (!range.empty) 7796 { 7797 if (range.front >= '0' && range.front <= '9') 7798 { 7799 uint digit = range.front - '0'; 7800 bool overflow = false; 7801 Unqual!T v = fma(value, 10U, digit, overflow); 7802 if (overflow) 7803 { 7804 //try to shrink the coefficient, this will loose some zeros 7805 coefficientShrink(value, exponent); 7806 overflow = false; 7807 v = fma(value, 10U, digit, overflow); 7808 if (overflow) 7809 break; 7810 } 7811 range.popFront(); 7812 value = v; 7813 if (afterDecimalPoint) 7814 { 7815 atLeastOneFractionalDigit = true; 7816 --exponent; 7817 } 7818 else 7819 atLeastOneDigit = true; 7820 } 7821 else if (range.front == '.' && !afterDecimalPoint) 7822 { 7823 afterDecimalPoint = true; 7824 range.popFront(); 7825 } 7826 else if (range.front == '_') 7827 range.popFront(); 7828 else 7829 break; 7830 } 7831 7832 //no more space in coefficient, just increase exponent before decimal point 7833 //detect if rounding is necessary 7834 int lastDigit = 0; 7835 bool mustRoundUp = false; 7836 while (!range.empty) 7837 { 7838 if (range.front >= '0' && range.front <= '9') 7839 { 7840 uint digit = range.front - '0'; 7841 if (afterDecimalPoint) 7842 atLeastOneFractionalDigit = true; 7843 else 7844 ++exponent; 7845 range.popFront(); 7846 if (digit != 0) 7847 flags = ExceptionFlags.inexact; 7848 if (digit <= 3) 7849 break; 7850 else if (digit >= 5) 7851 { 7852 if (lastDigit == 4) 7853 { 7854 mustRoundUp = true; 7855 break; 7856 } 7857 } 7858 else 7859 lastDigit = 4; 7860 7861 } 7862 else if (range.front == '.' && !afterDecimalPoint) 7863 { 7864 afterDecimalPoint = true; 7865 range.popFront(); 7866 } 7867 else if (range.front == '_') 7868 range.popFront(); 7869 else 7870 break; 7871 } 7872 7873 //just increase exponent before decimal point 7874 while (!range.empty) 7875 { 7876 if (range.front >= '0' && range.front <= '9') 7877 { 7878 if (range.front != '0') 7879 flags = ExceptionFlags.inexact; 7880 if (!afterDecimalPoint) 7881 ++exponent; 7882 else 7883 atLeastOneFractionalDigit = true; 7884 range.popFront(); 7885 } 7886 else if (range.front == '.' && !afterDecimalPoint) 7887 { 7888 afterDecimalPoint = true; 7889 range.popFront(); 7890 } 7891 else if (range.front == '_') 7892 range.popFront(); 7893 else 7894 break; 7895 } 7896 7897 if (mustRoundUp) 7898 { 7899 if (value < T.max) 7900 ++value; 7901 else 7902 { 7903 auto r = divrem(value, 10U); 7904 ++value; 7905 if (r >= 5U) 7906 ++value; 7907 else if (r == 4U && mustRoundUp) 7908 ++value; 7909 } 7910 } 7911 7912 7913 if (afterDecimalPoint) 7914 return flags; 7915 //return atLeastOneFractionalDigit ? flags : flags | ExceptionFlags.invalidOperation; 7916 else 7917 return atLeastOneDigit ? flags : flags | ExceptionFlags.invalidOperation; 7918 } 7919 7920 //parses hexadecimals if starts with 0x, otherwise decimals, false on failure 7921 bool parseHexNumberOrNumber(R, T)(ref R range, ref T value, out bool wasHex) 7922 if (isInputRange!R && isSomeChar!(ElementType!R)) 7923 { 7924 if (expect(range, '0')) 7925 { 7926 if (expectInsensitive(range, 'x')) 7927 { 7928 wasHex = true; 7929 return parseHexNumber(range, value); 7930 } 7931 else 7932 return parseNumber(range, value); 7933 } 7934 else 7935 return parseNumber(range, value); 7936 } 7937 7938 //parses $(B NaN) and optional payload, expect payload as number in optional (), [], {}, <>. invalidOperation on failure 7939 bool parseNaN(R, T)(ref R range, out T payload) 7940 if (isInputRange!R && isSomeChar!(ElementType!R)) 7941 { 7942 if (expectInsensitive(range, "nan")) 7943 { 7944 auto closingBracket = parseBracket(range); 7945 bool wasHex; 7946 if (!parseHexNumberOrNumber(range, payload, wasHex)) 7947 { 7948 if (wasHex) 7949 return false; 7950 } 7951 if (closingBracket) 7952 return expect(range, closingBracket); 7953 return true; 7954 } 7955 return false; 7956 } 7957 7958 @safe 7959 ExceptionFlags parseDecimalHex(R, T)(ref R range, out T coefficient, out int exponent) 7960 if (isInputRange!R && isSomeChar!(ElementType!R)) 7961 { 7962 if (parseHexNumber(range, coefficient)) 7963 { 7964 if (expectInsensitive(range, 'p')) 7965 { 7966 bool signedExponent; 7967 parseSign(range, signedExponent); 7968 uint e; 7969 if (parseNumber(range, e)) 7970 { 7971 if (signedExponent && e > -int.min) 7972 { 7973 exponent = int.min; 7974 return ExceptionFlags.underflow; 7975 } 7976 else if (!signedExponent && e > int.max) 7977 { 7978 exponent = int.max; 7979 return ExceptionFlags.overflow; 7980 } 7981 exponent = signedExponent ? -e : e; 7982 return ExceptionFlags.none; 7983 } 7984 } 7985 } 7986 return ExceptionFlags.invalidOperation; 7987 } 7988 7989 ExceptionFlags parseDecimalFloat(R, T)(ref R range, out T coefficient, out int exponent, const bool zeroPrefix) 7990 if (isInputRange!R && isSomeChar!(ElementType!R)) 7991 { 7992 auto flags = parseNumberAndExponent(range, coefficient, exponent, zeroPrefix); 7993 if ((flags & ExceptionFlags.invalidOperation) == 0) 7994 { 7995 if (expectInsensitive(range, 'e')) 7996 { 7997 bool signedExponent; 7998 parseSign(range, signedExponent); 7999 uint ue; 8000 if (!parseNumber(range, ue)) 8001 flags |= ExceptionFlags.invalidOperation; 8002 else 8003 { 8004 8005 bool overflow; 8006 if (!signedExponent) 8007 { 8008 if (ue > int.max) 8009 { 8010 exponent = int.max; 8011 flags |= ExceptionFlags.overflow; 8012 } 8013 else 8014 exponent = adds(exponent, cast(int)ue, overflow); 8015 } 8016 else 8017 { 8018 if (ue > -int.min || overflow) 8019 { 8020 exponent = int.min; 8021 flags |= ExceptionFlags.underflow; 8022 } 8023 else 8024 exponent = adds(exponent, cast(int)(-ue), overflow); 8025 } 8026 if (overflow) 8027 flags |= exponent > 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow; 8028 } 8029 } 8030 } 8031 return flags; 8032 } 8033 8034 @safe 8035 ExceptionFlags parseDecimal(R, T)(ref R range, out T coefficient, out int exponent, out bool isinf, out bool isnan, 8036 out bool signaling, out bool signed, out bool wasHex) 8037 if (isInputRange!R && isSomeChar!(ElementType!R)) 8038 { 8039 while (expect(range, '_')) { } 8040 if (range.empty) 8041 return ExceptionFlags.invalidOperation; 8042 bool hasSign = parseSign(range, signed); 8043 if (range.empty && hasSign) 8044 return ExceptionFlags.invalidOperation; 8045 while (expect(range, '_')) { } 8046 switch (range.front) 8047 { 8048 case 'i': 8049 case 'I': 8050 isinf = true; 8051 return parseInfinity(range) ? ExceptionFlags.none : ExceptionFlags.invalidOperation; 8052 case 'n': 8053 case 'N': 8054 isnan = true; 8055 signaling = false; 8056 return parseNaN(range, coefficient) ? ExceptionFlags.none : ExceptionFlags.invalidOperation; 8057 case 's': 8058 case 'S': 8059 isnan = true; 8060 signaling = true; 8061 range.popFront(); 8062 return parseNaN(range, coefficient) ? ExceptionFlags.none : ExceptionFlags.invalidOperation; 8063 case '0': 8064 range.popFront(); 8065 if (expectInsensitive(range, 'x')) 8066 { 8067 wasHex = true; 8068 return parseDecimalHex(range, coefficient, exponent); 8069 } 8070 else 8071 return parseDecimalFloat(range, coefficient, exponent, true); 8072 case '1': .. case '9': 8073 return parseDecimalFloat(range, coefficient, exponent, false); 8074 case '.': 8075 return parseDecimalFloat(range, coefficient, exponent, false); 8076 default: 8077 return ExceptionFlags.invalidOperation; 8078 } 8079 } 8080 8081 ExceptionFlags parse(D, R)(ref R range, out D decimal, const int precision, const RoundingMode mode) 8082 if (isInputRange!R && isSomeChar!(ElementType!R) && isDecimal!D) 8083 { 8084 DataType!D coefficient; 8085 bool isinf, isnan, signaling, signed; 8086 int exponent; 8087 auto flags = parseDecimal(range, coefficient, exponent, isinf, isnan, signaling, isnegative); 8088 8089 if (flags & ExceptionFlags.invalidOperation) 8090 { 8091 decimal.data = D.MASK_QNAN; 8092 decimal.data |= coefficient | D.MASK_PAYL; 8093 if (isnegative) 8094 decimal.data |= D.MASK_SGN; 8095 return flags; 8096 } 8097 8098 if (signaling) 8099 decimal.data = D.MASK_SNAN; 8100 else if (isnan) 8101 decimal.data = D.MASK_QNAN; 8102 else if (isinf) 8103 decimal.data = D.MASK_INF; 8104 else if (coefficient == 0) 8105 decimal.data - D.MASK_ZERO; 8106 else 8107 { 8108 flags |= adjustCoefficient(coefficient, exponent, D.EXP_MIN, D.EXP_MAX, D.COEF_MAX, isnegative, mode); 8109 flags |= adjustPrecision(coefficient, exponent, D.EXP_MIN, D.EXP_MAX, precision, isnegative, mode); 8110 if (flags & ExceptionFlags.overflow) 8111 decimal.data = D.MASK_INF; 8112 else if ((flags & ExceptionFlags.underflow) || coefficient == 0) 8113 decimal.data = D.MASK_ZERO; 8114 else 8115 { 8116 flags |= decimal.pack(coefficient, exponent, isnegative); 8117 if (flags & ExceptionFlags.overflow) 8118 decimal.data = D.MASK_INF; 8119 else if ((flags & ExceptionFlags.underflow) || coefficient == 0) 8120 decimal.data = D.MASK_ZERO; 8121 } 8122 } 8123 8124 if (isNegative) 8125 decimal.data |= D.MASK_SGN; 8126 return flags; 8127 } 8128 8129 D fromString(D, C)(const(C)[] s) 8130 if (isDecimal!D && isSomeChar!C) 8131 { 8132 Unqual!D result = void; 8133 auto flags = result.packString(s, 8134 __ctfe ? D.PRECISION : DecimalControl.precision, 8135 __ctfe ? RoundingMode.implicit: DecimalControl.rounding); 8136 DecimalControl.raiseFlags(flags); 8137 return result; 8138 } 8139 8140 8141 /* ****************************************************************************************************************** */ 8142 /* DECIMAL TO DECIMAL CONVERSION */ 8143 /* ****************************************************************************************************************** */ 8144 8145 ExceptionFlags decimalToDecimal(D1, D2)(auto const ref D1 source, out D2 target, 8146 const int precision, const RoundingMode mode) 8147 if (isDecimal!(D1, D2)) 8148 { 8149 DataType!D1 cx; int ex; bool sx; 8150 final switch(fastDecode(source, cx, ex, sx)) 8151 { 8152 case FastClass.finite: 8153 static if (D2.sizeof == D1.sizeof) 8154 { 8155 target.data = source.data; 8156 return ExceptionFlags.none; 8157 } 8158 else 8159 return target.adjustedPack(cx, ex, sx, precision, mode); 8160 case FastClass.zero: 8161 target = sx ? -D2.zero : D2.zero; 8162 return ExceptionFlags.none; 8163 case FastClass.infinite: 8164 target = sx ? -D2.infinity : D2.infinity; 8165 return ExceptionFlags.none; 8166 case FastClass.quietNaN: 8167 target = sx ? -D2.nan : D2.nan; 8168 return ExceptionFlags.none; 8169 case FastClass.signalingNaN: 8170 target = sx ? -D2.nan : D2.nan; 8171 return ExceptionFlags.invalidOperation; 8172 } 8173 } 8174 8175 ExceptionFlags decimalToUnsigned(D, T)(auto const ref D source, out T target, const RoundingMode mode) 8176 if (isDecimal!D && isUnsigned!T) 8177 { 8178 alias U = CommonStorage!(D, T); 8179 U cx; int ex; bool sx; 8180 final switch (fastDecode(source, cx, ex, sx)) 8181 { 8182 case FastClass.finite: 8183 auto flags = coefficientAdjust(cx, ex, 0, 0, U(T.max), sx, mode); 8184 if (flags & ExceptionFlags.overflow) 8185 { 8186 target = T(1) << (T.sizeof * 8 - 1); 8187 flags = ExceptionFlags.overflow | ExceptionFlags.invalidOperation; 8188 } 8189 else if (flags & ExceptionFlags.underflow) 8190 target = 0; 8191 else if (sx) 8192 { 8193 target = T(1) << (T.sizeof * 8 - 1); 8194 return ExceptionFlags.overflow | ExceptionFlags.invalidOperation; 8195 } 8196 else 8197 target = cast(T)cx; 8198 return flags; 8199 case FastClass.zero: 8200 target = 0; 8201 return ExceptionFlags.none; 8202 case FastClass.infinite: 8203 target = T(1) << (T.sizeof * 8 - 1); 8204 return ExceptionFlags.overflow | ExceptionFlags.invalidOperation; 8205 case FastClass.quietNaN: 8206 case FastClass.signalingNaN: 8207 target = T(1) << (T.sizeof * 8 - 1); 8208 return ExceptionFlags.invalidOperation; 8209 } 8210 } 8211 8212 ExceptionFlags decimalToSigned(D, T)(auto const ref D source, out T target, const RoundingMode mode) 8213 if (isDecimal!D && isSigned!T) 8214 { 8215 alias U = CommonStorage!(D, T); 8216 U cx; int ex; bool sx; 8217 final switch (fastDecode(source, cx, ex, sx)) 8218 { 8219 case FastClass.finite: 8220 U max = sx ? unsign!U(T.min) : unsign!U(T.max); 8221 auto flags = coefficientAdjust(cx, ex, 0, 0, max, sx, mode); 8222 if (flags & ExceptionFlags.overflow) 8223 { 8224 target = T.min; 8225 flags = ExceptionFlags.overflow | ExceptionFlags.invalidOperation; 8226 } 8227 else if (flags & ExceptionFlags.underflow) 8228 target = 0; 8229 else 8230 target = sign!T(cx, sx); 8231 return flags; 8232 case FastClass.zero: 8233 target = 0; 8234 return ExceptionFlags.none; 8235 case FastClass.infinite: 8236 target = T.min; 8237 return ExceptionFlags.overflow | ExceptionFlags.invalidOperation; 8238 case FastClass.quietNaN: 8239 case FastClass.signalingNaN: 8240 target = T.min; 8241 return ExceptionFlags.invalidOperation; 8242 } 8243 } 8244 8245 ExceptionFlags decimalToFloat(D, T)(auto const ref D source, out T target, const RoundingMode mode) 8246 if (isDecimal!D && isFloatingPoint!T) 8247 { 8248 DataType!D cx; int ex; bool sx; 8249 final switch (fastDecode(source, cx, ex, sx)) 8250 { 8251 case FastClass.finite: 8252 ExceptionFlags flags; 8253 static if (is(D: decimal128)) 8254 flags = coefficientAdjust(cx, ex, uint128(ulong.max), sx, mode); 8255 ulong m = cvt!ulong(cx); 8256 final switch (mode) 8257 { 8258 case RoundingMode.tiesToAway: 8259 flags |= exp10to2!(RoundingMode.tiesToAway)(m, ex, sx); 8260 break; 8261 case RoundingMode.tiesToEven: 8262 flags |= exp10to2!(RoundingMode.tiesToEven)(m, ex, sx); 8263 break; 8264 case RoundingMode.towardNegative: 8265 flags |= exp10to2!(RoundingMode.towardNegative)(m, ex, sx); 8266 break; 8267 case RoundingMode.towardPositive: 8268 flags |= exp10to2!(RoundingMode.towardPositive)(m, ex, sx); 8269 break; 8270 case RoundingMode.towardZero: 8271 flags |= exp10to2!(RoundingMode.towardZero)(m, ex, sx); 8272 break; 8273 } 8274 synchronized 8275 { 8276 FloatingPointControl fpctrl; 8277 auto savedExceptions = fpctrl.enabledExceptions; 8278 fpctrl.disableExceptions(FloatingPointControl.allExceptions); 8279 auto savedMode = fpctrl.rounding; 8280 switch (mode) 8281 { 8282 case RoundingMode.tiesToAway: 8283 case RoundingMode.tiesToEven: 8284 fpctrl.rounding = FloatingPointControl.roundToNearest; 8285 break; 8286 case RoundingMode.towardNegative: 8287 fpctrl.rounding = FloatingPointControl.roundDown; 8288 break; 8289 case RoundingMode.towardPositive: 8290 fpctrl.rounding = FloatingPointControl.roundUp; 8291 break; 8292 case RoundingMode.towardZero: 8293 fpctrl.rounding = FloatingPointControl.roundToZero; 8294 break; 8295 default: 8296 break; 8297 } 8298 resetIeeeFlags(); 8299 8300 real r = m; 8301 target = ldexp(r, ex); 8302 if (sx) 8303 target = -target; 8304 8305 if (ieeeFlags.inexact) 8306 flags |= ExceptionFlags.inexact; 8307 if (ieeeFlags.underflow) 8308 flags |= ExceptionFlags.underflow; 8309 if (ieeeFlags.overflow) 8310 flags |= ExceptionFlags.overflow; 8311 if (ieeeFlags.invalid) 8312 flags |= ExceptionFlags.invalidOperation; 8313 if (ieeeFlags.divByZero) 8314 flags |= ExceptionFlags.divisionByZero; 8315 fpctrl.enableExceptions(savedExceptions); 8316 } 8317 8318 return flags; 8319 case FastClass.zero: 8320 target = sx ? -0.0: 0.0; 8321 return ExceptionFlags.none; 8322 case FastClass.infinite: 8323 target = sx ? -T.infinity : T.infinity; 8324 return ExceptionFlags.none; 8325 case FastClass.quietNaN: 8326 case FastClass.signalingNaN: 8327 target = T.nan; 8328 return ExceptionFlags.none; 8329 } 8330 8331 8332 8333 } 8334 8335 /* ****************************************************************************************************************** */ 8336 /* DECIMAL ARITHMETIC */ 8337 /* ****************************************************************************************************************** */ 8338 8339 template CommonStorage(D, T) if (isDecimal!D && isDecimal!T) 8340 { 8341 static if (D.sizeof >= T.sizeof) 8342 alias CommonStorage = DataType!D; 8343 else 8344 alias CommonStorage = DataType!T; 8345 } 8346 8347 template CommonStorage(D, T) if (isDecimal!D && isIntegral!T) 8348 { 8349 static if (D.sizeof >= T.sizeof) 8350 alias CommonStorage = DataType!D; 8351 else 8352 alias CommonStorage = Unsigned!T; 8353 } 8354 8355 template CommonStorage(D, T) if (isDecimal!D && isFloatingPoint!T) 8356 { 8357 static if (is(Unqual!T == float)) 8358 alias CommonStorage = DataType!D; 8359 else 8360 alias CommonStorage = CommonStorage!(D, ulong); 8361 } 8362 8363 8364 @safe pure nothrow @nogc 8365 D canonical(D)(auto const ref D x) 8366 if (isDecimal!D) 8367 { 8368 Unqual!D result = x; 8369 canonicalize(result); 8370 return x; 8371 } 8372 8373 @safe pure nothrow @nogc 8374 void canonicalize(D)(ref D x) 8375 if (isDecimal!D) 8376 { 8377 if ((x.data & D.MASK_INF) == D.MASK_INF) 8378 { 8379 if ((x.data & D.MASK_QNAN) == D.MASK_QNAN) 8380 x.data &= D.MASK_SNAN | D.MASK_SGN | D.MASK_PAYL; 8381 else 8382 x.data &= D.MASK_INF | D.MASK_SGN; 8383 } 8384 else if ((x.data & D.MASK_EXT) == D.MASK_EXT && 8385 (((x.data & D.MASK_COE2) | D.MASK_COEX) > D.COEF_MAX)) 8386 x.data &= D.MASK_ZERO | D.MASK_SGN; 8387 else if ((x.data & D.MASK_COE1) == 0U) 8388 x.data &= D.MASK_ZERO | D.MASK_SGN; 8389 } 8390 8391 @safe pure nothrow @nogc 8392 void unsignalize(D)(ref D x) 8393 if (isDecimal!D) 8394 { 8395 x.data &= ~D.MASK_SNANBIT; 8396 } 8397 8398 @safe pure nothrow @nogc 8399 DecimalClass decimalDecode(D, T)(auto const ref D x, out T cx, out int ex, out bool sx) 8400 if (isDecimal!D && is(T: DataType!D)) 8401 { 8402 sx = cast(bool)(x.data & D.MASK_SGN); 8403 8404 if ((x.data & D.MASK_INF) == D.MASK_INF) 8405 if ((x.data & D.MASK_QNAN) == D.MASK_QNAN) 8406 if ((x.data & D.MASK_SNAN) == D.MASK_SNAN) 8407 return DecimalClass.signalingNaN; 8408 else 8409 return DecimalClass.quietNaN; 8410 else 8411 return sx ? DecimalClass.negativeInfinity : DecimalClass.positiveInfinity; 8412 else if ((x.data & D.MASK_EXT) == D.MASK_EXT) 8413 { 8414 cx = (x.data & D.MASK_COE2) | D.MASK_COEX; 8415 if (cx > D.COEF_MAX) 8416 { 8417 return sx ? DecimalClass.negativeZero : DecimalClass.positiveZero; 8418 } 8419 ex = cast(uint)((x.data & D.MASK_EXP2) >>> D.SHIFT_EXP2) - D.EXP_BIAS; 8420 } 8421 else 8422 { 8423 cx = x.data & D.MASK_COE1; 8424 if (cx == 0U || cx > D.COEF_MAX) 8425 { 8426 ex = 0; 8427 return sx ? DecimalClass.negativeZero : DecimalClass.positiveZero; 8428 } 8429 ex = cast(uint)((x.data & D.MASK_EXP1) >>> D.SHIFT_EXP1) - D.EXP_BIAS; 8430 } 8431 8432 if (ex + D.EXP_BIAS < D.PRECISION - 1) 8433 { 8434 if (prec(cx) < D.PRECISION - ex + D.EXP_BIAS) 8435 return sx ? DecimalClass.negativeSubnormal : DecimalClass.positiveSubnormal; 8436 } 8437 return sx ? DecimalClass.negativeNormal : DecimalClass.positiveNormal; 8438 } 8439 8440 enum FastClass 8441 { 8442 signalingNaN, 8443 quietNaN, 8444 infinite, 8445 zero, 8446 finite, 8447 } 8448 8449 @safe pure nothrow @nogc 8450 FastClass fastDecode(D, T)(auto const ref D x, out T cx, out int ex, out bool sx) 8451 if ((is(D: decimal32) || is(D: decimal64)) && isAnyUnsigned!T) 8452 { 8453 static assert (T.sizeof >= D.sizeof); 8454 8455 sx = cast(bool)(x.data & D.MASK_SGN); 8456 8457 if ((x.data & D.MASK_INF) == D.MASK_INF) 8458 if ((x.data & D.MASK_QNAN) == D.MASK_QNAN) 8459 { 8460 cx = x.data & D.MASK_PAYL; 8461 if (cx > D.PAYL_MAX) 8462 cx = 0U; 8463 if ((x.data & D.MASK_SNAN) == D.MASK_SNAN) 8464 return FastClass.signalingNaN; 8465 else 8466 return FastClass.quietNaN; 8467 8468 } 8469 else 8470 return FastClass.infinite; 8471 else if ((x.data & D.MASK_EXT) == D.MASK_EXT) 8472 { 8473 cx = (x.data & D.MASK_COE2) | D.MASK_COEX; 8474 if (cx > D.COEF_MAX) 8475 cx = 0U; 8476 ex = cast(uint)((x.data & D.MASK_EXP2) >>> D.SHIFT_EXP2) - D.EXP_BIAS; 8477 } 8478 else 8479 { 8480 cx = x.data & D.MASK_COE1; 8481 ex = cast(uint)((x.data & D.MASK_EXP1) >>> D.SHIFT_EXP1) - D.EXP_BIAS; 8482 } 8483 8484 return cx == 0U ? FastClass.zero : FastClass.finite; 8485 } 8486 8487 @safe pure nothrow @nogc 8488 FastClass fastDecode(D, T)(auto const ref D x, out T cx, out int ex, out bool sx) 8489 if (is(D: decimal128) && isAnyUnsigned!T) 8490 { 8491 static assert (T.sizeof >= D.sizeof); 8492 8493 sx = cast(bool)(x.data.hi & D.MASK_SGN.hi); 8494 8495 if ((x.data.hi & D.MASK_INF.hi) == D.MASK_INF.hi) 8496 if ((x.data.hi & D.MASK_QNAN.hi) == D.MASK_QNAN.hi) 8497 { 8498 cx = x.data & D.MASK_PAYL; 8499 if (cx > D.PAYL_MAX) 8500 cx = 0U; 8501 if ((x.data.hi & D.MASK_SNAN.hi) == D.MASK_SNAN.hi) 8502 return FastClass.signalingNaN; 8503 else 8504 return FastClass.quietNaN; 8505 } 8506 else 8507 return FastClass.infinite; 8508 else if ((x.data.hi & D.MASK_EXT.hi) == D.MASK_EXT.hi) 8509 { 8510 cx = 0U; 8511 ex = cast(uint)((x.data.hi & D.MASK_EXP2.hi) >>> (D.SHIFT_EXP2 - 64)) - D.EXP_BIAS; 8512 } 8513 else 8514 { 8515 cx = x.data & D.MASK_COE1; 8516 if (cx > D.COEF_MAX) 8517 cx = 0U; 8518 ex = cast(uint)((x.data.hi & D.MASK_EXP1.hi) >>> (D.SHIFT_EXP1 - 64)) - D.EXP_BIAS; 8519 } 8520 8521 return cx == 0U ? FastClass.zero : FastClass.finite; 8522 } 8523 8524 @safe pure nothrow @nogc 8525 FastClass fastDecode(F, T)(auto const ref F x, out T cx, out int ex, out bool sx, const RoundingMode mode, out ExceptionFlags flags) 8526 if (isFloatingPoint!F && isAnyUnsigned!T) 8527 { 8528 bool nan, inf; 8529 static if (is(Unqual!F == float)) 8530 { 8531 uint m; 8532 sx = funpack(x, ex, m, inf, nan); 8533 } 8534 else static if (is(Unqual!F == real) && real.mant_dig == 64) 8535 { 8536 ulong m; 8537 sx = runpack(x, ex, m, inf, nan); 8538 } 8539 else 8540 { 8541 ulong m; 8542 sx = dunpack(cast(double)x, ex, m, inf, nan); 8543 } 8544 8545 if (x == 0.0) 8546 return FastClass.zero; 8547 8548 if (inf) 8549 return FastClass.infinite; 8550 8551 if (nan) 8552 { 8553 cx = cvt!T(m); 8554 return FastClass.quietNaN; 8555 } 8556 8557 static if (is(F == float) && T.sizeof > uint.sizeof) 8558 alias U = uint; 8559 else static if (is(F == double) && T.sizeof > ulong.sizeof) 8560 alias U = ulong; 8561 else static if (is(F == real) && T.sizeof > uint128.sizeof) 8562 alias U = uint128; 8563 else static if (T.sizeof < typeof(m).sizeof) 8564 alias U = typeof(m); 8565 else 8566 alias U = T; 8567 8568 U u = m; 8569 8570 final switch(mode) 8571 { 8572 case RoundingMode.tiesToAway: 8573 flags = exp2to10!(RoundingMode.tiesToAway)(u, ex, sx); 8574 break; 8575 case RoundingMode.tiesToEven: 8576 flags = exp2to10!(RoundingMode.tiesToEven)(u, ex, sx); 8577 break; 8578 case RoundingMode.towardZero: 8579 flags = exp2to10!(RoundingMode.towardZero)(u, ex, sx); 8580 break; 8581 case RoundingMode.towardNegative: 8582 flags = exp2to10!(RoundingMode.towardNegative)(u, ex, sx); 8583 break; 8584 case RoundingMode.towardPositive: 8585 flags = exp2to10!(RoundingMode.towardPositive)(u, ex, sx); 8586 break; 8587 } 8588 8589 static if (T.sizeof < U.sizeof) 8590 { 8591 flags |= coefficientAdjust(u, ex, cvt!U(T.max), sx, mode); 8592 } 8593 8594 cx = cvt!T(u); 8595 return cx ? FastClass.finite : FastClass.zero; 8596 8597 } 8598 8599 @safe pure nothrow @nogc 8600 ExceptionFlags decimalInc(D)(ref D x, const int precision, const RoundingMode mode) 8601 { 8602 8603 DataType!D cx; int ex; bool sx; 8604 final switch(fastDecode(x, cx, ex, sx)) 8605 { 8606 case FastClass.finite: 8607 auto flags = coefficientAdd(cx, ex, sx, DataType!D(1U), 0, false, RoundingMode.implicit); 8608 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 8609 case FastClass.zero: 8610 x = D.one; 8611 return ExceptionFlags.none; 8612 case FastClass.quietNaN: 8613 case FastClass.infinite: 8614 return ExceptionFlags.none; 8615 case FastClass.signalingNaN: 8616 unsignalize(x); 8617 return ExceptionFlags.invalidOperation; 8618 } 8619 } 8620 8621 @safe pure nothrow @nogc 8622 ExceptionFlags decimalDec(D)(ref D x, const int precision, const RoundingMode mode) 8623 { 8624 DataType!D cx; int ex; bool sx; 8625 final switch(fastDecode(x, cx, ex, sx)) 8626 { 8627 case FastClass.finite: 8628 auto flags = coefficientAdd(cx, ex, sx, DataType!D(1U), 0, true, RoundingMode.implicit); 8629 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 8630 case FastClass.zero: 8631 x = -D.one; 8632 return ExceptionFlags.none; 8633 case FastClass.infinite: 8634 case FastClass.quietNaN: 8635 return ExceptionFlags.none; 8636 case FastClass.signalingNaN: 8637 unsignalize(x); 8638 return ExceptionFlags.invalidOperation; 8639 } 8640 } 8641 8642 @safe pure nothrow @nogc 8643 ExceptionFlags decimalRound(D)(ref D x, const int precision, const RoundingMode mode) 8644 if (isDecimal!D) 8645 { 8646 DataType!D cx; int ex; bool sx; 8647 final switch(fastDecode(x, cx, ex, sx)) 8648 { 8649 case FastClass.finite: 8650 auto flags = coefficientAdjust(cx, ex, 0, D.EXP_MAX, D.COEF_MAX, sx, mode); 8651 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 8652 case FastClass.zero: 8653 case FastClass.infinite: 8654 case FastClass.quietNaN: 8655 return ExceptionFlags.none; 8656 case FastClass.signalingNaN: 8657 unsignalize(x); 8658 return ExceptionFlags.invalidOperation; 8659 } 8660 } 8661 8662 @safe pure nothrow @nogc 8663 ExceptionFlags decimalAdjust(D)(ref D x, const int precision, const RoundingMode mode) 8664 { 8665 DataType!D cx; int ex; bool sx; 8666 final switch(fastDecode(x, cx, ex, sx)) 8667 { 8668 case FastClass.finite: 8669 return x.adjustedPack(cx, ex, sx, precision, mode, ExceptionFlags.none); 8670 case FastClass.zero: 8671 case FastClass.infinite: 8672 case FastClass.quietNaN: 8673 return ExceptionFlags.none; 8674 case FastClass.signalingNaN: 8675 unsignalize(x); 8676 return ExceptionFlags.invalidOperation; 8677 } 8678 } 8679 8680 @safe pure nothrow @nogc 8681 ExceptionFlags decimalNextUp(D)(ref D x) 8682 if (isDecimal!D) 8683 { 8684 DataType!D cx; int ex; bool sx; 8685 final switch(fastDecode(x, cx, ex, sx)) 8686 { 8687 case FastClass.finite: 8688 coefficientExpand(cx, ex); 8689 if (sx) 8690 --cx; 8691 else 8692 ++cx; 8693 return x.adjustedPack(cx, ex, sx, 0, RoundingMode.towardPositive, ExceptionFlags.none); 8694 case FastClass.zero: 8695 x.pack(DataType!D(1U), D.EXP_MIN, false); 8696 return ExceptionFlags.none; 8697 case FastClass.infinite: 8698 if (sx) 8699 x = -D.max; 8700 return ExceptionFlags.none; 8701 case FastClass.quietNaN: 8702 return ExceptionFlags.none; 8703 case FastClass.signalingNaN: 8704 unsignalize(x); 8705 return ExceptionFlags.invalidOperation; 8706 } 8707 } 8708 8709 @safe pure nothrow @nogc 8710 ExceptionFlags decimalNextDown(D)(ref D x) 8711 if (isDecimal!D) 8712 { 8713 DataType!D cx; int ex; bool sx; 8714 final switch(fastDecode(x, cx, ex, sx)) 8715 { 8716 case FastClass.finite: 8717 coefficientExpand(cx, ex); 8718 if (!sx) 8719 --cx; 8720 else 8721 ++cx; 8722 return x.adjustedPack(cx, ex, sx, 0, RoundingMode.towardNegative, ExceptionFlags.none); 8723 case FastClass.zero: 8724 x.pack(DataType!D(1U), D.EXP_MIN, true); 8725 return ExceptionFlags.none; 8726 case FastClass.infinite: 8727 if (!sx) 8728 x = D.max; 8729 return ExceptionFlags.none; 8730 case FastClass.quietNaN: 8731 return ExceptionFlags.none; 8732 case FastClass.signalingNaN: 8733 unsignalize(x); 8734 return ExceptionFlags.invalidOperation; 8735 } 8736 } 8737 8738 ExceptionFlags decimalMin(D1, D2, D)(auto const ref D1 x, auto const ref D2 y, out D z) 8739 if (isDecimal!(D1, D2, D) && is(D: CommonDecimal!(D1, D2))) 8740 { 8741 DataType!D cx, cy; int ex, ey; bool sx, sy; 8742 immutable fx = fastDecode(x, cx, ex, sx); 8743 immutable fy = fastDecode(y, cy, ey, sy); 8744 8745 if (fx == FastClass.signalingNaN) 8746 { 8747 z = copysign(D.nan, x); 8748 return ExceptionFlags.invalidOperation; 8749 } 8750 8751 if (fy == FastClass.signalingNaN) 8752 { 8753 if (fx == FastClass.quietNaN) 8754 z = copysign(D.nan, x); 8755 else 8756 z = copysign(D.nan, y); 8757 return ExceptionFlags.invalidOperation; 8758 } 8759 8760 if (fx == FastClass.quietNaN) 8761 { 8762 if (fy == FastClass.quietNaN) 8763 z = x; 8764 else 8765 z = y; 8766 return ExceptionFlags.none; 8767 } 8768 8769 if (fy == FastClass.quietNaN) 8770 { 8771 z = x; 8772 return ExceptionFlags.none; 8773 } 8774 8775 if (fx == FastClass.infinite) 8776 { 8777 if (sx) 8778 z = x; 8779 else 8780 z = y; 8781 return ExceptionFlags.none; 8782 } 8783 8784 if (fy == FastClass.infinite) 8785 { 8786 if (sy) 8787 z = y; 8788 else 8789 z = x; 8790 return ExceptionFlags.none; 8791 } 8792 8793 if (fx == FastClass.zero) 8794 { 8795 if (sy) 8796 z = y; 8797 else 8798 z = x; 8799 return ExceptionFlags.none; 8800 } 8801 8802 if (fy == FastClass.zero) 8803 { 8804 if (sx) 8805 z = x; 8806 else 8807 z = y; 8808 return ExceptionFlags.none; 8809 } 8810 8811 immutable c = coefficientCmp(cx, ex, sx, cy, ey, sy); 8812 if (c <= 0) 8813 z = x; 8814 else 8815 z = y; 8816 return ExceptionFlags.none; 8817 } 8818 8819 ExceptionFlags decimalMinAbs(D1, D2, D)(auto const ref D1 x, auto const ref D2 y, out D z) 8820 if (isDecimal!(D1, D2, D) && is(D: CommonDecimal!(D1, D2))) 8821 { 8822 DataType!D cx, cy; int ex, ey; bool sx, sy; 8823 immutable fx = fastDecode(x, cx, ex, sx); 8824 immutable fy = fastDecode(y, cy, ey, sy); 8825 8826 if (fx == FastClass.signalingNaN) 8827 { 8828 z = copysign(D.nan, x); 8829 return ExceptionFlags.invalidOperation; 8830 } 8831 8832 if (fy == FastClass.signalingNaN) 8833 { 8834 if (fx == FastClass.quietNaN) 8835 z = copysign(D.nan, x); 8836 else 8837 z = copysign(D.nan, y); 8838 return ExceptionFlags.invalidOperation; 8839 } 8840 8841 if (fx == FastClass.quietNaN) 8842 { 8843 if (fy == FastClass.quietNaN) 8844 z = x; 8845 else 8846 z = y; 8847 return ExceptionFlags.none; 8848 } 8849 8850 if (fy == FastClass.quietNaN) 8851 { 8852 z = x; 8853 return ExceptionFlags.none; 8854 } 8855 8856 if (fx == FastClass.infinite) 8857 { 8858 if (fy == FastClass.infinite && sx) 8859 z = x; 8860 else 8861 z = y; 8862 return ExceptionFlags.none; 8863 } 8864 8865 if (fy == FastClass.infinite) 8866 { 8867 z = x; 8868 return ExceptionFlags.none; 8869 } 8870 8871 if (fx == FastClass.zero) 8872 { 8873 z = x; 8874 return ExceptionFlags.none; 8875 } 8876 8877 if (fy == FastClass.zero) 8878 { 8879 z = y; 8880 return ExceptionFlags.none; 8881 } 8882 8883 immutable c = coefficientCmp(cx, ex, cy, ey); 8884 if (c < 0) 8885 z = x; 8886 else if (c == 0 && sx) 8887 z = x; 8888 else 8889 z = y; 8890 return ExceptionFlags.none; 8891 } 8892 8893 ExceptionFlags decimalMax(D1, D2, D)(auto const ref D1 x, auto const ref D2 y, out D z) 8894 if (isDecimal!(D1, D2, D) && is(D: CommonDecimal!(D1, D2))) 8895 { 8896 DataType!D cx, cy; int ex, ey; bool sx, sy; 8897 immutable fx = fastDecode(x, cx, ex, sx); 8898 immutable fy = fastDecode(y, cy, ey, sy); 8899 8900 if (fx == FastClass.signalingNaN) 8901 { 8902 z = copysign(D.nan, x); 8903 return ExceptionFlags.invalidOperation; 8904 } 8905 8906 if (fy == FastClass.signalingNaN) 8907 { 8908 if (fx == FastClass.quietNaN) 8909 z = copysign(D.nan, x); 8910 else 8911 z = copysign(D.nan, y); 8912 return ExceptionFlags.invalidOperation; 8913 } 8914 8915 if (fx == FastClass.quietNaN) 8916 { 8917 if (fy == FastClass.quietNaN) 8918 z = x; 8919 else 8920 z = y; 8921 return ExceptionFlags.none; 8922 } 8923 8924 if (fy == FastClass.quietNaN) 8925 { 8926 z = x; 8927 return ExceptionFlags.none; 8928 } 8929 8930 if (fx == FastClass.infinite) 8931 { 8932 if (sx) 8933 z = y; 8934 else 8935 z = x; 8936 return ExceptionFlags.none; 8937 } 8938 8939 if (fy == FastClass.infinite) 8940 { 8941 if (sy) 8942 z = x; 8943 else 8944 z = y; 8945 return ExceptionFlags.none; 8946 } 8947 8948 if (fx == FastClass.zero) 8949 { 8950 if (sy) 8951 z = x; 8952 else 8953 z = y; 8954 return ExceptionFlags.none; 8955 } 8956 8957 if (fy == FastClass.zero) 8958 { 8959 if (sx) 8960 z = y; 8961 else 8962 z = x; 8963 return ExceptionFlags.none; 8964 } 8965 8966 immutable c = coefficientCmp(cx, ex, sx, cy, ey, sy); 8967 if (c >= 0) 8968 z = x; 8969 else 8970 z = y; 8971 return ExceptionFlags.none; 8972 } 8973 8974 ExceptionFlags decimalMaxAbs(D1, D2, D)(auto const ref D1 x, auto const ref D2 y, out D z) 8975 if (isDecimal!(D1, D2, D) && is(D: CommonDecimal!(D1, D2))) 8976 { 8977 DataType!D cx, cy; int ex, ey; bool sx, sy; 8978 immutable fx = fastDecode(x, cx, ex, sx); 8979 immutable fy = fastDecode(y, cy, ey, sy); 8980 8981 if (fx == FastClass.signalingNaN) 8982 { 8983 z = copysign(D.nan, x); 8984 return ExceptionFlags.invalidOperation; 8985 } 8986 8987 if (fy == FastClass.signalingNaN) 8988 { 8989 if (fx == FastClass.quietNaN) 8990 z = copysign(D.nan, x); 8991 else 8992 z = copysign(D.nan, y); 8993 return ExceptionFlags.invalidOperation; 8994 } 8995 8996 if (fx == FastClass.quietNaN) 8997 { 8998 if (fy == FastClass.quietNaN) 8999 z = x; 9000 else 9001 z = y; 9002 return ExceptionFlags.none; 9003 } 9004 9005 if (fy == FastClass.quietNaN) 9006 { 9007 z = x; 9008 return ExceptionFlags.none; 9009 } 9010 9011 if (fx == FastClass.infinite) 9012 { 9013 if (!sx || fy != FastClass.infinite) 9014 z = x; 9015 else 9016 z = y; 9017 return ExceptionFlags.none; 9018 } 9019 9020 if (fy == FastClass.infinite) 9021 { 9022 z = y; 9023 return ExceptionFlags.none; 9024 } 9025 9026 if (fx == FastClass.zero) 9027 { 9028 z = y; 9029 return ExceptionFlags.none; 9030 } 9031 9032 if (fy == FastClass.zero) 9033 { 9034 z = x; 9035 return ExceptionFlags.none; 9036 } 9037 9038 immutable c = coefficientCmp(cx, ex, cy, ey); 9039 if (c > 0) 9040 z = x; 9041 else if (c == 0 && !sx) 9042 z = x; 9043 else 9044 z = y; 9045 return ExceptionFlags.none; 9046 } 9047 9048 @safe pure nothrow @nogc 9049 ExceptionFlags decimalQuantize(D1, D2)(ref D1 x, auto const ref D2 y, const int precision, const RoundingMode mode) 9050 if (isDecimal!(D1, D2)) 9051 { 9052 alias U = CommonStorage!(D1, D2); 9053 U cx, cy; int ex, ey; bool sx, sy; 9054 immutable fx = fastDecode(x, cx, ex, sx); 9055 immutable fy = fastDecode(y, cy, ey, sy); 9056 9057 if (fx == FastClass.signalingNaN) 9058 { 9059 unsignalize(x); 9060 return ExceptionFlags.invalidOperation; 9061 } 9062 9063 if (fy == FastClass.signalingNaN) 9064 { 9065 x = D1.nan; 9066 return ExceptionFlags.invalidOperation; 9067 } 9068 9069 if (fx == FastClass.quietNaN) 9070 return ExceptionFlags.none; 9071 9072 if (fy == FastClass.quietNaN) 9073 { 9074 x = D1.nan; 9075 return ExceptionFlags.none; 9076 } 9077 9078 if (fx == FastClass.infinite) 9079 { 9080 if (fy == FastClass.infinite) 9081 return ExceptionFlags.none; 9082 x = D1.nan; 9083 return ExceptionFlags.invalidOperation; 9084 } 9085 9086 if (fy == FastClass.infinite) 9087 { 9088 x = D1.nan; 9089 return ExceptionFlags.invalidOperation; 9090 } 9091 9092 auto flags = coefficientAdjust(cx, ex, ey, ey, cvt!U(D1.COEF_MAX), sx, mode); 9093 if (flags & ExceptionFlags.overflow) 9094 flags = ExceptionFlags.invalidOperation; 9095 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 9096 9097 } 9098 9099 @safe pure nothrow @nogc 9100 ExceptionFlags decimalScale(D)(ref D x, const int n, const int precision, const RoundingMode mode) 9101 if (isDecimal!D) 9102 { 9103 DataType!D cx; int ex; bool sx; 9104 final switch(fastDecode(x, cx, ex, sx)) 9105 { 9106 case FastClass.finite: 9107 if (!n) 9108 return ExceptionFlags.none; 9109 auto remainder = cappedAdd(ex, n) - n; 9110 ExceptionFlags flags; 9111 if (remainder) 9112 { 9113 if (remainder < 0) 9114 coefficientShrink(cx, ex); 9115 else 9116 coefficientExpand(cx, ex); 9117 if (cappedAdd(ex, remainder) != remainder) 9118 flags = ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow; 9119 } 9120 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 9121 case FastClass.zero: 9122 case FastClass.infinite: 9123 case FastClass.quietNaN: 9124 return ExceptionFlags.none; 9125 case FastClass.signalingNaN: 9126 unsignalize(x); 9127 return ExceptionFlags.invalidOperation; 9128 } 9129 } 9130 9131 9132 @safe pure nothrow @nogc 9133 ExceptionFlags decimalMulPow2(D)(ref D x, const int n, const int precision, const RoundingMode mode) 9134 if (isDecimal!D) 9135 { 9136 DataType!D cx; int ex; bool sx; 9137 final switch(fastDecode(x, cx, ex, sx)) 9138 { 9139 case FastClass.finite: 9140 if (!n) 9141 return ExceptionFlags.none; 9142 DataType!D cy = 1U; 9143 int ey = n; 9144 ExceptionFlags flags; 9145 final switch(mode) 9146 { 9147 case RoundingMode.tiesToAway: 9148 flags = exp2to10!(RoundingMode.tiesToAway)(cy, ey, false); 9149 break; 9150 case RoundingMode.tiesToEven: 9151 flags = exp2to10!(RoundingMode.tiesToEven)(cy, ey, false); 9152 break; 9153 case RoundingMode.towardZero: 9154 flags = exp2to10!(RoundingMode.towardZero)(cy, ey, false); 9155 break; 9156 case RoundingMode.towardNegative: 9157 flags = exp2to10!(RoundingMode.towardNegative)(cy, ey, false); 9158 break; 9159 case RoundingMode.towardPositive: 9160 flags = exp2to10!(RoundingMode.towardPositive)(cy, ey, false); 9161 break; 9162 } 9163 flags |= coefficientMul(cx, ex, sx, cy, ey, false, mode); 9164 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 9165 case FastClass.zero: 9166 case FastClass.infinite: 9167 case FastClass.quietNaN: 9168 return ExceptionFlags.none; 9169 case FastClass.signalingNaN: 9170 unsignalize(x); 9171 return ExceptionFlags.invalidOperation; 9172 } 9173 } 9174 9175 @safe pure nothrow @nogc 9176 ExceptionFlags decimalLog(D)(auto const ref D x, out int y) 9177 if (isDecimal!D) 9178 { 9179 DataType!D cx; int ex; bool sx; 9180 final switch(fastDecode(x, cx, ex, sx)) 9181 { 9182 case FastClass.finite: 9183 y = prec(cx) + ex - 1; 9184 return ExceptionFlags.none; 9185 case FastClass.zero: 9186 y = int.min; 9187 return ExceptionFlags.invalidOperation; 9188 case FastClass.infinite: 9189 y = int.max; 9190 return ExceptionFlags.invalidOperation; 9191 case FastClass.quietNaN: 9192 case FastClass.signalingNaN: 9193 y = int.min; 9194 return ExceptionFlags.invalidOperation; 9195 } 9196 } 9197 9198 @safe pure nothrow @nogc 9199 ExceptionFlags decimalMul(D1, D2)(ref D1 x, auto const ref D2 y, const int precision, const RoundingMode mode) 9200 if (isDecimal!(D1, D2)) 9201 { 9202 alias D = CommonDecimal!(D1, D2); 9203 alias T = DataType!D; 9204 alias T1 = DataType!D1; 9205 9206 T cx, cy; int ex, ey; bool sx, sy; 9207 9208 immutable fx = fastDecode(x, cx, ex, sx); 9209 immutable fy = fastDecode(y, cy, ey, sy); 9210 9211 if (fx == FastClass.signalingNaN || fy == FastClass.signalingNaN) 9212 { 9213 x = sx ^ sy ? -D1.nan : D1.nan; 9214 return ExceptionFlags.invalidOperation; 9215 } 9216 9217 if (fx == FastClass.quietNaN || fy == FastClass.quietNaN) 9218 { 9219 x = sx ^ sy ? -D1.nan : D1.nan; 9220 return ExceptionFlags.none; 9221 } 9222 9223 if (fx == FastClass.infinite) 9224 { 9225 if (fy == FastClass.zero) 9226 { 9227 x = sx ^ sy ? -D1.nan : D1.nan; 9228 return ExceptionFlags.invalidOperation; 9229 } 9230 x = sx ^ sy ? -D1.infinity : D1.infinity; 9231 return ExceptionFlags.none; 9232 } 9233 9234 if (fy == FastClass.infinite) 9235 { 9236 if (fx == FastClass.zero) 9237 { 9238 x = sx ^ sy ? -D1.nan : D1.nan; 9239 return ExceptionFlags.invalidOperation; 9240 } 9241 x = sx ^ sy ? -D1.infinity : D1.infinity; 9242 return ExceptionFlags.none; 9243 } 9244 9245 if (fx == FastClass.zero || fy == FastClass.zero) 9246 { 9247 x = sx ^ sy ? -D1.zero : D1.zero; 9248 return ExceptionFlags.none; 9249 } 9250 9251 auto flags = coefficientMul(cx, ex, sx, cy, ey, sy, mode); 9252 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 9253 } 9254 9255 @safe pure nothrow @nogc 9256 ExceptionFlags decimalMul(D, T)(ref D x, auto const ref T y, const int precision, const RoundingMode mode) 9257 if (isDecimal!D && isIntegral!T) 9258 { 9259 alias U = CommonStorage!(D, T); 9260 alias X = DataType!D; 9261 U cx; int ex; bool sx; 9262 bool sy; 9263 U cy = unsign!U(y, sy); 9264 final switch(fastDecode(x, cx, ex, sx)) 9265 { 9266 case FastClass.finite: 9267 if (!y) 9268 { 9269 x = sx ^ sy ? -D.zero : D.zero; 9270 return ExceptionFlags.none; 9271 } 9272 auto flags = coefficientMul(cx, ex, sx, cy, 0, sy, RoundingMode.implicit); 9273 flags |= coefficientAdjust(cx, ex, cvt!U(X.max), sx, RoundingMode.implicit); 9274 return x.adjustedPack(cvt!X(cx), ex, sx, precision, mode, flags); 9275 case FastClass.zero: 9276 x = sx ^ sy ? -D.zero : D.zero; 9277 return ExceptionFlags.none; 9278 case FastClass.infinite: 9279 if (!y) 9280 { 9281 x = sx ^ sy ? -D.nan : D.nan; 9282 return ExceptionFlags.invalidOperation; 9283 } 9284 return ExceptionFlags.none; 9285 case FastClass.quietNaN: 9286 return ExceptionFlags.none; 9287 case FastClass.signalingNaN: 9288 unsignalize(x); 9289 return ExceptionFlags.invalidOperation; 9290 } 9291 } 9292 9293 @safe pure nothrow @nogc 9294 ExceptionFlags decimalMul(D, F)(ref D x, auto const ref F y, const int precision, const RoundingMode mode) 9295 if (isDecimal!D && isFloatingPoint!F) 9296 { 9297 alias T = CommonStorage!(D, F); 9298 9299 T cx, cy; int ex, ey; bool sx, sy; 9300 ExceptionFlags flags; 9301 immutable fx = fastDecode(x, cx, ex, sx); 9302 immutable fy = fastDecode(y, cy, ey, sy, mode, flags); 9303 9304 if (fx == FastClass.signalingNaN) 9305 { 9306 x = sx ^ sy ? -D.nan : D.nan; 9307 return ExceptionFlags.invalidOperation; 9308 } 9309 9310 if (fx == FastClass.quietNaN || fy == FastClass.quietNaN) 9311 { 9312 x = sx ^ sy ? -D.nan : D.nan; 9313 return ExceptionFlags.none; 9314 } 9315 9316 if (fx == FastClass.infinite) 9317 { 9318 if (fy == FastClass.zero) 9319 { 9320 x = sx ^ sy ? -D.nan : D.nan; 9321 return ExceptionFlags.invalidOperation; 9322 } 9323 x = sx ^ sy ? -D.infinity : D.infinity; 9324 return ExceptionFlags.none; 9325 } 9326 9327 if (fy == FastClass.infinite) 9328 { 9329 if (fx == FastClass.zero) 9330 { 9331 x = sx ^ sy ? -D.nan : D.nan; 9332 return ExceptionFlags.invalidOperation; 9333 } 9334 x = sx ^ sy ? -D.infinity : D.infinity; 9335 return ExceptionFlags.none; 9336 } 9337 9338 if (fx == FastClass.zero || fy == FastClass.zero) 9339 { 9340 x = sx ^ sy ? -D.zero : D.zero; 9341 return ExceptionFlags.none; 9342 } 9343 flags |= coefficientAdjust(cy, ey, realFloatPrecision!F(0), sy, mode); 9344 flags |= coefficientMul(cx, ex, sx, cy, ey, sy, mode); 9345 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 9346 } 9347 9348 @safe pure nothrow @nogc 9349 ExceptionFlags decimalMul(T, D)(auto const ref T x, auto const ref D y, out D z, const int precision, const RoundingMode mode) 9350 if (isDecimal!D && isIntegral!T) 9351 { 9352 z = y; 9353 return decimalMul(z, x, precision, mode); 9354 } 9355 9356 @safe pure nothrow @nogc 9357 ExceptionFlags decimalMul(F, D)(auto const ref F x, auto const ref D y, out D z, const int precision, const RoundingMode mode) 9358 if (isDecimal!D && isFloatingPoint!F) 9359 { 9360 z = y; 9361 return decimalMul(z, x, precision, mode); 9362 } 9363 9364 @safe pure nothrow @nogc 9365 ExceptionFlags decimalDiv(D1, D2)(ref D1 x, auto const ref D2 y, const int precision, const RoundingMode mode) 9366 if (isDecimal!(D1, D2)) 9367 { 9368 alias D = CommonDecimal!(D1, D2); 9369 alias T = DataType!D; 9370 alias T1 = DataType!D1; 9371 9372 T cx, cy; int ex, ey; bool sx, sy; 9373 9374 immutable fx = fastDecode(x, cx, ex, sx); 9375 immutable fy = fastDecode(y, cy, ey, sy); 9376 9377 if (fx == FastClass.signalingNaN || fy == FastClass.signalingNaN) 9378 { 9379 x = sx ^ sy ? -D1.nan : D1.nan; 9380 return ExceptionFlags.invalidOperation; 9381 } 9382 9383 if (fx == FastClass.quietNaN || fy == FastClass.quietNaN) 9384 { 9385 x = sx ^ sy ? -D1.nan : D1.nan; 9386 return ExceptionFlags.none; 9387 } 9388 9389 if (fx == FastClass.infinite) 9390 { 9391 if (fy == FastClass.infinite) 9392 { 9393 x = sx ^ sy ? -D1.nan : D1.nan; 9394 return ExceptionFlags.invalidOperation; 9395 } 9396 x = sx ^ sy ? -D1.infinity : D1.infinity; 9397 return ExceptionFlags.none; 9398 } 9399 9400 9401 9402 if (fx == FastClass.zero) 9403 { 9404 if (fy == FastClass.zero) 9405 { 9406 x = sx ^ sy ? -D1.nan : D1.nan; 9407 return ExceptionFlags.invalidOperation; 9408 } 9409 9410 x = sx ^ sy ? -D1.zero : D1.zero; 9411 return ExceptionFlags.none; 9412 } 9413 9414 if (fy == FastClass.infinite) 9415 { 9416 x = sx ^ sy ? -D1.zero : D1.zero; 9417 return ExceptionFlags.none; 9418 } 9419 9420 if (fy == FastClass.zero) 9421 { 9422 x = sx ^ sy ? -D1.infinity : D1.infinity; 9423 return ExceptionFlags.divisionByZero; 9424 } 9425 9426 auto flags = coefficientDiv(cx, ex, sx, cy, ey, sy, RoundingMode.implicit); 9427 flags |= coefficientAdjust(cx, ex, cvt!T(T1.max), sx, RoundingMode.implicit); 9428 return x.adjustedPack(cvt!T1(cx), ex, sx, precision, mode, flags); 9429 } 9430 9431 @safe pure nothrow @nogc 9432 ExceptionFlags decimalDiv(D, T)(ref D x, auto const ref T y, const int precision, const RoundingMode mode) 9433 if (isDecimal!D && isIntegral!T) 9434 { 9435 alias U = CommonStorage!(D, T); 9436 U cx; int ex; bool sx; 9437 bool sy; 9438 U cy = unsign!U(y, sy); 9439 final switch (fastDecode(x, cx, ex, sx)) 9440 { 9441 case FastClass.finite: 9442 if (!y) 9443 { 9444 x = sx ^ sy ? -D.infinity : D.infinity; 9445 return ExceptionFlags.divisionByZero; 9446 } 9447 auto flags = coefficientDiv(cx, ex, sx, cy, 0, sy, mode); 9448 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 9449 case FastClass.zero: 9450 x = sx ^ sy ? -D.zero : D.zero; 9451 return ExceptionFlags.none; 9452 case FastClass.infinite: 9453 if (!y) 9454 { 9455 x = sx ^ sy ? -D.nan : D.nan; 9456 return ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero; 9457 } 9458 return ExceptionFlags.none; 9459 case FastClass.quietNaN: 9460 return ExceptionFlags.none; 9461 case FastClass.signalingNaN: 9462 unsignalize(x); 9463 return ExceptionFlags.invalidOperation; 9464 } 9465 } 9466 9467 @safe pure nothrow @nogc 9468 ExceptionFlags decimalDiv(T, D)(auto const ref T x, auto const ref D y, out D z, const int precision, const RoundingMode mode) 9469 if (isDecimal!D && isIntegral!T) 9470 { 9471 alias U = CommonStorage!(D, T); 9472 U cy; int ey; bool sy; 9473 int ex = 0; 9474 bool sx; 9475 U cx = unsign!U(x, sx); 9476 final switch (fastDecode(y, cy, ey, sy)) 9477 { 9478 case FastClass.finite: 9479 auto flags = coefficientDiv(cx, ex, sx, cy, 0, sy, RoundingMode.implicit); 9480 flags |= coefficientAdjust(cx, ex, cvt!U(DataType!D.max), sx, RoundingMode.implicit); 9481 return z.adjustedPack(cvt!(DataType!D)(cx), ex, sx, precision, mode, flags); 9482 case FastClass.zero: 9483 z = sx ^ sy ? -D.infinity : D.infinity; 9484 return ExceptionFlags.divisionByZero; 9485 case FastClass.infinite: 9486 z = y; 9487 return ExceptionFlags.none; 9488 case FastClass.quietNaN: 9489 z = sx ^ sy ? -D.nan : D.nan; 9490 return ExceptionFlags.none; 9491 case FastClass.signalingNaN: 9492 z = sx ^ sy ? -D.nan : D.nan; 9493 return ExceptionFlags.invalidOperation; 9494 } 9495 } 9496 9497 @safe pure nothrow @nogc 9498 ExceptionFlags decimalDiv(D, F)(ref D x, auto const ref F y, const int precision, const RoundingMode mode) 9499 if (isDecimal!D && isFloatingPoint!F) 9500 { 9501 alias T = CommonStorage!(D, F); 9502 9503 T cx, cy; int ex, ey; bool sx, sy; 9504 9505 ExceptionFlags flags; 9506 immutable fx = fastDecode(x, cx, ex, sx); 9507 immutable fy = fastDecode(y, cy, ey, sy, mode, flags); 9508 9509 if (fx == FastClass.signalingNaN) 9510 { 9511 x = sx ^ sy ? -D.nan : D.nan; 9512 return ExceptionFlags.invalidOperation; 9513 } 9514 9515 if (fx == FastClass.quietNaN || fy == FastClass.quietNaN) 9516 { 9517 x = sx ^ sy ? -D.nan : D.nan; 9518 return ExceptionFlags.none; 9519 } 9520 9521 if (fx == FastClass.infinite) 9522 { 9523 if (fy == FastClass.zero) 9524 { 9525 x = sx ^ sy ? -D.nan : D.nan; 9526 return ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero; 9527 } 9528 9529 if (fy == FastClass.infinite) 9530 { 9531 x = sx ^ sy ? -D.nan : D.nan; 9532 return ExceptionFlags.invalidOperation; 9533 } 9534 x = sx ^ sy ? -D.infinity : D.infinity; 9535 return ExceptionFlags.none; 9536 } 9537 9538 if (fy == FastClass.infinite) 9539 { 9540 x = sx ^ sy ? -D.infinity : D.infinity; 9541 return ExceptionFlags.none; 9542 } 9543 9544 if (fx == FastClass.zero) 9545 { 9546 x = sx ^ sy ? -D.zero : D.zero; 9547 return ExceptionFlags.none; 9548 } 9549 9550 if (fy == FastClass.zero) 9551 { 9552 x = sx ^ sy ? -D.infinity : D.infinity; 9553 return ExceptionFlags.divisionByZero; 9554 } 9555 9556 flags |= coefficientAdjust(cy, ey, realFloatPrecision!F(0), sy, mode); 9557 flags |= coefficientDiv(cx, ex, sx, cy, ey, sy, mode); 9558 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 9559 } 9560 9561 @safe pure nothrow @nogc 9562 ExceptionFlags decimalDiv(F, D)(auto const ref F x, auto const ref D y, out D z, const int precision, const RoundingMode mode) 9563 if (isDecimal!D && isFloatingPoint!F) 9564 { 9565 alias T = CommonStorage!(D, F); 9566 9567 T cx, cy; int ex, ey; bool sx, sy; 9568 ExceptionFlags flags; 9569 immutable fx = fastDecode(x, cx, ex, sx, mode, flags); 9570 immutable fy = fastDecode(y, cy, ey, sy); 9571 9572 if (fy == FastClass.signalingNaN) 9573 { 9574 z = sx ^ sy ? -D.nan : D.nan; 9575 return ExceptionFlags.invalidOperation; 9576 } 9577 9578 if (fx == FastClass.quietNaN || fy == FastClass.quietNaN) 9579 { 9580 z = sx ^ sy ? -D.nan : D.nan; 9581 return ExceptionFlags.none; 9582 } 9583 9584 if (fx == FastClass.infinite) 9585 { 9586 if (fy == FastClass.zero) 9587 { 9588 z = sx ^ sy ? -D.nan : D.nan; 9589 return ExceptionFlags.invalidOperation | ExceptionFlags.divisionByZero; 9590 } 9591 9592 if (fy == FastClass.infinite) 9593 { 9594 z = sx ^ sy ? -D.nan : D.nan; 9595 return ExceptionFlags.invalidOperation; 9596 } 9597 z = sx ^ sy ? -D.infinity : D.infinity; 9598 return ExceptionFlags.none; 9599 } 9600 9601 if (fy == FastClass.infinite) 9602 { 9603 z = sx ^ sy ? -D.infinity : D.infinity; 9604 return ExceptionFlags.none; 9605 } 9606 9607 if (fx == FastClass.zero) 9608 { 9609 z = sx ^ sy ? -D.zero : D.zero; 9610 return ExceptionFlags.none; 9611 } 9612 9613 if (fy == FastClass.zero) 9614 { 9615 z = sx ^ sy ? -D.infinity : D.infinity; 9616 return ExceptionFlags.divisionByZero; 9617 } 9618 flags |= coefficientAdjust(cx, ex, realFloatPrecision!F(0), sx, mode); 9619 flags |= coefficientDiv(cx, ex, sx, cy, ey, sy, mode); 9620 return z.adjustedPack(cx, ex, sx, precision, mode, flags); 9621 } 9622 9623 @safe pure nothrow @nogc 9624 ExceptionFlags decimalAdd(D1, D2)(ref D1 x, auto const ref D2 y, const int precision, const RoundingMode mode) 9625 if (isDecimal!(D1, D2)) 9626 { 9627 alias D = CommonDecimal!(D1, D2); 9628 alias T = DataType!D; 9629 alias T1 = DataType!D1; 9630 9631 T cx, cy; int ex, ey; bool sx, sy; 9632 9633 immutable fx = fastDecode(x, cx, ex, sx); 9634 immutable fy = fastDecode(y, cy, ey, sy); 9635 9636 if (fx == FastClass.signalingNaN) 9637 { 9638 x = sx ? -D1.nan : D1.nan; 9639 return ExceptionFlags.invalidOperation; 9640 } 9641 9642 if (fy == FastClass.signalingNaN) 9643 { 9644 x = sy && (fx == FastClass.quietNaN ? sx : true) ? -D1.nan : D1.nan; 9645 return ExceptionFlags.invalidOperation; 9646 } 9647 9648 if (fx == FastClass.quietNaN) 9649 return ExceptionFlags.none; 9650 9651 if (fy == FastClass.quietNaN) 9652 { 9653 x = sy ? -D1.nan : D1.nan; 9654 return ExceptionFlags.none; 9655 } 9656 9657 if (fx == FastClass.infinite) 9658 { 9659 if (fy == FastClass.infinite && sx != sy) 9660 { 9661 x = D1.nan; 9662 return ExceptionFlags.invalidOperation; 9663 } 9664 return ExceptionFlags.none; 9665 } 9666 9667 if (fy == FastClass.infinite) 9668 { 9669 x = sy ? -D1.infinity : D1.infinity; 9670 return ExceptionFlags.none; 9671 } 9672 9673 if (fx == FastClass.zero) 9674 { 9675 if (fy == FastClass.zero) 9676 { 9677 x = (mode == RoundingMode.towardNegative && sx != sy) || (sx && sy) ? -D1.zero : D1.zero; 9678 return ExceptionFlags.none; 9679 } 9680 return decimalToDecimal(y, x, precision, mode); 9681 } 9682 9683 if (fy == FastClass.zero) 9684 return ExceptionFlags.none; 9685 9686 ExceptionFlags flags = coefficientAdd(cx, ex, sx, cy, ey, sy, mode); 9687 flags = x.adjustedPack(cx, ex, sx, precision, mode, flags); 9688 if (isZero(x)) 9689 x = (mode == RoundingMode.towardNegative && sx != sy) || (sx && sy) ? -D1.zero : D1.zero; 9690 return flags; 9691 } 9692 9693 @safe pure nothrow @nogc 9694 ExceptionFlags decimalAdd(D, T)(ref D x, auto const ref T y, const int precision, const RoundingMode mode) 9695 if (isDecimal!D && isIntegral!T) 9696 { 9697 alias U = CommonStorage!(D, T); 9698 alias X = DataType!D; 9699 U cx; int ex; bool sx; 9700 final switch(fastDecode(x, cx, ex, sx)) 9701 { 9702 case FastClass.finite: 9703 if (!y) 9704 return ExceptionFlags.none; 9705 bool sy; 9706 U cy = unsign!U(y, sy); 9707 auto flags = coefficientAdd(cx, ex, sx, cy, 0, sy, RoundingMode.implicit); 9708 flags |= coefficientAdjust(cx, ex, cvt!U(X.max), sx, RoundingMode.implicit); 9709 return x.adjustedPack(cvt!X(cx), ex, sx, precision, mode, flags); 9710 case FastClass.zero: 9711 return x.packIntegral(y, precision, mode); 9712 case FastClass.infinite: 9713 case FastClass.quietNaN: 9714 return ExceptionFlags.none; 9715 case FastClass.signalingNaN: 9716 unsignalize(x); 9717 return ExceptionFlags.invalidOperation; 9718 } 9719 } 9720 9721 int realFloatPrecision(F)(const int precision) 9722 { 9723 static if (is(F == float)) 9724 return precision == 0 ? 9 : (precision > 9 ? 9 : precision); 9725 else static if (is(F == float)) 9726 return precision == 0 ? 17 : (precision > 17 ? 17 : precision); 9727 else 9728 return precision == 0 ? 21 : (precision > 21 ? 21 : precision); 9729 } 9730 9731 @safe pure nothrow @nogc 9732 ExceptionFlags decimalAdd(D, F)(ref D x, auto const ref F y, const int precision, const RoundingMode mode) 9733 if (isDecimal!D && isFloatingPoint!F) 9734 { 9735 alias T = CommonStorage!(D, F); 9736 alias X = DataType!D; 9737 9738 T cx, cy; int ex, ey; bool sx, sy; 9739 ExceptionFlags flags; 9740 immutable fx = fastDecode(x, cx, ex, sx); 9741 immutable fy = fastDecode(y, cy, ey, sy, mode, flags); 9742 9743 if (fx == FastClass.signalingNaN) 9744 { 9745 x = sy ? -D.nan : D.nan; 9746 return ExceptionFlags.invalidOperation; 9747 } 9748 9749 if (fx == FastClass.quietNaN) 9750 return ExceptionFlags.none; 9751 9752 if (fy == FastClass.quietNaN) 9753 { 9754 x = sy ? -D.nan : D.nan; 9755 return ExceptionFlags.invalidOperation; 9756 } 9757 9758 if (fx == FastClass.infinite) 9759 { 9760 if (fy == FastClass.infinite && sx != sy) 9761 { 9762 x = sx ? -D.nan : D.nan; 9763 return ExceptionFlags.invalidOperation; 9764 } 9765 return ExceptionFlags.none; 9766 } 9767 9768 if (fy == FastClass.infinite) 9769 { 9770 x = sy ? -D.infinity : D.infinity; 9771 return ExceptionFlags.none; 9772 } 9773 9774 if (fx == FastClass.zero) 9775 return x.adjustedPack(cy, ey, sy, realFloatPrecision!F(precision), mode, flags); 9776 9777 if (fy == FastClass.zero) 9778 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 9779 9780 flags |= coefficientAdjust(cy, ey, realFloatPrecision!F(0), sy, mode); 9781 flags |= coefficientAdd(cx, ex, sx, cy, ey, sy, mode); 9782 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 9783 } 9784 9785 @safe pure nothrow @nogc 9786 ExceptionFlags decimalAdd(T, D)(auto const ref T x, auto const ref D y, out D z, const int precision, const RoundingMode mode) 9787 if (isDecimal!D && isIntegral!T) 9788 { 9789 z = y; 9790 return decimalAdd(z, x, precision, mode); 9791 } 9792 9793 @safe pure nothrow @nogc 9794 ExceptionFlags decimalAdd(F, D)(auto const ref F x, auto const ref D y, out D z, const int precision, const RoundingMode mode) 9795 if (isDecimal!D && isFloatingPoint!F) 9796 { 9797 z = y; 9798 return decimalAdd(z, x, precision, mode); 9799 } 9800 9801 @safe pure nothrow @nogc 9802 ExceptionFlags decimalSub(D1, D2)(ref D1 x, auto const ref D2 y, const int precision, const RoundingMode mode) 9803 if (isDecimal!(D1, D2)) 9804 { 9805 return decimalAdd(x, -y, precision, mode); 9806 } 9807 9808 @safe pure nothrow @nogc 9809 ExceptionFlags decimalSub(D, T)(ref D x, auto const ref T y, const int precision, const RoundingMode mode) 9810 if (isDecimal!D && isIntegral!T) 9811 { 9812 alias U = CommonStorage!(D, T); 9813 alias X = DataType!D; 9814 U cx; int ex; bool sx; 9815 final switch(fastDecode(x, cx, ex, sx)) 9816 { 9817 case FastClass.finite: 9818 if (!y) 9819 return x.adjustedPack(cvt!X(cx), ex, sx, precision, mode, ExceptionFlags.none); 9820 bool sy; 9821 U cy = unsign!U(y, sy); 9822 auto flags = coefficientAdd(cx, ex, sx, cy, 0, !sy, RoundingMode.implicit); 9823 flags |= coefficientAdjust(cx, ex, cvt!U(X.max), sx, RoundingMode.implicit); 9824 return x.adjustedPack(cvt!X(cx), ex, sx, precision, mode, flags); 9825 case FastClass.zero: 9826 auto flags = x.packIntegral(y, precision, mode); 9827 x = -x; 9828 return flags; 9829 case FastClass.infinite: 9830 case FastClass.quietNaN: 9831 return ExceptionFlags.none; 9832 case FastClass.signalingNaN: 9833 unsignalize(x); 9834 return ExceptionFlags.invalidOperation; 9835 } 9836 } 9837 9838 @safe pure nothrow @nogc 9839 ExceptionFlags decimalSub(D, F)(ref D x, auto const ref F y, const int precision, const RoundingMode mode) 9840 if (isDecimal!D && isFloatingPoint!F) 9841 { 9842 return decimalAdd(x, -y, precision, mode); 9843 } 9844 9845 @safe pure nothrow @nogc 9846 ExceptionFlags decimalSub(T, D)(auto const ref T x, auto const ref D y, out D z, const int precision, const RoundingMode mode) 9847 if (isDecimal!D && isIntegral!T) 9848 { 9849 z = -y; 9850 return decimalAdd(z, x, precision, mode); 9851 } 9852 9853 @safe pure nothrow @nogc 9854 ExceptionFlags decimalSub(F, D)(auto const ref F x, auto const ref D y, out D z, const int precision, const RoundingMode mode) 9855 if (isDecimal!D && isFloatingPoint!F) 9856 { 9857 z = -y; 9858 return decimalAdd(z, x, precision, mode); 9859 } 9860 9861 @safe pure nothrow @nogc 9862 ExceptionFlags decimalMod(D1, D2)(ref D1 x, auto const ref D2 y, const int precision, const RoundingMode mode) 9863 if (isDecimal!(D1, D2)) 9864 { 9865 9866 alias D = CommonDecimal!(D1, D2); 9867 alias T = DataType!D; 9868 alias T1 = DataType!D1; 9869 9870 T cx, cy; int ex, ey; bool sx, sy; 9871 9872 immutable fx = fastDecode(x, cx, ex, sx); 9873 immutable fy = fastDecode(y, cy, ey, sy); 9874 immutable sxx = sx; 9875 9876 if (fx == FastClass.signalingNaN) 9877 { 9878 unsignalize(x); 9879 return ExceptionFlags.invalidOperation; 9880 } 9881 9882 if (fy == FastClass.signalingNaN) 9883 { 9884 x = sy ? -D1.nan : D1.nan; 9885 return ExceptionFlags.invalidOperation; 9886 } 9887 9888 if (fx == FastClass.quietNaN) 9889 return ExceptionFlags.none; 9890 9891 if (fy == FastClass.quietNaN) 9892 { 9893 x = sy ? -D1.nan : D1.nan; 9894 return ExceptionFlags.none; 9895 } 9896 9897 if (fx == FastClass.infinite) 9898 { 9899 x = sx ? -D1.nan : D1.nan; 9900 return ExceptionFlags.invalidOperation; 9901 } 9902 9903 if (fy == FastClass.zero) 9904 { 9905 x = sx ? -D1.nan : D1.nan; 9906 return ExceptionFlags.invalidOperation; 9907 } 9908 9909 if (fx == FastClass.zero) 9910 return ExceptionFlags.none; 9911 9912 9913 9914 if (fy == FastClass.infinite) 9915 return ExceptionFlags.none; 9916 9917 ////coefficientShrink(cx, ex); 9918 //coefficientShrink(cy, ey); 9919 // 9920 //if (cy == 1U && ey == 0) 9921 //{ 9922 // //if (cx == 1U && ex == 0) 9923 // x = sx ? -D1.zero : D1.zero; 9924 // return ExceptionFlags.none; 9925 //} 9926 9927 9928 9929 ExceptionFlags flags = coefficientMod(cx, ex, sx, cy, ey, sy, mode); 9930 flags = x.adjustedPack(cx, ex, sx, precision, mode, flags); 9931 9932 if (isZero(x)) 9933 x = sxx ? -D1.zero : D1.zero; 9934 return flags; 9935 } 9936 9937 @safe pure nothrow @nogc 9938 ExceptionFlags decimalMod(D, T)(ref D x, auto const ref T y, const int precision, const RoundingMode mode) 9939 if (isDecimal!D && isIntegral!T) 9940 { 9941 alias U = CommonStorage!(D, T); 9942 alias X = DataType!D; 9943 9944 U cx; int ex; bool sx; 9945 bool sy; 9946 U cy = unsign!U(y, sy); 9947 9948 if (!y) 9949 { 9950 x = sx ^ sy ? -D.nan : D.nan; 9951 return ExceptionFlags.invalidOperation; 9952 } 9953 9954 final switch (fastDecode(x, cx, ex, sx)) 9955 { 9956 case FastClass.finite: 9957 auto flags = coefficientMod(cx, ex, sx, cy, 0, sy, mode); 9958 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 9959 case FastClass.zero: 9960 return ExceptionFlags.none; 9961 case FastClass.infinite: 9962 x = sx ? -D.nan : D.nan; 9963 return ExceptionFlags.invalidOperation; 9964 case FastClass.quietNaN: 9965 return ExceptionFlags.none; 9966 case FastClass.signalingNaN: 9967 unsignalize(x); 9968 return ExceptionFlags.invalidOperation; 9969 } 9970 } 9971 9972 @safe pure nothrow @nogc 9973 ExceptionFlags decimalMod(T, D)(auto const ref T x, auto const ref D y, out D z, const int precision, const RoundingMode mode) 9974 if (isDecimal!D && isIntegral!T) 9975 { 9976 9977 alias U = CommonStorage!(D, T); 9978 alias X = DataType!D; 9979 U cy; int ey; bool sy; 9980 int ex = 0; 9981 bool sx; 9982 U cx = unsign!U(x, sx); 9983 final switch (fastDecode(y, cy, ey, sy)) 9984 { 9985 case FastClass.finite: 9986 if (x == 0) 9987 { 9988 z = D.zero; 9989 return ExceptionFlags.none; 9990 } 9991 auto flags = coefficientMod(cx, ex, sx, cy, 0, sy, mode); 9992 flags |= coefficientAdjust(cx, ex, cvt!U(X.max), sx, RoundingMode.implicit); 9993 return z.adjustedPack(cvt!X(cx), ex, sx, precision, mode, flags); 9994 case FastClass.zero: 9995 z = sy ? -D.nan : D.nan; 9996 return ExceptionFlags.invalidOperation; 9997 case FastClass.infinite: 9998 return z.packIntegral(x, precision, mode); 9999 case FastClass.quietNaN: 10000 z = sy ? -D.nan : D.nan; 10001 return ExceptionFlags.none; 10002 case FastClass.signalingNaN: 10003 z = sy ? -D.nan : D.nan; 10004 return ExceptionFlags.invalidOperation; 10005 } 10006 10007 } 10008 10009 @safe pure nothrow @nogc 10010 ExceptionFlags decimalMod(D, F)(ref D x, auto const ref F y, const int precision, const RoundingMode mode) 10011 if (isDecimal!D && isFloatingPoint!F) 10012 { 10013 alias T = CommonStorage!(D, F); 10014 10015 T cx, cy; int ex, ey; bool sx, sy; 10016 ExceptionFlags flags; 10017 immutable fx = fastDecode(x, cx, ex, sx); 10018 immutable fy = fastDecode(y, cy, ey, sy, mode, flags); 10019 10020 if (fx == FastClass.signalingNaN) 10021 { 10022 unsignalize(x); 10023 return ExceptionFlags.invalidOperation; 10024 } 10025 10026 if (fx == FastClass.quietNaN) 10027 return ExceptionFlags.none; 10028 10029 if (fy == FastClass.quietNaN) 10030 { 10031 x = sy ? -D.nan : D.nan; 10032 return ExceptionFlags.none; 10033 } 10034 10035 if (fx == FastClass.infinite || fy == FastClass.zero) 10036 { 10037 x = sx ? -D.nan : D.nan; 10038 return ExceptionFlags.invalidOperation; 10039 } 10040 10041 if (fx == FastClass.zero) 10042 return ExceptionFlags.none; 10043 10044 if (fy == FastClass.infinite) 10045 return ExceptionFlags.none; 10046 10047 flags |= coefficientAdjust(cy, ey, realFloatPrecision!F(0), sy, mode); 10048 flags |= coefficientMod(cx, ex, sx, cy, ey, sy, mode); 10049 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 10050 } 10051 10052 @safe pure nothrow @nogc 10053 ExceptionFlags decimalMod(F, D)(auto const ref F x, auto const ref D y, out D z, const int precision, const RoundingMode mode) 10054 if (isDecimal!D && isFloatingPoint!F) 10055 { 10056 alias T = CommonStorage!(D, F); 10057 alias X = DataType!D; 10058 10059 T cx, cy; int ex, ey; bool sx, sy; 10060 ExceptionFlags flags; 10061 immutable fx = fastDecode(x, cx, ex, sx, mode, flags); 10062 immutable fy = fastDecode(y, cy, ey, sy); 10063 10064 if (fy == FastClass.signalingNaN) 10065 { 10066 z = sy ? -D.nan : D.nan; 10067 return ExceptionFlags.invalidOperation; 10068 } 10069 10070 if (fx == FastClass.quietNaN) 10071 { 10072 z = sx ? -D.nan : D.nan; 10073 return ExceptionFlags.none; 10074 } 10075 10076 if (fy == FastClass.quietNaN) 10077 { 10078 z = sy ? -D.nan : D.nan; 10079 return ExceptionFlags.none; 10080 } 10081 10082 if (fx == FastClass.infinite || fy == FastClass.zero) 10083 { 10084 z = sx ? -D.nan : D.nan; 10085 return ExceptionFlags.invalidOperation; 10086 } 10087 10088 if (fy == FastClass.infinite) 10089 return ExceptionFlags.none; 10090 10091 flags |= coefficientAdjust(cx, ex, realFloatPrecision!F(0), sx, mode); 10092 flags |= coefficientMod(cx, ex, sx, cy, ey, sy, mode); 10093 return z.adjustedPack(cx, ex, sx, precision, mode, flags); 10094 10095 } 10096 10097 @safe pure nothrow @nogc 10098 int decimalCmp(D1, D2)(auto const ref D1 x, auto const ref D2 y) 10099 if (isDecimal!(D1, D2)) 10100 { 10101 //-3 signan 10102 //-2 nan 10103 alias D = CommonDecimal!(D1, D2); 10104 DataType!D cx, cy; int ex, ey; bool sx, sy; 10105 immutable fx = fastDecode(x, cx, ex, sx); 10106 immutable fy = fastDecode(y, cy, ey, sy); 10107 final switch(fx) 10108 { 10109 case FastClass.finite: 10110 if (fy == FastClass.finite) 10111 return coefficientCmp(cx, ex, sx, cy, ey, sy); 10112 if (fy == FastClass.zero) 10113 return sx ? -1: 1; 10114 if (fy == FastClass.infinite) 10115 return sy ? 1 : -1; 10116 return fy == FastClass.signalingNaN ? -3 : -2; 10117 case FastClass.zero: 10118 if (fy == FastClass.finite || fy == FastClass.infinite) 10119 return sy ? 1 : -1; 10120 if (fy == FastClass.zero) 10121 return 0; 10122 return fy == FastClass.signalingNaN ? -3 : -2; 10123 case FastClass.infinite: 10124 if (fy == FastClass.finite || fy == FastClass.zero) 10125 return sx ? -1 : 1; 10126 if (fy == FastClass.infinite) 10127 return sx == sy ? 0 : (sx ? -1 : 1); 10128 return fy == FastClass.signalingNaN ? -3 : -2; 10129 case FastClass.quietNaN: 10130 return fy == FastClass.signalingNaN ? -3 : -2; 10131 case FastClass.signalingNaN: 10132 return -3; 10133 10134 } 10135 } 10136 10137 @safe pure nothrow @nogc 10138 int decimalCmp(D, T)(auto const ref D x, auto const ref T y) 10139 if (isDecimal!D && isIntegral!T) 10140 { 10141 alias U = CommonStorage!(D, T); 10142 U cx; int ex; bool sx; 10143 final switch(fastDecode(x, cx, ex, sx)) 10144 { 10145 case FastClass.finite: 10146 bool sy; 10147 U cy = unsign!U(y, sy); 10148 return coefficientCmp(cx, ex, sx, cy, 0, sy); 10149 case FastClass.zero: 10150 static if (isUnsigned!T) 10151 return y == 0 ? 0 : -1; 10152 else 10153 return y == 0 ? 0 : (y < 0 ? 1 : -1); 10154 case FastClass.infinite: 10155 return sx ? -1 : 1; 10156 case FastClass.quietNaN: 10157 case FastClass.signalingNaN: 10158 return -2; 10159 } 10160 } 10161 10162 @safe pure nothrow @nogc 10163 int decimalCmp(D, F)(auto const ref D x, auto const ref F y) 10164 if (isDecimal!D && isFloatingPoint!F) 10165 { 10166 if (isSignaling(x)) 10167 return -3; 10168 if (isNaN(x) || isNaN(y)) 10169 return -2; 10170 10171 bool sx = cast(bool)signbit(x); 10172 bool sy = cast(bool)signbit(y); 10173 10174 if (isZero(x)) 10175 { 10176 if (y == 0.0) 10177 return 0; 10178 return sy ? 1 : -1; 10179 } 10180 10181 if (y == 0.0) 10182 return sx ? -1 : 1; 10183 10184 if (sx != sy) 10185 return sx ? -1 : 1; 10186 10187 if (isInfinity(x)) 10188 { 10189 if (isInfinity(y)) 10190 return 0; 10191 return sx ? -1 : 1; 10192 } 10193 10194 if (isInfinity(y)) 10195 return sx ? 1 : -1; 10196 10197 Unqual!D v = void; 10198 10199 auto flags = v.packFloatingPoint(y, 0, RoundingMode.towardZero); 10200 10201 if (flags & ExceptionFlags.overflow) 10202 { 10203 //floating point is too big 10204 return sx ? 1 : -1; 10205 } 10206 else if (flags & ExceptionFlags.underflow) 10207 { 10208 //floating point is too small 10209 return sx ? -1 : 1; 10210 } 10211 10212 auto result = decimalCmp(x, v); 10213 10214 if (result == 0 && (flags & ExceptionFlags.inexact)) 10215 { 10216 //seems equal, but float was truncated toward zero, so it's smaller 10217 return sx ? -1 : 1; 10218 } 10219 10220 return result; 10221 } 10222 10223 @safe pure nothrow @nogc 10224 int decimalEqu(D1, D2)(auto const ref D1 x, auto const ref D2 y) 10225 if (isDecimal!(D1, D2)) 10226 { 10227 alias D = CommonDecimal!(D1, D2); 10228 DataType!D cx, cy; int ex, ey; bool sx, sy; 10229 immutable fx = fastDecode(x, cx, ex, sx); 10230 immutable fy = fastDecode(y, cy, ey, sy); 10231 10232 final switch(fx) 10233 { 10234 case FastClass.finite: 10235 if (fy == FastClass.finite && coefficientEqu(cx, ex, sx, cy, ey, sy)) 10236 return 1; 10237 if (fy == FastClass.zero || fy == FastClass.infinite) 10238 return 0; 10239 return fy == FastClass.signalingNaN ? -3 : -2; 10240 case FastClass.zero: 10241 if (fy == FastClass.zero) 10242 return 1; 10243 if (fy == FastClass.finite || fy == FastClass.infinite) 10244 return 0; 10245 return fy == FastClass.signalingNaN ? -3 : -2; 10246 case FastClass.infinite: 10247 if (fy == FastClass.infinite) 10248 return sx == sy ? 1 : 0; 10249 if (fy == FastClass.finite || fy == FastClass.zero) 10250 return 0; 10251 return fy == FastClass.signalingNaN ? -3 : -2; 10252 case FastClass.quietNaN: 10253 return fy == FastClass.signalingNaN ? -3 : -2; 10254 case FastClass.signalingNaN: 10255 return -3; 10256 } 10257 } 10258 10259 @safe pure nothrow @nogc 10260 int decimalEqu(D, T)(auto const ref D x, auto const ref T y) 10261 if (isDecimal!D && isIntegral!T) 10262 { 10263 alias U = CommonStorage!(D, T); 10264 U cx; int ex; bool sx; 10265 final switch(fastDecode(x, cx, ex, sx)) 10266 { 10267 case FastClass.finite: 10268 bool sy; 10269 U cy = unsign!U(y, sy); 10270 return coefficientEqu(cx, ex, sx, cy, 0, sy) ? 1 : 0; 10271 case FastClass.zero: 10272 return y == 0 ? 1 : 0; 10273 case FastClass.infinite: 10274 return 0; 10275 case FastClass.quietNaN: 10276 return -2; 10277 case FastClass.signalingNaN: 10278 return -3; 10279 } 10280 return ExceptionFlags.none; 10281 } 10282 10283 @safe pure nothrow @nogc 10284 int decimalEqu(D, F)(auto const ref D x, auto const ref F y) 10285 if (isDecimal!D && isFloatingPoint!F) 10286 { 10287 if (isSignaling(x)) 10288 return -3; 10289 if (isNaN(x) || isNaN(y)) 10290 return -2; 10291 if (isZero(x)) 10292 return y == 0.0 ? 1 : 0; 10293 if (y == 0.0) 10294 return 0; 10295 10296 bool sx = cast(bool)signbit(x); 10297 bool sy = cast(bool)signbit(y); 10298 10299 if (sx != sy) 10300 return 0; 10301 if (isInfinity(x)) 10302 return isInfinity(y) ? 1 : 0; 10303 if (isInfinity(y)) 10304 return 0; 10305 Unqual!D v = void; 10306 auto flags = v.packFloatingPoint(y, D.PRECISION, RoundingMode.towardZero); 10307 if (flags) 10308 return 0; 10309 else 10310 return decimalEqu(x, v); 10311 10312 } 10313 10314 @safe pure nothrow @nogc 10315 ExceptionFlags decimalSqrt(D)(ref D x, const int precision, const RoundingMode mode) 10316 if (isDecimal!D) 10317 { 10318 DataType!D cx; int ex; bool sx; 10319 final switch(fastDecode(x, cx, ex, sx)) 10320 { 10321 case FastClass.finite: 10322 if (sx) 10323 { 10324 x = -D.nan; 10325 return ExceptionFlags.invalidOperation; 10326 } 10327 auto flags = coefficientSqrt(cx, ex); 10328 return x.adjustedPack(cx, ex, false, precision, mode, flags); 10329 case FastClass.zero: 10330 return ExceptionFlags.none; 10331 case FastClass.infinite: 10332 if (sx) 10333 { 10334 x = -D.nan; 10335 return ExceptionFlags.invalidOperation; 10336 } 10337 return ExceptionFlags.none; 10338 case FastClass.quietNaN: 10339 return ExceptionFlags.none; 10340 case FastClass.signalingNaN: 10341 unsignalize(x); 10342 return ExceptionFlags.invalidOperation; 10343 } 10344 10345 } 10346 10347 @safe pure nothrow @nogc 10348 ExceptionFlags decimalRSqrt(D)(ref D x, const int precision, const RoundingMode mode) 10349 if (isDecimal!D) 10350 { 10351 DataType!D cx; int ex; bool sx; 10352 final switch(fastDecode(x, cx, ex, sx)) 10353 { 10354 case FastClass.finite: 10355 if (sx) 10356 { 10357 x = -D.nan; 10358 return ExceptionFlags.invalidOperation; 10359 } 10360 auto flags = coefficientRSqrt(cx, ex); 10361 return x.adjustedPack(cx, ex, false, precision, mode, flags); 10362 case FastClass.zero: 10363 x = D.infinity; 10364 return ExceptionFlags.divisionByZero; 10365 case FastClass.infinite: 10366 if (sx) 10367 { 10368 x = -D.nan; 10369 return ExceptionFlags.invalidOperation; 10370 } 10371 x = D.zero; 10372 return ExceptionFlags.none; 10373 case FastClass.quietNaN: 10374 return ExceptionFlags.none; 10375 case FastClass.signalingNaN: 10376 unsignalize(x); 10377 return ExceptionFlags.invalidOperation; 10378 } 10379 } 10380 10381 @safe pure nothrow @nogc 10382 ExceptionFlags decimalSqr(D)(ref D x, const int precision, const RoundingMode mode) 10383 if (isDecimal!D) 10384 { 10385 DataType!D cx; int ex; bool sx; 10386 final switch(fastDecode(x, cx, ex, sx)) 10387 { 10388 case FastClass.finite: 10389 auto flags = coefficientSqr(cx, ex, RoundingMode.implicit); 10390 return x.adjustedPack(cx, ex, false, precision, mode, flags); 10391 case FastClass.zero: 10392 x = D.zero; 10393 return ExceptionFlags.none; 10394 case FastClass.infinite: 10395 x = D.infinity; 10396 return ExceptionFlags.none; 10397 case FastClass.quietNaN: 10398 return ExceptionFlags.none; 10399 case FastClass.signalingNaN: 10400 unsignalize(x); 10401 return ExceptionFlags.invalidOperation; 10402 } 10403 } 10404 10405 @safe pure nothrow @nogc 10406 ExceptionFlags decimalCbrt(D)(ref D x, const int precision, const RoundingMode mode) 10407 if (isDecimal!D) 10408 { 10409 DataType!D cx; int ex; bool sx; 10410 final switch(fastDecode(x, cx, ex, sx)) 10411 { 10412 case FastClass.finite: 10413 auto flags = coefficientCbrt(cx, ex); 10414 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 10415 case FastClass.zero: 10416 case FastClass.infinite: 10417 case FastClass.quietNaN: 10418 return ExceptionFlags.none; 10419 case FastClass.signalingNaN: 10420 unsignalize(x); 10421 return ExceptionFlags.invalidOperation; 10422 } 10423 } 10424 10425 @safe pure nothrow @nogc 10426 ExceptionFlags decimalHypot(D1, D2, D)(auto const ref D1 x, auto const ref D2 y, out D z, 10427 const int precision, const RoundingMode mode) 10428 if (isDecimal!(D1, D2) && is(D: CommonDecimal!(D1, D2))) 10429 { 10430 alias U = DataType!D; 10431 10432 U cx, cy; int ex, ey; bool sx, sy; 10433 10434 immutable fx = fastDecode(x, cx, ex, sx); 10435 immutable fy = fastDecode(y, cy, ey, sy); 10436 10437 if (fx == FastClass.signalingNaN || fy == FastClass.signalingNaN) 10438 { 10439 z = D.nan; 10440 return ExceptionFlags.invalidOperation; 10441 } 10442 10443 if (fx == FastClass.quietNaN || fy == FastClass.quietNaN) 10444 { 10445 z = D.nan; 10446 return ExceptionFlags.none; 10447 } 10448 10449 if (fx == FastClass.infinite || fy == FastClass.infinite) 10450 { 10451 z = D.infinity; 10452 return ExceptionFlags.none; 10453 } 10454 10455 if (fx == FastClass.zero) 10456 return z.adjustedPack(cy, ey, false, precision, mode, ExceptionFlags.none); 10457 10458 if (fy == FastClass.zero) 10459 return z.adjustedPack(cx, ex, false, precision, mode, ExceptionFlags.none); 10460 10461 auto flags = coefficientHypot(cx, ex, cy, ey); 10462 return z.adjustedPack(cx, ex, false, precision, mode, flags); 10463 } 10464 10465 10466 @safe pure nothrow @nogc 10467 ExceptionFlags decimalFMA(D1, D2, D3, D)(auto const ref D1 x, auto const ref D2 y, auto const ref D3 z, 10468 out D result, 10469 const int precision, const RoundingMode mode) 10470 if (isDecimal!(D1, D2, D3) && is(D : CommonDecimal!(D1, D2, D3))) 10471 { 10472 alias U = DataType!D; 10473 10474 U cx, cy, cz; int ex, ey, ez; bool sx, sy, sz; 10475 10476 immutable fx = fastDecode(x, cx, ex, sx); 10477 immutable fy = fastDecode(y, cy, ey, sy); 10478 immutable fz = fastDecode(z, cz, ez, sz); 10479 10480 if (fx == FastClass.signalingNaN || fy == FastClass.signalingNaN || fz == FastClass.signalingNaN) 10481 { 10482 result = D.nan; 10483 return ExceptionFlags.invalidOperation; 10484 } 10485 10486 if (fx == FastClass.quietNaN || fy == FastClass.quietNaN || fz == FastClass.quietNaN) 10487 { 10488 result = D.nan; 10489 return ExceptionFlags.none; 10490 } 10491 10492 if (fx == FastClass.infinite) 10493 { 10494 if (fy == FastClass.zero) 10495 { 10496 result = D.nan; 10497 return ExceptionFlags.invalidOperation; 10498 } 10499 10500 if (fz == FastClass.infinite) 10501 { 10502 if ((sx ^ sy) != sz) 10503 { 10504 result = D.nan; 10505 return ExceptionFlags.invalidOperation; 10506 } 10507 } 10508 result = sx ^ sy ? -D.infinity : D.infinity; 10509 return ExceptionFlags.none; 10510 } 10511 10512 if (fy == FastClass.infinite) 10513 { 10514 if (fx == FastClass.zero) 10515 { 10516 result = D.nan; 10517 return ExceptionFlags.invalidOperation; 10518 } 10519 10520 if (fz == FastClass.infinite) 10521 { 10522 if ((sx ^ sy) != sz) 10523 { 10524 result = D.nan; 10525 return ExceptionFlags.invalidOperation; 10526 } 10527 } 10528 result = sx ^ sy ? -D.infinity : D.infinity; 10529 return ExceptionFlags.none; 10530 } 10531 10532 if (fx == FastClass.zero || fy == FastClass.zero) 10533 return result.adjustedPack(cx, ex, sx, precision, mode, ExceptionFlags.none); 10534 10535 if (fz == FastClass.zero) 10536 { 10537 auto flags = coefficientMul(cx, ex, sx, cy, ey, sy, RoundingMode.implicit); 10538 return result.adjustedPack(cx, ex, sx, precision, mode, flags); 10539 } 10540 10541 auto flags = coefficientFMA(cx, ex, sx, cy, ey, sy, cz, ez, sz, mode); 10542 return result.adjustedPack(cx, ex, sx, precision, mode, flags); 10543 } 10544 10545 ExceptionFlags decimalPow(D, T)(ref D x, const T n, const int precision, const RoundingMode mode) 10546 if (isDecimal!D & isIntegral!T) 10547 { 10548 DataType!D cx; int ex; bool sx; 10549 10550 final switch (fastDecode(x, cx, ex, sx)) 10551 { 10552 case FastClass.finite: 10553 if (!n) 10554 { 10555 x = D.one; 10556 return ExceptionFlags.none; 10557 } 10558 10559 DataType!D cv; int ev; bool sv; 10560 ExceptionFlags flags; 10561 static if (isSigned!T) 10562 { 10563 auto m = unsign!(Unsigned!T)(n); 10564 if (n < 0) 10565 { 10566 cv = 1U; 10567 ev = 0; 10568 sv = false; 10569 flags = coefficientDiv(cv, ev, sv, cx, ex, sx, RoundingMode.implicit); 10570 } 10571 else 10572 { 10573 cv = cx; 10574 ev = ex; 10575 sv = sx; 10576 } 10577 } 10578 else 10579 { 10580 Unqual!T m = n; 10581 cv = cx; 10582 ev = ex; 10583 sv = sx; 10584 } 10585 10586 cx = 1U; 10587 ex = 0; 10588 sx = false; 10589 10590 ExceptionFlags sqrFlags; 10591 while (m) 10592 { 10593 if (m & 1) 10594 { 10595 flags |= sqrFlags | coefficientMul(cx, ex, sx, cv, ev, sv, RoundingMode.implicit); 10596 sqrFlags = ExceptionFlags.none; 10597 if (flags & (ExceptionFlags.overflow | ExceptionFlags.underflow)) 10598 break; 10599 } 10600 m >>>= 1; 10601 sqrFlags |= coefficientSqr(cv, ev, RoundingMode.implicit); 10602 sv = false; 10603 } 10604 10605 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 10606 case FastClass.zero: 10607 if (!n) 10608 x = D.one; 10609 else 10610 { 10611 if (n & 1) //odd 10612 return n < 0 ? ExceptionFlags.divisionByZero : ExceptionFlags.none; 10613 else //even 10614 { 10615 if (n < 0) 10616 return ExceptionFlags.divisionByZero; 10617 else 10618 { 10619 x = D.zero; 10620 return ExceptionFlags.none; 10621 } 10622 } 10623 } 10624 return ExceptionFlags.none; 10625 case FastClass.infinite: 10626 if (!n) 10627 x = D.one; 10628 else 10629 x = !sx || (n & 1) ? D.infinity : -D.infinity; 10630 return ExceptionFlags.none; 10631 case FastClass.quietNaN: 10632 if (!n) 10633 x = D.one; 10634 return ExceptionFlags.none; 10635 case FastClass.signalingNaN: 10636 unsignalize(x); 10637 return ExceptionFlags.invalidOperation; 10638 } 10639 10640 10641 } 10642 10643 ExceptionFlags decimalPow(D1, D2)(ref D1 x, auto const ref D2 y, const int precision, const RoundingMode mode) 10644 if (isDecimal!(D1, D2)) 10645 { 10646 long ip; 10647 auto flags = decimalToSigned(y, ip, mode); 10648 if (flags == ExceptionFlags.none) 10649 return decimalPow(x, ip, precision, mode); 10650 10651 flags = decimalLog(x, 0, mode); 10652 flags |= decimalMul(x, y, 0, mode); 10653 return flags | decimalExp(x, precision, mode); 10654 } 10655 10656 ExceptionFlags decimalPow(D, F)(ref D x, auto const ref F y, const int precision, const RoundingMode mode) 10657 if (isDecimal!D && isFloatingPoint!F) 10658 { 10659 Unqual!D z; 10660 auto flags = z.packFloatingPoint(y, 0, mode); 10661 return flags | decimalPow(x, z, precision, mode); 10662 } 10663 10664 ExceptionFlags decimalPow(T, D)(auto const ref T x, auto const ref D y, out D result, const int precision, const RoundingMode mode) 10665 if (isDecimal!D && isIntegral!T) 10666 { 10667 decimal128 r = x; 10668 auto flags = decimalPow(r, y, precision, mode); 10669 return flags | decimalToDecimal(r, result, precision, mode); 10670 } 10671 10672 ExceptionFlags decimalPow(F, D)(auto const ref F x, auto const ref D y, out D result, const int precision, const RoundingMode mode) 10673 if (isDecimal!D && isFloatingPoint!F) 10674 { 10675 decimal128 r = x; 10676 auto flags = decimalPow(r, y, precision, mode); 10677 return flags | decimalToDecimal(r, result, precision, mode); 10678 } 10679 10680 ExceptionFlags decimalExp(D)(ref D x, const int precision, const RoundingMode mode) 10681 if (isDecimal!D) 10682 { 10683 if (isSignaling(x)) 10684 { 10685 x = D.nan; 10686 return ExceptionFlags.invalidOperation; 10687 } 10688 10689 if (isZero(x)) 10690 { 10691 x = D.one; 10692 return ExceptionFlags.none; 10693 } 10694 10695 if (isNaN(x)) 10696 return ExceptionFlags.none; 10697 10698 if (isInfinity(x)) 10699 { 10700 x = signbit(x) ? D.zero : D.infinity; 10701 return ExceptionFlags.none; 10702 } 10703 10704 long n; 10705 auto flags = decimalToSigned(x, n, mode); 10706 if (flags == ExceptionFlags.none) 10707 { 10708 x = D.E; 10709 return decimalPow(x, n, precision, mode); 10710 } 10711 10712 static if (is(D : decimal32)) 10713 { 10714 enum lnmax = decimal32("+223.3507"); 10715 enum lnmin = decimal32("-232.5610"); 10716 } 10717 else static if (is(D: decimal64)) 10718 { 10719 enum lnmax = decimal64("+886.4952608027075"); 10720 enum lnmin = decimal64("-916.4288670116301"); 10721 } 10722 else 10723 { 10724 enum lnmax = decimal128("+14149.38539644841072829055748903541"); 10725 enum lnmin = decimal128("-14220.76553433122614449511522413063"); 10726 } 10727 10728 if (isLess(x, lnmin)) 10729 { 10730 x = D.zero; 10731 return ExceptionFlags.underflow | ExceptionFlags.inexact; 10732 } 10733 10734 if (isGreater(x, lnmax)) 10735 { 10736 x = D.infinity; 10737 return ExceptionFlags.overflow | ExceptionFlags.inexact; 10738 } 10739 10740 DataType!D cx; 10741 int ex; 10742 10743 bool sx = x.unpack(cx, ex); 10744 flags = coefficientExp(cx, ex, sx); 10745 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 10746 } 10747 10748 ExceptionFlags decimalLog(D)(ref D x, const int precision, const RoundingMode mode) 10749 if (isDecimal!D) 10750 { 10751 if (isSignaling(x)) 10752 { 10753 x = D.nan; 10754 return ExceptionFlags.invalidOperation; 10755 } 10756 10757 if (isNaN(x)) 10758 return ExceptionFlags.none; 10759 10760 if (signbit(x)) 10761 { 10762 x = D.nan; 10763 return ExceptionFlags.invalidOperation; 10764 } 10765 10766 if (isInfinity(x)) 10767 { 10768 x = D.infinity; 10769 return ExceptionFlags.none; 10770 } 10771 10772 if (isZero(x)) 10773 { 10774 x = -D.infinity; 10775 return ExceptionFlags.divisionByZero; 10776 } 10777 10778 DataType!D cx; 10779 int ex; 10780 bool sx = x.unpack(cx, ex); 10781 auto flags = coefficientLog(cx, ex, sx); 10782 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 10783 } 10784 10785 ExceptionFlags decimalExp10(D)(out D x, int n, const int precision, const RoundingMode mode) 10786 if (isDecimal!D) 10787 { 10788 if (n == 0) 10789 { 10790 x = D.one; 10791 return ExceptionFlags.none; 10792 } 10793 alias T = DataType!D; 10794 return x.adjustedPack(T(1U), n, false, precision, mode, ExceptionFlags.none); 10795 } 10796 10797 ExceptionFlags decimalExp10(D)(ref D x, const int precision, const RoundingMode mode) 10798 if (isDecimal!D) 10799 { 10800 if (isSignaling(x)) 10801 { 10802 x = D.nan; 10803 return ExceptionFlags.invalidOperation; 10804 } 10805 10806 if (isZero(x)) 10807 { 10808 x = D.one; 10809 return ExceptionFlags.none; 10810 } 10811 10812 if (isNaN(x)) 10813 return ExceptionFlags.none; 10814 10815 if (isInfinity(x)) 10816 { 10817 x = signbit(x) ? D.zero : D.infinity; 10818 return ExceptionFlags.none; 10819 } 10820 10821 int n; 10822 auto flags = decimalToSigned(x, n, RoundingMode.implicit); 10823 if (flags == ExceptionFlags.none) 10824 return decimalExp10(x, n, precision, mode); 10825 10826 flags = decimalMul(x, D.LN10, 0, mode); 10827 return flags | decimalExp(x, precision, mode); 10828 } 10829 10830 ExceptionFlags decimalExp10m1(D)(ref D x, const int precision, const RoundingMode mode) 10831 if (isDecimal!D) 10832 { 10833 if (isSignaling(x)) 10834 { 10835 x = D.nan; 10836 return ExceptionFlags.invalidOperation; 10837 } 10838 10839 if (isZero(x)) 10840 return ExceptionFlags.none; 10841 10842 if (isNaN(x)) 10843 return ExceptionFlags.none; 10844 10845 if (isInfinity(x)) 10846 { 10847 x = signbit(x) ? -D.one : D.infinity; 10848 return ExceptionFlags.none; 10849 } 10850 10851 auto flags = decimalExp10(x, 0, mode); 10852 return flags | decimalAdd(x, -1, precision, mode); 10853 } 10854 10855 10856 ExceptionFlags decimalExpm1(D)(ref D x, const int precision, const RoundingMode mode) 10857 if (isDecimal!D) 10858 { 10859 if (isSignaling(x)) 10860 { 10861 x = D.nan; 10862 return ExceptionFlags.invalidOperation; 10863 } 10864 10865 if (isZero(x)) 10866 return ExceptionFlags.none; 10867 10868 if (isNaN(x)) 10869 return ExceptionFlags.none; 10870 10871 if (isInfinity(x)) 10872 { 10873 x = signbit(x) ? -D.one : D.infinity; 10874 return ExceptionFlags.none; 10875 } 10876 10877 auto flags = decimalExp(x, 0, mode); 10878 return flags | decimalAdd(x, -1, precision, mode); 10879 } 10880 10881 ExceptionFlags decimalExp2(D)(ref D x, const int precision, const RoundingMode mode) 10882 if (isDecimal!D) 10883 { 10884 if (isSignaling(x)) 10885 { 10886 x = D.nan; 10887 return ExceptionFlags.invalidOperation; 10888 } 10889 10890 if (isZero(x)) 10891 { 10892 x = D.one; 10893 return ExceptionFlags.none; 10894 } 10895 10896 if (isNaN(x)) 10897 return ExceptionFlags.none; 10898 10899 if (isInfinity(x)) 10900 { 10901 x = signbit(x) ? D.zero : D.infinity; 10902 return ExceptionFlags.none; 10903 } 10904 10905 int n; 10906 auto flags = decimalToSigned(x, n, RoundingMode.implicit); 10907 if (flags == ExceptionFlags.none) 10908 { 10909 x = D.two; 10910 return decimalPow(x, n, precision, mode); 10911 } 10912 10913 flags = decimalMul(x, D.LN2, 0, mode); 10914 return flags | decimalExp(x, precision, mode); 10915 } 10916 10917 ExceptionFlags decimalExp2m1(D)(ref D x, const int precision, const RoundingMode mode) 10918 if (isDecimal!D) 10919 { 10920 if (isSignaling(x)) 10921 { 10922 x = D.nan; 10923 return ExceptionFlags.invalidOperation; 10924 } 10925 10926 if (isZero(x)) 10927 return ExceptionFlags.none; 10928 10929 if (isNaN(x)) 10930 return ExceptionFlags.none; 10931 10932 if (isInfinity(x)) 10933 { 10934 x = signbit(x) ? -D.one : D.infinity; 10935 return ExceptionFlags.none; 10936 } 10937 10938 auto flags = decimalExp2(x, 0, mode); 10939 return flags |= decimalAdd(x, -1, precision, mode); 10940 } 10941 10942 ExceptionFlags decimalLog2(D)(ref D x, const int precision, const RoundingMode mode) 10943 if (isDecimal!D) 10944 { 10945 auto flags = decimalLog(x, 0, mode); 10946 return flags | decimalDiv(x, D.LN2, precision, mode); 10947 } 10948 10949 ExceptionFlags decimalLog10(D)(ref D x, const int precision, const RoundingMode mode) 10950 if (isDecimal!D) 10951 { 10952 if (isSignaling(x)) 10953 { 10954 x = D.nan; 10955 return ExceptionFlags.invalidOperation; 10956 } 10957 10958 if (isNaN(x)) 10959 return ExceptionFlags.none; 10960 10961 if (signbit(x)) 10962 { 10963 x = D.nan; 10964 return ExceptionFlags.invalidOperation; 10965 } 10966 10967 if (isInfinity(x)) 10968 { 10969 x = D.infinity; 10970 return ExceptionFlags.none; 10971 } 10972 10973 if (isZero(x)) 10974 { 10975 x = -D.infinity; 10976 return ExceptionFlags.divisionByZero; 10977 } 10978 10979 DataType!D c; 10980 int e; 10981 x.unpack(c, e); 10982 coefficientShrink(c, e); 10983 10984 Unqual!D y = e; 10985 auto flags = decimalMul(y, D.LN10, 0, RoundingMode.implicit); 10986 x = c; 10987 flags |= decimalLog(x, 0, mode); 10988 return flags | decimalAdd(x, y, precision, mode); 10989 } 10990 10991 ExceptionFlags decimalLogp1(D)(ref D x, const int precision, const RoundingMode mode) 10992 if (isDecimal!D) 10993 { 10994 auto flags = decimalAdd(x, 1U, 0, mode); 10995 return flags | decimalLog(x); 10996 } 10997 10998 ExceptionFlags decimalLog2p1(D)(ref D x, const int precision, const RoundingMode mode) 10999 if (isDecimal!D) 11000 { 11001 auto flags = decimalAdd(x, 1U, 0, mode); 11002 return flags | decimalLog2(x, precision, mode); 11003 } 11004 11005 ExceptionFlags decimalLog10p1(D)(ref D x, const int precision, const RoundingMode mode) 11006 if (isDecimal!D) 11007 { 11008 auto flags = decimalAdd(x, 1U, 0, mode); 11009 return flags | decimalLog10(x, precision, mode); 11010 } 11011 11012 ExceptionFlags decimalCompound(D)(ref D x, const int n, const int precision, const RoundingMode mode) 11013 if (isDecimal!D) 11014 { 11015 if (isSignaling(x)) 11016 { 11017 x = D.nan; 11018 return ExceptionFlags.invalidOperation; 11019 } 11020 11021 if (isLess(x, -D.one)) 11022 { 11023 x = D.nan; 11024 return ExceptionFlags.invalidOperation; 11025 } 11026 11027 if (n == 0) 11028 { 11029 x = D.one; 11030 return ExceptionFlags.none; 11031 } 11032 11033 if (x == -1 && n < 0) 11034 { 11035 x = D.infinity; 11036 return ExceptionFlags.divisionByZero; 11037 } 11038 11039 if (x == -1) 11040 { 11041 x = D.zero; 11042 return ExceptionFlags.none; 11043 } 11044 11045 if (isNaN(x)) 11046 return ExceptionFlags.none; 11047 11048 if (isInfinity(x)) 11049 { 11050 if (signbit(x)) 11051 x = n & 1 ? -D.infinity : D.infinity; 11052 else 11053 x = D.infinity; 11054 return ExceptionFlags.none; 11055 } 11056 11057 Unqual!D y = x; 11058 auto flags = decimalAdd(x, 1U, 0, mode); 11059 if ((flags & ExceptionFlags.overflow) && n < 0) 11060 { 11061 x = y; 11062 flags &= ~ExceptionFlags.overflow; 11063 } 11064 11065 if (flags & ExceptionFlags.overflow) 11066 return flags; 11067 11068 return flags | decimalPow(x, n, precision, mode); 11069 } 11070 11071 ExceptionFlags decimalRoot(D, T)(ref D x, const T n, const int precision, const RoundingMode mode) 11072 if (isDecimal!D && isIntegral!T) 11073 { 11074 if (isSignaling(x)) 11075 { 11076 x = D.nan; 11077 return ExceptionFlags.invalidOperation; 11078 } 11079 11080 if (!n) 11081 { 11082 x = D.nan; 11083 return ExceptionFlags.invalidOperation; 11084 } 11085 11086 if (n == -1) 11087 { 11088 return ExceptionFlags.overflow | ExceptionFlags.underflow; 11089 } 11090 11091 if (isNaN(x)) 11092 return ExceptionFlags.none; 11093 11094 if (isInfinity(x)) 11095 { 11096 x = !signbit(x) || (n & 1) ? D.infinity : -D.infinity; 11097 } 11098 11099 if (isZero(x)) 11100 { 11101 if (n & 1) //odd 11102 { 11103 if (n < 0) 11104 { 11105 x = signbit(x) ? -D.infinity : D.infinity; 11106 return ExceptionFlags.divisionByZero; 11107 } 11108 else 11109 return ExceptionFlags.none; 11110 } 11111 else //even 11112 { 11113 if (n < 0) 11114 { 11115 x = D.infinity; 11116 return ExceptionFlags.divisionByZero; 11117 } 11118 else 11119 { 11120 x = D.zero; 11121 return ExceptionFlags.none; 11122 } 11123 } 11124 } 11125 11126 if (n == 1) 11127 return ExceptionFlags.none; 11128 Unqual!D y = 1U; 11129 auto flags = decimalDiv(y, n, 0, mode); 11130 return flags | decimalPow(x, y, precision, mode); 11131 } 11132 11133 ExceptionFlags decimalSin(D)(ref D x, const int precision, const RoundingMode mode) 11134 if (isDecimal!D) 11135 { 11136 DataType!D cx; int ex; bool sx; 11137 switch(fastDecode(x, cx, ex, sx)) 11138 { 11139 case FastClass.signalingNaN: 11140 unsignalize(x); 11141 return ExceptionFlags.invalidOperation; 11142 case FastClass.infinite: 11143 x = sx ? -D.nan : D.nan; 11144 return ExceptionFlags.invalidOperation; 11145 case FastClass.quietNaN: 11146 case FastClass.zero: 11147 return ExceptionFlags.none; 11148 default: 11149 int quadrant; 11150 auto flags = coefficientCapAngle(cx, ex, sx, quadrant); 11151 switch (quadrant) 11152 { 11153 case 1: 11154 flags |= coefficientSinQ(cx, ex, sx); 11155 break; 11156 case 2: 11157 flags |= coefficientCosQ(cx, ex, sx); 11158 break; 11159 case 3: 11160 flags |= coefficientSinQ(cx, ex, sx); 11161 sx = !sx; 11162 break; 11163 case 4: 11164 flags |= coefficientCosQ(cx, ex, sx); 11165 sx = !sx; 11166 break; 11167 default: 11168 assert(0); 11169 } 11170 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 11171 } 11172 } 11173 11174 ExceptionFlags decimalCos(D)(ref D x, const int precision, const RoundingMode mode) 11175 if (isDecimal!D) 11176 { 11177 DataType!D cx; int ex; bool sx; 11178 switch(fastDecode(x, cx, ex, sx)) 11179 { 11180 case FastClass.signalingNaN: 11181 return ExceptionFlags.invalidOperation; 11182 case FastClass.infinite: 11183 x = sx ? -D.nan : D.nan; 11184 return ExceptionFlags.invalidOperation; 11185 case FastClass.quietNaN: 11186 return ExceptionFlags.none; 11187 case FastClass.zero: 11188 x = D.one; 11189 return ExceptionFlags.none; 11190 default: 11191 int quadrant; 11192 auto flags = coefficientCapAngle(cx, ex, sx, quadrant); 11193 switch (quadrant) 11194 { 11195 case 1: 11196 flags |= coefficientCosQ(cx, ex, sx); 11197 break; 11198 case 2: 11199 flags |= coefficientSinQ(cx, ex, sx); 11200 sx = !sx; 11201 break; 11202 case 3: 11203 flags |= coefficientCosQ(cx, ex, sx); 11204 sx = !sx; 11205 break; 11206 case 4: 11207 flags |= coefficientSinQ(cx, ex, sx); 11208 break; 11209 default: 11210 assert(0); 11211 } 11212 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 11213 } 11214 } 11215 11216 ExceptionFlags decimalTan(D)(ref D x, const int precision, const RoundingMode mode) 11217 if (isDecimal!D) 11218 { 11219 11220 DataType!D cx; int ex; bool sx; 11221 switch(fastDecode(x, cx, ex, sx)) 11222 { 11223 case FastClass.signalingNaN: 11224 return ExceptionFlags.invalidOperation; 11225 case FastClass.infinite: 11226 x = sx ? -D.nan : D.nan; 11227 return ExceptionFlags.invalidOperation; 11228 case FastClass.quietNaN: 11229 case FastClass.zero: 11230 return ExceptionFlags.none; 11231 default: 11232 int quadrant; 11233 auto flags = coefficientCapAngle(cx, ex, sx, quadrant); 11234 DataType!D csin, ccos; int esin, ecos; bool ssin, scos; 11235 flags |= coefficientSinCosQ(cx, ex, sx, csin, esin, ssin, ccos, ecos, scos); 11236 switch (quadrant) 11237 { 11238 case 1: 11239 //sin/cos, -sin/-cos 11240 case 3: 11241 cx = csin; ex = esin; sx = ssin; 11242 flags |= coefficientDiv(cx, ex, sx, ccos, ecos, scos, RoundingMode.implicit); 11243 break; 11244 case 2: 11245 //cos/-sin 11246 cx = ccos; ex = ecos; sx = scos; 11247 flags |= coefficientDiv(cx, ex, sx, csin, esin, !ssin, RoundingMode.implicit); 11248 break; 11249 case 4://-cos/sin 11250 cx = ccos; ex = ecos; sx = !scos; 11251 flags |= coefficientDiv(cx, ex, sx, csin, esin, ssin, RoundingMode.implicit); 11252 break; 11253 default: 11254 assert(0); 11255 } 11256 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 11257 } 11258 } 11259 11260 ExceptionFlags decimalAtan(D)(ref D x, const int precision, const RoundingMode mode) 11261 if (isDecimal!D) 11262 { 11263 DataType!D cx; int ex; bool sx; 11264 switch (fastDecode(x, cx, ex, sx)) 11265 { 11266 case FastClass.signalingNaN: 11267 return ExceptionFlags.invalidOperation; 11268 case FastClass.quietNaN: 11269 case FastClass.zero: 11270 return ExceptionFlags.none; 11271 case FastClass.infinite: 11272 x = signbit(x) ? -D.PI_2 : D.PI_2; 11273 return decimalAdjust(x, precision, mode); 11274 default: 11275 DataType!D reductions; 11276 coefficientCapAtan(cx, ex, sx, reductions); 11277 auto flags = coefficientAtan(cx, ex, sx); 11278 if (reductions) 11279 { 11280 flags |= coefficientMul(cx, ex, sx, reductions, 0, false, RoundingMode.implicit); 11281 flags |= coefficientMul(cx, ex, sx, DataType!D(2U), 0, false, RoundingMode.implicit); 11282 } 11283 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 11284 } 11285 } 11286 11287 ExceptionFlags decimalSinPi(D)(ref D x, const int precision, const RoundingMode mode) 11288 if (isDecimal!D) 11289 { 11290 if (isSignaling(x) || isInfinity(x)) 11291 { 11292 x = D.nan; 11293 return ExceptionFlags.invalidOperation; 11294 } 11295 11296 if (isNaN(x)) 11297 return ExceptionFlags.none; 11298 11299 decimalReduceAngle(x); 11300 11301 auto flags = decimalMul(x, D.PI, 0, mode); 11302 return flags | decimalSin(x, precision, mode); 11303 } 11304 11305 ExceptionFlags decimalCosPi(D)(ref D x, const int precision, const RoundingMode mode) 11306 if (isDecimal!D) 11307 { 11308 if (isSignaling(x) || isInfinity(x)) 11309 { 11310 x = D.nan; 11311 return ExceptionFlags.invalidOperation; 11312 } 11313 11314 if (isNaN(x)) 11315 return ExceptionFlags.none; 11316 11317 decimalReduceAngle(x); 11318 11319 auto flags = decimalMul(x, D.PI, 0, mode); 11320 return flags | decimalCos(x, precision, mode); 11321 } 11322 11323 ExceptionFlags decimalAtanPi(D)(ref D x, const int precision, const RoundingMode mode) 11324 if (isDecimal!D) 11325 { 11326 11327 if (isSignaling(x)) 11328 { 11329 x = D.nan; 11330 return ExceptionFlags.invalidOperation; 11331 } 11332 11333 if (isNaN(x) || isZero(x)) 11334 return ExceptionFlags.none; 11335 11336 if (isInfinity(x)) 11337 { 11338 x = signbit(x) ? -D.half : D.half; 11339 return ExceptionFlags.none; 11340 } 11341 11342 bool sx = cast(bool)signbit(x); 11343 x = fabs(x); 11344 11345 //if (decimalEqu(x, D.SQRT3)) 11346 //{ 11347 // x = sx ? -D.onethird : D.onethird; 11348 // return ExceptionFlags.none; 11349 //} 11350 // 11351 //if (decimalEqu(x, D.one)) 11352 //{ 11353 // x = sx ? -D.quarter : D.quarter; 11354 // return ExceptionFlags.none; 11355 //} 11356 // 11357 //if (decimalEqu(x, D.M_SQRT3)) 11358 //{ 11359 // x = sx ? -D._1_6 : D._1_6; 11360 // return ExceptionFlags.none; 11361 //} 11362 11363 11364 auto flags = decimalAtan(x, 0, mode); 11365 return flags | decimalDiv(x, D.PI, precision, mode); 11366 } 11367 11368 ExceptionFlags decimalAtan2(D1, D2, D3)(auto const ref D1 y, auto const ref D2 x, out D3 z, 11369 const int precision, const RoundingMode mode) 11370 { 11371 alias D = CommonDecimal!(D1, D2); 11372 11373 if (isSignaling(x) || isSignaling(y)) 11374 { 11375 z = D.nan; 11376 return ExceptionFlags.invalidOperation; 11377 } 11378 11379 if (isNaN(x) || isNaN(y)) 11380 { 11381 z = D.nan; 11382 return ExceptionFlags.none; 11383 } 11384 11385 if (isZero(y)) 11386 { 11387 if (signbit(x)) 11388 z = signbit(y) ? -D.PI : D.PI; 11389 else 11390 z = signbit(y) ? -D.zero : D.zero; 11391 return ExceptionFlags.inexact; 11392 } 11393 11394 if (isZero(x)) 11395 { 11396 z = signbit(y) ? -D.PI_2 : D.PI_2; 11397 return ExceptionFlags.inexact; 11398 } 11399 11400 if (isInfinity(y)) 11401 { 11402 if (isInfinity(x)) 11403 { 11404 if (signbit(x)) 11405 z = signbit(y) ? -D._3PI_4 : D._3PI_4; 11406 else 11407 z = signbit(y) ? -D.PI_4 : D.PI_4; 11408 } 11409 else 11410 z = signbit(y) ? -D.PI_2 : D.PI_2; 11411 return ExceptionFlags.inexact; 11412 } 11413 11414 if (isInfinity(x)) 11415 { 11416 if (signbit(x)) 11417 z = signbit(y) ? -D.PI : D.PI; 11418 else 11419 z = signbit(y) ? -D.zero : D.zero; 11420 return ExceptionFlags.inexact; 11421 } 11422 11423 z = y; 11424 D xx = x; 11425 auto flags = decimalDiv(z, xx, 0, mode); 11426 z = fabs(z); 11427 flags |= decimalAtan(z, 0, mode); 11428 11429 if (signbit(x)) 11430 { 11431 z = -z; 11432 return (flags | decimalAdd(z, D.PI, precision, mode)) & ExceptionFlags.inexact; 11433 } 11434 else 11435 return (flags | decimalAdjust(z, precision, mode)) & (ExceptionFlags.inexact | ExceptionFlags.underflow); 11436 } 11437 11438 ExceptionFlags decimalAtan2Pi(D1, D2, D3)(auto const ref D1 y, auto const ref D2 x, out D3 z, const int precision, const RoundingMode mode) 11439 if (isDecimal!(D1, D2, D3)) 11440 { 11441 alias D = CommonDecimal!(D1, D2); 11442 11443 if (isSignaling(x) || isSignaling(y)) 11444 { 11445 z = D.nan; 11446 return ExceptionFlags.invalidOperation; 11447 } 11448 11449 if (isNaN(x) || isNaN(y)) 11450 { 11451 z = D.nan; 11452 return ExceptionFlags.none; 11453 } 11454 11455 if (isZero(y)) 11456 { 11457 if (signbit(x)) 11458 z = signbit(y) ? -D.one : D.one; 11459 else 11460 z = signbit(y) ? -D.zero : D.zero; 11461 return ExceptionFlags.inexact; 11462 } 11463 11464 if (isZero(x)) 11465 { 11466 z = signbit(y) ? -D.half : D.half; 11467 return ExceptionFlags.inexact; 11468 } 11469 11470 if (isInfinity(y)) 11471 { 11472 if (isInfinity(x)) 11473 { 11474 if (signbit(x)) 11475 z = signbit(y) ? -D.threequarters : D.threequarters; 11476 else 11477 z = signbit(y) ? -D.quarter : D.quarter; 11478 } 11479 else 11480 z = signbit(y) ? -D.half : D.half; 11481 return ExceptionFlags.inexact; 11482 } 11483 11484 if (isInfinity(x)) 11485 { 11486 if (signbit(x)) 11487 z = signbit(y) ? -D.one : D.one; 11488 else 11489 z = signbit(y) ? -D.zero : D.zero; 11490 return ExceptionFlags.inexact; 11491 } 11492 auto flags = decimalAtan2(y, x, z, 0, mode); 11493 return flags | decimalDiv(z, D.PI, precision, mode); 11494 } 11495 11496 ExceptionFlags decimalAsin(D)(ref D x, const int precision, const RoundingMode mode) 11497 { 11498 if (isSignaling(x)) 11499 { 11500 x = D.nan; 11501 return ExceptionFlags.invalidOperation; 11502 } 11503 11504 if (isNaN(x)) 11505 return ExceptionFlags.none; 11506 11507 if (isLess(x, -D.one) || isGreater(x, D.one)) 11508 { 11509 x = D.nan; 11510 return ExceptionFlags.invalidOperation; 11511 } 11512 11513 if (isZero(x)) 11514 return ExceptionFlags.none; 11515 11516 11517 if (x == -D.one) 11518 { 11519 x = -D.PI_2; 11520 return decimalAdjust(x, precision, mode); 11521 } 11522 11523 if (x == D.one) 11524 { 11525 x = D.PI_2; 11526 return ExceptionFlags.none; 11527 } 11528 11529 11530 11531 if (x == -D.SQRT3_2) 11532 { 11533 x = -D.PI_3; 11534 return ExceptionFlags.none; 11535 } 11536 11537 if (x == -D.SQRT2_2) 11538 { 11539 x = -D.PI_4; 11540 return ExceptionFlags.none; 11541 } 11542 11543 if (x == -D.half) 11544 { 11545 x = -D.PI_6; 11546 return ExceptionFlags.none; 11547 } 11548 11549 if (x == D.half) 11550 { 11551 x = D.PI_6; 11552 return ExceptionFlags.none; 11553 } 11554 11555 if (x == D.SQRT2_2) 11556 { 11557 x = D.PI_4; 11558 return ExceptionFlags.none; 11559 } 11560 11561 if (x == D.SQRT3_2) 11562 { 11563 x = D.PI_6; 11564 return ExceptionFlags.none; 11565 } 11566 11567 //asin(x) = 2 * atan(x / ( 1 + sqrt(1 - x* x)) 11568 Unqual!D x2 = x; 11569 auto flags = decimalSqr(x2, 0, mode); 11570 x2 = -x2; 11571 flags |= decimalAdd(x2, 1U, 0, mode); 11572 flags |= decimalSqrt(x2, 0, mode); 11573 flags |= decimalAdd(x2, 1U, 0, mode); 11574 flags |= decimalDiv(x, x2, 0, mode); 11575 flags |= decimalAtan(x, 0, mode); 11576 return flags | decimalMul(x, 2U, precision, mode); 11577 } 11578 11579 ExceptionFlags decimalAcos(D)(ref D x, const int precision, const RoundingMode mode) 11580 { 11581 if (isSignaling(x)) 11582 { 11583 x = D.nan; 11584 return ExceptionFlags.invalidOperation; 11585 } 11586 11587 if (isNaN(x)) 11588 return ExceptionFlags.none; 11589 11590 if (isLess(x, -D.one) || isGreater(x, D.one)) 11591 { 11592 x = D.nan; 11593 return ExceptionFlags.invalidOperation; 11594 } 11595 11596 if (isZero(x)) 11597 { 11598 x = D.PI_2; 11599 return decimalAdjust(x, precision, mode); 11600 } 11601 11602 if (x == -D.one) 11603 { 11604 x = D.PI; 11605 return decimalAdjust(x, precision, mode); 11606 } 11607 11608 if (x == D.one) 11609 { 11610 x = D.zero; 11611 return ExceptionFlags.none; 11612 } 11613 11614 11615 11616 if (x == -D.SQRT3_2) 11617 { 11618 x = D._5PI_6; 11619 return ExceptionFlags.none; 11620 } 11621 11622 if (x == -D.SQRT2_2) 11623 { 11624 x = D._3PI_4; 11625 return ExceptionFlags.none; 11626 } 11627 11628 if (x == -D.half) 11629 { 11630 x = D._2PI_3; 11631 return ExceptionFlags.none; 11632 } 11633 11634 if (x == D.half) 11635 { 11636 x = D.PI_2; 11637 return ExceptionFlags.none; 11638 } 11639 11640 if (x == D.SQRT2_2) 11641 { 11642 x = D.PI_4; 11643 return ExceptionFlags.none; 11644 } 11645 11646 if (x == D.SQRT3_2) 11647 { 11648 x = D.PI_6; 11649 return ExceptionFlags.none; 11650 } 11651 11652 11653 11654 Unqual!D x2 = x; 11655 auto flags = decimalSqr(x2, 0, mode); 11656 x2 = -x2; 11657 flags |= decimalAdd(x2, 1U, 0, mode); 11658 flags |= decimalSqrt(x2, 0, mode); 11659 flags |= decimalAdd(x, 1U, 0, mode); 11660 flags |= decimalDiv(x2, x, 0, mode); 11661 x = x2; 11662 flags |= decimalAtan(x, 0, mode); 11663 return flags | decimalMul(x, 2U, precision, mode); 11664 } 11665 11666 ExceptionFlags decimalSinh(D)(ref D x, const int precision, const RoundingMode mode) 11667 { 11668 if (isSignaling(x)) 11669 { 11670 x = D.nan; 11671 return ExceptionFlags.invalidOperation; 11672 } 11673 11674 if (isNaN(x)) 11675 return ExceptionFlags.none; 11676 11677 if (isInfinity(x)) 11678 { 11679 x = D.infinity; 11680 return ExceptionFlags.none; 11681 } 11682 11683 if (isZero(x)) 11684 return ExceptionFlags.none; 11685 11686 Unqual!D x1 = x; 11687 Unqual!D x2 = -x; 11688 11689 11690 auto flags = decimalExp(x1, 0, mode); 11691 flags |= decimalExp(x2, 0, mode); 11692 flags |= decimalSub(x1, x2, 0, mode); 11693 x = x1; 11694 return flags | decimalMul(x, 2U, precision, mode); 11695 } 11696 11697 ExceptionFlags decimalCosh(D)(ref D x, const int precision, const RoundingMode mode) 11698 { 11699 if (isSignaling(x)) 11700 { 11701 x = D.nan; 11702 return ExceptionFlags.invalidOperation; 11703 } 11704 11705 if (isNaN(x)) 11706 return ExceptionFlags.none; 11707 11708 if (isInfinity(x)) 11709 { 11710 x = D.infinity; 11711 return ExceptionFlags.none; 11712 } 11713 11714 if (isZero(x)) 11715 { 11716 x = D.one; 11717 return ExceptionFlags.none; 11718 } 11719 11720 Unqual!D x1 = x; 11721 Unqual!D x2 = -x; 11722 auto flags = decimalExp(x1, 0, mode); 11723 flags |= decimalExp(x2, 0, mode); 11724 flags |= decimalAdd(x1, x2, 0, mode); 11725 x = x1; 11726 return flags | decimalMul(x, D.half, precision, mode); 11727 } 11728 11729 ExceptionFlags decimalTanh(D)(ref D x, const int precision, const RoundingMode mode) 11730 { 11731 11732 if (isSignaling(x)) 11733 { 11734 x = D.nan; 11735 return ExceptionFlags.invalidOperation; 11736 } 11737 11738 if (isNaN(x)) 11739 return ExceptionFlags.none; 11740 11741 if (isInfinity(x)) 11742 { 11743 x = signbit(x) ? -D.one : D.one; 11744 return ExceptionFlags.none; 11745 } 11746 11747 if (isZero(x)) 11748 return ExceptionFlags.none; 11749 11750 Unqual!D x1 = x; 11751 Unqual!D x2 = -x; 11752 auto flags = decimalSinh(x1, 0, mode); 11753 flags |= decimalCosh(x2, 0, mode); 11754 x = x1; 11755 return flags | decimalDiv(x, x2, precision, mode); 11756 } 11757 11758 ExceptionFlags decimalAsinh(D)(ref D x, const int precision, const RoundingMode mode) 11759 { 11760 if (isSignaling(x)) 11761 { 11762 x = D.nan; 11763 return ExceptionFlags.invalidOperation; 11764 } 11765 11766 if (isNaN(x) || isZero(x) || isInfinity(x)) 11767 return ExceptionFlags.none; 11768 11769 //+- ln(|x| + sqrt(x*x + 1)) 11770 //+-[ln(2) + ln(|x|)] for very big x, 11771 11772 //sqrt(D.max)/2 11773 static if (is(D: decimal32)) 11774 { 11775 enum asinhmax = decimal32("1.581138e51"); 11776 } 11777 else static if (is(D: decimal64)) 11778 { 11779 enum asinhmax = decimal64("1.581138830084189e192"); 11780 } 11781 else 11782 { 11783 enum asinhmax = decimal128("1.581138830084189665999446772216359e3072"); 11784 } 11785 11786 bool sx = cast(bool)signbit(x); 11787 x = fabs(x); 11788 11789 ExceptionFlags flags; 11790 if (isGreater(x, asinhmax)) 11791 { 11792 flags = decimalLog(x, 0, mode) | ExceptionFlags.inexact; 11793 flags |= decimalAdd(x, D.LN2, 0, mode); 11794 11795 } 11796 else 11797 { 11798 Unqual!D x1 = x; 11799 flags = decimalSqr(x1, 0, mode); 11800 flags |= decimalAdd(x1, 1U, 0, mode); 11801 flags |= decimalSqrt(x1, 0, mode); 11802 flags |= decimalAdd(x, x1, 0, mode); 11803 flags |= decimalLog(x, 0, mode); 11804 } 11805 11806 if (sx) 11807 x = -x; 11808 return flags | decimalAdjust(x, precision, mode); 11809 11810 11811 } 11812 11813 ExceptionFlags decimalAcosh(D)(ref D x, const int precision, const RoundingMode mode) 11814 { 11815 if (isSignaling(x)) 11816 { 11817 x = D.nan; 11818 return ExceptionFlags.invalidOperation; 11819 } 11820 11821 if (isNaN(x)) 11822 return ExceptionFlags.none; 11823 11824 if (isLess(x, D.one)) 11825 { 11826 x = D.nan; 11827 return ExceptionFlags.invalidOperation; 11828 } 11829 11830 if (x == D.one) 11831 { 11832 x = D.zero; 11833 return ExceptionFlags.none; 11834 } 11835 11836 if (isInfinity(x)) 11837 return ExceptionFlags.none; 11838 11839 ExceptionFlags flags; 11840 11841 /* 11842 ln(x+sqrt(x*x - 1)) 11843 for very big x: (ln(x + x) = ln(2) + ln(x), otherwise will overflow 11844 */ 11845 11846 //sqrt(D.max)/2 11847 static if (is(D: decimal32)) 11848 { 11849 enum acoshmax = decimal32("1.581138e51"); 11850 } 11851 else static if (is(D: decimal64)) 11852 { 11853 enum acoshmax = decimal64("1.581138830084189e192"); 11854 } 11855 else 11856 { 11857 enum acoshmax = decimal128("1.581138830084189665999446772216359e3072"); 11858 } 11859 11860 if (isGreater(x, acoshmax)) 11861 { 11862 flags = decimalLog(x, 0, mode) | ExceptionFlags.inexact; 11863 return flags |= decimalAdd(x, D.LN2, precision, mode); 11864 } 11865 else 11866 { 11867 Unqual!D x1 = x; 11868 flags = decimalSqr(x1, 0, mode); 11869 flags |= decimalSub(x1, 1U, 0, mode); 11870 flags |= decimalSqrt(x1, 0, mode); 11871 flags |= decimalAdd(x, x1, 0, mode); 11872 return flags | decimalLog(x, precision, mode); 11873 } 11874 } 11875 11876 ExceptionFlags decimalAtanh(D)(ref D x, const int precision, const RoundingMode mode) 11877 { 11878 if (isSignaling(x)) 11879 { 11880 x = D.nan; 11881 return ExceptionFlags.invalidOperation; 11882 } 11883 11884 if (isNaN(x) || isZero(x)) 11885 return ExceptionFlags.none; 11886 11887 alias T = DataType!D; 11888 T cx; 11889 int ex; 11890 bool sx = x.unpack(cx, ex); 11891 11892 auto cmp = coefficientCmp(cx, ex, false, T(1U), 0, false); 11893 11894 if (cmp > 0) 11895 { 11896 x = signbit(x) ? -D.nan : D.nan; 11897 return ExceptionFlags.none; 11898 } 11899 11900 if (cmp == 0) 11901 { 11902 x = signbit(x) ? -D.infinity : D.infinity; 11903 return ExceptionFlags.none; 11904 } 11905 11906 auto flags = coefficientAtanh(cx, ex, sx); 11907 return x.adjustedPack(cx, ex, sx, precision, mode, flags); 11908 11909 } 11910 11911 ExceptionFlags decimalSum(D)(const(D)[] x, out D result, const int precision, const RoundingMode mode) 11912 if (isDecimal!D) 11913 { 11914 ExceptionFlags flags; 11915 alias T = MakeUnsigned!(D.sizeof * 16); 11916 DataType!D cx; 11917 T cxx, cr; 11918 int ex, er; 11919 bool sx, sr; 11920 11921 result = 0; 11922 bool hasPositiveInfinity, hasNegativeInfinity; 11923 size_t i = 0; 11924 while (i < x.length) 11925 { 11926 if (isSignaling(x[i])) 11927 { 11928 result = D.nan; 11929 return ExceptionFlags.invalidOperation; 11930 } 11931 11932 if (isNaN(x[i])) 11933 { 11934 result = D.nan; 11935 return ExceptionFlags.none; 11936 } 11937 11938 if (isInfinity(x[i])) 11939 { 11940 if (signbit(x[i])) 11941 hasNegativeInfinity = true; 11942 else 11943 hasPositiveInfinity = true; 11944 ++i; 11945 break; 11946 } 11947 11948 if (isZero(x[i])) 11949 { 11950 ++i; 11951 continue; 11952 } 11953 11954 sx = x.unpack(cx, ex); 11955 cxx = cx; 11956 flags |= coefficientAdd(cr, er, sr, cxx, ex, sx, mode); 11957 ++i; 11958 11959 if (flags & ExceptionFlags.overflow) 11960 break; 11961 } 11962 11963 while (i < x.length) 11964 { 11965 //infinity or overflow detected 11966 if (isSignaling(x[i])) 11967 { 11968 result = D.nan; 11969 return ExceptionFlags.invalidOperation; 11970 } 11971 11972 if (isNaN(x[i])) 11973 { 11974 result = D.nan; 11975 return ExceptionFlags.none; 11976 } 11977 11978 if (isInfinity(x[i])) 11979 { 11980 if (signbit(x[i])) 11981 hasNegativeInfinity = true; 11982 else 11983 hasPositiveInfinity = true; 11984 } 11985 ++i; 11986 } 11987 11988 if (hasPositiveInfinity) 11989 { 11990 if (hasNegativeInfinity) 11991 { 11992 result = D.nan; 11993 return ExceptionFlags.invalidOperation; 11994 } 11995 result = D.infinity; 11996 return ExceptionFlags.none; 11997 } 11998 11999 if (hasNegativeInfinity) 12000 { 12001 result = -D.infinity; 12002 return ExceptionFlags.none; 12003 } 12004 12005 flags |= coefficientAdjust(cr, er, cvt!T(DataType!D.max), sr, mode); 12006 return result.adjustedPack(cvt!(DataType!D)(cr), er, sr, precision, mode, flags); 12007 } 12008 12009 ExceptionFlags decimalSumSquare(D)(const(D)[] x, out D result, const int precision, const RoundingMode mode) 12010 if (isDecimal!D) 12011 { 12012 ExceptionFlags flags; 12013 alias T = MakeUnsigned!(D.sizeof * 16); 12014 DataType!D cx; 12015 T cxx, cr; 12016 int ex, er; 12017 bool sr; 12018 result = 0; 12019 bool hasInfinity; 12020 size_t i = 0; 12021 while (i < x.length) 12022 { 12023 if (isSignaling(x[i])) 12024 { 12025 result = D.nan; 12026 return ExceptionFlags.invalidOperation; 12027 } 12028 12029 if (isNaN(x[i])) 12030 { 12031 result = D.nan; 12032 return ExceptionFlags.none; 12033 } 12034 12035 if (isInfinity(x[i])) 12036 { 12037 hasInfinity = true; 12038 ++i; 12039 break; 12040 } 12041 12042 if (isZero(x[i])) 12043 { 12044 ++i; 12045 continue; 12046 } 12047 12048 x.unpack(cx, ex); 12049 cxx = cx; 12050 flags |= coefficientSqr(cxx, ex); 12051 flags |= coefficientAdd(cr, er, sr, cxx, ex, false, mode); 12052 ++i; 12053 12054 if (flags & ExceptionFlags.overflow) 12055 break; 12056 } 12057 12058 while (i < x.length) 12059 { 12060 //infinity or overflow detected 12061 if (isSignaling(x[i])) 12062 { 12063 result = D.nan; 12064 return ExceptionFlags.invalidOperation; 12065 } 12066 12067 if (isNaN(x[i])) 12068 { 12069 result = D.nan; 12070 return ExceptionFlags.none; 12071 } 12072 12073 if (isInfinity(x[i])) 12074 hasInfinity = true; 12075 ++i; 12076 } 12077 12078 if (hasInfinity) 12079 { 12080 result = D.infinity; 12081 return ExceptionFlags.none; 12082 } 12083 12084 flags |= coefficientAdjust(cr, er, cvt!T(DataType!D.max), sr, mode); 12085 return result.adjustedPack(cvt!(DataType!D)(cr), er, sr, precision, mode, flags); 12086 12087 } 12088 12089 ExceptionFlags decimalSumAbs(D)(const(D)[] x, out D result, const int precision, const RoundingMode mode) 12090 if (isDecimal!D) 12091 { 12092 ExceptionFlags flags; 12093 alias T = MakeUnsigned!(D.sizeof * 16); 12094 DataType!D cx; 12095 T cxx, cr; 12096 int ex, er; 12097 bool sr; 12098 12099 result = 0; 12100 bool hasInfinity; 12101 size_t i = 0; 12102 while (i < x.length) 12103 { 12104 if (isSignaling(x[i])) 12105 { 12106 result = D.nan; 12107 return ExceptionFlags.invalidOperation; 12108 } 12109 12110 if (isNaN(x[i])) 12111 { 12112 result = D.nan; 12113 return ExceptionFlags.none; 12114 } 12115 12116 if (isInfinity(x[i])) 12117 { 12118 hasInfinity = true; 12119 ++i; 12120 break; 12121 } 12122 12123 if (isZero(x[i])) 12124 { 12125 ++i; 12126 continue; 12127 } 12128 12129 x.unpack(cx, ex); 12130 cxx = cx; 12131 flags |= coefficientAdd(cr, er, sr, cxx, ex, false, mode); 12132 ++i; 12133 12134 if (flags & ExceptionFlags.overflow) 12135 break; 12136 } 12137 12138 while (i < x.length) 12139 { 12140 //infinity or overflow detected 12141 if (isSignaling(x[i])) 12142 { 12143 result = D.nan; 12144 return ExceptionFlags.invalidOperation; 12145 } 12146 12147 if (isNaN(x[i])) 12148 { 12149 result = D.nan; 12150 return ExceptionFlags.none; 12151 } 12152 12153 if (isInfinity(x[i])) 12154 hasInfinity = true; 12155 ++i; 12156 } 12157 12158 12159 12160 if (hasInfinity) 12161 { 12162 result = D.infinity; 12163 return ExceptionFlags.none; 12164 } 12165 12166 flags |= coefficientAdjust(cr, er, cvt!T(DataType!D.max), sr, mode); 12167 return result.adjustedPack(cvt!(DataType!D)(cr), er, sr, precision, mode, flags); 12168 } 12169 12170 ExceptionFlags decimalDot(D)(const(D)[] x, const(D)[] y, out D result, const int precision, const RoundingMode mode) 12171 if (isDecimal!D) 12172 { 12173 size_t len = x.length; 12174 if (len > y.length) 12175 len = y.length; 12176 12177 bool hasPositiveInfinity, hasNegativeInfinity; 12178 12179 alias T = MakeUnsigned!(D.sizeof * 16); 12180 DataType!D cx, cy; 12181 T cxx, cyy, cr; 12182 int ex, ey, er; 12183 bool sx, sy, sr; 12184 12185 size_t i = 0; 12186 while (i < len) 12187 { 12188 if (isSignaling(x[i]) || isSignaling(y[i])) 12189 { 12190 result = D.nan; 12191 return ExceptionFlags.invalidOperation; 12192 } 12193 12194 if (isNaN(x[i]) || isNaN(y[i])) 12195 { 12196 result = D.nan; 12197 return ExceptionFlags.none; 12198 } 12199 12200 if (isInfinity(x[i])) 12201 { 12202 if (isZero(y[i])) 12203 { 12204 result = D.nan; 12205 return ExceptionFlags.invalidOperation; 12206 } 12207 12208 if (isInfinity(y[i])) 12209 { 12210 if (signbit(x[i]) ^ signbit(y[i])) 12211 hasNegativeInfinity = true; 12212 else 12213 hasPositiveInfinity = true; 12214 12215 } 12216 else 12217 { 12218 if (signbit(x[i])) 12219 hasNegativeInfinity = true; 12220 else 12221 hasPositiveInfinity = true; 12222 } 12223 ++i; 12224 break; 12225 } 12226 12227 if (isInfinity(y[i])) 12228 { 12229 if (isZero(x[i])) 12230 { 12231 result = D.nan; 12232 return ExceptionFlags.invalidOperation; 12233 } 12234 12235 12236 if (signbit(y[i])) 12237 hasNegativeInfinity = true; 12238 else 12239 hasPositiveInfinity = true; 12240 12241 ++i; 12242 break; 12243 } 12244 12245 if (isZero(x[i]) || isZero(y[i])) 12246 { 12247 ++i; 12248 continue; 12249 } 12250 12251 sx = x[i].unpack(cx, ex); 12252 sy = y[i].unpack(cy, ey); 12253 cxx = cx; cyy = cy; 12254 flags |= coefficientMul(cx, ex, sx, cy, ey, sy, mode); 12255 flags |= coefficientAdd(cr, er, sr, cx, ex, sx, mode); 12256 ++i; 12257 if (flags & ExceptionFlags.overflow) 12258 break; 12259 } 12260 12261 while (i < len) 12262 { 12263 if (isSignaling(x[i]) || isSignaling(y[i])) 12264 { 12265 result = D.nan; 12266 return ExceptionFlags.invalidOperation; 12267 } 12268 12269 if (isNaN(x[i]) || isNaN(y[i])) 12270 { 12271 result = D.nan; 12272 return ExceptionFlags.none; 12273 } 12274 12275 if (isInfinity(x[i])) 12276 { 12277 if (isZero(y[i])) 12278 { 12279 result = D.nan; 12280 return ExceptionFlags.invalidOperation; 12281 } 12282 12283 if (isInfinity(y[i])) 12284 { 12285 if (signbit(x[i]) ^ signbit(y[i])) 12286 hasNegativeInfinity = true; 12287 else 12288 hasPositiveInfinity = true; 12289 12290 } 12291 else 12292 { 12293 if (signbit(x[i])) 12294 hasNegativeInfinity = true; 12295 else 12296 hasPositiveInfinity = true; 12297 } 12298 } 12299 12300 if (isInfinity(y[i])) 12301 { 12302 if (isZero(x[i])) 12303 { 12304 result = D.nan; 12305 return ExceptionFlags.invalidOperation; 12306 } 12307 12308 12309 if (signbit(y[i])) 12310 hasNegativeInfinity = true; 12311 else 12312 hasPositiveInfinity = true; 12313 } 12314 12315 ++i; 12316 } 12317 12318 if (hasPositiveInfinity) 12319 { 12320 if (hasNegativeInfinity) 12321 { 12322 result = D.nan; 12323 return ExceptionFlags.invalidOperation; 12324 } 12325 result = D.infinity; 12326 return ExceptionFlags.none; 12327 } 12328 12329 if (hasNegativeInfinity) 12330 { 12331 result = -D.infinity; 12332 return ExceptionFlags.none; 12333 } 12334 12335 flags |= coefficientAdjust(cr, er, cvt!T(DataType!D.max), sr, mode); 12336 return result.adjustedPack(cvt!(DataType!D)(cr), er, sr, precision, mode, flags); 12337 } 12338 12339 ExceptionFlags decimalProd(D)(const(D)[] x, out D result, out int scale, const int precision, const RoundingMode mode) 12340 if (isDecimal!D) 12341 { 12342 ExceptionFlags flags; 12343 alias T = MakeUnsigned!(D.sizeof * 16); 12344 DataType!D cx; 12345 T cxx, cr; 12346 int ex, er; 12347 bool sx, sr; 12348 12349 result = 0; 12350 scale = 0; 12351 bool hasInfinity; 12352 bool hasZero; 12353 bool infinitySign; 12354 bool zeroSign; 12355 size_t i = 0; 12356 while (i < x.length) 12357 { 12358 if (isSignaling(x[i])) 12359 { 12360 result = D.nan; 12361 return ExceptionFlags.invalidOperation; 12362 } 12363 12364 if (isNaN(x[i])) 12365 { 12366 result = D.nan; 12367 return ExceptionFlags.none; 12368 } 12369 12370 if (isInfinity(x[i])) 12371 { 12372 hasInfinity = true; 12373 infinitySign = cast(bool)(signbit(x[i])); 12374 ++i; 12375 break; 12376 } 12377 12378 if (isZero(x[i])) 12379 { 12380 hasZero = true; 12381 zeroSign = cast(bool)(signbit(x[i])); 12382 ++i; 12383 break; 12384 } 12385 12386 sx = x.unpack(cx, ex); 12387 cxx = cx; 12388 flags |= coefficientMul(cr, er, sr, cxx, ex, sx, mode); 12389 er -= cappedAdd(scale, er); 12390 ++i; 12391 12392 if (flags & ExceptionFlags.overflow) 12393 break; 12394 } 12395 12396 while (i < x.length) 12397 { 12398 //infinity or overflow detected 12399 if (isSignaling(x[i])) 12400 { 12401 result = D.nan; 12402 return ExceptionFlags.invalidOperation; 12403 } 12404 12405 if (isNaN(x[i])) 12406 { 12407 result = D.nan; 12408 return ExceptionFlags.none; 12409 } 12410 12411 if (isInfinity(x[i])) 12412 { 12413 hasInfinity = true; 12414 infinitySign ^= cast(bool)(signbit(x[i])); 12415 } 12416 else if (isZero(x[i])) 12417 { 12418 hasZero = true; 12419 zeroSign ^= cast(bool)(signbit(x[i])); 12420 } 12421 else 12422 { 12423 zeroSign ^= cast(bool)(signbit(x[i])); 12424 } 12425 12426 12427 ++i; 12428 } 12429 12430 if (hasInfinity & hasZero) 12431 { 12432 result = D.nan; 12433 return ExceptionFlags.invalidOperation; 12434 } 12435 12436 if (hasInfinity) 12437 { 12438 result = infinitySign ? -D.infinity : D.infinity; 12439 return ExceptionFlags.none; 12440 } 12441 12442 if (hasZero) 12443 { 12444 result = zeroSign ? -D.zero : D.zero; 12445 return ExceptionFlags.none; 12446 } 12447 12448 flags |= coefficientAdjust(cr, er, cvt!T(DataType!D.max), sr, mode); 12449 return result.adjustedPack(cvt!(DataType!D)(cr), er, sr, precision, mode, flags); 12450 } 12451 12452 ExceptionFlags decimalProdSum(D)(const(D)[] x, const(D)[] y, out D result, out int scale, const int precision, const RoundingMode mode) 12453 if (isDecimal!D) 12454 { 12455 size_t len = x.length; 12456 if (len > y.length) 12457 len = y.length; 12458 12459 bool hasInfinity; 12460 bool hasZero; 12461 12462 bool infinitySign; 12463 12464 bool invalidSum; 12465 12466 alias T = MakeUnsigned!(D.sizeof * 16); 12467 DataType!D cx, cy; 12468 T cxx, cyy, cr; 12469 int ex, ey, er; 12470 bool sx, sy, sr; 12471 12472 size_t i = 0; 12473 while (i < len) 12474 { 12475 if (isSignaling(x[i]) || isSignaling(y[i])) 12476 { 12477 result = D.nan; 12478 return ExceptionFlags.invalidOperation; 12479 } 12480 12481 if (isNaN(x[i]) || isNaN(y[i])) 12482 { 12483 result = D.nan; 12484 return ExceptionFlags.none; 12485 } 12486 12487 if (isInfinity(x[i])) 12488 { 12489 if (isInfinity(y[i]) && signbit(x) != signbit(y)) 12490 { 12491 invalidSum = true; 12492 ++i; 12493 break; 12494 } 12495 12496 hasInfinity = true; 12497 infinitySign = cast(bool)signbit(x[i]); 12498 ++i; 12499 break; 12500 } 12501 12502 if (isInfinity(y[i])) 12503 { 12504 hasInfinity = true; 12505 infinitySign = cast(bool)signbit(x[i]); 12506 ++i; 12507 break; 12508 } 12509 12510 if (x[i] == -y[i]) 12511 { 12512 hasZero = true; 12513 ++i; 12514 break; 12515 } 12516 sx = x[i].unpack(cx, ex); 12517 sy = y[i].unpack(cy, ey); 12518 cxx = cx; cyy = cy; 12519 flags |= coefficientAdd(cx, ex, sx, cy, ey, sy, mode); 12520 flags |= coefficientMul(cr, er, sr, cx, ex, sx, mode); 12521 er -= cappedAdd(scale, er); 12522 ++i; 12523 if (flags & ExceptionFlags.overflow) 12524 break; 12525 if (flags & ExceptionFlags.underflow) 12526 break; 12527 12528 } 12529 12530 while (i < len) 12531 { 12532 //inf, zero or overflow, underflow, invalidSum; 12533 if (isSignaling(x[i]) || isSignaling(y[i])) 12534 { 12535 result = D.nan; 12536 return ExceptionFlags.invalidOperation; 12537 } 12538 12539 if (isNaN(x[i]) || isNaN(y[i])) 12540 { 12541 result = D.nan; 12542 return ExceptionFlags.none; 12543 } 12544 12545 if (isInfinity(x[i])) 12546 { 12547 if (isInfinity(y[i]) && signbit(x) != signbit(y)) 12548 invalidSum = true; 12549 else 12550 { 12551 hasInfinity = true; 12552 infinitySign ^= cast(bool)signbit(x[i]); 12553 } 12554 } 12555 else if (isInfinity(y[i])) 12556 { 12557 hasInfinity = true; 12558 infinitySign ^= cast(bool)signbit(y[i]); 12559 } 12560 else if (x[i] == -y[i]) 12561 hasZero = true; 12562 ++i; 12563 } 12564 12565 if (invalidSum) 12566 { 12567 result = D.nan; 12568 return ExceptionFlags.invalidOperation; 12569 } 12570 12571 if (hasInfinity & hasZero) 12572 { 12573 result = D.nan; 12574 return ExceptionFlags.invalidOperation; 12575 } 12576 12577 if (hasInfinity) 12578 { 12579 result = infinitySign ? -D.infinity : D.infinity; 12580 return ExceptionFlags.none; 12581 } 12582 12583 if (hasZero) 12584 { 12585 result = D.zero; 12586 return ExceptionFlags.none; 12587 } 12588 12589 flags |= coefficientAdjust(cr, er, cvt!T(DataType!D.max), sr, mode); 12590 return result.adjustedPack(cvt!(DataType!D)(cr), er, sr, precision, mode, flags); 12591 } 12592 12593 ExceptionFlags decimalProdDiff(D)(const(D)[] x, const(D)[] y, out D result, out int scale, const int precision, const RoundingMode mode) 12594 if (isDecimal!D) 12595 { 12596 size_t len = x.length; 12597 if (len > y.length) 12598 len = y.length; 12599 12600 bool hasInfinity; 12601 bool hasZero; 12602 12603 bool infinitySign; 12604 12605 bool invalidSum; 12606 12607 alias T = MakeUnsigned!(D.sizeof * 16); 12608 DataType!D cx, cy; 12609 T cxx, cyy, cr; 12610 int ex, ey, er; 12611 bool sx, sy, sr; 12612 12613 size_t i = 0; 12614 while (i < len) 12615 { 12616 if (isSignaling(x[i]) || isSignaling(y[i])) 12617 { 12618 result = D.nan; 12619 return ExceptionFlags.invalidOperation; 12620 } 12621 12622 if (isNaN(x[i]) || isNaN(y[i])) 12623 { 12624 result = D.nan; 12625 return ExceptionFlags.none; 12626 } 12627 12628 if (isInfinity(x[i])) 12629 { 12630 if (isInfinity(y[i]) && signbit(x) != signbit(y)) 12631 { 12632 invalidSum = true; 12633 ++i; 12634 break; 12635 } 12636 12637 hasInfinity = true; 12638 infinitySign = cast(bool)signbit(x[i]); 12639 ++i; 12640 break; 12641 } 12642 12643 if (isInfinity(y[i])) 12644 { 12645 hasInfinity = true; 12646 infinitySign = cast(bool)signbit(x[i]); 12647 ++i; 12648 break; 12649 } 12650 12651 if (x[i] == y[i]) 12652 { 12653 hasZero = true; 12654 ++i; 12655 break; 12656 } 12657 sx = x[i].unpack(cx, ex); 12658 sy = y[i].unpack(cy, ey); 12659 cxx = cx; cyy = cy; 12660 flags |= coefficientSub(cx, ex, sx, cy, ey, sy, mode); 12661 flags |= coefficientMul(cr, er, sr, cx, ex, sx, mode); 12662 er -= cappedAdd(scale, er); 12663 ++i; 12664 if (flags & ExceptionFlags.overflow) 12665 break; 12666 if (flags & ExceptionFlags.underflow) 12667 break; 12668 12669 } 12670 12671 while (i < len) 12672 { 12673 //inf, zero or overflow, underflow, invalidSum; 12674 if (isSignaling(x[i]) || isSignaling(y[i])) 12675 { 12676 result = D.nan; 12677 return ExceptionFlags.invalidOperation; 12678 } 12679 12680 if (isNaN(x[i]) || isNaN(y[i])) 12681 { 12682 result = D.nan; 12683 return ExceptionFlags.none; 12684 } 12685 12686 if (isInfinity(x[i])) 12687 { 12688 if (isInfinity(y[i]) && signbit(x) != signbit(y)) 12689 invalidSum = true; 12690 else 12691 { 12692 hasInfinity = true; 12693 infinitySign ^= cast(bool)signbit(x[i]); 12694 } 12695 } 12696 else if (isInfinity(y[i])) 12697 { 12698 hasInfinity = true; 12699 infinitySign ^= cast(bool)signbit(y[i]); 12700 } 12701 else if (x[i] == y[i]) 12702 hasZero = true; 12703 ++i; 12704 } 12705 12706 if (invalidSum) 12707 { 12708 result = D.nan; 12709 return ExceptionFlags.invalidOperation; 12710 } 12711 12712 if (hasInfinity & hasZero) 12713 { 12714 result = D.nan; 12715 return ExceptionFlags.invalidOperation; 12716 } 12717 12718 if (hasInfinity) 12719 { 12720 result = infinitySign ? -D.infinity : D.infinity; 12721 return ExceptionFlags.none; 12722 } 12723 12724 if (hasZero) 12725 { 12726 result = D.zero; 12727 return ExceptionFlags.none; 12728 } 12729 12730 flags |= coefficientAdjust(cr, er, cvt!T(DataType!D.max), sr, mode); 12731 return result.adjustedPack(cvt!(DataType!D)(cr), er, sr, precision, mode, flags); 12732 } 12733 12734 ExceptionFlags decimalPoly(D1, D2, D)(auto const ref D1 x, const(D2)[] a, out D result) 12735 if (isDecimal!(D1, D2) && is(D: CommonDecimal!(D1, D2))) 12736 { 12737 if (!a.length) 12738 { 12739 result = 0; 12740 return ExceptionFlags.none; 12741 } 12742 ptrdiff_t i = a.length - 1; 12743 D result = a[i]; 12744 ExceptionFlags flags; 12745 while (--i >= 0) 12746 { 12747 flags |= decimalMul(result, x); 12748 flags |= decimalAdd(result, a[i]); 12749 } 12750 return flags; 12751 } 12752 12753 /* ****************************************************************************************************************** */ 12754 /* COEFFICIENT ARITHMETIC */ 12755 /* ****************************************************************************************************************** */ 12756 //divPow10 - inexact 12757 //mulPow10 - overflow 12758 //coefficientAdjust - inexact, overflow, underflow 12759 //coefficientExpand - none 12760 //coefficientShrink - inexact 12761 //coefficientAdd - inexact, overflow 12762 //coefficientMul - inexact, overflow, underflow 12763 //coefficientDiv - inexact, overflow, underflow, div0 12764 //coefficientMod - inexact, overflow, underflow, invalid 12765 //coefficientFMA - inexact, overflow, underflow 12766 //coefficientCmp - none 12767 //coefficientEqu - none 12768 //coefficientSqr - inexact, overflow, underflow 12769 12770 12771 12772 12773 ExceptionFlags exp2to10(RoundingMode mode = RoundingMode.implicit, U)(ref U coefficient, ref int exponent, const bool isNegative) 12774 { 12775 enum maxMultiplicable = U.max / 5U; 12776 12777 enum hibit = U(1U) << (U.sizeof * 8 - 1); 12778 ExceptionFlags flags; 12779 auto e5 = -exponent; 12780 12781 if (e5 > 0) 12782 { 12783 auto tz = ctz(coefficient); 12784 if (tz) 12785 { 12786 auto shift = e5 > tz ? tz : e5; 12787 e5 -= shift; 12788 exponent += shift; 12789 coefficient >>= shift; 12790 } 12791 12792 while (e5 > 0) 12793 { 12794 --e5; 12795 if (coefficient < maxMultiplicable) 12796 coefficient *= 5U; 12797 else 12798 { 12799 ++exponent; 12800 bool mustRound = cast(bool)(coefficient & 1U); 12801 coefficient >>= 1; 12802 if (mustRound) 12803 { 12804 flags = ExceptionFlags.inexact; 12805 static if (mode == RoundingMode.tiesToAway) 12806 { 12807 ++coefficient; 12808 } 12809 else static if (mode == RoundingMode.tiesToEven) 12810 { 12811 if ((coefficient & 1U)) 12812 ++coefficient; 12813 } 12814 else static if (mode == RoundingMode.towardNegative) 12815 { 12816 if (isNegative) 12817 ++coefficient; 12818 } 12819 else static if (mode == RoundingMode.towardPositive) 12820 { 12821 if (!isNegative) 12822 ++coefficient; 12823 } 12824 } 12825 } 12826 } 12827 } 12828 12829 if (e5 < 0) 12830 { 12831 auto lz = clz(coefficient); 12832 if (lz) 12833 { 12834 auto shift = -e5 > lz ? lz : -e5; 12835 exponent -= shift; 12836 e5 += shift; 12837 coefficient <<= shift; 12838 } 12839 12840 while (e5 < 0) 12841 { 12842 ++e5; 12843 if (coefficient & hibit) 12844 { 12845 auto r = divrem(coefficient, 5U); 12846 if (r) 12847 { 12848 flags = ExceptionFlags.inexact; 12849 static if (mode == RoundingMode.towardNegative) 12850 { 12851 if (isNegative) 12852 ++coefficient; 12853 } 12854 else static if (mode == RoundingMode.towardPositive) 12855 { 12856 if (!isNegative) 12857 ++coefficient; 12858 } 12859 else static if (mode == RoundingMode.tiesToAway || mode == RoundingMode.tiesToEven) 12860 { 12861 if (r >= 3U) 12862 ++coefficient; 12863 } 12864 } 12865 } 12866 else 12867 { 12868 coefficient <<= 1; 12869 --exponent; 12870 } 12871 } 12872 12873 } 12874 12875 return flags; 12876 } 12877 12878 ExceptionFlags exp10to2(RoundingMode mode = RoundingMode.implicit, U)(ref U coefficient, ref int exponent, const bool isNegative) 12879 { 12880 enum maxMultiplicable = U.max / 5U; 12881 12882 enum hibit = U(1U) << (U.sizeof * 8 - 1); 12883 ExceptionFlags flags; 12884 auto e5 = exponent; 12885 12886 if (e5 > 0) 12887 { 12888 while (e5 > 0) 12889 { 12890 12891 if (coefficient < maxMultiplicable) 12892 { 12893 --e5; 12894 coefficient *= 5U; 12895 } 12896 else 12897 { 12898 ++exponent; 12899 bool mustRound = cast(bool)(coefficient & 1U); 12900 coefficient >>= 1; 12901 if (mustRound) 12902 { 12903 flags = ExceptionFlags.inexact; 12904 static if (mode == RoundingMode.tiesToAway) 12905 { 12906 ++coefficient; 12907 } 12908 else static if (mode == RoundingMode.tiesToEven) 12909 { 12910 if ((coefficient & 1U)) 12911 ++coefficient; 12912 } 12913 else static if (mode == RoundingMode.towardNegative) 12914 { 12915 if (isNegative) 12916 ++coefficient; 12917 } 12918 else static if (mode == RoundingMode.towardPositive) 12919 { 12920 if (!isNegative) 12921 ++coefficient; 12922 } 12923 } 12924 } 12925 } 12926 } 12927 12928 if (e5 < 0) 12929 { 12930 while (e5 < 0) 12931 { 12932 12933 if (coefficient & hibit) 12934 { 12935 ++e5; 12936 auto r = divrem(coefficient, 5U); 12937 if (r) 12938 { 12939 flags = ExceptionFlags.inexact; 12940 static if (mode == RoundingMode.towardNegative) 12941 { 12942 if (isNegative) 12943 ++coefficient; 12944 } 12945 else static if (mode == RoundingMode.towardPositive) 12946 { 12947 if (!isNegative) 12948 ++coefficient; 12949 } 12950 else static if (mode == RoundingMode.tiesToAway || mode == RoundingMode.tiesToEven) 12951 { 12952 if (r >= 3U) 12953 ++coefficient; 12954 } 12955 } 12956 } 12957 else 12958 { 12959 coefficient <<= 1; 12960 --exponent; 12961 } 12962 } 12963 12964 } 12965 12966 return flags; 12967 } 12968 12969 unittest 12970 { 12971 uint cx = 3402823; 12972 int ex = 32; 12973 12974 12975 exp10to2!(RoundingMode.towardZero)(cx, ex, false); 12976 } 12977 12978 //divides coefficient by 10^power 12979 //inexact 12980 @safe pure nothrow @nogc 12981 ExceptionFlags divpow10(T)(ref T coefficient, const int power, const bool isNegative, const RoundingMode mode) 12982 if (isAnyUnsigned!T) 12983 in 12984 { 12985 assert (power >= 0); 12986 } 12987 body 12988 { 12989 Unqual!T remainder; 12990 12991 if (coefficient == 0U) 12992 return ExceptionFlags.none; 12993 12994 if (power == 0) 12995 return ExceptionFlags.none; 12996 12997 if (power >= pow10!T.length) 12998 { 12999 remainder = coefficient; 13000 coefficient = 0U; 13001 } 13002 else 13003 remainder = divrem(coefficient, pow10!T[power]); 13004 13005 if (remainder == 0U) 13006 return ExceptionFlags.none; 13007 13008 immutable half = power >= pow10!T.length ? T.max : pow10!T[power] >>> 1; 13009 final switch (mode) 13010 { 13011 case RoundingMode.tiesToEven: 13012 if (remainder > half) 13013 ++coefficient; 13014 else if ((remainder == half) && ((coefficient & 1U) != 0U)) 13015 ++coefficient; 13016 break; 13017 case RoundingMode.tiesToAway: 13018 if (remainder >= half) 13019 ++coefficient; 13020 break; 13021 case RoundingMode.towardNegative: 13022 if (isNegative) 13023 ++coefficient; 13024 break; 13025 case RoundingMode.towardPositive: 13026 if (!isNegative) 13027 ++coefficient; 13028 break; 13029 case RoundingMode.towardZero: 13030 break; 13031 } 13032 13033 return ExceptionFlags.inexact; 13034 } 13035 13036 unittest 13037 { 13038 struct S {uint c; int p; bool n; RoundingMode r; uint outc; bool inexact; } 13039 13040 S[] test = 13041 [ 13042 S (0, 0, false, RoundingMode.tiesToAway, 0, false), 13043 S (0, 0, false, RoundingMode.tiesToEven, 0, false), 13044 S (0, 0, false, RoundingMode.towardNegative, 0, false), 13045 S (0, 0, false, RoundingMode.towardPositive, 0, false), 13046 S (0, 0, false, RoundingMode.towardZero, 0, false), 13047 13048 S (10, 1, false, RoundingMode.tiesToAway, 1, false), 13049 S (10, 1, false, RoundingMode.tiesToEven, 1, false), 13050 S (10, 1, false, RoundingMode.towardNegative, 1, false), 13051 S (10, 1, false, RoundingMode.towardPositive, 1, false), 13052 S (10, 1, false, RoundingMode.towardZero, 1, false), 13053 13054 S (13, 1, false, RoundingMode.tiesToAway, 1, true), 13055 S (13, 1, false, RoundingMode.tiesToEven, 1, true), 13056 S (13, 1, false, RoundingMode.towardNegative, 1, true), 13057 S (13, 1, false, RoundingMode.towardPositive, 2, true), 13058 S (13, 1, false, RoundingMode.towardZero, 1, true), 13059 13060 S (13, 1, true, RoundingMode.tiesToAway, 1, true), 13061 S (13, 1, true, RoundingMode.tiesToEven, 1, true), 13062 S (13, 1, true, RoundingMode.towardNegative, 2, true), 13063 S (13, 1, true, RoundingMode.towardPositive, 1, true), 13064 S (13, 1, true, RoundingMode.towardZero, 1, true), 13065 13066 13067 S (15, 1, false, RoundingMode.tiesToAway, 2, true), 13068 S (15, 1, false, RoundingMode.tiesToEven, 2, true), 13069 S (15, 1, false, RoundingMode.towardNegative, 1, true), 13070 S (15, 1, false, RoundingMode.towardPositive, 2, true), 13071 S (15, 1, false, RoundingMode.towardZero, 1, true), 13072 13073 S (15, 1, true, RoundingMode.tiesToAway, 2, true), 13074 S (15, 1, true, RoundingMode.tiesToEven, 2, true), 13075 S (15, 1, true, RoundingMode.towardNegative, 2, true), 13076 S (15, 1, true, RoundingMode.towardPositive, 1, true), 13077 S (15, 1, true, RoundingMode.towardZero, 1, true), 13078 13079 13080 S (18, 1, false, RoundingMode.tiesToAway, 2, true), 13081 S (18, 1, false, RoundingMode.tiesToEven, 2, true), 13082 S (18, 1, false, RoundingMode.towardNegative, 1, true), 13083 S (18, 1, false, RoundingMode.towardPositive, 2, true), 13084 S (18, 1, false, RoundingMode.towardZero, 1, true), 13085 13086 S (18, 1, true, RoundingMode.tiesToAway, 2, true), 13087 S (18, 1, true, RoundingMode.tiesToEven, 2, true), 13088 S (18, 1, true, RoundingMode.towardNegative, 2, true), 13089 S (18, 1, true, RoundingMode.towardPositive, 1, true), 13090 S (18, 1, true, RoundingMode.towardZero, 1, true), 13091 13092 S (25, 1, false, RoundingMode.tiesToAway, 3, true), 13093 S (25, 1, false, RoundingMode.tiesToEven, 2, true), 13094 S (25, 1, false, RoundingMode.towardNegative, 2, true), 13095 S (25, 1, false, RoundingMode.towardPositive, 3, true), 13096 S (25, 1, false, RoundingMode.towardZero, 2, true), 13097 13098 S (25, 1, true, RoundingMode.tiesToAway, 3, true), 13099 S (25, 1, true, RoundingMode.tiesToEven, 2, true), 13100 S (25, 1, true, RoundingMode.towardNegative, 3, true), 13101 S (25, 1, true, RoundingMode.towardPositive, 2, true), 13102 S (25, 1, true, RoundingMode.towardZero, 2, true), 13103 ]; 13104 13105 foreach (ref s; test) 13106 { 13107 auto flags = divpow10(s.c, s.p, s.n, s.r); 13108 assert (s.c == s.outc); 13109 assert (flags == ExceptionFlags.inexact ? s.inexact : !s.inexact); 13110 13111 } 13112 13113 } 13114 13115 //multiplies coefficient by 10^^power, returns possible overflow 13116 //overflow 13117 @safe pure nothrow @nogc 13118 ExceptionFlags mulpow10(T)(ref T coefficient, const int power) 13119 if (isAnyUnsigned!T) 13120 in 13121 { 13122 assert (power >= 0); 13123 } 13124 body 13125 { 13126 if (coefficient == 0U || power == 0) 13127 return ExceptionFlags.none; 13128 if (power >= pow10!T.length || coefficient > maxmul10!T[power]) 13129 return ExceptionFlags.overflow; 13130 coefficient *= pow10!T[power]; 13131 return ExceptionFlags.none; 13132 } 13133 13134 13135 //adjusts coefficient to fit minExponent <= exponent <= maxExponent and coefficient <= maxCoefficient 13136 //inexact, overflow, underflow 13137 @safe pure nothrow @nogc 13138 ExceptionFlags coefficientAdjust(T)(ref T coefficient, ref int exponent, const int minExponent, const int maxExponent, 13139 const T maxCoefficient, const bool isNegative, const RoundingMode mode) 13140 if (isAnyUnsigned!T) 13141 in 13142 { 13143 assert (minExponent <= maxExponent); 13144 assert (maxCoefficient >= 1U); 13145 } 13146 body 13147 { 13148 bool overflow; 13149 ExceptionFlags flags; 13150 13151 if (coefficient == 0U) 13152 { 13153 if (exponent < minExponent) 13154 exponent = minExponent; 13155 if (exponent > maxExponent) 13156 exponent = maxExponent; 13157 return ExceptionFlags.none; 13158 } 13159 13160 if (exponent < minExponent) 13161 { 13162 //increase exponent, divide coefficient 13163 immutable dif = minExponent - exponent; 13164 flags = divpow10(coefficient, dif, isNegative, mode); 13165 if (coefficient == 0U) 13166 flags |= ExceptionFlags.underflow | ExceptionFlags.inexact; 13167 exponent += dif; 13168 } 13169 else if (exponent > maxExponent) 13170 { 13171 //decrease exponent, multiply coefficient 13172 immutable dif = exponent - maxExponent; 13173 flags = mulpow10(coefficient, dif); 13174 if (flags & ExceptionFlags.overflow) 13175 return flags | ExceptionFlags.inexact; 13176 else 13177 exponent -= dif; 13178 } 13179 13180 if (coefficient > maxCoefficient) 13181 { 13182 //increase exponent, divide coefficient 13183 auto dif = prec(coefficient) - prec(maxCoefficient); 13184 if (!dif) 13185 dif = 1; 13186 flags |= divpow10(coefficient, dif, isNegative, mode); 13187 if (coefficient > maxCoefficient) 13188 { 13189 //same precision but greater 13190 flags |= divpow10(coefficient, 1, isNegative, mode); 13191 ++dif; 13192 } 13193 if (cappedAdd(exponent, dif) != dif) 13194 { 13195 if (coefficient != 0U) 13196 return flags | ExceptionFlags.overflow | ExceptionFlags.inexact; 13197 } 13198 } 13199 13200 13201 //coefficient became 0, dont' bother with exponents; 13202 if (coefficient == 0U) 13203 { 13204 exponent = 0; 13205 if (exponent < minExponent) 13206 exponent = minExponent; 13207 if (exponent > maxExponent) 13208 exponent = maxExponent; 13209 return flags; 13210 } 13211 13212 if (exponent < minExponent) 13213 return flags | ExceptionFlags.underflow | ExceptionFlags.inexact; 13214 13215 if (exponent > maxExponent) 13216 return flags | ExceptionFlags.overflow | ExceptionFlags.inexact; 13217 13218 13219 return flags; 13220 13221 } 13222 13223 13224 //adjusts coefficient to fit minExponent <= exponent <= maxExponent 13225 //inexact, overflow, underflow 13226 @safe pure nothrow @nogc 13227 ExceptionFlags coefficientAdjust(T)(ref T coefficient, ref int exponent, const int minExponent, const int maxExponent, 13228 const bool isNegative, const RoundingMode mode) 13229 if (isAnyUnsigned!T) 13230 in 13231 { 13232 assert (minExponent <= maxExponent); 13233 } 13234 body 13235 { 13236 return coefficientAdjust(coefficient, exponent, minExponent, maxExponent, T.max, isNegative, mode); 13237 } 13238 13239 //adjusts coefficient to fit coefficient in maxCoefficient 13240 //inexact, overflow, underflow 13241 @safe pure nothrow @nogc 13242 ExceptionFlags coefficientAdjust(T)(ref T coefficient, ref int exponent, const T maxCoefficient, 13243 const bool isNegative, const RoundingMode mode) 13244 if (isAnyUnsigned!T) 13245 in 13246 { 13247 assert (maxCoefficient >= 1U); 13248 } 13249 body 13250 { 13251 return coefficientAdjust(coefficient, exponent, int.min, int.max, maxCoefficient, isNegative, mode); 13252 } 13253 13254 13255 //adjusts coefficient to fit minExponent <= exponent <= maxExponent and to fit precision 13256 //inexact, overflow, underflow 13257 @safe pure nothrow @nogc 13258 ExceptionFlags coefficientAdjust(T)(ref T coefficient, ref int exponent, const int minExponent, const int maxExponent, 13259 const int precision, const bool isNegative, const RoundingMode mode) 13260 if (isAnyUnsigned!T) 13261 in 13262 { 13263 assert (precision >= 1); 13264 assert (minExponent <= maxExponent); 13265 } 13266 body 13267 { 13268 immutable maxCoefficient = precision >= pow10!T.length ? T.max : pow10!T[precision] - 1U; 13269 auto flags = coefficientAdjust(coefficient, exponent, minExponent, maxExponent, maxCoefficient, isNegative, mode); 13270 if (flags & (ExceptionFlags.overflow | ExceptionFlags.underflow)) 13271 return flags; 13272 13273 immutable p = prec(coefficient); 13274 if (p > precision) 13275 { 13276 flags |= divpow10(coefficient, 1, isNegative, mode); 13277 if (coefficient == 0U) 13278 { 13279 exponent = 0; 13280 if (exponent < minExponent) 13281 exponent = minExponent; 13282 if (exponent > maxExponent) 13283 exponent = maxExponent; 13284 return flags; 13285 } 13286 else 13287 { 13288 if (cappedAdd(exponent, 1) != 1) 13289 return flags | ExceptionFlags.overflow; 13290 if (exponent > maxExponent) 13291 return flags | ExceptionFlags.overflow; 13292 } 13293 } 13294 return flags; 13295 } 13296 13297 //adjusts coefficient to fit precision 13298 //inexact, overflow, underflow 13299 @safe pure nothrow @nogc 13300 ExceptionFlags coefficientAdjust(T)(ref T coefficient, ref int exponent, 13301 const int precision, const bool isNegative, const RoundingMode mode) 13302 if (isAnyUnsigned!T) 13303 in 13304 { 13305 assert (precision >= 1); 13306 } 13307 body 13308 { 13309 return coefficientAdjust(coefficient, exponent, int.min, int.max, precision, isNegative, mode); 13310 } 13311 13312 //shrinks coefficient by cutting out terminating zeros and increasing exponent 13313 @safe pure nothrow @nogc 13314 void coefficientShrink(T)(ref T coefficient, ref int exponent) 13315 { 13316 if (coefficient > 9U && (coefficient & 1U) == 0U && exponent < int.max) 13317 { 13318 Unqual!T c = coefficient; 13319 Unqual!T r = divrem(c, 10U); 13320 int e = exponent + 1; 13321 while (r == 0U) 13322 { 13323 coefficient = c; 13324 exponent = e; 13325 if ((c & 1U) || e == int.max) 13326 break; 13327 r = divrem(c, 10U); 13328 ++e; 13329 } 13330 } 13331 } 13332 13333 //expands cx with 10^^target if possible 13334 @safe pure nothrow @nogc 13335 void coefficientExpand(T)(ref T cx, ref int ex, ref int target) 13336 in 13337 { 13338 assert (cx); 13339 assert (target > 0); 13340 } 13341 body 13342 { 13343 int px = prec(cx); 13344 int maxPow10 = cast(int)pow10!T.length - px; 13345 auto maxCoefficient = maxmul10!T[$ - px]; 13346 if (cx > maxCoefficient) 13347 --maxPow10; 13348 auto pow = target > maxPow10 ? maxPow10 : target; 13349 pow = cappedSub(ex, pow); 13350 if (pow) 13351 { 13352 cx *= pow10!T[pow]; 13353 target -= pow; 13354 } 13355 } 13356 13357 //expands cx to maximum available digits 13358 @safe pure nothrow @nogc 13359 void coefficientExpand(T)(ref T cx, ref int ex) 13360 { 13361 if (cx) 13362 { 13363 int px = prec(cx); 13364 int pow = cast(int)pow10!T.length - px; 13365 auto maxCoefficient = maxmul10!T[$ - px]; 13366 if (cx > maxCoefficient) 13367 --pow; 13368 pow = cappedSub(ex, pow); 13369 if (pow) 13370 { 13371 cx *= pow10!T[pow]; 13372 } 13373 } 13374 } 13375 13376 unittest 13377 { 13378 struct S {uint x1; int ex1; int target1; uint x2; int ex2; int target2; } 13379 S[] tests = 13380 [ 13381 S(1, 0, 4, 10000, -4, 0), 13382 S(429496729, 0, 1, 4294967290, -1, 0), 13383 S(429496739, 0, 1, 429496739, 0, 1), 13384 S(429496729, 0, 2, 4294967290, -1, 1), 13385 S(42949672, 0, 1, 429496720, -1, 0), 13386 S(42949672, 0, 2, 4294967200, -2, 0), 13387 S(42949672, 0, 3, 4294967200, -2, 1), 13388 ]; 13389 13390 foreach( s; tests) 13391 { 13392 coefficientExpand(s.x1, s.ex1, s.target1); 13393 assert (s.x1 == s.x2); 13394 assert (s.ex1 == s.ex2); 13395 assert (s.target1 == s.target2); 13396 } 13397 } 13398 13399 //shrinks cx with 10^^target 13400 //inexact 13401 @safe pure nothrow @nogc 13402 ExceptionFlags coefficientShrink(T)(ref T cx, ref int ex, const bool sx, ref int target, const RoundingMode mode) 13403 in 13404 { 13405 assert (cx); 13406 assert (target > 0); 13407 } 13408 body 13409 { 13410 auto pow = cappedAdd(ex, target); 13411 if (pow) 13412 { 13413 auto flags = divpow10(cx, pow, sx, mode); 13414 target -= pow; 13415 return flags; 13416 } 13417 else 13418 return ExceptionFlags.none; 13419 } 13420 13421 //inexact 13422 @safe pure nothrow @nogc 13423 ExceptionFlags exponentAlign(T)(ref T cx, ref int ex, const bool sx, ref T cy, ref int ey, const bool sy, const RoundingMode mode) 13424 out 13425 { 13426 assert (ex == ey); 13427 } 13428 body 13429 { 13430 if (ex == ey) 13431 return ExceptionFlags.none; 13432 13433 if (!cx) 13434 { 13435 ex = ey; 13436 return ExceptionFlags.none; 13437 } 13438 13439 if (!cy) 13440 { 13441 ey = ex; 13442 return ExceptionFlags.none; 13443 } 13444 13445 ExceptionFlags flags; 13446 int dif = ex - ey; 13447 if (dif > 0) //ex > ey 13448 { 13449 coefficientExpand(cx, ex, dif); 13450 if (dif) 13451 flags = coefficientShrink(cy, ey, sy, dif, mode); 13452 assert(!dif); 13453 } 13454 else //ex < ey 13455 { 13456 dif = -dif; 13457 coefficientExpand(cy, ey, dif); 13458 if (dif) 13459 flags = coefficientShrink(cx, ex, sx, dif, mode); 13460 assert(!dif); 13461 } 13462 return flags; 13463 } 13464 13465 //inexact, overflow, underflow 13466 @safe pure nothrow @nogc 13467 ExceptionFlags coefficientAdd(T)(ref T cx, ref int ex, ref bool sx, const T cy, const int ey, const bool sy, const RoundingMode mode) 13468 { 13469 if (!cy) 13470 return ExceptionFlags.none; 13471 13472 if (!cx) 13473 { 13474 cx = cy; 13475 ex = ey; 13476 sx = sy; 13477 return ExceptionFlags.none; 13478 } 13479 13480 Unqual!T cyy = cy; 13481 int eyy = ey; 13482 13483 //if cx or cy underflowed, don't propagate 13484 auto flags = exponentAlign(cx, ex, sx, cyy, eyy, sy, mode) & ~ExceptionFlags.underflow; 13485 13486 if (!cyy) 13487 { 13488 //cx is very big 13489 switch (mode) 13490 { 13491 case RoundingMode.towardPositive: 13492 if (!sx && !sy) 13493 ++cx; 13494 else if (sx && !sy) 13495 --cx; 13496 break; 13497 case RoundingMode.towardNegative: 13498 if (sx && sy) 13499 ++cx; 13500 else if (!sx && sy) 13501 --cx; 13502 break; 13503 case RoundingMode.towardZero: 13504 if (sx != sy) 13505 --cx; 13506 break; 13507 default: 13508 break; 13509 } 13510 13511 13512 //if (sx == sy) 13513 //{ 13514 // //cx + 0.0.....001 => cx0000.0....001 13515 // if (sx && mode == RoundingMode.towardNegative) 13516 // ++cx; 13517 // else if (!sx && mode == RoundingMode.towardPositive) 13518 // ++cx; 13519 //} 13520 //else 13521 //{ 13522 // //cx - 0.0.....001 => (cx-1)9999.9...999 13523 // if (sx && mode == RoundingMode.towardZero) 13524 // --cx; 13525 // else if (!sx && mode == RoundingMode.towardNegative) 13526 // --cx; 13527 //} 13528 } 13529 13530 if (!cx) 13531 { 13532 //cy is very big, cx is tiny 13533 switch (mode) 13534 { 13535 case RoundingMode.towardPositive: 13536 if (!sx && !sy) 13537 ++cyy; 13538 else if (!sx && sy) 13539 --cyy; 13540 break; 13541 case RoundingMode.towardNegative: 13542 if (sx && sy) 13543 ++cyy; 13544 else if (sx && !sy) 13545 --cyy; 13546 break; 13547 case RoundingMode.towardZero: 13548 if (sx != sy) 13549 --cyy; 13550 break; 13551 default: 13552 break; 13553 } 13554 13555 13556 //if (sx == sy) 13557 //{ 13558 // //0.0.....001 + cyy => cyy0000.0....001 13559 // if (sy && mode == RoundingMode.towardNegative) 13560 // ++cyy; 13561 // else if (!sy && mode == RoundingMode.towardPositive) 13562 // ++cyy; 13563 //} 13564 //else 13565 //{ 13566 // //0.0.....001 - cyy => -(cyy + 0.0.....001) 13567 // if (sy && mode == RoundingMode.towardZero) 13568 // --cyy; 13569 // else if (!sy && mode == RoundingMode.towardNegative) 13570 // --cyy; 13571 //} 13572 } 13573 13574 if (sx == sy) 13575 { 13576 Unqual!T savecx = cx; 13577 auto carry = xadd(cx, cyy); 13578 if (carry) 13579 { 13580 if (!cappedAdd(ex, 1)) 13581 return flags | ExceptionFlags.overflow; 13582 flags |= divpow10(savecx, 1, sx, mode); 13583 flags |= divpow10(cyy, 1, sy, mode); 13584 cx = savecx + cyy; 13585 } 13586 return flags; 13587 } 13588 else 13589 { 13590 if (cx == cyy) 13591 { 13592 cx = T(0U); 13593 ex = 0; 13594 sx = false; 13595 return flags; 13596 } 13597 13598 if (cx > cyy) 13599 cx -= cyy; 13600 else 13601 { 13602 cx = cyy - cx; 13603 sx = sy; 13604 } 13605 return flags; 13606 } 13607 } 13608 13609 unittest 13610 { 13611 int x = 0; 13612 } 13613 13614 //inexact, overflow, underflow 13615 @safe pure nothrow @nogc 13616 ExceptionFlags coefficientMul(T)(ref T cx, ref int ex, ref bool sx, const T cy, const int ey, const bool sy, const RoundingMode mode) 13617 { 13618 if (!cy || !cy) 13619 { 13620 cx = T(0U); 13621 sx ^= sy; 13622 return ExceptionFlags.none; 13623 } 13624 13625 auto r = xmul(cx, cy); 13626 13627 if (cappedAdd(ex, ey) != ey) 13628 return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow; 13629 13630 sx ^= sy; 13631 13632 if (r > T.max) 13633 { 13634 auto px = prec(r); 13635 auto pm = prec(T.max) - 1; 13636 auto flags = divpow10(r, px - pm, sx, mode); 13637 if (cappedAdd(ex, px - pm) != px - pm) 13638 return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow; 13639 cx = cvt!T(r); 13640 return flags; 13641 } 13642 else 13643 { 13644 cx = cvt!T(r); 13645 return ExceptionFlags.none; 13646 } 13647 } 13648 13649 //div0, overflow, underflow 13650 @safe pure nothrow @nogc 13651 ExceptionFlags coefficientDiv(T)(ref T cx, ref int ex, ref bool sx, const T cy, const int ey, const bool sy, const RoundingMode mode) 13652 { 13653 if (!cy) 13654 { 13655 sx ^= sy; 13656 return ExceptionFlags.divisionByZero; 13657 } 13658 13659 if (!cx) 13660 { 13661 ex = 0; 13662 sx ^= sy; 13663 return ExceptionFlags.none; 13664 } 13665 13666 if (cy == 1U) 13667 { 13668 if (cappedSub(ex, ey) != ey) 13669 return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow; 13670 sx ^= sy; 13671 return ExceptionFlags.none; 13672 } 13673 13674 Unqual!T savecx = cx; 13675 sx ^= sy; 13676 auto r = divrem(cx, cy); 13677 if (!r) 13678 { 13679 if (cappedSub(ex, ey) != ey) 13680 return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow; 13681 return ExceptionFlags.none; 13682 } 13683 13684 alias U = MakeUnsigned!(T.sizeof * 16); 13685 U cxx = savecx; 13686 auto px = prec(savecx); 13687 auto pm = prec(U.max) - 1; 13688 mulpow10(cxx, pm - px); 13689 auto scale = pm - px - cappedSub(ex, pm - px); 13690 auto s = divrem(cxx, cy); 13691 ExceptionFlags flags; 13692 if (s) 13693 { 13694 immutable half = cy >>> 1; 13695 final switch (mode) 13696 { 13697 case RoundingMode.tiesToEven: 13698 if (s > half) 13699 ++cxx; 13700 else if ((s == half) && ((cxx & 1U) == 0U)) 13701 ++cxx; 13702 break; 13703 case RoundingMode.tiesToAway: 13704 if (s >= half) 13705 ++cxx; 13706 break; 13707 case RoundingMode.towardNegative: 13708 if (sx) 13709 ++cxx; 13710 break; 13711 case RoundingMode.towardPositive: 13712 if (!sx) 13713 ++cxx; 13714 break; 13715 case RoundingMode.towardZero: 13716 break; 13717 } 13718 flags = ExceptionFlags.inexact; 13719 } 13720 13721 flags |= coefficientAdjust(cxx, ex, U(T.max), sx, mode); 13722 13723 if (flags & ExceptionFlags.underflow) 13724 { 13725 cx = 0U; 13726 ex = 0U; 13727 return flags; 13728 } 13729 13730 if (flags & ExceptionFlags.overflow) 13731 return flags; 13732 13733 13734 cx = cast(T)cxx; 13735 if (cappedSub(ex, ey) != ey) 13736 flags |= ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow; 13737 if (cappedSub(ex, scale) != scale) 13738 flags |= ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow; 13739 13740 return flags; 13741 } 13742 13743 //inexact, overflow, underflow 13744 @safe pure nothrow @nogc 13745 ExceptionFlags coefficientFMA(T)(ref T cx, ref int ex, ref bool sx, const T cy, const int ey, const bool sy, const T cz, const int ez, const bool sz, const RoundingMode mode) 13746 { 13747 if (!cx || !cy) 13748 { 13749 cx = cz; 13750 ex = ez; 13751 sx = sz; 13752 return ExceptionFlags.none; 13753 } 13754 13755 if (!cz) 13756 return coefficientMul(cx, ex, sx, cy, ey, sy, mode); 13757 13758 13759 if (cappedAdd(ex, ey) != ey) 13760 return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow; 13761 auto m = xmul(cx, cy); 13762 sx ^= sy; 13763 13764 typeof(m) czz = cz; 13765 auto flags = coefficientAdd(m, ex, sx, czz, ez, sz, mode); 13766 auto pm = prec(m); 13767 auto pmax = prec(T.max) - 1; 13768 if (pm > pmax) 13769 { 13770 flags |= divpow10(m, pm - pmax, sx, mode); 13771 if (cappedAdd(ex, pm - pmax) != pm - pmax) 13772 return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow; 13773 } 13774 cx = cast(Unqual!T)m; 13775 return flags; 13776 } 13777 13778 //inexact 13779 @safe pure nothrow @nogc 13780 ExceptionFlags coefficientRound(T)(ref T cx, ref int ex, const bool sx, const RoundingMode mode) 13781 { 13782 if (ex < 0) 13783 { 13784 auto flags = divpow10(cx, -ex, sx, mode); 13785 ex = 0; 13786 return flags; 13787 } 13788 return ExceptionFlags.none; 13789 } 13790 13791 //inexact, overflow, underflow 13792 @safe pure nothrow @nogc 13793 ExceptionFlags coefficientMod(T)(ref T cx, ref int ex, ref bool sx, const T cy, const int ey, const bool sy, const RoundingMode mode) 13794 { 13795 if (!cy) 13796 return ExceptionFlags.invalidOperation; 13797 Unqual!T rcx = cx; 13798 int rex = ex; 13799 bool rsx = sx; 13800 coefficientDiv(rcx, rex, rsx, cy, ey, sy, mode); //16 13801 coefficientRound(rcx, rex, rsx, mode); //00 13802 coefficientMul(rcx, rex, rsx, cy, ey, sy, mode); //16 13803 return coefficientAdd(cx, ex, sx, rcx, rex, !rsx, mode); //0 13804 } 13805 13806 unittest 13807 { 13808 13809 } 13810 13811 @safe pure nothrow @nogc 13812 int coefficientCmp(T)(const T cx, const int ex, const bool sx, const T cy, const int ey, const bool sy) 13813 { 13814 if (!cx) 13815 return cy ? (sy ? 1 : -1) : 0; 13816 if (!cy) 13817 return sx ? -1 : 1; 13818 13819 if (sx && !sy) 13820 return -1; 13821 else if (!sx && sy) 13822 return 1; 13823 else 13824 return sx ? -coefficientCmp(cx, ex, cy, ey) : coefficientCmp(cx, ex, cy, ey); 13825 } 13826 13827 @safe pure nothrow @nogc 13828 int coefficientCmp(T)(const T cx, const int ex, const T cy, const int ey) 13829 { 13830 if (!cx) 13831 return cy ? -1 : 0; 13832 if (!cy) 13833 return 1; 13834 13835 int px = prec(cx); 13836 int py = prec(cy); 13837 13838 if (px > py) 13839 { 13840 int eyy = ey - (px - py); 13841 if (ex > eyy) 13842 return 1; 13843 if (ex < eyy) 13844 return -1; 13845 Unqual!T cyy = cy; 13846 mulpow10(cyy, px - py); 13847 if (cx > cyy) 13848 return 1; 13849 if (cx < cyy) 13850 return -1; 13851 return 0; 13852 } 13853 13854 if (px < py) 13855 { 13856 int exx = ex - (py - px); 13857 if (exx > ey) 13858 return 1; 13859 if (exx < ey) 13860 return -1; 13861 Unqual!T cxx = cx; 13862 mulpow10(cxx, py - px); 13863 if (cxx > cy) 13864 return 1; 13865 if (cxx < cy) 13866 return -1; 13867 return 0; 13868 } 13869 13870 if (ex > ey) 13871 return 1; 13872 if (ex < ey) 13873 return -1; 13874 13875 if (cx > cy) 13876 return 1; 13877 else if (cx < cy) 13878 return -1; 13879 return 0; 13880 13881 } 13882 13883 @safe pure nothrow @nogc 13884 bool coefficientEqu(T)(const T cx, const int ex, const bool sx, const T cy, const int ey, const bool sy) 13885 { 13886 if (!cx) 13887 return cy == 0U; 13888 13889 if (sx != sy) 13890 return false; 13891 else 13892 { 13893 int px = prec(cx); 13894 int py = prec(cy); 13895 13896 if (px > py) 13897 { 13898 int eyy = ey - (px - py); 13899 if (ex != eyy) 13900 return false; 13901 Unqual!T cyy = cy; 13902 mulpow10(cyy, px - py); 13903 return cx == cyy; 13904 } 13905 13906 if (px < py) 13907 { 13908 int exx = ex - (py - px); 13909 if (exx != ey) 13910 return false; 13911 Unqual!T cxx = cx; 13912 mulpow10(cxx, py - px); 13913 return cxx == cy; 13914 } 13915 13916 return cx == cy && ex == ey; 13917 } 13918 } 13919 13920 @safe pure nothrow @nogc 13921 bool coefficientApproxEqu(T)(const T cx, const int ex, const bool sx, const T cy, const int ey, const bool sy) 13922 { 13923 //same as coefficientEqu, but we ignore the last digit if coefficient > 10^max 13924 //this is useful in convergence loops to not become infinite 13925 if (!cx) 13926 return cy == 0U; 13927 13928 if (sx != sy) 13929 return false; 13930 else 13931 { 13932 int px = prec(cx); 13933 int py = prec(cy); 13934 13935 if (px > py) 13936 { 13937 int eyy = ey - (px - py); 13938 if (ex != eyy) 13939 return false; 13940 Unqual!T cyy = cy; 13941 mulpow10(cyy, px - py); 13942 if (cx > pow10!T[$ - 2]) 13943 return cx >= cy ? cx - cy < 10U : cy - cx < 10U; 13944 return cx == cy; 13945 } 13946 13947 if (px < py) 13948 { 13949 int exx = ex - (py - px); 13950 if (exx != ey) 13951 return false; 13952 Unqual!T cxx = cx; 13953 mulpow10(cxx, py - px); 13954 if (cxx > pow10!T[$ - 2]) 13955 return cxx >= cy ? cxx - cy < 10U : cy - cxx < 10U; 13956 return cx == cy; 13957 } 13958 13959 if (cx > pow10!T[$ - 2]) 13960 return cx >= cy ? cx - cy < 10U : cy - cx < 10U; 13961 13962 return cx == cy; 13963 } 13964 } 13965 13966 //inexact, overflow, underflow 13967 @safe pure nothrow @nogc 13968 ExceptionFlags coefficientSqr(T)(ref T cx, ref int ex, const RoundingMode mode) 13969 { 13970 if (!cx) 13971 { 13972 cx = T(0U); 13973 ex = 0; 13974 return ExceptionFlags.none; 13975 } 13976 13977 auto r = xsqr(cx); 13978 13979 int ey = ex; 13980 if (cappedAdd(ex, ey) != ey) 13981 return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow; 13982 13983 13984 if (r > T.max) 13985 { 13986 auto px = prec(r); 13987 auto pm = prec(T.max) - 1; 13988 auto flags = divpow10(r, px - pm, false, mode); 13989 if (cappedAdd(ex, px - pm) != px - pm) 13990 return ex < 0 ? ExceptionFlags.underflow : ExceptionFlags.overflow; 13991 cx = cvt!T(r); 13992 return flags; 13993 } 13994 else 13995 { 13996 cx = cvt!T(r); 13997 return ExceptionFlags.none; 13998 } 13999 } 14000 14001 //inexact, underflow 14002 @safe pure nothrow @nogc 14003 ExceptionFlags coefficientSqrt(T)(ref T cx, ref int ex) 14004 { 14005 // Newton-Raphson: x = (x + n/x) / 2; 14006 if (!cx) 14007 { 14008 cx = 0U; 14009 ex = 0; 14010 return ExceptionFlags.none; 14011 } 14012 14013 alias U = MakeUnsigned!(T.sizeof * 16); 14014 14015 U cxx = cx; 14016 ExceptionFlags flags; 14017 14018 //we need full precision 14019 coefficientExpand(cxx, ex); 14020 14021 if (ex & 1) 14022 { 14023 //exponent is odd, make it even 14024 flags = divpow10(cxx, 1, false, RoundingMode.implicit); 14025 ++ex; 14026 } 14027 14028 ex /= 2; 14029 bool inexact = decimal.integrals.sqrt(cxx); 14030 flags |= coefficientAdjust(cxx, ex, cvt!U(T.max), false, RoundingMode.implicit); 14031 cx = cast(T)cxx; 14032 return inexact ? flags | ExceptionFlags.inexact : flags; 14033 } 14034 14035 //inexact, underflow 14036 @safe pure nothrow @nogc 14037 ExceptionFlags coefficientRSqrt(T)(ref T cx, ref int ex) 14038 { 14039 bool sx = false; 14040 if (!cx) 14041 return ExceptionFlags.divisionByZero; 14042 Unqual!T cy = cx; int ey = ex; 14043 auto flags = coefficientSqrt(cy, ey); 14044 if (flags & ExceptionFlags.underflow) 14045 return ExceptionFlags.overflow; 14046 cx = 1U; 14047 ex = 0; 14048 return flags | coefficientDiv(cx, ex, sx, cy, ey, false, RoundingMode.implicit); 14049 } 14050 14051 @safe pure nothrow @nogc 14052 ExceptionFlags coefficientCbrt(T)(ref T cx, ref int ex) 14053 { 14054 // Newton-Raphson: x = (2x + N/x2)/3 14055 14056 if (!cx) 14057 { 14058 cx = 0U; 14059 ex = 0; 14060 return ExceptionFlags.none; 14061 } 14062 14063 alias U = MakeUnsigned!(T.sizeof * 16); 14064 14065 U cxx = cx; 14066 ExceptionFlags flags; 14067 14068 //we need full precision 14069 coefficientExpand(cxx, ex); 14070 14071 auto r = ex % 3; 14072 if (r) 14073 { 14074 //exponent is not divisible by 3, make it 14075 flags = divpow10(cxx, 3 - r, false, RoundingMode.implicit); 14076 ex += 3 - r; 14077 } 14078 14079 ex /= 3; 14080 bool inexact = decimal.integrals.cbrt(cxx); 14081 flags |= coefficientAdjust(cxx, ex, cvt!U(T.max), false, RoundingMode.implicit); 14082 cx = cast(T)cxx; 14083 return inexact ? flags | ExceptionFlags.inexact : flags; 14084 } 14085 14086 @safe pure nothrow @nogc 14087 ExceptionFlags coefficientHypot(T)(ref T cx, ref int ex, auto const ref T cy, const int ey) 14088 { 14089 Unqual!T cyy = cy; 14090 int eyy = ey; 14091 bool sx; 14092 auto flags = coefficientSqr(cx, ex, RoundingMode.implicit); 14093 flags |= coefficientSqr(cyy, eyy, RoundingMode.implicit); 14094 flags |= coefficientAdd(cx, ex, sx, cyy, eyy, false, RoundingMode.implicit); 14095 return flags | coefficientSqrt(cx, ex); 14096 } 14097 14098 @safe pure nothrow @nogc 14099 ExceptionFlags coefficientExp(T)(ref T cx, ref int ex, ref bool sx) 14100 { 14101 //e^x = 1 + x + x2/2! + x3/3! + x4/4! ... 14102 //to avoid overflow and underflow: 14103 //x^n/n! = (x^(n-1)/(n-1)! * x/n 14104 14105 ExceptionFlags flags; 14106 14107 //save x for repeated multiplication 14108 immutable Unqual!T cxx = cx; 14109 immutable exx = ex; 14110 immutable sxx = sx; 14111 14112 //shadow value 14113 Unqual!T cy; 14114 int ey = 0; 14115 bool sy = false; 14116 14117 Unqual!T cf = cx; 14118 int ef = ex; 14119 bool sf = sx; 14120 14121 if (coefficientAdd(cx, ex, sx, T(1U), 0, false, RoundingMode.implicit) & ExceptionFlags.overflow) 14122 return ExceptionFlags.overflow; 14123 14124 14125 Unqual!T n = 1U; 14126 14127 do 14128 { 14129 cy = cx; 14130 ey = ex; 14131 sy = sx; 14132 14133 Unqual!T cp = cxx; 14134 int ep = exx; 14135 bool sp = sxx; 14136 14137 coefficientDiv(cp, ep, sp, ++n, 0, false, RoundingMode.implicit); 14138 coefficientMul(cf, ef, sf, cp, ep, sp, RoundingMode.implicit); 14139 coefficientAdd(cx, ex, sx, cf, ef, sf, RoundingMode.implicit); 14140 14141 } 14142 while (!coefficientApproxEqu(cx, ex, sx, cy, ey, sy)); 14143 14144 return ExceptionFlags.inexact; 14145 14146 } 14147 14148 @safe pure nothrow @nogc 14149 ExceptionFlags coefficientLog(T)(ref T cx, ref int ex, ref bool sx) 14150 { 14151 14152 assert(!sx); //only positive 14153 assert(cx); 14154 14155 //ln(coefficient * 10^exponent) = ln(coefficient) + exponent * ln(10); 14156 14157 static if (is(T:uint)) 14158 { 14159 immutable uint ce = 2718281828U; 14160 immutable int ee = -9; 14161 immutable uint cl = 2302585093U; 14162 immutable int el = -9; 14163 14164 } 14165 else static if (is(T:ulong)) 14166 { 14167 immutable ulong ce = 2718281828459045235UL; 14168 immutable int ee = -18; 14169 immutable ulong cl = 2302585092994045684UL; 14170 immutable int el = -18; 14171 } 14172 else static if (is(T:uint128)) 14173 { 14174 immutable uint128 ce = uint128("271828182845904523536028747135266249776"); 14175 immutable int ee = -38; 14176 immutable uint128 cl = uint128("230258509299404568401799145468436420760"); 14177 immutable int el = -38; 14178 } 14179 else 14180 static assert(0); 14181 14182 //ln(x) = ln(n*e) = ln(n) + ln(e); 14183 //we divide x by e to find out how many times (n) we must add ln(e) = 1 14184 //ln(x + 1) taylor series works in the interval (-1 .. 1] 14185 //so our taylor series is valid for x in (0 .. 2] 14186 14187 //save exponent for later 14188 int exponent = ex; 14189 ex = 0; 14190 14191 enum one = T(1U); 14192 enum two = T(2U); 14193 14194 Unqual!T n = 0U; 14195 bool ss = false; 14196 14197 immutable aaa = cx; 14198 14199 while (coefficientCmp(cx, ex, false, two, 0, false) >= 0) 14200 { 14201 coefficientDiv(cx, ex, sx, ce, ee, false, RoundingMode.implicit); 14202 ++n; 14203 } 14204 14205 coefficientDiv(cx, ex, sx, ce, ee, false, RoundingMode.implicit); 14206 ++n; 14207 14208 //ln(x) = (x - 1) - [(x - 1)^2]/2 + [(x - 1)^3]/3 - .... 14209 14210 //initialize our result to x - 1; 14211 coefficientAdd(cx, ex, sx, one, 0, true, RoundingMode.implicit); 14212 14213 //store cx in cxm1, this will be used for repeated multiplication 14214 //we negate the sign to alternate between +/- 14215 Unqual!T cxm1 = cx; 14216 int exm1 = ex; 14217 bool sxm1 = !sx; 14218 14219 //shadow 14220 Unqual!T cy; 14221 int ey; 14222 bool sy; 14223 14224 Unqual!T cd = cxm1; 14225 int ed = exm1; 14226 bool sd = !sxm1; 14227 14228 Unqual!T i = 2U; 14229 14230 do 14231 { 14232 cy = cx; 14233 ey = ex; 14234 sy = sx; 14235 14236 coefficientMul(cd, ed, sd, cxm1, exm1, sxm1, RoundingMode.implicit); 14237 14238 Unqual!T cf = cd; 14239 int ef = ed; 14240 bool sf = sd; 14241 14242 coefficientDiv(cf, ef, sf, i++, 0, false, RoundingMode.implicit); 14243 coefficientAdd(cx, ex, sx, cf, ef, sf, RoundingMode.implicit); 14244 14245 //writefln("%10d %10d %10d %10d %10d %10d", cx, ex, cy, ey, cx - cy, i); 14246 } 14247 while (!coefficientApproxEqu(cx, ex, sx, cy, ey, sy)); 14248 14249 14250 14251 coefficientAdd(cx, ex, sx, n, 0, false, RoundingMode.implicit); 14252 14253 if (exponent != 0) 14254 { 14255 sy = exponent < 0; 14256 cy = sy ? cast(uint)(-exponent) : cast(uint)(exponent); 14257 ey = 0; 14258 coefficientMul(cy, ey, sy, cl, el, false, RoundingMode.implicit); 14259 coefficientAdd(cx, ex, sx, cy, ey, sy, RoundingMode.implicit); 14260 } 14261 14262 //iterations 14263 //decimal32 min: 15, max: 48 avg: 30.03 14264 //decimal64 min: 30, max: 234 avg: 149.25 14265 14266 14267 return ExceptionFlags.inexact; 14268 } 14269 14270 @safe pure nothrow @nogc 14271 ExceptionFlags coefficientAtanh(T)(ref T cx, ref int ex, ref bool sx) 14272 { 14273 //1/2*ln[(1 + x)/(1 - x)] 14274 14275 assert (coefficientCmp(cx, ex, sx, T(1U), 0, true) > 0); 14276 assert (coefficientCmp(cx, ex, sx, T(1U), 0, false) < 0); 14277 14278 //1/2*ln[(1 + x)/(1 - x)] 14279 14280 Unqual!T cm1 = cx; 14281 int em1 = ex; 14282 bool sm1 = !sx; 14283 coefficientAdd(cm1, em1, sm1, T(1U), 0, false, RoundingMode.implicit); 14284 coefficientAdd(cx, ex, sx, T(1U), 0, false, RoundingMode.implicit); 14285 coefficientDiv(cx, ex, sx, cm1, em1, sm1, RoundingMode.implicit); 14286 coefficientLog(cx, ex, sx); 14287 coefficientMul(cx, ex, sx, T(5U), -1, false, RoundingMode.implicit); 14288 return ExceptionFlags.inexact; 14289 } 14290 14291 //caps angle to -2π ... +2π 14292 @safe pure nothrow @nogc 14293 ExceptionFlags coefficientCapAngle(T)(ref T cx, ref int ex, ref bool sx) 14294 { 14295 if (coefficientCmp(cx, ex, Constants!T.c2π, Constants!T.e2π) > 0) 14296 { 14297 Unqual!T cy = cx; 14298 int ey = ex; 14299 bool sy = sx; 14300 coefficientMul(cy, ey, sy, Constants!T.c1_2π, Constants!T.e1_2π, false, RoundingMode.towardZero); 14301 coefficientRound(cy, ey, sy, RoundingMode.towardZero); 14302 coefficientMul(cy, ey, sy, Constants!T.c2π, Constants!T.e2π, false, RoundingMode.towardZero); 14303 coefficientAdd(cx, ex, sx, cy, ey, !sy, RoundingMode.towardZero); 14304 return ExceptionFlags.inexact; 14305 } 14306 return ExceptionFlags.none; 14307 } 14308 14309 //caps angle to -π/2 .. +π/2 14310 @safe pure nothrow @nogc 14311 ExceptionFlags coefficientCapAngle(T)(ref T cx, ref int ex, ref bool sx, out int quadrant) 14312 { 14313 quadrant = 1; 14314 auto flags = coefficientCapAngle(cx, ex, sx); 14315 if (coefficientCmp(cx, ex, Constants!T.c2π, Constants!T.e2π) > 0) 14316 { 14317 Unqual!T cy = cx; 14318 int ey = ex; 14319 bool sy = sx; 14320 coefficientMul(cy, ey, sy, Constants!T.c2_π, Constants!T.e2_π, false, RoundingMode.towardZero); 14321 coefficientRound(cy, ey, sy, RoundingMode.towardZero); 14322 quadrant = cast(uint)(cy % 4U) + 1; 14323 coefficientMul(cy, ey, sy, Constants!T.cπ_2, Constants!T.eπ_2, false, RoundingMode.towardZero); 14324 coefficientAdd(cx, ex, sx, cy, ey, !sy, RoundingMode.towardZero); 14325 flags |= ExceptionFlags.inexact; 14326 } 14327 return flags; 14328 } 14329 14330 @safe pure nothrow @nogc 14331 ExceptionFlags coefficientSinQ(T)(ref T cx, ref int ex, ref bool sx) 14332 { 14333 //taylor series: sin(x) = x - x^3/3! + x^5/5! - x^7/7! ... 14334 14335 Unqual!T cx2 = cx; int ex2 = ex; bool sx2 = true; 14336 coefficientSqr(cx2, ex2, RoundingMode.implicit); 14337 14338 Unqual!T cy; int ey; bool sy; 14339 Unqual!T cf = cx; int ef = ex; bool sf = sx; 14340 14341 Unqual!T n = 2U; 14342 14343 do 14344 { 14345 cy = cx; 14346 ey = ex; 14347 sy = sx; 14348 14349 coefficientMul(cf, ef, sf, cx2, ex2, sx2, RoundingMode.implicit); 14350 coefficientDiv(cf, ef, sf, n++, 0, false, RoundingMode.implicit); 14351 coefficientDiv(cf, ef, sf, n++, 0, false, RoundingMode.implicit); 14352 coefficientAdd(cx, ex, sx, cf, ef, sf, RoundingMode.implicit); 14353 //writefln("%10d %10d %10d %10d", cx, ex, cy, ey); 14354 // writefln("%016x%016x %10d %016x%016x %10d", cx.hi, cx.lo, ex, cy.hi, cy.lo, ey); 14355 } 14356 while (!coefficientApproxEqu(cx, ex, sx, cy, ey, sy)); 14357 return ExceptionFlags.inexact; 14358 } 14359 14360 unittest 14361 { 14362 ulong cx = 11000000000000000855UL; 14363 int ex = -19; 14364 bool sx; 14365 14366 coefficientSinQ(cx, ex, sx); 14367 14368 //writefln("%35.34f", sin(decimal128("1.1000000000000000855000000000000000"))); 14369 //writefln("%35.34f", decimal128(1.1)); 14370 } 14371 14372 @safe pure nothrow @nogc 14373 ExceptionFlags coefficientCosQ(T)(ref T cx, ref int ex, ref bool sx) 14374 { 14375 //taylor series: cos(x) = 1 - x^2/2! + x^4/4! - x^6/6! ... 14376 14377 Unqual!T cx2 = cx; int ex2 = ex; bool sx2 = true; 14378 coefficientSqr(cx2, ex2, RoundingMode.implicit); 14379 14380 cx = 1U; 14381 ex = 0; 14382 sx = false; 14383 Unqual!T cy; int ey; bool sy; 14384 Unqual!T cf = cx; int ef = ex; bool sf = sx; 14385 14386 Unqual!T n = 1U; 14387 14388 do 14389 { 14390 cy = cx; 14391 ey = ex; 14392 sy = sx; 14393 14394 coefficientMul(cf, ef, sf, cx2, ex2, sx2, RoundingMode.implicit); 14395 coefficientDiv(cf, ef, sf, n++, 0, false, RoundingMode.implicit); 14396 coefficientDiv(cf, ef, sf, n++, 0, false, RoundingMode.implicit); 14397 coefficientAdd(cx, ex, sx, cf, ef, sf, RoundingMode.implicit); 14398 //writefln("%10d %10d %10d %10d", cx, ex, cy, ey); 14399 } 14400 while (!coefficientApproxEqu(cx, ex, sx, cy, ey, sy)); 14401 return ExceptionFlags.inexact; 14402 } 14403 14404 @safe pure nothrow @nogc 14405 ExceptionFlags coefficientSinCosQ(T)(const T cx, const int ex, const bool sx, 14406 out T csin, out int esin, out bool ssin, 14407 out T ccos, out int ecos, out bool scos) 14408 { 14409 csin = cx; esin = ex; ssin = sx; 14410 ccos = 1U; ecos = 0; scos = false; 14411 Unqual!T cs, cc; int es, ec; bool ss, sc; 14412 14413 Unqual!T cf = cx; int ef = ex; bool sf = sx; 14414 Unqual!T n = 2U; 14415 do 14416 { 14417 cs = csin; es = esin; ss = ssin; 14418 cc = ccos; ec = ecos; sc = scos; 14419 coefficientMul(cf, ef, sf, cx, ex, !sx, RoundingMode.implicit); 14420 coefficientDiv(cf, ef, sf, n++, 0, false, RoundingMode.implicit); 14421 coefficientAdd(ccos, ecos, scos, cf, ef, sf, RoundingMode.implicit); 14422 coefficientMul(cf, ef, sf, cx, ex, sx, RoundingMode.implicit); 14423 coefficientDiv(cf, ef, sf, n++, 0, false, RoundingMode.implicit); 14424 coefficientAdd(csin, esin, ssin, cf, ef, sf, RoundingMode.implicit); 14425 //writefln("%10d %10d %10d %10d %10d %10d %10d %10d", csin, esin, cs, es, ccos, ecos, cc, ec); 14426 } 14427 while(!coefficientApproxEqu(csin, esin, ssin, cs, es, ss) && 14428 !coefficientApproxEqu(ccos, ecos, scos, cc, ec, sc)); 14429 14430 return ExceptionFlags.inexact; 14431 } 14432 14433 @safe pure nothrow @nogc 14434 ExceptionFlags coefficientCapAtan(T)(ref T cx, ref int ex, ref bool sx, out T reductions) 14435 { 14436 //half angle formula: atan(x/2) = 2 * atan(x/(1 + sqrt(1 +x^^2)))) 14437 //reduce x = x / (sqrt(x * x + 1) + 1); 14438 14439 reductions = 0U; 14440 while (coefficientCmp(cx, ex, T(1U), 0) >= 0) 14441 { 14442 Unqual!T cy = cx; int ey = ex; bool sy = false; 14443 coefficientSqr(cy, ey, RoundingMode.implicit); 14444 coefficientAdd(cy, ey, sy, T(1U), 0, false, RoundingMode.implicit); 14445 coefficientSqrt(cy, ey); 14446 coefficientAdd(cy, ey, sy, T(1U), 0, false, RoundingMode.implicit); 14447 coefficientDiv(cx, ex, sx, cy, ey, false, RoundingMode.implicit); 14448 ++reductions; 14449 } 14450 14451 return ExceptionFlags.inexact; 14452 } 14453 14454 @safe pure nothrow @nogc 14455 ExceptionFlags coefficientAtan(T)(ref T cx, ref int ex, bool sx) 14456 { 14457 //taylor series: 14458 //atan(x) = x - x^3/3 + x^5/5 - x^7/7 ... 14459 14460 Unqual!T cx2 = cx; int ex2 = ex; 14461 coefficientSqr(cx2, ex2, RoundingMode.implicit); 14462 14463 Unqual!T cy; int ey; bool sy; 14464 14465 Unqual!T cxx = cx; int exx = ex; bool sxx = sx; 14466 14467 Unqual!T n = 3U; 14468 14469 do 14470 { 14471 cy = cx; 14472 ey = ex; 14473 sy = sx; 14474 14475 coefficientMul(cxx, exx, sxx, cx2, ex2, true, RoundingMode.implicit); 14476 14477 Unqual!T cf = cxx; 14478 int ef = exx; 14479 bool sf = sxx; 14480 14481 coefficientDiv(cf, ef, sf, n, 0, false, RoundingMode.implicit); 14482 coefficientAdd(cx, ex, sx, cf, ef, sf, RoundingMode.implicit); 14483 n += 2U; 14484 14485 } 14486 while (!coefficientApproxEqu(cx, ex, sx, cy, ey, sy)); 14487 return ExceptionFlags.inexact; 14488 } 14489 14490 14491 struct Constants(T) 14492 { 14493 static if (is(T:uint)) 14494 { 14495 enum uint c1_2π = 1591549431U; 14496 enum int e1_2π = -10; 14497 enum uint c2π = 628318531U; 14498 enum int e2π = -8; 14499 enum uint c2_π = 636619772U; 14500 enum int e2_π = -9; 14501 enum uint cπ_2 = 1570796327U; 14502 enum int eπ_2 = -9; 14503 enum uint chalf = 5; 14504 enum int ehalf = -1; 14505 enum uint cthird = 3333333333; 14506 enum int ethird = -10; 14507 enum uint ce = 2718281828U; 14508 enum int ee = -9; 14509 enum uint cln10 = 2302585093U; 14510 enum int eln10 = -9; 14511 } 14512 else static if (is(T:ulong)) 14513 { 14514 enum ulong c1_2π = 15915494309189533577UL; 14515 enum int e1_2π = -20; 14516 enum ulong c2π = 6283185307179586477UL; 14517 enum int e2π = -18; 14518 enum ulong c2_π = 6366197723675813431UL; 14519 enum int e2_π = -19; 14520 enum ulong cπ_2 = 15707963267948966192UL; 14521 enum int eπ_2 = -19; 14522 enum ulong chalf = 5; 14523 enum int ehalf = -1; 14524 enum ulong cthird = 3333333333333333333UL; 14525 enum int ethird = -19; 14526 enum ulong ce = 2718281828459045235UL; 14527 enum int ee = -18; 14528 enum ulong cln10 = 2302585092994045684UL; 14529 enum int eln10 = -18; 14530 } 14531 else static if (is(T:uint128)) 14532 { 14533 enum uint128 c1_2π = uint128("159154943091895335768883763372514362034"); 14534 enum int e1_2π = -39; 14535 enum uint128 c2π = uint128("62831853071795864769252867665590057684"); 14536 enum int e2π = -37; 14537 enum uint128 c2_π = uint128("63661977236758134307553505349005744814"); 14538 enum int e2_π = -38; 14539 enum uint128 cπ_2 = uint128("157079632679489661923132169163975144210"); 14540 enum int eπ_2 = -38; 14541 enum uint128 chalf = 5U; 14542 enum int ehalf = -1; 14543 enum uint128 cthird = uint128("333333333333333333333333333333333333333"); 14544 enum int ethird = -39; 14545 enum uint128 ce = uint128("271828182845904523536028747135266249776"); 14546 enum int ee = -38; 14547 enum uint128 cln10 = uint128("230258509299404568401799145468436420760"); 14548 enum int eln10 = -38; 14549 } 14550 else 14551 static assert(0); 14552 } 14553 14554 enum 14555 { 14556 s_e = "2.7182818284590452353602874713526625", 14557 s_pi = "3.1415926535897932384626433832795029", 14558 s_pi_2 = "1.5707963267948966192313216916397514", 14559 s_pi_4 = "0.7853981633974483096156608458198757", 14560 s_m_1_pi = "0.3183098861837906715377675267450287", 14561 s_m_2_pi = "0.6366197723675813430755350534900574", 14562 s_m_2_sqrtpi = "1.1283791670955125738961589031215452", 14563 s_sqrt2 = "1.4142135623730950488016887242096981", 14564 s_sqrt1_2 = "0.7071067811865475244008443621048490", 14565 s_ln10 = "2.3025850929940456840179914546843642", 14566 s_log2t = "3.3219280948873623478703194294893902", 14567 s_log2e = "1.4426950408889634073599246810018921", 14568 s_log2 = "0.3010299956639811952137388947244930", 14569 s_log10e = "0.4342944819032518276511289189166051", 14570 s_ln2 = "0.6931471805599453094172321214581766", 14571 14572 s_sqrt3 = "1.7320508075688772935274463415058723", 14573 s_m_sqrt3 = "0.5773502691896257645091487805019574", 14574 s_pi_3 = "1.0471975511965977461542144610931676", 14575 s_pi_6 = "0.5235987755982988730771072305465838", 14576 14577 s_sqrt2_2 = "0.7071067811865475244008443621048490", 14578 s_sqrt3_2 = "0.8660254037844386467637231707529361", 14579 s_5pi_6 = "2.6179938779914943653855361527329190", 14580 s_3pi_4 = "2.3561944901923449288469825374596271", 14581 s_2pi_3 = "2.0943951023931954923084289221863352", 14582 s_onethird = "0.3333333333333333333333333333333333", 14583 s_twothirds = "0.6666666666666666666666666666666667", 14584 s_5_6 = "0.8333333333333333333333333333333333", 14585 s_1_6 = "0.1666666666666666666666666666666667", 14586 s_m_1_2pi = "0.1591549430918953357688837633725144", 14587 s_pi2 = "6.2831853071795864769252867665590058", 14588 } 14589 14590 struct IEEECompliant 14591 { 14592 string name; 14593 int page; 14594 } 14595 14596 D parse(D, R)(ref R range) 14597 if (isInputRange!R && isSomeChar!(ElementType!R) && isDecimal!D) 14598 { 14599 Unqual!D result; 14600 auto flags = parse(range, result, D.realPrecision(DecimalControl.precision), DecimalControl.rounding); 14601 if (flags) 14602 DecimalControl.raiseFlags(flags); 14603 } 14604 14605 //10 bit encoding 14606 @safe pure nothrow @nogc 14607 private uint packDPD(const uint d1, const uint d2, const uint d3) 14608 { 14609 uint x = ((d1 & 8) >>> 1) | ((d2 & 8) >>> 2) | ((d3 & 8) >>> 3); 14610 14611 switch(x) 14612 { 14613 case 0: 14614 return (d1 << 7) | (d2 << 4) | d3; 14615 case 1: 14616 return (d1 << 7) | (d2 << 4) | (d3 & 1) | 8; 14617 case 2: 14618 return (d1 << 7) | ((d3 & 6) << 4) | ((d2 & 1) << 4) | (d3 & 1) | 10; 14619 case 3: 14620 return (d1 << 7) | ((d2 & 1) << 4) | (d3 & 1) | 78; 14621 case 4: 14622 return ((d3 & 6) << 7) | ((d1 & 1) << 7) | (d2 << 4) | (d3 & 1) | 12; 14623 case 5: 14624 return ((d2 & 6) << 7) | ((d1 & 1) << 7) | ((d2 & 1) << 4) | (d3 & 1) | 46; 14625 case 6: 14626 return ((d3 & 6) << 7) | ((d1 & 1) << 7) | ((d2 & 1) << 4) | (d3 & 1) | 14; 14627 case 7: 14628 return ((d1 & 1) << 7) | ((d2 & 1) << 4) | (d3 & 1) | 110; 14629 default: 14630 assert(0); 14631 } 14632 } 14633 14634 //10 bit decoding 14635 @safe pure nothrow @nogc 14636 private void unpackDPD(const uint declet, out uint d1, out uint d2, out uint d3) 14637 { 14638 uint x = declet & 14; 14639 uint decoded; 14640 switch (x) 14641 { 14642 case 0: 14643 decoded = ((declet & 896) << 1) | (declet & 119); 14644 break; 14645 case 1: 14646 decoded = ((declet & 128) << 1) | (declet & 113) | ((declet & 768) >> 7) | 2048; 14647 break; 14648 case 2: 14649 decoded = ((declet & 896) << 1) | (declet & 17) | ((declet & 96) >> 4) | 128; 14650 break; 14651 case 3: 14652 decoded = ((declet & 896) << 1) | (declet & 113) | 8; 14653 break; 14654 case 4: 14655 decoded = ((declet & 128) << 1) | (declet & 17) | ((declet & 768) >> 7) | 2176; 14656 break; 14657 case 5: 14658 decoded = ((declet & 128) << 1) | (declet & 17) | ((declet & 768) >> 3) | 2056; 14659 break; 14660 case 6: 14661 decoded = ((declet & 896) << 1) | (declet & 17) | 136; 14662 break; 14663 case 7: 14664 decoded = ((declet & 128) << 1) | (declet & 17) | 2184; 14665 break; 14666 default: 14667 assert(0); 14668 } 14669 14670 d1 = (decoded & 3840) >> 8; 14671 d2 = (decoded & 240) >> 4; 14672 d3 = (decoded & 15); 14673 }