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