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