The OpenD Programming Language

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 }