-
-
Notifications
You must be signed in to change notification settings - Fork 606
/
ctfloat.d
218 lines (194 loc) · 7.72 KB
/
ctfloat.d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/***
* Compiler implementation of the
* $(LINK2 http://www.dlang.org, D programming language).
*
* Copyright: Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/ctfloat.d, root/_ctfloat.d)
* Documentation: https://dlang.org/phobos/dmd_root_ctfloat.html
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/ctfloat.d
*/
module dmd.root.ctfloat;
static import core.math, core.stdc.math;
import core.stdc.errno;
import core.stdc.stdio;
import core.stdc.stdlib;
import core.stdc.string;
nothrow:
// Type used by the front-end for compile-time reals
public import dmd.root.longdouble : real_t = longdouble;
private
{
version(CRuntime_DigitalMars) __gshared extern (C) extern const(char)* __locale_decpoint;
version(CRuntime_Microsoft) extern (C++)
{
public import dmd.root.longdouble : longdouble_soft, ld_sprint;
longdouble_soft strtold_dm(const(char)* p, char** endp);
}
}
// Compile-time floating-point helper
extern (C++) struct CTFloat
{
nothrow:
version (GNU)
enum yl2x_supported = false;
else
enum yl2x_supported = __traits(compiles, core.math.yl2x(1.0L, 2.0L));
enum yl2xp1_supported = yl2x_supported;
static void yl2x(const real_t* x, const real_t* y, real_t* res)
{
static if (yl2x_supported)
*res = core.math.yl2x(*x, *y);
else
assert(0);
}
static void yl2xp1(const real_t* x, const real_t* y, real_t* res)
{
static if (yl2xp1_supported)
*res = core.math.yl2xp1(*x, *y);
else
assert(0);
}
static if (!is(real_t == real))
{
alias sin = dmd.root.longdouble.sinl;
alias cos = dmd.root.longdouble.cosl;
alias tan = dmd.root.longdouble.tanl;
alias sqrt = dmd.root.longdouble.sqrtl;
alias fabs = dmd.root.longdouble.fabsl;
alias ldexp = dmd.root.longdouble.ldexpl;
}
else
{
static real_t sin(real_t x) { return core.math.sin(x); }
static real_t cos(real_t x) { return core.math.cos(x); }
static real_t tan(real_t x) { return core.stdc.math.tanl(x); }
static real_t sqrt(real_t x) { return core.math.sqrt(x); }
static real_t fabs(real_t x) { return core.math.fabs(x); }
static real_t ldexp(real_t n, int exp) { return core.math.ldexp(n, exp); }
}
static if (!is(real_t == real))
{
static real_t round(real_t x) { return real_t(cast(double)core.stdc.math.roundl(cast(double)x)); }
static real_t floor(real_t x) { return real_t(cast(double)core.stdc.math.floor(cast(double)x)); }
static real_t ceil(real_t x) { return real_t(cast(double)core.stdc.math.ceil(cast(double)x)); }
static real_t trunc(real_t x) { return real_t(cast(double)core.stdc.math.trunc(cast(double)x)); }
static real_t log(real_t x) { return real_t(cast(double)core.stdc.math.logl(cast(double)x)); }
static real_t log2(real_t x) { return real_t(cast(double)core.stdc.math.log2l(cast(double)x)); }
static real_t log10(real_t x) { return real_t(cast(double)core.stdc.math.log10l(cast(double)x)); }
static real_t pow(real_t x, real_t y) { return real_t(cast(double)core.stdc.math.powl(cast(double)x, cast(double)y)); }
static real_t exp(real_t x) { return real_t(cast(double)core.stdc.math.expl(cast(double)x)); }
static real_t expm1(real_t x) { return real_t(cast(double)core.stdc.math.expm1l(cast(double)x)); }
static real_t exp2(real_t x) { return real_t(cast(double)core.stdc.math.exp2l(cast(double)x)); }
static real_t copysign(real_t x, real_t s) { return real_t(cast(double)core.stdc.math.copysignl(cast(double)x, cast(double)s)); }
}
else
{
static real_t round(real_t x) { return core.stdc.math.roundl(x); }
static real_t floor(real_t x) { return core.stdc.math.floor(x); }
static real_t ceil(real_t x) { return core.stdc.math.ceil(x); }
static real_t trunc(real_t x) { return core.stdc.math.trunc(x); }
static real_t log(real_t x) { return core.stdc.math.logl(x); }
static real_t log2(real_t x) { return core.stdc.math.log2l(x); }
static real_t log10(real_t x) { return core.stdc.math.log10l(x); }
static real_t pow(real_t x, real_t y) { return core.stdc.math.powl(x, y); }
static real_t exp(real_t x) { return core.stdc.math.expl(x); }
static real_t expm1(real_t x) { return core.stdc.math.expm1l(x); }
static real_t exp2(real_t x) { return core.stdc.math.exp2l(x); }
static real_t copysign(real_t x, real_t s) { return core.stdc.math.copysignl(x, s); }
}
static real_t fmin(real_t x, real_t y) { return x < y ? x : y; }
static real_t fmax(real_t x, real_t y) { return x > y ? x : y; }
static real_t fma(real_t x, real_t y, real_t z) { return (x * y) + z; }
static bool isIdentical(real_t a, real_t b)
{
// don't compare pad bytes in extended precision
enum sz = (real_t.mant_dig == 64) ? 10 : real_t.sizeof;
return memcmp(&a, &b, sz) == 0;
}
static size_t hash(real_t a)
{
import dmd.root.hash : calcHash;
if (isNaN(a))
a = real_t.nan;
enum sz = (real_t.mant_dig == 64) ? 10 : real_t.sizeof;
return calcHash(cast(ubyte*) &a, sz);
}
static bool isNaN(real_t r)
{
return !(r == r);
}
static bool isSNaN(real_t r)
{
return isNaN(r) && !(((cast(ubyte*)&r)[7]) & 0x40);
}
// the implementation of longdouble for MSVC is a struct, so mangling
// doesn't match with the C++ header.
// add a wrapper just for isSNaN as this is the only function called from C++
version(CRuntime_Microsoft) static if (is(real_t == real))
static bool isSNaN(longdouble_soft ld)
{
return isSNaN(cast(real)ld);
}
static bool isInfinity(real_t r)
{
return isIdentical(fabs(r), real_t.infinity);
}
static real_t parse(const(char)* literal, bool* isOutOfRange = null)
{
errno = 0;
version(CRuntime_DigitalMars)
{
auto save = __locale_decpoint;
__locale_decpoint = ".";
}
version(CRuntime_Microsoft)
{
auto r = cast(real_t) strtold_dm(literal, null);
}
else
auto r = strtold(literal, null);
version(CRuntime_DigitalMars) __locale_decpoint = save;
if (isOutOfRange)
*isOutOfRange = (errno == ERANGE);
return r;
}
static int sprint(char* str, char fmt, real_t x)
{
version(CRuntime_Microsoft)
{
return cast(int)ld_sprint(str, fmt, longdouble_soft(x));
}
else
{
if (real_t(cast(ulong)x) == x)
{
// ((1.5 -> 1 -> 1.0) == 1.5) is false
// ((1.0 -> 1 -> 1.0) == 1.0) is true
// see http://en.cppreference.com/w/cpp/io/c/fprintf
char[5] sfmt = "%#Lg\0";
sfmt[3] = fmt;
return sprintf(str, sfmt.ptr, x);
}
else
{
char[4] sfmt = "%Lg\0";
sfmt[2] = fmt;
return sprintf(str, sfmt.ptr, x);
}
}
}
// Constant real values 0, 1, -1 and 0.5.
__gshared real_t zero;
__gshared real_t one;
__gshared real_t minusone;
__gshared real_t half;
static void initialize()
{
zero = real_t(0);
one = real_t(1);
minusone = real_t(-1);
half = real_t(0.5);
}
}