1 // Written in the D programming language. 2 3 /** 4 This is a submodule of $(MREF std, math). 5 6 It contains several functions for introspection on numerical values. 7 8 Copyright: Copyright The D Language Foundation 2000 - 2011. 9 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 10 Authors: $(HTTP digitalmars.com, Walter Bright), Don Clugston, 11 Conversion of CEPHES math library to D by Iain Buclaw and David Nadlinger 12 Source: $(PHOBOSSRC std/math/traits.d) 13 14 Macros: 15 NAN = $(RED NAN) 16 PLUSMN = ± 17 INFIN = ∞ 18 */ 19 20 module std.math.traits; 21 22 import std.traits : isFloatingPoint, isIntegral, isNumeric, isSigned; 23 24 25 /********************************* 26 * Determines if $(D_PARAM x) is NaN. 27 * Params: 28 * x = a floating point number. 29 * Returns: 30 * `true` if $(D_PARAM x) is Nan. 31 */ 32 bool isNaN(X)(X x) @nogc @trusted pure nothrow 33 if (isFloatingPoint!(X)) 34 { 35 version (all) 36 { 37 return x != x; 38 } 39 else 40 { 41 /* 42 Code kept for historical context. At least on Intel, the simple test 43 x != x uses one dedicated instruction (ucomiss/ucomisd) that runs in one 44 cycle. Code for 80- and 128-bits is larger but still smaller than the 45 integrals-based solutions below. Future revisions may enable the code 46 below conditionally depending on hardware. 47 */ 48 alias F = floatTraits!(X); 49 static if (F.realFormat == RealFormat.ieeeSingle) 50 { 51 const uint p = *cast(uint *)&x; 52 // Sign bit (MSB) is irrelevant so mask it out. 53 // Next 8 bits should be all set. 54 // At least one bit among the least significant 23 bits should be set. 55 return (p & 0x7FFF_FFFF) > 0x7F80_0000; 56 } 57 else static if (F.realFormat == RealFormat.ieeeDouble) 58 { 59 const ulong p = *cast(ulong *)&x; 60 // Sign bit (MSB) is irrelevant so mask it out. 61 // Next 11 bits should be all set. 62 // At least one bit among the least significant 52 bits should be set. 63 return (p & 0x7FFF_FFFF_FFFF_FFFF) > 0x7FF0_0000_0000_0000; 64 } 65 else static if (F.realFormat == RealFormat.ieeeExtended || 66 F.realFormat == RealFormat.ieeeExtended53) 67 { 68 const ushort e = F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT]; 69 const ulong ps = *cast(ulong *)&x; 70 return e == F.EXPMASK && 71 ps & 0x7FFF_FFFF_FFFF_FFFF; // not infinity 72 } 73 else static if (F.realFormat == RealFormat.ieeeQuadruple) 74 { 75 const ushort e = F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT]; 76 const ulong psLsb = (cast(ulong *)&x)[MANTISSA_LSB]; 77 const ulong psMsb = (cast(ulong *)&x)[MANTISSA_MSB]; 78 return e == F.EXPMASK && 79 (psLsb | (psMsb& 0x0000_FFFF_FFFF_FFFF)) != 0; 80 } 81 else 82 { 83 return x != x; 84 } 85 } 86 } 87 88 /// 89 @safe pure nothrow @nogc unittest 90 { 91 assert( isNaN(float.init)); 92 assert( isNaN(-double.init)); 93 assert( isNaN(real.nan)); 94 assert( isNaN(-real.nan)); 95 assert(!isNaN(cast(float) 53.6)); 96 assert(!isNaN(cast(real)-53.6)); 97 } 98 99 @safe pure nothrow @nogc unittest 100 { 101 import std.meta : AliasSeq; 102 103 static foreach (T; AliasSeq!(float, double, real)) 104 {{ 105 // CTFE-able tests 106 assert(isNaN(T.init)); 107 assert(isNaN(-T.init)); 108 assert(isNaN(T.nan)); 109 assert(isNaN(-T.nan)); 110 assert(!isNaN(T.infinity)); 111 assert(!isNaN(-T.infinity)); 112 assert(!isNaN(cast(T) 53.6)); 113 assert(!isNaN(cast(T)-53.6)); 114 115 // Runtime tests 116 shared T f; 117 f = T.init; 118 assert(isNaN(f)); 119 assert(isNaN(-f)); 120 f = T.nan; 121 assert(isNaN(f)); 122 assert(isNaN(-f)); 123 f = T.infinity; 124 assert(!isNaN(f)); 125 assert(!isNaN(-f)); 126 f = cast(T) 53.6; 127 assert(!isNaN(f)); 128 assert(!isNaN(-f)); 129 }} 130 } 131 132 /********************************* 133 * Determines if $(D_PARAM x) is finite. 134 * Params: 135 * x = a floating point number. 136 * Returns: 137 * `true` if $(D_PARAM x) is finite. 138 */ 139 bool isFinite(X)(X x) @trusted pure nothrow @nogc 140 { 141 import std.math.traits : floatTraits, RealFormat; 142 143 static if (__traits(isFloating, X)) 144 if (__ctfe) 145 return x == x && x != X.infinity && x != -X.infinity; 146 alias F = floatTraits!(X); 147 ushort* pe = cast(ushort *)&x; 148 return (pe[F.EXPPOS_SHORT] & F.EXPMASK) != F.EXPMASK; 149 } 150 151 /// 152 @safe pure nothrow @nogc unittest 153 { 154 assert( isFinite(1.23f)); 155 assert( isFinite(float.max)); 156 assert( isFinite(float.min_normal)); 157 assert(!isFinite(float.nan)); 158 assert(!isFinite(float.infinity)); 159 } 160 161 @safe pure nothrow @nogc unittest 162 { 163 assert(isFinite(1.23)); 164 assert(isFinite(double.max)); 165 assert(isFinite(double.min_normal)); 166 assert(!isFinite(double.nan)); 167 assert(!isFinite(double.infinity)); 168 169 assert(isFinite(1.23L)); 170 assert(isFinite(real.max)); 171 assert(isFinite(real.min_normal)); 172 assert(!isFinite(real.nan)); 173 assert(!isFinite(real.infinity)); 174 175 //CTFE 176 static assert(isFinite(1.23)); 177 static assert(isFinite(double.max)); 178 static assert(isFinite(double.min_normal)); 179 static assert(!isFinite(double.nan)); 180 static assert(!isFinite(double.infinity)); 181 182 static assert(isFinite(1.23L)); 183 static assert(isFinite(real.max)); 184 static assert(isFinite(real.min_normal)); 185 static assert(!isFinite(real.nan)); 186 static assert(!isFinite(real.infinity)); 187 } 188 189 190 /********************************* 191 * Determines if $(D_PARAM x) is normalized. 192 * 193 * A normalized number must not be zero, subnormal, infinite nor $(NAN). 194 * 195 * Params: 196 * x = a floating point number. 197 * Returns: 198 * `true` if $(D_PARAM x) is normalized. 199 */ 200 201 /* Need one for each format because subnormal floats might 202 * be converted to normal reals. 203 */ 204 bool isNormal(X)(X x) @trusted pure nothrow @nogc 205 { 206 import std.math.traits : floatTraits, RealFormat; 207 208 static if (__traits(isFloating, X)) 209 if (__ctfe) 210 return (x <= -X.min_normal && x != -X.infinity) || (x >= X.min_normal && x != X.infinity); 211 alias F = floatTraits!(X); 212 ushort e = F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT]; 213 return (e != F.EXPMASK && e != 0); 214 } 215 216 /// 217 @safe pure nothrow @nogc unittest 218 { 219 float f = 3; 220 double d = 500; 221 real e = 10e+48; 222 223 assert(isNormal(f)); 224 assert(isNormal(d)); 225 assert(isNormal(e)); 226 f = d = e = 0; 227 assert(!isNormal(f)); 228 assert(!isNormal(d)); 229 assert(!isNormal(e)); 230 assert(!isNormal(real.infinity)); 231 assert(isNormal(-real.max)); 232 assert(!isNormal(real.min_normal/4)); 233 234 } 235 236 @safe pure nothrow @nogc unittest 237 { 238 // CTFE 239 enum float f = 3; 240 enum double d = 500; 241 enum real e = 10e+48; 242 243 static assert(isNormal(f)); 244 static assert(isNormal(d)); 245 static assert(isNormal(e)); 246 247 static assert(!isNormal(0.0f)); 248 static assert(!isNormal(0.0)); 249 static assert(!isNormal(0.0L)); 250 static assert(!isNormal(real.infinity)); 251 static assert(isNormal(-real.max)); 252 static assert(!isNormal(real.min_normal/4)); 253 } 254 255 /********************************* 256 * Determines if $(D_PARAM x) is subnormal. 257 * 258 * Subnormals (also known as "denormal number"), have a 0 exponent 259 * and a 0 most significant mantissa bit. 260 * 261 * Params: 262 * x = a floating point number. 263 * Returns: 264 * `true` if $(D_PARAM x) is a denormal number. 265 */ 266 bool isSubnormal(X)(X x) @trusted pure nothrow @nogc 267 { 268 import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB; 269 270 static if (__traits(isFloating, X)) 271 if (__ctfe) 272 return -X.min_normal < x && x < X.min_normal; 273 /* 274 Need one for each format because subnormal floats might 275 be converted to normal reals. 276 */ 277 alias F = floatTraits!(X); 278 static if (F.realFormat == RealFormat.ieeeSingle) 279 { 280 uint *p = cast(uint *)&x; 281 return (*p & F.EXPMASK_INT) == 0 && *p & F.MANTISSAMASK_INT; 282 } 283 else static if (F.realFormat == RealFormat.ieeeDouble) 284 { 285 uint *p = cast(uint *)&x; 286 return (p[MANTISSA_MSB] & F.EXPMASK_INT) == 0 287 && (p[MANTISSA_LSB] || p[MANTISSA_MSB] & F.MANTISSAMASK_INT); 288 } 289 else static if (F.realFormat == RealFormat.ieeeQuadruple) 290 { 291 ushort e = F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT]; 292 long* ps = cast(long *)&x; 293 return (e == 0 && 294 ((ps[MANTISSA_LSB]|(ps[MANTISSA_MSB]& 0x0000_FFFF_FFFF_FFFF)) != 0)); 295 } 296 else static if (F.realFormat == RealFormat.ieeeExtended || 297 F.realFormat == RealFormat.ieeeExtended53) 298 { 299 ushort* pe = cast(ushort *)&x; 300 long* ps = cast(long *)&x; 301 302 return (pe[F.EXPPOS_SHORT] & F.EXPMASK) == 0 && *ps > 0; 303 } 304 else 305 { 306 static assert(false, "Not implemented for this architecture"); 307 } 308 } 309 310 /// 311 @safe pure nothrow @nogc unittest 312 { 313 import std.meta : AliasSeq; 314 315 static foreach (T; AliasSeq!(float, double, real)) 316 {{ 317 T f; 318 for (f = 1.0; !isSubnormal(f); f /= 2) 319 assert(f != 0); 320 }} 321 } 322 323 @safe pure nothrow @nogc unittest 324 { 325 static bool subnormalTest(T)() 326 { 327 T f; 328 for (f = 1.0; !isSubnormal(f); f /= 2) 329 if (f == 0) 330 return false; 331 return true; 332 } 333 static assert(subnormalTest!float()); 334 static assert(subnormalTest!double()); 335 static assert(subnormalTest!real()); 336 } 337 338 /********************************* 339 * Determines if $(D_PARAM x) is $(PLUSMN)$(INFIN). 340 * Params: 341 * x = a floating point number. 342 * Returns: 343 * `true` if $(D_PARAM x) is $(PLUSMN)$(INFIN). 344 */ 345 bool isInfinity(X)(X x) @nogc @trusted pure nothrow 346 if (isFloatingPoint!(X)) 347 { 348 import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB; 349 350 alias F = floatTraits!(X); 351 static if (F.realFormat == RealFormat.ieeeSingle) 352 { 353 return ((*cast(uint *)&x) & 0x7FFF_FFFF) == 0x7F80_0000; 354 } 355 else static if (F.realFormat == RealFormat.ieeeDouble) 356 { 357 return ((*cast(ulong *)&x) & 0x7FFF_FFFF_FFFF_FFFF) 358 == 0x7FF0_0000_0000_0000; 359 } 360 else static if (F.realFormat == RealFormat.ieeeExtended || 361 F.realFormat == RealFormat.ieeeExtended53) 362 { 363 const ushort e = cast(ushort)(F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT]); 364 const ulong ps = *cast(ulong *)&x; 365 366 // On Motorola 68K, infinity can have hidden bit = 1 or 0. On x86, it is always 1. 367 return e == F.EXPMASK && (ps & 0x7FFF_FFFF_FFFF_FFFF) == 0; 368 } 369 else static if (F.realFormat == RealFormat.ieeeQuadruple) 370 { 371 const long psLsb = (cast(long *)&x)[MANTISSA_LSB]; 372 const long psMsb = (cast(long *)&x)[MANTISSA_MSB]; 373 return (psLsb == 0) 374 && (psMsb & 0x7FFF_FFFF_FFFF_FFFF) == 0x7FFF_0000_0000_0000; 375 } 376 else 377 { 378 return (x < -X.max) || (X.max < x); 379 } 380 } 381 382 /// 383 @nogc @safe pure nothrow unittest 384 { 385 assert(!isInfinity(float.init)); 386 assert(!isInfinity(-float.init)); 387 assert(!isInfinity(float.nan)); 388 assert(!isInfinity(-float.nan)); 389 assert(isInfinity(float.infinity)); 390 assert(isInfinity(-float.infinity)); 391 assert(isInfinity(-1.0f / 0.0f)); 392 } 393 394 @safe pure nothrow @nogc unittest 395 { 396 // CTFE-able tests 397 assert(!isInfinity(double.init)); 398 assert(!isInfinity(-double.init)); 399 assert(!isInfinity(double.nan)); 400 assert(!isInfinity(-double.nan)); 401 assert(isInfinity(double.infinity)); 402 assert(isInfinity(-double.infinity)); 403 assert(isInfinity(-1.0 / 0.0)); 404 405 assert(!isInfinity(real.init)); 406 assert(!isInfinity(-real.init)); 407 assert(!isInfinity(real.nan)); 408 assert(!isInfinity(-real.nan)); 409 assert(isInfinity(real.infinity)); 410 assert(isInfinity(-real.infinity)); 411 assert(isInfinity(-1.0L / 0.0L)); 412 413 // Runtime tests 414 shared float f; 415 f = float.init; 416 assert(!isInfinity(f)); 417 assert(!isInfinity(-f)); 418 f = float.nan; 419 assert(!isInfinity(f)); 420 assert(!isInfinity(-f)); 421 f = float.infinity; 422 assert(isInfinity(f)); 423 assert(isInfinity(-f)); 424 f = (-1.0f / 0.0f); 425 assert(isInfinity(f)); 426 427 shared double d; 428 d = double.init; 429 assert(!isInfinity(d)); 430 assert(!isInfinity(-d)); 431 d = double.nan; 432 assert(!isInfinity(d)); 433 assert(!isInfinity(-d)); 434 d = double.infinity; 435 assert(isInfinity(d)); 436 assert(isInfinity(-d)); 437 d = (-1.0 / 0.0); 438 assert(isInfinity(d)); 439 440 shared real e; 441 e = real.init; 442 assert(!isInfinity(e)); 443 assert(!isInfinity(-e)); 444 e = real.nan; 445 assert(!isInfinity(e)); 446 assert(!isInfinity(-e)); 447 e = real.infinity; 448 assert(isInfinity(e)); 449 assert(isInfinity(-e)); 450 e = (-1.0L / 0.0L); 451 assert(isInfinity(e)); 452 } 453 454 @nogc @safe pure nothrow unittest 455 { 456 import std.meta : AliasSeq; 457 static bool foo(T)(inout T x) { return isInfinity(x); } 458 foreach (T; AliasSeq!(float, double, real)) 459 { 460 assert(!foo(T(3.14f))); 461 assert(foo(T.infinity)); 462 } 463 } 464 465 /********************************* 466 * Is the binary representation of x identical to y? 467 */ 468 bool isIdentical(real x, real y) @trusted pure nothrow @nogc 469 { 470 if (__ctfe) 471 { 472 if (x !is y) return false; 473 if (x == x) return true; // If not NaN `is` implies identical representation. 474 static if (double.mant_dig != real.mant_dig) 475 { 476 // Works because we are in CTFE and there is no way in CTFE to set more 477 // bits of NaN payload than can fit in a double, and since 2.087 478 // changed real.init to be non-signaling I *think* there is no way in 479 // CTFE for a real to be a signaling NaN unless real and double have 480 // the same representation so real's bits can be manipulated directly. 481 double d1 = x, d2 = y; 482 } 483 else 484 { 485 // Alias to avoid converting signaling to quiet. 486 alias d1 = x; 487 alias d2 = y; 488 } 489 return *cast(long*) &d1 == *cast(long*) &d2; 490 } 491 // We're doing a bitwise comparison so the endianness is irrelevant. 492 long* pxs = cast(long *)&x; 493 long* pys = cast(long *)&y; 494 alias F = floatTraits!(real); 495 static if (F.realFormat == RealFormat.ieeeDouble) 496 { 497 return pxs[0] == pys[0]; 498 } 499 else static if (F.realFormat == RealFormat.ieeeQuadruple) 500 { 501 return pxs[0] == pys[0] && pxs[1] == pys[1]; 502 } 503 else static if (F.realFormat == RealFormat.ieeeExtended) 504 { 505 ushort* pxe = cast(ushort *)&x; 506 ushort* pye = cast(ushort *)&y; 507 return pxe[4] == pye[4] && pxs[0] == pys[0]; 508 } 509 else 510 { 511 assert(0, "isIdentical not implemented"); 512 } 513 } 514 /// 515 @safe @nogc pure nothrow unittest 516 { 517 // We're forcing the CTFE to run by assigning the result of the function to an enum 518 enum test1 = isIdentical(1.0,1.0); 519 enum test2 = isIdentical(real.nan,real.nan); 520 enum test3 = isIdentical(real.infinity, real.infinity); 521 enum test4 = isIdentical(real.infinity, real.infinity); 522 enum test5 = isIdentical(0.0, 0.0); 523 524 assert(test1); 525 assert(test2); 526 assert(test3); 527 assert(test4); 528 assert(test5); 529 530 enum test6 = !isIdentical(0.0, -0.0); 531 enum test7 = !isIdentical(real.nan, -real.nan); 532 enum test8 = !isIdentical(real.infinity, -real.infinity); 533 534 assert(test6); 535 assert(test7); 536 assert(test8); 537 } 538 539 @safe @nogc pure nothrow unittest 540 { 541 assert( !isIdentical(1.2,1.3)); 542 assert( isIdentical(0.0, 0.0)); 543 assert( isIdentical(1.0, 1.0)); 544 assert( isIdentical(real.infinity, real.infinity)); 545 assert( isIdentical(-real.infinity, -real.infinity)); 546 assert( isIdentical(real.nan, real.nan)); 547 548 assert(!isIdentical(0.0, -0.0)); 549 assert(!isIdentical(real.nan, -real.nan)); 550 assert(!isIdentical(real.infinity, -real.infinity)); 551 } 552 /********************************* 553 * Return 1 if sign bit of e is set, 0 if not. 554 */ 555 int signbit(X)(X x) @nogc @trusted pure nothrow 556 { 557 import std.math.traits : floatTraits, RealFormat; 558 559 if (__ctfe) 560 { 561 double dval = cast(double) x; // Precision can increase or decrease but sign won't change (even NaN). 562 return 0 > *cast(long*) &dval; 563 } 564 565 alias F = floatTraits!(X); 566 return ((cast(ubyte *)&x)[F.SIGNPOS_BYTE] & 0x80) != 0; 567 } 568 569 /// 570 @nogc @safe pure nothrow unittest 571 { 572 assert(!signbit(float.nan)); 573 assert(signbit(-float.nan)); 574 assert(!signbit(168.1234f)); 575 assert(signbit(-168.1234f)); 576 assert(!signbit(0.0f)); 577 assert(signbit(-0.0f)); 578 assert(signbit(-float.max)); 579 assert(!signbit(float.max)); 580 581 assert(!signbit(double.nan)); 582 assert(signbit(-double.nan)); 583 assert(!signbit(168.1234)); 584 assert(signbit(-168.1234)); 585 assert(!signbit(0.0)); 586 assert(signbit(-0.0)); 587 assert(signbit(-double.max)); 588 assert(!signbit(double.max)); 589 590 assert(!signbit(real.nan)); 591 assert(signbit(-real.nan)); 592 assert(!signbit(168.1234L)); 593 assert(signbit(-168.1234L)); 594 assert(!signbit(0.0L)); 595 assert(signbit(-0.0L)); 596 assert(signbit(-real.max)); 597 assert(!signbit(real.max)); 598 } 599 600 @nogc @safe pure nothrow unittest 601 { 602 // CTFE 603 static assert(!signbit(float.nan)); 604 static assert(signbit(-float.nan)); 605 static assert(!signbit(168.1234f)); 606 static assert(signbit(-168.1234f)); 607 static assert(!signbit(0.0f)); 608 static assert(signbit(-0.0f)); 609 static assert(signbit(-float.max)); 610 static assert(!signbit(float.max)); 611 612 static assert(!signbit(double.nan)); 613 static assert(signbit(-double.nan)); 614 static assert(!signbit(168.1234)); 615 static assert(signbit(-168.1234)); 616 static assert(!signbit(0.0)); 617 static assert(signbit(-0.0)); 618 static assert(signbit(-double.max)); 619 static assert(!signbit(double.max)); 620 621 static assert(!signbit(real.nan)); 622 static assert(signbit(-real.nan)); 623 static assert(!signbit(168.1234L)); 624 static assert(signbit(-168.1234L)); 625 static assert(!signbit(0.0L)); 626 static assert(signbit(-0.0L)); 627 static assert(signbit(-real.max)); 628 static assert(!signbit(real.max)); 629 } 630 631 /** 632 Params: 633 to = the numeric value to use 634 from = the sign value to use 635 Returns: 636 a value composed of to with from's sign bit. 637 */ 638 R copysign(R, X)(R to, X from) @trusted pure nothrow @nogc 639 if (isFloatingPoint!(R) && isFloatingPoint!(X)) 640 { 641 import std.math.traits : floatTraits, RealFormat; 642 643 if (__ctfe) 644 { 645 return signbit(to) == signbit(from) ? to : -to; 646 } 647 ubyte* pto = cast(ubyte *)&to; 648 const ubyte* pfrom = cast(ubyte *)&from; 649 650 alias T = floatTraits!(R); 651 alias F = floatTraits!(X); 652 pto[T.SIGNPOS_BYTE] &= 0x7F; 653 pto[T.SIGNPOS_BYTE] |= pfrom[F.SIGNPOS_BYTE] & 0x80; 654 return to; 655 } 656 657 /// ditto 658 R copysign(R, X)(X to, R from) @trusted pure nothrow @nogc 659 if (isIntegral!(X) && isFloatingPoint!(R)) 660 { 661 return copysign(cast(R) to, from); 662 } 663 664 /// 665 @safe pure nothrow @nogc unittest 666 { 667 assert(copysign(1.0, 1.0) == 1.0); 668 assert(copysign(1.0, -0.0) == -1.0); 669 assert(copysign(1UL, -1.0) == -1.0); 670 assert(copysign(-1.0, -1.0) == -1.0); 671 672 assert(copysign(real.infinity, -1.0) == -real.infinity); 673 assert(copysign(real.nan, 1.0) is real.nan); 674 assert(copysign(-real.nan, 1.0) is real.nan); 675 assert(copysign(real.nan, -1.0) is -real.nan); 676 } 677 678 @safe pure nothrow @nogc unittest 679 { 680 import std.meta : AliasSeq; 681 682 static foreach (X; AliasSeq!(float, double, real, int, long)) 683 { 684 static foreach (Y; AliasSeq!(float, double, real)) 685 {{ 686 X x = 21; 687 Y y = 23.8; 688 Y e = void; 689 690 e = copysign(x, y); 691 assert(e == 21.0); 692 693 e = copysign(-x, y); 694 assert(e == 21.0); 695 696 e = copysign(x, -y); 697 assert(e == -21.0); 698 699 e = copysign(-x, -y); 700 assert(e == -21.0); 701 702 static if (isFloatingPoint!X) 703 { 704 e = copysign(X.nan, y); 705 assert(isNaN(e) && !signbit(e)); 706 707 e = copysign(X.nan, -y); 708 assert(isNaN(e) && signbit(e)); 709 } 710 }} 711 } 712 // CTFE 713 static foreach (X; AliasSeq!(float, double, real, int, long)) 714 { 715 static foreach (Y; AliasSeq!(float, double, real)) 716 {{ 717 enum X x = 21; 718 enum Y y = 23.8; 719 720 assert(21.0 == copysign(x, y)); 721 assert(21.0 == copysign(-x, y)); 722 assert(-21.0 == copysign(x, -y)); 723 assert(-21.0 == copysign(-x, -y)); 724 725 static if (isFloatingPoint!X) 726 { 727 static assert(isNaN(copysign(X.nan, y)) && !signbit(copysign(X.nan, y))); 728 assert(isNaN(copysign(X.nan, -y)) && signbit(copysign(X.nan, -y))); 729 } 730 }} 731 } 732 } 733 734 /********************************* 735 Returns `-1` if $(D x < 0), `x` if $(D x == 0), `1` if 736 $(D x > 0), and $(NAN) if x==$(NAN). 737 */ 738 F sgn(F)(F x) @safe pure nothrow @nogc 739 if (isFloatingPoint!F || isIntegral!F) 740 { 741 // @@@TODO@@@: make this faster 742 return x > 0 ? 1 : x < 0 ? -1 : x; 743 } 744 745 /// 746 @safe pure nothrow @nogc unittest 747 { 748 assert(sgn(168.1234) == 1); 749 assert(sgn(-168.1234) == -1); 750 assert(sgn(0.0) == 0); 751 assert(sgn(-0.0) == 0); 752 } 753 754 /** 755 Check whether a number is an integer power of two. 756 757 Note that only positive numbers can be integer powers of two. This 758 function always return `false` if `x` is negative or zero. 759 760 Params: 761 x = the number to test 762 763 Returns: 764 `true` if `x` is an integer power of two. 765 */ 766 bool isPowerOf2(X)(const X x) pure @safe nothrow @nogc 767 if (isNumeric!X) 768 { 769 import std.math.exponential : frexp; 770 771 static if (isFloatingPoint!X) 772 { 773 int exp; 774 const X sig = frexp(x, exp); 775 776 return (exp != int.min) && (sig is cast(X) 0.5L); 777 } 778 else 779 { 780 static if (isSigned!X) 781 { 782 auto y = cast(typeof(x + 0))x; 783 return y > 0 && !(y & (y - 1)); 784 } 785 else 786 { 787 auto y = cast(typeof(x + 0u))x; 788 return (y & -y) > (y - 1); 789 } 790 } 791 } 792 /// 793 @safe unittest 794 { 795 import std.math.exponential : pow; 796 797 assert( isPowerOf2(1.0L)); 798 assert( isPowerOf2(2.0L)); 799 assert( isPowerOf2(0.5L)); 800 assert( isPowerOf2(pow(2.0L, 96))); 801 assert( isPowerOf2(pow(2.0L, -77))); 802 803 assert(!isPowerOf2(-2.0L)); 804 assert(!isPowerOf2(-0.5L)); 805 assert(!isPowerOf2(0.0L)); 806 assert(!isPowerOf2(4.315)); 807 assert(!isPowerOf2(1.0L / 3.0L)); 808 809 assert(!isPowerOf2(real.nan)); 810 assert(!isPowerOf2(real.infinity)); 811 } 812 /// 813 @safe unittest 814 { 815 assert( isPowerOf2(1)); 816 assert( isPowerOf2(2)); 817 assert( isPowerOf2(1uL << 63)); 818 819 assert(!isPowerOf2(-4)); 820 assert(!isPowerOf2(0)); 821 assert(!isPowerOf2(1337u)); 822 } 823 824 @safe unittest 825 { 826 import std.math.exponential : pow; 827 import std.meta : AliasSeq; 828 829 enum smallP2 = pow(2.0L, -62); 830 enum bigP2 = pow(2.0L, 50); 831 enum smallP7 = pow(7.0L, -35); 832 enum bigP7 = pow(7.0L, 30); 833 834 static foreach (X; AliasSeq!(float, double, real)) 835 {{ 836 immutable min_sub = X.min_normal * X.epsilon; 837 838 foreach (x; [smallP2, min_sub, X.min_normal, .25L, 0.5L, 1.0L, 839 2.0L, 8.0L, pow(2.0L, X.max_exp - 1), bigP2]) 840 { 841 assert( isPowerOf2(cast(X) x)); 842 assert(!isPowerOf2(cast(X)-x)); 843 } 844 845 foreach (x; [0.0L, 3 * min_sub, smallP7, 0.1L, 1337.0L, bigP7, X.max, real.nan, real.infinity]) 846 { 847 assert(!isPowerOf2(cast(X) x)); 848 assert(!isPowerOf2(cast(X)-x)); 849 } 850 }} 851 852 static foreach (X; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong)) 853 {{ 854 foreach (x; [1, 2, 4, 8, (X.max >>> 1) + 1]) 855 { 856 assert( isPowerOf2(cast(X) x)); 857 static if (isSigned!X) 858 assert(!isPowerOf2(cast(X)-x)); 859 } 860 861 foreach (x; [0, 3, 5, 13, 77, X.min, X.max]) 862 assert(!isPowerOf2(cast(X) x)); 863 }} 864 865 // CTFE 866 static foreach (X; AliasSeq!(float, double, real)) 867 {{ 868 enum min_sub = X.min_normal * X.epsilon; 869 870 static foreach (x; [smallP2, min_sub, X.min_normal, .25L, 0.5L, 1.0L, 871 2.0L, 8.0L, pow(2.0L, X.max_exp - 1), bigP2]) 872 { 873 static assert( isPowerOf2(cast(X) x)); 874 static assert(!isPowerOf2(cast(X)-x)); 875 } 876 877 static foreach (x; [0.0L, 3 * min_sub, smallP7, 0.1L, 1337.0L, bigP7, X.max, real.nan, real.infinity]) 878 { 879 static assert(!isPowerOf2(cast(X) x)); 880 static assert(!isPowerOf2(cast(X)-x)); 881 } 882 }} 883 884 static foreach (X; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong)) 885 {{ 886 static foreach (x; [1, 2, 4, 8, (X.max >>> 1) + 1]) 887 { 888 static assert( isPowerOf2(cast(X) x)); 889 static if (isSigned!X) 890 static assert(!isPowerOf2(cast(X)-x)); 891 } 892 893 static foreach (x; [0, 3, 5, 13, 77, X.min, X.max]) 894 static assert(!isPowerOf2(cast(X) x)); 895 }} 896 } 897 898 // Underlying format exposed through floatTraits 899 enum RealFormat 900 { 901 ieeeHalf, 902 ieeeSingle, 903 ieeeDouble, 904 ieeeExtended, // x87 80-bit real 905 ieeeExtended53, // x87 real rounded to precision of double. 906 ibmExtended, // IBM 128-bit extended 907 ieeeQuadruple, 908 } 909 910 // Constants used for extracting the components of the representation. 911 // They supplement the built-in floating point properties. 912 template floatTraits(T) 913 { 914 import std.traits : Unqual; 915 916 // EXPMASK is a ushort mask to select the exponent portion (without sign) 917 // EXPSHIFT is the number of bits the exponent is left-shifted by in its ushort 918 // EXPBIAS is the exponent bias - 1 (exp == EXPBIAS yields ×2^-1). 919 // EXPPOS_SHORT is the index of the exponent when represented as a ushort array. 920 // SIGNPOS_BYTE is the index of the sign when represented as a ubyte array. 921 // RECIP_EPSILON is the value such that (smallest_subnormal) * RECIP_EPSILON == T.min_normal 922 enum Unqual!T RECIP_EPSILON = (1/T.epsilon); 923 static if (T.mant_dig == 24) 924 { 925 // Single precision float 926 enum ushort EXPMASK = 0x7F80; 927 enum ushort EXPSHIFT = 7; 928 enum ushort EXPBIAS = 0x3F00; 929 enum uint EXPMASK_INT = 0x7F80_0000; 930 enum uint MANTISSAMASK_INT = 0x007F_FFFF; 931 enum realFormat = RealFormat.ieeeSingle; 932 version (LittleEndian) 933 { 934 enum EXPPOS_SHORT = 1; 935 enum SIGNPOS_BYTE = 3; 936 } 937 else 938 { 939 enum EXPPOS_SHORT = 0; 940 enum SIGNPOS_BYTE = 0; 941 } 942 } 943 else static if (T.mant_dig == 53) 944 { 945 static if (T.sizeof == 8) 946 { 947 // Double precision float, or real == double 948 enum ushort EXPMASK = 0x7FF0; 949 enum ushort EXPSHIFT = 4; 950 enum ushort EXPBIAS = 0x3FE0; 951 enum uint EXPMASK_INT = 0x7FF0_0000; 952 enum uint MANTISSAMASK_INT = 0x000F_FFFF; // for the MSB only 953 enum ulong MANTISSAMASK_LONG = 0x000F_FFFF_FFFF_FFFF; 954 enum realFormat = RealFormat.ieeeDouble; 955 version (LittleEndian) 956 { 957 enum EXPPOS_SHORT = 3; 958 enum SIGNPOS_BYTE = 7; 959 } 960 else 961 { 962 enum EXPPOS_SHORT = 0; 963 enum SIGNPOS_BYTE = 0; 964 } 965 } 966 else static if (T.sizeof == 12) 967 { 968 // Intel extended real80 rounded to double 969 enum ushort EXPMASK = 0x7FFF; 970 enum ushort EXPSHIFT = 0; 971 enum ushort EXPBIAS = 0x3FFE; 972 enum realFormat = RealFormat.ieeeExtended53; 973 version (LittleEndian) 974 { 975 enum EXPPOS_SHORT = 4; 976 enum SIGNPOS_BYTE = 9; 977 } 978 else 979 { 980 enum EXPPOS_SHORT = 0; 981 enum SIGNPOS_BYTE = 0; 982 } 983 } 984 else 985 static assert(false, "No traits support for " ~ T.stringof); 986 } 987 else static if (T.mant_dig == 64) 988 { 989 // Intel extended real80 990 enum ushort EXPMASK = 0x7FFF; 991 enum ushort EXPSHIFT = 0; 992 enum ushort EXPBIAS = 0x3FFE; 993 enum realFormat = RealFormat.ieeeExtended; 994 version (LittleEndian) 995 { 996 enum EXPPOS_SHORT = 4; 997 enum SIGNPOS_BYTE = 9; 998 } 999 else 1000 { 1001 enum EXPPOS_SHORT = 0; 1002 enum SIGNPOS_BYTE = 0; 1003 } 1004 } 1005 else static if (T.mant_dig == 113) 1006 { 1007 // Quadruple precision float 1008 enum ushort EXPMASK = 0x7FFF; 1009 enum ushort EXPSHIFT = 0; 1010 enum ushort EXPBIAS = 0x3FFE; 1011 enum realFormat = RealFormat.ieeeQuadruple; 1012 version (LittleEndian) 1013 { 1014 enum EXPPOS_SHORT = 7; 1015 enum SIGNPOS_BYTE = 15; 1016 } 1017 else 1018 { 1019 enum EXPPOS_SHORT = 0; 1020 enum SIGNPOS_BYTE = 0; 1021 } 1022 } 1023 else static if (T.mant_dig == 106) 1024 { 1025 // IBM Extended doubledouble 1026 enum ushort EXPMASK = 0x7FF0; 1027 enum ushort EXPSHIFT = 4; 1028 enum realFormat = RealFormat.ibmExtended; 1029 1030 // For IBM doubledouble the larger magnitude double comes first. 1031 // It's really a double[2] and arrays don't index differently 1032 // between little and big-endian targets. 1033 enum DOUBLEPAIR_MSB = 0; 1034 enum DOUBLEPAIR_LSB = 1; 1035 1036 // The exponent/sign byte is for most significant part. 1037 version (LittleEndian) 1038 { 1039 enum EXPPOS_SHORT = 3; 1040 enum SIGNPOS_BYTE = 7; 1041 } 1042 else 1043 { 1044 enum EXPPOS_SHORT = 0; 1045 enum SIGNPOS_BYTE = 0; 1046 } 1047 } 1048 else 1049 static assert(false, "No traits support for " ~ T.stringof); 1050 } 1051 1052 // These apply to all floating-point types 1053 version (LittleEndian) 1054 { 1055 enum MANTISSA_LSB = 0; 1056 enum MANTISSA_MSB = 1; 1057 } 1058 else 1059 { 1060 enum MANTISSA_LSB = 1; 1061 enum MANTISSA_MSB = 0; 1062 }