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