1 /*
2 This file is part of GNU APL, a free implementation of the
3 ISO/IEC Standard 13751, "Programming Language APL, Extended"
4
5 Copyright (C) 2008-2017 Dr. Jürgen Sauermann
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 /*
22 This file is an example of how to define a
23
24 'class APL_Float'
25
26 that can be used instead of the
27
28 'typedef double APL_Float'
29
30 in file APL_types.hh. It can be used as a starting point for creating your
31 own APL_Float class, for example to use some bignum library instead of the
32 built-in C++ double type.
33
34 This file (but not the APL_Float class itself) is expected to (and does)
35 provide the following (wrapper-) functions:
36
37 APL_Float abs(x)
38 APL_Float acos(x)
39 APL_Float asin(x)
40 APL_Float asinh(x)
41 APL_Float atan(x)
42 APL_Float ceil(x)
43 APL_Float cos(x)
44 APL_Float cosh(x)
45 APL_Float acosh(x)
46 APL_Float exp(x)
47 APL_Float floor(x)
48 APL_Float isfinite(x)
49 APL_Float log(x)
50 APL_Float round(x)
51 APL_Float sqrt(x)
52 APL_Float sin(x)
53 APL_Float sinh(x)
54 APL_Float tan(x)
55 APL_Float tgamma(x)
56 APL_Float tanh(x)
57
58 APL_Float atan2(x,y)
59 APL_Float fmod(x,y)
60 APL_Float pow(x,y)
61
62 APL_Float operator-(x)
63
64 APL_Float operator+(x, y)
65 APL_Float operator+(x, y)
66 APL_Float operator+(x, y)
67 APL_Float operator+(x, y)
68
69 bool operator<(x, y)
70 bool operator>(x, y)
71 bool operator<=(x, y)
72 bool operator>=(x, y)
73 bool operator==(x, y)
74 bool operator!=(x, y)
75 bool is_normal(x)
76
77 APL_Float_Base & operator+=(x)
78 APL_Float_Base & operator-=(x)
79 APL_Float_Base & operator*=(x)
80 APL_Float_Base & operator/=(x)
81
82 Each of these functions and operators must have multiple variants that all
83 have the same return type, but different argument types for x and y. The
84 possible argument types are:
85
86 const APL_Float_Base, double, APL_Integer, int64, and uint64.
87
88 Not all combinations are needed, though. Please note that the wrapper
89 macros used in this example will reduce the result precision to double
90 regardless of the precision of the operands.
91 */
92
93 #ifndef __APL_FLOAT_AS_CLASS_HH_DEFINED__
94 #define __APL_FLOAT_AS_CLASS_HH_DEFINED__
95
96 #ifndef __APL_TYPES_HH_DEFINED__
97 # error This file shall not be #included directly, but by #including APL_types.hh
98 #endif
99
100 class APL_Float;
101
102 /// the essential data of an APL_Float, so that it can be used in a union
103 class APL_Float_Base
104 {
105 public:
106 /// return the value as double
_get() const107 double _get() const
108 { return dval; }
109
110 /// set the value from a double
_set(double d)111 APL_Float_Base & _set(double d)
112 { dval = d; return *this; }
113
114 /// cast to APL_Float (creates a copy)
115 inline operator APL_Float() const;
116
117 /// up-cast const APL_Float_Base * to const APL_Float *
118 inline const APL_Float * pAPL_Float() const;
119
120 /// up-cast APL_Float_Base * to APL_Float *
121 inline APL_Float * pAPL_Float();
122
123 /// cast to double
operator double()124 inline operator double()
125 { return dval; }
126
127 /// cast to APL_Integer
operator const APL_Integer() const128 inline operator const APL_Integer() const
129 {
130 if (dval >= 0.0) return APL_Integer(dval);
131 const APL_Integer pa(-dval);
132 return -pa;
133 }
134
135 protected:
136 /// the value
137 double dval;
138 };
139 //------------------------------------------------------------------------------
140 /// a non-rational APL floating point value
141 class APL_Float : public APL_Float_Base
142 {
143 public:
144 /// default constructor
APL_Float()145 APL_Float() { dval = 0.0; }
146
147 /// constructor from a \b double value \b d
APL_Float(double d)148 APL_Float(double d) { dval = d; }
149
150 /// assingment from another APL_Float
operator =(const APL_Float & other)151 APL_Float & operator =(const APL_Float & other)
152 { dval = other.dval; return *this; }
153 };
154 /// isnormal() for APL_Float
isnormal(const APL_Float & val)155 inline bool isnormal(const APL_Float & val)
156 {
157 return std::isnormal(val._get());
158 }
159 //------------------------------------------------------------------------------
160 /// cast from APL_Float_Base to APL_Float
operator APL_Float() const161 APL_Float_Base::operator APL_Float() const
162 {
163 return APL_Float(dval);
164 }
165 //------------------------------------------------------------------------------
166 /// up-cast from const APL_Float_Base * to const APL_Float *
167 const APL_Float *
pAPL_Float() const168 APL_Float_Base::pAPL_Float() const
169 {
170 return static_cast<const APL_Float *>(this);
171 }
172 //------------------------------------------------------------------------------
173 /// up-cast from APL_Float_Base * to APL_Float *
174 APL_Float *
pAPL_Float()175 APL_Float_Base::pAPL_Float()
176 {
177 return static_cast<APL_Float *>(this);
178 }
179 //------------------------------------------------------------------------------
180
181 #define wrap1(type, fun) \
182 inline type fun(const APL_Float_Base & d) \
183 { return type(fun(double(d._get()))); }
184
185 /// double fun(double, double) ->
186 /// APL_Float fun(const APL_Float_Base &, const APL_Float_Base &)
187 #define wrap2(type, fun) \
188 inline type fun(const APL_Float_Base & d, const APL_Float_Base & e) \
189 { return type(fun(double(d._get()), \
190 double(e._get()))); } \
191 inline type fun(const APL_Float_Base & d, double e) \
192 { return type(fun(double(d._get()), e)); } \
193 inline type fun(double d, const APL_Float_Base & e) \
194 { return type(fun(d, double(e._get()))); }
195
196 /// double operator(double, double) ->
197 /// APL_Float operator (const APL_Float_Base &, const APL_Float_Base &)
198 #define op_wrap2(type, oper) \
199 inline type operator oper(const APL_Float_Base & d, \
200 const APL_Float_Base & e) \
201 { return type(double(d._get()) oper \
202 double(e._get())); } \
203 inline type operator oper(const APL_Float_Base & d, double e) \
204 { return type(double(d._get()) oper e); } \
205 inline type operator oper(const APL_Float_Base & d, APL_Integer e) \
206 { return type(double(d._get()) oper e); } \
207 inline type operator oper(const APL_Float_Base & d, uint64_t e) \
208 { return type(double(d._get()) oper e); } \
209 inline type operator oper(double d, const APL_Float_Base & e) \
210 { return type(d oper double(e._get())); } \
211 inline type operator oper(APL_Integer d, const APL_Float_Base & e) \
212 { return type(d oper double(e._get())); } \
213 inline type operator oper(int d, const APL_Float_Base & e) \
214 { return type(d oper double(e._get())); }
215
216 /// double operator(double, double) ->
217 /// APL_Float_Base & operator (const APL_Float_Base &, const APL_Float_Base &)
218 #define assop_wrap1(op) \
219 inline APL_Float_Base & operator op ## =(APL_Float_Base & d, \
220 const APL_Float_Base & e) \
221 { return d._set(d._get() op e._get()); } \
222 inline APL_Float_Base & operator op ## =(APL_Float_Base & d, double e) \
223 { return d._set(d._get() op e); }
224
225 // wrappers for libc functions with a single (double) argument
226 wrap1(double, abs)
227 wrap1(double, acos)
228 wrap1(double, asin)
229 wrap1(double, asinh)
230 wrap1(double, atan)
231 wrap1(double, ceil)
232 wrap1(double, cos)
233 wrap1(double, cosh)
234 wrap1(double, acosh)
235 wrap1(double, exp)
236 wrap1(double, floor)
237 wrap1(double, isfinite)
238 wrap1(double, log)
239 wrap1(double, round)
240 wrap1(double, sqrt)
241 wrap1(double, sin)
242 wrap1(double, sinh)
243 wrap1(double, tan)
244 wrap1(double, tgamma)
245 wrap1(double, tanh)
246
247 // wrappers for libc functions with two (double) arguments
248 wrap2(double, atan2)
249 wrap2(double, fmod)
250 wrap2(double, pow)
251
252 // wrapper for monadic -
253 inline APL_Float operator-(const APL_Float_Base & d)
254 { return APL_Float(-d._get()); }
255
256 // wrappers for dyadic + - * and /
257 op_wrap2(double, +)
258 op_wrap2(double, -)
259 op_wrap2(double, *)
260 op_wrap2(double, /)
261
262 // wrappers for < <= > >= == and !=
263 op_wrap2(bool, <)
264 op_wrap2(bool, >)
265 op_wrap2(bool, <=)
266 op_wrap2(bool, >=)
267 op_wrap2(bool, ==)
268 op_wrap2(bool, !=)
269
270 // wrappers for += -= *= and /=
271 assop_wrap1(+)
272 assop_wrap1(-)
273 assop_wrap1(*)
274 assop_wrap1(/)
275
276 //------------------------------------------------------------------------------
277 inline complex<APL_Float>
complex_sqrt(complex<APL_Float> x)278 complex_sqrt(complex<APL_Float> x)
279 {
280 const complex<double> cx(x.real()._get(), x.imag()._get());
281 const complex<double> cz = sqrt(cx);
282 return complex<APL_Float>(cz.real(), cz.imag());
283 }
284 //------------------------------------------------------------------------------
285 inline complex<APL_Float>
complex_exponent(complex<APL_Float> x)286 complex_exponent(complex<APL_Float> x)
287 {
288 const complex<double> cx(x.real()._get(), x.imag()._get());
289 const complex<double> cz = exp(cx);
290 return complex<APL_Float>(cz.real(), cz.imag());
291 }
292 //------------------------------------------------------------------------------
293 inline complex<APL_Float>
complex_power(complex<APL_Float> x,complex<APL_Float> y)294 complex_power(complex<APL_Float> x, complex<APL_Float> y)
295 {
296 const complex<double> cx(x.real()._get(), x.imag()._get());
297 const complex<double> cy(y.real()._get(), y.imag()._get());
298 const complex<double> cz = pow(cx, cy);
299 return complex<APL_Float>(cz.real(), cz.imag());
300 }
301 //------------------------------------------------------------------------------
302 #endif // __APL_FLOAT_AS_CLASS_HH_DEFINED__
303
304