1 // Written in the D programming language.
2 
3 /**
4  * Builtin mathematical intrinsics
5  *
6  * Source: $(DRUNTIMESRC core/_math.d)
7  * Macros:
8  *      TABLE_SV = <table border="1" cellpadding="4" cellspacing="0">
9  *              <caption>Special Values</caption>
10  *              $0</table>
11  *
12  *      NAN = $(RED NAN)
13  *      SUP = <span style="vertical-align:super;font-size:smaller">$0</span>
14  *      POWER = $1<sup>$2</sup>
15  *      PLUSMN = &plusmn;
16  *      INFIN = &infin;
17  *      PLUSMNINF = &plusmn;&infin;
18  *      LT = &lt;
19  *      GT = &gt;
20  *
21  * Copyright: Copyright Digital Mars 2000 - 2011.
22  * License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
23  * Authors:   $(HTTP digitalmars.com, Walter Bright),
24  *                        Don Clugston
25  */
26 module core.math;
27 
28 public:
29 @nogc:
30 nothrow:
31 @safe:
32 
33 /*****************************************
34  * Returns x rounded to a long value using the FE_TONEAREST rounding mode.
35  * If the integer value of x is
36  * greater than long.max, the result is
37  * indeterminate.
38  */
39 deprecated("rndtonl is to be removed by 2.100. Please use round instead")
40 extern (C) real rndtonl(real x);
41 
42 pure:
43 /***********************************
44  * Returns cosine of x. x is in radians.
45  *
46  *      $(TABLE_SV
47  *      $(TR $(TH x)                 $(TH cos(x)) $(TH invalid?))
48  *      $(TR $(TD $(NAN))            $(TD $(NAN)) $(TD yes)     )
49  *      $(TR $(TD $(PLUSMN)$(INFIN)) $(TD $(NAN)) $(TD yes)     )
50  *      )
51  * Bugs:
52  *      Results are undefined if |x| >= $(POWER 2,64).
53  */
54 
55 float cos(float x);     /* intrinsic */
56 double cos(double x);   /* intrinsic */ /// ditto
57 real cos(real x);       /* intrinsic */ /// ditto
58 
59 /***********************************
60  * Returns sine of x. x is in radians.
61  *
62  *      $(TABLE_SV
63  *      $(TR $(TH x)               $(TH sin(x))      $(TH invalid?))
64  *      $(TR $(TD $(NAN))          $(TD $(NAN))      $(TD yes))
65  *      $(TR $(TD $(PLUSMN)0.0)    $(TD $(PLUSMN)0.0) $(TD no))
66  *      $(TR $(TD $(PLUSMNINF))    $(TD $(NAN))      $(TD yes))
67  *      )
68  * Bugs:
69  *      Results are undefined if |x| >= $(POWER 2,64).
70  */
71 
72 float sin(float x);     /* intrinsic */
73 double sin(double x);   /* intrinsic */ /// ditto
74 real sin(real x);       /* intrinsic */ /// ditto
75 
76 /*****************************************
77  * Returns x rounded to a long value using the current rounding mode.
78  * If the integer value of x is
79  * greater than long.max, the result is
80  * indeterminate.
81  */
82 
83 long rndtol(float x);   /* intrinsic */
84 long rndtol(double x);  /* intrinsic */ /// ditto
85 long rndtol(real x);    /* intrinsic */ /// ditto
86 
87 /***************************************
88  * Compute square root of x.
89  *
90  *      $(TABLE_SV
91  *      $(TR $(TH x)         $(TH sqrt(x))   $(TH invalid?))
92  *      $(TR $(TD -0.0)      $(TD -0.0)      $(TD no))
93  *      $(TR $(TD $(LT)0.0)  $(TD $(NAN))    $(TD yes))
94  *      $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no))
95  *      )
96  */
97 
98 float sqrt(float x);    /* intrinsic */
99 double sqrt(double x);  /* intrinsic */ /// ditto
100 real sqrt(real x);      /* intrinsic */ /// ditto
101 
102 /*******************************************
103  * Compute n * 2$(SUPERSCRIPT exp)
104  * References: frexp
105  */
106 
107 float ldexp(float n, int exp);   /* intrinsic */
108 double ldexp(double n, int exp); /* intrinsic */ /// ditto
109 real ldexp(real n, int exp);     /* intrinsic */ /// ditto
110 
111 unittest {
112     static if (real.mant_dig == 113)
113     {
114         assert(ldexp(1.0L, -16384) == 0x1p-16384L);
115         assert(ldexp(1.0L, -16382) == 0x1p-16382L);
116     }
117     else static if (real.mant_dig == 106)
118     {
119         assert(ldexp(1.0L,  1023) == 0x1p1023L);
120         assert(ldexp(1.0L, -1022) == 0x1p-1022L);
121         assert(ldexp(1.0L, -1021) == 0x1p-1021L);
122     }
123     else static if (real.mant_dig == 64)
124     {
125         assert(ldexp(1.0L, -16384) == 0x1p-16384L);
126         assert(ldexp(1.0L, -16382) == 0x1p-16382L);
127     }
128     else static if (real.mant_dig == 53)
129     {
130         assert(ldexp(1.0L,  1023) == 0x1p1023L);
131         assert(ldexp(1.0L, -1022) == 0x1p-1022L);
132         assert(ldexp(1.0L, -1021) == 0x1p-1021L);
133     }
134     else
135         assert(false, "Only 128bit, 80bit and 64bit reals expected here");
136 }
137 
138 /*******************************
139  * Compute the absolute value.
140  *      $(TABLE_SV
141  *      $(TR $(TH x)                 $(TH fabs(x)))
142  *      $(TR $(TD $(PLUSMN)0.0)      $(TD +0.0) )
143  *      $(TR $(TD $(PLUSMN)$(INFIN)) $(TD +$(INFIN)) )
144  *      )
145  * It is implemented as a compiler intrinsic.
146  * Params:
147  *      x = floating point value
148  * Returns: |x|
149  * References: equivalent to `std.math.fabs`
150  */
151 @safe pure nothrow @nogc
152 {
153     float  fabs(float  x);
154     double fabs(double x); /// ditto
155     real   fabs(real   x); /// ditto
156 }
157 
158 /**********************************
159  * Rounds x to the nearest integer value, using the current rounding
160  * mode.
161  * If the return value is not equal to x, the FE_INEXACT
162  * exception is raised.
163  * $(B nearbyint) performs
164  * the same operation, but does not set the FE_INEXACT exception.
165  */
166 float rint(float x);    /* intrinsic */
167 double rint(double x);  /* intrinsic */ /// ditto
168 real rint(real x);      /* intrinsic */ /// ditto
169 
170 /***********************************
171  * Building block functions, they
172  * translate to a single x87 instruction.
173  */
174 // y * log2(x)
175 float yl2x(float x, float y);    /* intrinsic */
176 double yl2x(double x, double y);  /* intrinsic */ /// ditto
177 real yl2x(real x, real y);      /* intrinsic */ /// ditto
178 // y * log2(x +1)
179 float yl2xp1(float x, float y);    /* intrinsic */
180 double yl2xp1(double x, double y);  /* intrinsic */ /// ditto
181 real yl2xp1(real x, real y);      /* intrinsic */ /// ditto
182 
183 unittest
184 {
185     version (INLINE_YL2X)
186     {
187         assert(yl2x(1024.0L, 1) == 10);
188         assert(yl2xp1(1023.0L, 1) == 10);
189     }
190 }
191 
192 /*************************************
193  * Round argument to a specific precision.
194  *
195  * D language types specify only a minimum precision, not a maximum. The
196  * `toPrec()` function forces rounding of the argument `f` to the precision
197  * of the specified floating point type `T`.
198  * The rounding mode used is inevitably target-dependent, but will be done in
199  * a way to maximize accuracy. In most cases, the default is round-to-nearest.
200  *
201  * Params:
202  *      T = precision type to round to
203  *      f = value to convert
204  * Returns:
205  *      f in precision of type `T`
206  */
207 T toPrec(T:float)(float f) { pragma(inline, false); return f; }
208 /// ditto
209 T toPrec(T:float)(double f) { pragma(inline, false); return cast(T) f; }
210 /// ditto
211 T toPrec(T:float)(real f)  { pragma(inline, false); return cast(T) f; }
212 /// ditto
213 T toPrec(T:double)(float f) { pragma(inline, false); return f; }
214 /// ditto
215 T toPrec(T:double)(double f) { pragma(inline, false); return f; }
216 /// ditto
217 T toPrec(T:double)(real f)  { pragma(inline, false); return cast(T) f; }
218 /// ditto
219 T toPrec(T:real)(float f) { pragma(inline, false); return f; }
220 /// ditto
221 T toPrec(T:real)(double f) { pragma(inline, false); return f; }
222 /// ditto
223 T toPrec(T:real)(real f)  { pragma(inline, false); return f; }
224 
225 @safe unittest
226 {
227     // Test all instantiations work with all combinations of float.
228     float f = 1.1f;
229     double d = 1.1;
230     real r = 1.1L;
231     f = toPrec!float(f + f);
232     f = toPrec!float(d + d);
233     f = toPrec!float(r + r);
234     d = toPrec!double(f + f);
235     d = toPrec!double(d + d);
236     d = toPrec!double(r + r);
237     r = toPrec!real(f + f);
238     r = toPrec!real(d + d);
239     r = toPrec!real(r + r);
240 
241     // Comparison tests.
242     bool approxEqual(T)(T lhs, T rhs)
243     {
244         return fabs((lhs - rhs) / rhs) <= 1e-2 || fabs(lhs - rhs) <= 1e-5;
245     }
246 
247     enum real PIR = 0xc.90fdaa22168c235p-2;
248     enum double PID = 0x1.921fb54442d18p+1;
249     enum float PIF = 0x1.921fb6p+1;
250     static assert(approxEqual(toPrec!float(PIR), PIF));
251     static assert(approxEqual(toPrec!double(PIR), PID));
252     static assert(approxEqual(toPrec!real(PIR), PIR));
253     static assert(approxEqual(toPrec!float(PID), PIF));
254     static assert(approxEqual(toPrec!double(PID), PID));
255     static assert(approxEqual(toPrec!real(PID), PID));
256     static assert(approxEqual(toPrec!float(PIF), PIF));
257     static assert(approxEqual(toPrec!double(PIF), PIF));
258     static assert(approxEqual(toPrec!real(PIF), PIF));
259 
260     assert(approxEqual(toPrec!float(PIR), PIF));
261     assert(approxEqual(toPrec!double(PIR), PID));
262     assert(approxEqual(toPrec!real(PIR), PIR));
263     assert(approxEqual(toPrec!float(PID), PIF));
264     assert(approxEqual(toPrec!double(PID), PID));
265     assert(approxEqual(toPrec!real(PID), PID));
266     assert(approxEqual(toPrec!float(PIF), PIF));
267     assert(approxEqual(toPrec!double(PIF), PIF));
268     assert(approxEqual(toPrec!real(PIF), PIF));
269 }