1 // Compiler implementation of the D programming language
2 // Copyright (c) 1999-2016 by Digital Mars
3 // All Rights Reserved
4 // written by Walter Bright
5 // http://www.digitalmars.com
6 // Distributed under the Boost Software License, Version 1.0.
7 // http://www.boost.org/LICENSE_1_0.txt
8 
9 module ddmd.root.ctfloat;
10 
11 static import core.math, core.stdc.math;
12 import core.stdc.errno;
13 import core.stdc.stdio;
14 import core.stdc.stdlib;
15 import core.stdc..string;
16 
17 // Type used by the front-end for compile-time reals
18 alias real_t = real;
19 
20 private
21 {
22     version(CRuntime_DigitalMars) __gshared extern (C) extern const(char)* __locale_decpoint;
23 
24     version(CRuntime_Microsoft) extern (C++)
25     {
26         struct longdouble { real_t r; }
27         size_t ld_sprint(char* str, int fmt, longdouble x);
28         longdouble strtold_dm(const(char)* p, char** endp);
29     }
30 }
31 
32 // Compile-time floating-point helper
33 extern (C++) struct CTFloat
34 {
35     version(DigitalMars)
36     {
37         static __gshared bool yl2x_supported = true;
38         static __gshared bool yl2xp1_supported = true;
39     }
40     else
41     {
42         static __gshared bool yl2x_supported = false;
43         static __gshared bool yl2xp1_supported = false;
44     }
45 
46     static void yl2x(const real_t* x, const real_t* y, real_t* res)
47     {
48         version(DigitalMars)
49             *res = core.math.yl2x(*x, *y);
50         else
51             assert(0);
52     }
53 
54     static void yl2xp1(const real_t* x, const real_t* y, real_t* res)
55     {
56         version(DigitalMars)
57             *res = core.math.yl2xp1(*x, *y);
58         else
59             assert(0);
60     }
61 
62     static real_t sin(real_t x) { return core.math.sin(x); }
63     static real_t cos(real_t x) { return core.math.cos(x); }
64     static real_t tan(real_t x) { return core.stdc.math.tanl(x); }
65     static real_t sqrt(real_t x) { return core.math.sqrt(x); }
66     static real_t fabs(real_t x) { return core.math.fabs(x); }
67 
68     static bool isIdentical(real_t a, real_t b)
69     {
70         // don't compare pad bytes in extended precision
71         enum sz = (real_t.mant_dig == 64) ? 10 : real_t.sizeof;
72         return memcmp(&a, &b, sz) == 0;
73     }
74 
75     static bool isNaN(real_t r)
76     {
77         return !(r == r);
78     }
79 
80     static bool isSNaN(real_t r)
81     {
82         return isNaN(r) && !(((cast(ubyte*)&r)[7]) & 0x40);
83     }
84 
85     // the implementation of longdouble for MSVC is a struct, so mangling
86     //  doesn't match with the C++ header.
87     // add a wrapper just for isSNaN as this is the only function called from C++
88     version(CRuntime_Microsoft)
89         static bool isSNaN(longdouble ld)
90         {
91             return isSNaN(ld.r);
92         }
93 
94     static bool isInfinity(real_t r)
95     {
96         return r is real_t.infinity || r is -real_t.infinity;
97     }
98 
99     static real_t parse(const(char)* literal, bool* isOutOfRange = null)
100     {
101         errno = 0;
102         version(CRuntime_DigitalMars)
103         {
104             auto save = __locale_decpoint;
105             __locale_decpoint = ".";
106         }
107         version(CRuntime_Microsoft)
108             auto r = strtold_dm(literal, null).r;
109         else
110             auto r = strtold(literal, null);
111         version(CRuntime_DigitalMars) __locale_decpoint = save;
112         if (isOutOfRange)
113             *isOutOfRange = (errno == ERANGE);
114         return r;
115     }
116 
117     static int sprint(char* str, char fmt, real_t x)
118     {
119         version(CRuntime_Microsoft)
120         {
121             return cast(int)ld_sprint(str, fmt, longdouble(x));
122         }
123         else
124         {
125             if (real_t(cast(ulong)x) == x)
126             {
127                 // ((1.5 -> 1 -> 1.0) == 1.5) is false
128                 // ((1.0 -> 1 -> 1.0) == 1.0) is true
129                 // see http://en.cppreference.com/w/cpp/io/c/fprintf
130                 char[5] sfmt = "%#Lg\0";
131                 sfmt[3] = fmt;
132                 return sprintf(str, sfmt.ptr, x);
133             }
134             else
135             {
136                 char[4] sfmt = "%Lg\0";
137                 sfmt[2] = fmt;
138                 return sprintf(str, sfmt.ptr, x);
139             }
140         }
141     }
142 
143     // Constant real values 0, 1, -1 and 0.5.
144     static __gshared real_t zero = real_t(0);
145     static __gshared real_t one = real_t(1);
146     static __gshared real_t minusone = real_t(-1);
147     static __gshared real_t half = real_t(0.5);
148 }