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 rounding floating point numbers. 7 8 Copyright: Copyright The D Language Foundation 2000 - 2011. 9 D implementations of floor, ceil, and lrint functions are based on the 10 CEPHES math library, which is Copyright (C) 2001 Stephen L. Moshier 11 $(LT)steve@moshier.net$(GT) and are incorporated herein by permission 12 of the author. The author reserves the right to distribute this 13 material elsewhere under different copying permissions. 14 These modifications are distributed here under the following terms: 15 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 16 Authors: $(HTTP digitalmars.com, Walter Bright), Don Clugston, 17 Conversion of CEPHES math library to D by Iain Buclaw and David Nadlinger 18 Source: $(PHOBOSSRC std/math/rounding.d) 19 */ 20 21 module std.math.rounding; 22 23 static import core.math; 24 static import core.stdc.math; 25 26 import std.traits : isFloatingPoint, isIntegral, Unqual; 27 28 version (LDC) import ldc.intrinsics; 29 30 version (D_InlineAsm_X86) version = InlineAsm_X86_Any; 31 version (D_InlineAsm_X86_64) version = InlineAsm_X86_Any; 32 33 version (LDC) version (CRuntime_Microsoft) version = LDC_MSVCRT; 34 35 version (LDC_MSVCRT) {} 36 else version (Android) {} 37 else version (InlineAsm_X86_Any) version = InlineAsm_X87; 38 version (InlineAsm_X87) 39 { 40 static assert(real.mant_dig == 64); 41 version (CRuntime_Microsoft) version = InlineAsm_X87_MSVC; 42 } 43 44 /************************************** 45 * Returns the value of x rounded upward to the next integer 46 * (toward positive infinity). 47 */ 48 pragma(inline, true) // LDC 49 real ceil(real x) @trusted pure nothrow @nogc 50 { 51 version (LDC) 52 { 53 return llvm_ceil(x); 54 } 55 else version (InlineAsm_X87_MSVC) 56 { 57 version (X86_64) 58 { 59 asm pure nothrow @nogc 60 { 61 naked ; 62 fld real ptr [RCX] ; 63 fstcw 8[RSP] ; 64 mov AL,9[RSP] ; 65 mov DL,AL ; 66 and AL,0xC3 ; 67 or AL,0x08 ; // round to +infinity 68 mov 9[RSP],AL ; 69 fldcw 8[RSP] ; 70 frndint ; 71 mov 9[RSP],DL ; 72 fldcw 8[RSP] ; 73 ret ; 74 } 75 } 76 else 77 { 78 short cw; 79 asm pure nothrow @nogc 80 { 81 fld x ; 82 fstcw cw ; 83 mov AL,byte ptr cw+1 ; 84 mov DL,AL ; 85 and AL,0xC3 ; 86 or AL,0x08 ; // round to +infinity 87 mov byte ptr cw+1,AL ; 88 fldcw cw ; 89 frndint ; 90 mov byte ptr cw+1,DL ; 91 fldcw cw ; 92 } 93 } 94 } 95 else 96 { 97 import std.math.traits : isInfinity, isNaN; 98 99 // Special cases. 100 if (isNaN(x) || isInfinity(x)) 101 return x; 102 103 real y = floorImpl(x); 104 if (y < x) 105 y += 1.0; 106 107 return y; 108 } 109 } 110 111 /// 112 @safe pure nothrow @nogc unittest 113 { 114 import std.math.traits : isNaN; 115 116 assert(ceil(+123.456L) == +124); 117 assert(ceil(-123.456L) == -123); 118 assert(ceil(-1.234L) == -1); 119 assert(ceil(-0.123L) == 0); 120 assert(ceil(0.0L) == 0); 121 assert(ceil(+0.123L) == 1); 122 assert(ceil(+1.234L) == 2); 123 assert(ceil(real.infinity) == real.infinity); 124 assert(isNaN(ceil(real.nan))); 125 assert(isNaN(ceil(real.init))); 126 } 127 128 /// ditto 129 pragma(inline, true) // LDC 130 double ceil(double x) @trusted pure nothrow @nogc 131 { 132 version (LDC) 133 { 134 return llvm_ceil(x); 135 } 136 else 137 { 138 import std.math.traits : isInfinity, isNaN; 139 140 // Special cases. 141 if (isNaN(x) || isInfinity(x)) 142 return x; 143 144 double y = floorImpl(x); 145 if (y < x) 146 y += 1.0; 147 148 return y; 149 } 150 } 151 152 @safe pure nothrow @nogc unittest 153 { 154 import std.math.traits : isNaN; 155 156 assert(ceil(+123.456) == +124); 157 assert(ceil(-123.456) == -123); 158 assert(ceil(-1.234) == -1); 159 assert(ceil(-0.123) == 0); 160 assert(ceil(0.0) == 0); 161 assert(ceil(+0.123) == 1); 162 assert(ceil(+1.234) == 2); 163 assert(ceil(double.infinity) == double.infinity); 164 assert(isNaN(ceil(double.nan))); 165 assert(isNaN(ceil(double.init))); 166 } 167 168 /// ditto 169 pragma(inline, true) // LDC 170 float ceil(float x) @trusted pure nothrow @nogc 171 { 172 version (LDC) 173 { 174 return llvm_ceil(x); 175 } 176 else 177 { 178 import std.math.traits : isInfinity, isNaN; 179 180 // Special cases. 181 if (isNaN(x) || isInfinity(x)) 182 return x; 183 184 float y = floorImpl(x); 185 if (y < x) 186 y += 1.0; 187 188 return y; 189 } 190 } 191 192 @safe pure nothrow @nogc unittest 193 { 194 import std.math.traits : isNaN; 195 196 assert(ceil(+123.456f) == +124); 197 assert(ceil(-123.456f) == -123); 198 assert(ceil(-1.234f) == -1); 199 assert(ceil(-0.123f) == 0); 200 assert(ceil(0.0f) == 0); 201 assert(ceil(+0.123f) == 1); 202 assert(ceil(+1.234f) == 2); 203 assert(ceil(float.infinity) == float.infinity); 204 assert(isNaN(ceil(float.nan))); 205 assert(isNaN(ceil(float.init))); 206 } 207 208 /************************************** 209 * Returns the value of x rounded downward to the next integer 210 * (toward negative infinity). 211 */ 212 pragma(inline, true) // LDC 213 real floor(real x) @trusted pure nothrow @nogc 214 { 215 version (LDC) 216 { 217 return llvm_floor(x); 218 } 219 else version (InlineAsm_X87_MSVC) 220 { 221 version (X86_64) 222 { 223 asm pure nothrow @nogc 224 { 225 naked ; 226 fld real ptr [RCX] ; 227 fstcw 8[RSP] ; 228 mov AL,9[RSP] ; 229 mov DL,AL ; 230 and AL,0xC3 ; 231 or AL,0x04 ; // round to -infinity 232 mov 9[RSP],AL ; 233 fldcw 8[RSP] ; 234 frndint ; 235 mov 9[RSP],DL ; 236 fldcw 8[RSP] ; 237 ret ; 238 } 239 } 240 else 241 { 242 short cw; 243 asm pure nothrow @nogc 244 { 245 fld x ; 246 fstcw cw ; 247 mov AL,byte ptr cw+1 ; 248 mov DL,AL ; 249 and AL,0xC3 ; 250 or AL,0x04 ; // round to -infinity 251 mov byte ptr cw+1,AL ; 252 fldcw cw ; 253 frndint ; 254 mov byte ptr cw+1,DL ; 255 fldcw cw ; 256 } 257 } 258 } 259 else 260 { 261 import std.math.traits : isInfinity, isNaN; 262 263 // Special cases. 264 if (isNaN(x) || isInfinity(x) || x == 0.0) 265 return x; 266 267 return floorImpl(x); 268 } 269 } 270 271 /// 272 @safe pure nothrow @nogc unittest 273 { 274 import std.math.traits : isNaN; 275 276 assert(floor(+123.456L) == +123); 277 assert(floor(-123.456L) == -124); 278 assert(floor(+123.0L) == +123); 279 assert(floor(-124.0L) == -124); 280 assert(floor(-1.234L) == -2); 281 assert(floor(-0.123L) == -1); 282 assert(floor(0.0L) == 0); 283 assert(floor(+0.123L) == 0); 284 assert(floor(+1.234L) == 1); 285 assert(floor(real.infinity) == real.infinity); 286 assert(isNaN(floor(real.nan))); 287 assert(isNaN(floor(real.init))); 288 } 289 290 /// ditto 291 pragma(inline, true) // LDC 292 double floor(double x) @trusted pure nothrow @nogc 293 { 294 version (LDC) 295 { 296 return llvm_floor(x); 297 } 298 else 299 { 300 import std.math.traits : isInfinity, isNaN; 301 302 // Special cases. 303 if (isNaN(x) || isInfinity(x) || x == 0.0) 304 return x; 305 306 return floorImpl(x); 307 } 308 } 309 310 @safe pure nothrow @nogc unittest 311 { 312 import std.math.traits : isNaN; 313 314 assert(floor(+123.456) == +123); 315 assert(floor(-123.456) == -124); 316 assert(floor(+123.0) == +123); 317 assert(floor(-124.0) == -124); 318 assert(floor(-1.234) == -2); 319 assert(floor(-0.123) == -1); 320 assert(floor(0.0) == 0); 321 assert(floor(+0.123) == 0); 322 assert(floor(+1.234) == 1); 323 assert(floor(double.infinity) == double.infinity); 324 assert(isNaN(floor(double.nan))); 325 assert(isNaN(floor(double.init))); 326 } 327 328 /// ditto 329 pragma(inline, true) // LDC 330 float floor(float x) @trusted pure nothrow @nogc 331 { 332 version (LDC) 333 { 334 return llvm_floor(x); 335 } 336 else 337 { 338 import std.math.traits : isInfinity, isNaN; 339 340 // Special cases. 341 if (isNaN(x) || isInfinity(x) || x == 0.0) 342 return x; 343 344 return floorImpl(x); 345 } 346 } 347 348 @safe pure nothrow @nogc unittest 349 { 350 import std.math.traits : isNaN; 351 352 assert(floor(+123.456f) == +123); 353 assert(floor(-123.456f) == -124); 354 assert(floor(+123.0f) == +123); 355 assert(floor(-124.0f) == -124); 356 assert(floor(-1.234f) == -2); 357 assert(floor(-0.123f) == -1); 358 assert(floor(0.0f) == 0); 359 assert(floor(+0.123f) == 0); 360 assert(floor(+1.234f) == 1); 361 assert(floor(float.infinity) == float.infinity); 362 assert(isNaN(floor(float.nan))); 363 assert(isNaN(floor(float.init))); 364 } 365 366 // https://issues.dlang.org/show_bug.cgi?id=6381 367 // floor/ceil should be usable in pure function. 368 @safe pure nothrow unittest 369 { 370 auto x = floor(1.2); 371 auto y = ceil(1.2); 372 } 373 374 /** 375 * Round `val` to a multiple of `unit`. `rfunc` specifies the rounding 376 * function to use; by default this is `rint`, which uses the current 377 * rounding mode. 378 */ 379 Unqual!F quantize(alias rfunc = rint, F)(const F val, const F unit) 380 if (is(typeof(rfunc(F.init)) : F) && isFloatingPoint!F) 381 { 382 import std.math.traits : isInfinity; 383 384 typeof(return) ret = val; 385 if (unit != 0) 386 { 387 const scaled = val / unit; 388 if (!scaled.isInfinity) 389 ret = rfunc(scaled) * unit; 390 } 391 return ret; 392 } 393 394 /// 395 @safe pure nothrow @nogc unittest 396 { 397 import std.math.operations : isClose; 398 399 assert(isClose(12345.6789L.quantize(0.01L), 12345.68L)); 400 assert(isClose(12345.6789L.quantize!floor(0.01L), 12345.67L)); 401 assert(isClose(12345.6789L.quantize(22.0L), 12342.0L)); 402 } 403 404 /// 405 @safe pure nothrow @nogc unittest 406 { 407 import std.math.operations : isClose; 408 import std.math.traits : isNaN; 409 410 assert(isClose(12345.6789L.quantize(0), 12345.6789L)); 411 assert(12345.6789L.quantize(real.infinity).isNaN); 412 assert(12345.6789L.quantize(real.nan).isNaN); 413 assert(real.infinity.quantize(0.01L) == real.infinity); 414 assert(real.infinity.quantize(real.nan).isNaN); 415 assert(real.nan.quantize(0.01L).isNaN); 416 assert(real.nan.quantize(real.infinity).isNaN); 417 assert(real.nan.quantize(real.nan).isNaN); 418 } 419 420 /** 421 * Round `val` to a multiple of `pow(base, exp)`. `rfunc` specifies the 422 * rounding function to use; by default this is `rint`, which uses the 423 * current rounding mode. 424 */ 425 Unqual!F quantize(real base, alias rfunc = rint, F, E)(const F val, const E exp) 426 if (is(typeof(rfunc(F.init)) : F) && isFloatingPoint!F && isIntegral!E) 427 { 428 import std.math.exponential : pow; 429 430 // TODO: Compile-time optimization for power-of-two bases? 431 return quantize!rfunc(val, pow(cast(F) base, exp)); 432 } 433 434 /// ditto 435 Unqual!F quantize(real base, long exp = 1, alias rfunc = rint, F)(const F val) 436 if (is(typeof(rfunc(F.init)) : F) && isFloatingPoint!F) 437 { 438 import std.math.exponential : pow; 439 440 enum unit = cast(F) pow(base, exp); 441 return quantize!rfunc(val, unit); 442 } 443 444 /// 445 @safe pure nothrow @nogc unittest 446 { 447 import std.math.operations : isClose; 448 449 assert(isClose(12345.6789L.quantize!10(-2), 12345.68L)); 450 assert(isClose(12345.6789L.quantize!(10, -2), 12345.68L)); 451 assert(isClose(12345.6789L.quantize!(10, floor)(-2), 12345.67L)); 452 assert(isClose(12345.6789L.quantize!(10, -2, floor), 12345.67L)); 453 454 assert(isClose(12345.6789L.quantize!22(1), 12342.0L)); 455 assert(isClose(12345.6789L.quantize!22, 12342.0L)); 456 } 457 458 @safe pure nothrow @nogc unittest 459 { 460 import std.math.exponential : log10, pow; 461 import std.math.operations : isClose; 462 import std.meta : AliasSeq; 463 464 static foreach (F; AliasSeq!(real, double, float)) 465 {{ 466 const maxL10 = cast(int) F.max.log10.floor; 467 const maxR10 = pow(cast(F) 10, maxL10); 468 assert(isClose((cast(F) 0.9L * maxR10).quantize!10(maxL10), maxR10)); 469 assert(isClose((cast(F)-0.9L * maxR10).quantize!10(maxL10), -maxR10)); 470 471 assert(F.max.quantize(F.min_normal) == F.max); 472 assert((-F.max).quantize(F.min_normal) == -F.max); 473 assert(F.min_normal.quantize(F.max) == 0); 474 assert((-F.min_normal).quantize(F.max) == 0); 475 assert(F.min_normal.quantize(F.min_normal) == F.min_normal); 476 assert((-F.min_normal).quantize(F.min_normal) == -F.min_normal); 477 }} 478 } 479 480 /****************************************** 481 * Rounds x to the nearest integer value, using the current rounding 482 * mode. 483 * 484 * Unlike the rint functions, nearbyint does not raise the 485 * FE_INEXACT exception. 486 */ 487 version (LDC) 488 { 489 pragma(inline, true): 490 real nearbyint(real x) @safe pure nothrow @nogc { return llvm_nearbyint(x); } 491 //double nearbyint(double x) @safe pure nothrow @nogc { return llvm_nearbyint(x); } 492 //float nearbyint(float x) @safe pure nothrow @nogc { return llvm_nearbyint(x); } 493 } 494 else 495 { 496 497 pragma(inline, true) 498 real nearbyint(real x) @safe pure nothrow @nogc 499 { 500 return core.stdc.math.nearbyintl(x); 501 } 502 503 } // !LDC 504 505 /// 506 @safe pure unittest 507 { 508 import std.math.traits : isNaN; 509 510 assert(nearbyint(0.4) == 0); 511 assert(nearbyint(0.5) == 0); 512 assert(nearbyint(0.6) == 1); 513 assert(nearbyint(100.0) == 100); 514 515 assert(isNaN(nearbyint(real.nan))); 516 assert(nearbyint(real.infinity) == real.infinity); 517 assert(nearbyint(-real.infinity) == -real.infinity); 518 } 519 520 /********************************** 521 * Rounds x to the nearest integer value, using the current rounding 522 * mode. 523 * 524 * If the return value is not equal to x, the FE_INEXACT 525 * exception is raised. 526 * 527 * $(LREF nearbyint) performs the same operation, but does 528 * not set the FE_INEXACT exception. 529 */ 530 pragma(inline, true) 531 real rint(real x) @safe pure nothrow @nogc 532 { 533 return core.math.rint(x); 534 } 535 ///ditto 536 pragma(inline, true) 537 double rint(double x) @safe pure nothrow @nogc 538 { 539 return core.math.rint(x); 540 } 541 ///ditto 542 pragma(inline, true) 543 float rint(float x) @safe pure nothrow @nogc 544 { 545 return core.math.rint(x); 546 } 547 548 /// 549 @safe unittest 550 { 551 import std.math.traits : isNaN; 552 553 version (IeeeFlagsSupport) resetIeeeFlags(); 554 assert(rint(0.4) == 0); 555 version (LDC) { /* inexact bit not set with enabled optimizations */ } else 556 version (IeeeFlagsSupport) assert(ieeeFlags.inexact); 557 558 assert(rint(0.5) == 0); 559 assert(rint(0.6) == 1); 560 assert(rint(100.0) == 100); 561 562 assert(isNaN(rint(real.nan))); 563 assert(rint(real.infinity) == real.infinity); 564 assert(rint(-real.infinity) == -real.infinity); 565 } 566 567 @safe unittest 568 { 569 real function(real) print = &rint; 570 assert(print != null); 571 } 572 573 /*************************************** 574 * Rounds x to the nearest integer value, using the current rounding 575 * mode. 576 * 577 * This is generally the fastest method to convert a floating-point number 578 * to an integer. Note that the results from this function 579 * depend on the rounding mode, if the fractional part of x is exactly 0.5. 580 * If using the default rounding mode (ties round to even integers) 581 * lrint(4.5) == 4, lrint(5.5)==6. 582 */ 583 long lrint(real x) @trusted pure nothrow @nogc 584 { 585 version (InlineAsm_X87) 586 { 587 version (Win64) 588 { 589 asm pure nothrow @nogc 590 { 591 naked; 592 fld real ptr [RCX]; 593 fistp qword ptr 8[RSP]; 594 mov RAX,8[RSP]; 595 ret; 596 } 597 } 598 else 599 { 600 long n; 601 asm pure nothrow @nogc 602 { 603 fld x; 604 fistp n; 605 } 606 return n; 607 } 608 } 609 else 610 { 611 import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB; 612 613 alias F = floatTraits!(real); 614 static if (F.realFormat == RealFormat.ieeeDouble) 615 { 616 long result; 617 618 // Rounding limit when casting from real(double) to ulong. 619 enum real OF = 4.50359962737049600000E15L; 620 621 uint* vi = cast(uint*)(&x); 622 623 // Find the exponent and sign 624 uint msb = vi[MANTISSA_MSB]; 625 uint lsb = vi[MANTISSA_LSB]; 626 int exp = ((msb >> 20) & 0x7ff) - 0x3ff; 627 const int sign = msb >> 31; 628 msb &= 0xfffff; 629 msb |= 0x100000; 630 631 if (exp < 63) 632 { 633 if (exp >= 52) 634 result = (cast(long) msb << (exp - 20)) | (lsb << (exp - 52)); 635 else 636 { 637 // Adjust x and check result. 638 const real j = sign ? -OF : OF; 639 x = (j + x) - j; 640 msb = vi[MANTISSA_MSB]; 641 lsb = vi[MANTISSA_LSB]; 642 exp = ((msb >> 20) & 0x7ff) - 0x3ff; 643 msb &= 0xfffff; 644 msb |= 0x100000; 645 646 if (exp < 0) 647 result = 0; 648 else if (exp < 20) 649 result = cast(long) msb >> (20 - exp); 650 else if (exp == 20) 651 result = cast(long) msb; 652 else 653 result = (cast(long) msb << (exp - 20)) | (lsb >> (52 - exp)); 654 } 655 } 656 else 657 { 658 // It is left implementation defined when the number is too large. 659 return cast(long) x; 660 } 661 662 return sign ? -result : result; 663 } 664 else static if (F.realFormat == RealFormat.ieeeExtended || 665 F.realFormat == RealFormat.ieeeExtended53) 666 { 667 long result; 668 669 // Rounding limit when casting from real(80-bit) to ulong. 670 static if (F.realFormat == RealFormat.ieeeExtended) 671 enum real OF = 9.22337203685477580800E18L; 672 else 673 enum real OF = 4.50359962737049600000E15L; 674 675 ushort* vu = cast(ushort*)(&x); 676 uint* vi = cast(uint*)(&x); 677 678 // Find the exponent and sign 679 int exp = (vu[F.EXPPOS_SHORT] & 0x7fff) - 0x3fff; 680 const int sign = (vu[F.EXPPOS_SHORT] >> 15) & 1; 681 682 if (exp < 63) 683 { 684 // Adjust x and check result. 685 const real j = sign ? -OF : OF; 686 x = (j + x) - j; 687 exp = (vu[F.EXPPOS_SHORT] & 0x7fff) - 0x3fff; 688 689 version (LittleEndian) 690 { 691 if (exp < 0) 692 result = 0; 693 else if (exp <= 31) 694 result = vi[1] >> (31 - exp); 695 else 696 result = (cast(long) vi[1] << (exp - 31)) | (vi[0] >> (63 - exp)); 697 } 698 else 699 { 700 if (exp < 0) 701 result = 0; 702 else if (exp <= 31) 703 result = vi[1] >> (31 - exp); 704 else 705 result = (cast(long) vi[1] << (exp - 31)) | (vi[2] >> (63 - exp)); 706 } 707 } 708 else 709 { 710 // It is left implementation defined when the number is too large 711 // to fit in a 64bit long. 712 return cast(long) x; 713 } 714 715 return sign ? -result : result; 716 } 717 else static if (F.realFormat == RealFormat.ieeeQuadruple) 718 { 719 const vu = cast(ushort*)(&x); 720 721 // Find the exponent and sign 722 const sign = (vu[F.EXPPOS_SHORT] >> 15) & 1; 723 if ((vu[F.EXPPOS_SHORT] & F.EXPMASK) - (F.EXPBIAS + 1) > 63) 724 { 725 // The result is left implementation defined when the number is 726 // too large to fit in a 64 bit long. 727 return cast(long) x; 728 } 729 730 // Force rounding of lower bits according to current rounding 731 // mode by adding ±2^-112 and subtracting it again. 732 enum OF = 5.19229685853482762853049632922009600E33L; 733 const j = sign ? -OF : OF; 734 x = (j + x) - j; 735 736 const exp = (vu[F.EXPPOS_SHORT] & F.EXPMASK) - (F.EXPBIAS + 1); 737 const implicitOne = 1UL << 48; 738 auto vl = cast(ulong*)(&x); 739 vl[MANTISSA_MSB] &= implicitOne - 1; 740 vl[MANTISSA_MSB] |= implicitOne; 741 742 long result; 743 744 if (exp < 0) 745 result = 0; 746 else if (exp <= 48) 747 result = vl[MANTISSA_MSB] >> (48 - exp); 748 else 749 result = (vl[MANTISSA_MSB] << (exp - 48)) | (vl[MANTISSA_LSB] >> (112 - exp)); 750 751 return sign ? -result : result; 752 } 753 else 754 { 755 static assert(false, "real type not supported by lrint()"); 756 } 757 } 758 } 759 760 /// 761 @safe pure nothrow @nogc unittest 762 { 763 assert(lrint(4.5) == 4); 764 assert(lrint(5.5) == 6); 765 assert(lrint(-4.5) == -4); 766 assert(lrint(-5.5) == -6); 767 768 assert(lrint(int.max - 0.5) == 2147483646L); 769 assert(lrint(int.max + 0.5) == 2147483648L); 770 assert(lrint(int.min - 0.5) == -2147483648L); 771 assert(lrint(int.min + 0.5) == -2147483648L); 772 } 773 774 static if (real.mant_dig >= long.sizeof * 8) 775 { 776 @safe pure nothrow @nogc unittest 777 { 778 assert(lrint(long.max - 1.5L) == long.max - 1); 779 assert(lrint(long.max - 0.5L) == long.max - 1); 780 assert(lrint(long.min + 0.5L) == long.min); 781 assert(lrint(long.min + 1.5L) == long.min + 2); 782 } 783 } 784 785 /******************************************* 786 * Return the value of x rounded to the nearest integer. 787 * If the fractional part of x is exactly 0.5, the return value is 788 * rounded away from zero. 789 * 790 * Returns: 791 * A `real`. 792 */ 793 version (LDC) 794 { 795 pragma(inline, true): 796 real round(real x) @safe pure nothrow @nogc { return llvm_round(x); } 797 //double round(double x) @safe pure nothrow @nogc { return llvm_round(x); } 798 //float round(float x) @safe pure nothrow @nogc { return llvm_round(x); } 799 } 800 else 801 { 802 803 auto round(real x) @trusted nothrow @nogc 804 { 805 version (CRuntime_Microsoft) 806 { 807 import std.math.hardware : FloatingPointControl; 808 809 auto old = FloatingPointControl.getControlState(); 810 FloatingPointControl.setControlState( 811 (old & (-1 - FloatingPointControl.roundingMask)) | FloatingPointControl.roundToZero 812 ); 813 x = core.math.rint((x >= 0) ? x + 0.5 : x - 0.5); 814 FloatingPointControl.setControlState(old); 815 return x; 816 } 817 else 818 { 819 return core.stdc.math.roundl(x); 820 } 821 } 822 823 } // !LDC 824 825 /// 826 @safe nothrow @nogc unittest 827 { 828 assert(round(4.5) == 5); 829 assert(round(5.4) == 5); 830 assert(round(-4.5) == -5); 831 assert(round(-5.1) == -5); 832 } 833 834 // assure purity on Posix 835 version (Posix) 836 { 837 @safe pure nothrow @nogc unittest 838 { 839 assert(round(4.5) == 5); 840 } 841 } 842 843 /********************************************** 844 * Return the value of x rounded to the nearest integer. 845 * 846 * If the fractional part of x is exactly 0.5, the return value is rounded 847 * away from zero. 848 * 849 * $(BLUE This function is not implemented for Digital Mars C runtime.) 850 */ 851 long lround(real x) @trusted nothrow @nogc 852 { 853 version (CRuntime_DigitalMars) 854 assert(0, "lround not implemented"); 855 else 856 return core.stdc.math.llroundl(x); 857 } 858 859 /// 860 @safe nothrow @nogc unittest 861 { 862 version (CRuntime_DigitalMars) {} 863 else 864 { 865 assert(lround(0.49) == 0); 866 assert(lround(0.5) == 1); 867 assert(lround(1.5) == 2); 868 } 869 } 870 871 /** 872 Returns the integer portion of x, dropping the fractional portion. 873 This is also known as "chop" rounding. 874 `pure` on all platforms. 875 */ 876 version (LDC) 877 { 878 pragma(inline, true): 879 real trunc(real x) @safe pure nothrow @nogc { return llvm_trunc(x); } 880 //double trunc(double x) @safe pure nothrow @nogc { return llvm_trunc(x); } 881 //float trunc(float x) @safe pure nothrow @nogc { return llvm_trunc(x); } 882 } 883 else 884 { 885 886 real trunc(real x) @trusted nothrow @nogc pure 887 { 888 version (InlineAsm_X87_MSVC) 889 { 890 version (X86_64) 891 { 892 asm pure nothrow @nogc 893 { 894 naked ; 895 fld real ptr [RCX] ; 896 fstcw 8[RSP] ; 897 mov AL,9[RSP] ; 898 mov DL,AL ; 899 and AL,0xC3 ; 900 or AL,0x0C ; // round to 0 901 mov 9[RSP],AL ; 902 fldcw 8[RSP] ; 903 frndint ; 904 mov 9[RSP],DL ; 905 fldcw 8[RSP] ; 906 ret ; 907 } 908 } 909 else 910 { 911 short cw; 912 asm pure nothrow @nogc 913 { 914 fld x ; 915 fstcw cw ; 916 mov AL,byte ptr cw+1 ; 917 mov DL,AL ; 918 and AL,0xC3 ; 919 or AL,0x0C ; // round to 0 920 mov byte ptr cw+1,AL ; 921 fldcw cw ; 922 frndint ; 923 mov byte ptr cw+1,DL ; 924 fldcw cw ; 925 } 926 } 927 } 928 else 929 { 930 return core.stdc.math.truncl(x); 931 } 932 } 933 934 } // !LDC 935 936 /// 937 @safe pure unittest 938 { 939 assert(trunc(0.01) == 0); 940 assert(trunc(0.49) == 0); 941 assert(trunc(0.5) == 0); 942 assert(trunc(1.5) == 1); 943 } 944 945 /***************************************** 946 * Returns x rounded to a long value using the current rounding mode. 947 * If the integer value of x is 948 * greater than long.max, the result is 949 * indeterminate. 950 */ 951 pragma(inline, true) 952 long rndtol(real x) @nogc @safe pure nothrow { return core.math.rndtol(x); } 953 //FIXME 954 ///ditto 955 pragma(inline, true) 956 long rndtol(double x) @safe pure nothrow @nogc { return rndtol(cast(real) x); } 957 //FIXME 958 ///ditto 959 pragma(inline, true) 960 long rndtol(float x) @safe pure nothrow @nogc { return rndtol(cast(real) x); } 961 962 /// 963 @safe unittest 964 { 965 assert(rndtol(1.0) == 1L); 966 assert(rndtol(1.2) == 1L); 967 assert(rndtol(1.7) == 2L); 968 assert(rndtol(1.0001) == 1L); 969 } 970 971 @safe unittest 972 { 973 long function(real) prndtol = &rndtol; 974 assert(prndtol != null); 975 } 976 977 // Helper for floor/ceil 978 T floorImpl(T)(const T x) @trusted pure nothrow @nogc 979 { 980 import std.math : floatTraits, RealFormat; 981 982 alias F = floatTraits!(T); 983 // Take care not to trigger library calls from the compiler, 984 // while ensuring that we don't get defeated by some optimizers. 985 union floatBits 986 { 987 T rv; 988 ushort[T.sizeof/2] vu; 989 990 // Other kinds of extractors for real formats. 991 static if (F.realFormat == RealFormat.ieeeSingle) 992 uint vi; 993 else static if (F.realFormat == RealFormat.ieeeDouble) 994 ulong vi; 995 } 996 floatBits y = void; 997 y.rv = x; 998 999 // Find the exponent (power of 2) 1000 // Do this by shifting the raw value so that the exponent lies in the low bits, 1001 // then mask out the sign bit, and subtract the bias. 1002 static if (F.realFormat == RealFormat.ieeeSingle) 1003 { 1004 int exp = ((y.vi >> (T.mant_dig - 1)) & 0xff) - 0x7f; 1005 enum mantissa_mask = F.MANTISSAMASK_INT; 1006 enum sign_shift = 31; 1007 } 1008 else static if (F.realFormat == RealFormat.ieeeDouble) 1009 { 1010 long exp = ((y.vi >> (T.mant_dig - 1)) & 0x7ff) - 0x3ff; 1011 enum mantissa_mask = F.MANTISSAMASK_LONG; 1012 enum sign_shift = 63; 1013 } 1014 else static if (F.realFormat == RealFormat.ieeeExtended || 1015 F.realFormat == RealFormat.ieeeExtended53) 1016 { 1017 int exp = (y.vu[F.EXPPOS_SHORT] & 0x7fff) - 0x3fff; 1018 1019 version (LittleEndian) 1020 int pos = 0; 1021 else 1022 int pos = 4; 1023 } 1024 else static if (F.realFormat == RealFormat.ieeeQuadruple) 1025 { 1026 int exp = (y.vu[F.EXPPOS_SHORT] & 0x7fff) - 0x3fff; 1027 1028 version (LittleEndian) 1029 int pos = 0; 1030 else 1031 int pos = 7; 1032 } 1033 else 1034 static assert(false, "Not implemented for this architecture"); 1035 1036 if (exp < 0) 1037 { 1038 if (x < 0.0) 1039 return -1.0; 1040 else 1041 return 0.0; 1042 } 1043 1044 static if (F.realFormat == RealFormat.ieeeSingle || 1045 F.realFormat == RealFormat.ieeeDouble) 1046 { 1047 if (exp < (T.mant_dig - 1)) 1048 { 1049 // Clear all bits representing the fraction part. 1050 // Note: the fraction mask represents the floating point number 0.999999... 1051 // i.e: `2.0 ^^ (exp - T.mant_dig + 1) * (fraction_mask + 1) == 1.0` 1052 const fraction_mask = mantissa_mask >> exp; 1053 1054 if ((y.vi & fraction_mask) != 0) 1055 { 1056 // If 'x' is negative, then first substract (1.0 - T.epsilon) from the value. 1057 if (y.vi >> sign_shift) 1058 y.vi += fraction_mask; 1059 y.vi &= ~fraction_mask; 1060 } 1061 } 1062 } 1063 else 1064 { 1065 static if (F.realFormat == RealFormat.ieeeExtended53) 1066 exp = (T.mant_dig + 11 - 1) - exp; // mant_dig is really 64 1067 else 1068 exp = (T.mant_dig - 1) - exp; 1069 1070 // Zero 16 bits at a time. 1071 while (exp >= 16) 1072 { 1073 version (LittleEndian) 1074 y.vu[pos++] = 0; 1075 else 1076 y.vu[pos--] = 0; 1077 exp -= 16; 1078 } 1079 1080 // Clear the remaining bits. 1081 if (exp > 0) 1082 y.vu[pos] &= 0xffff ^ ((1 << exp) - 1); 1083 1084 if ((x < 0.0) && (x != y.rv)) 1085 y.rv -= 1.0; 1086 } 1087 1088 return y.rv; 1089 }