1 /*
2  * float.h - auxilirary floating-point number support
3  *
4  *   Copyright (c) 2007-2020  Shiro Kawai  <shiro@acm.org>
5  *
6  *   Redistribution and use in source and binary forms, with or without
7  *   modification, are permitted provided that the following conditions
8  *   are met:
9  *
10  *   1. Redistributions of source code must retain the above copyright
11  *      notice, this list of conditions and the following disclaimer.
12  *
13  *   2. Redistributions in binary form must reproduce the above copyright
14  *      notice, this list of conditions and the following disclaimer in the
15  *      documentation and/or other materials provided with the distribution.
16  *
17  *   3. Neither the name of the authors nor the names of its contributors
18  *      may be used to endorse or promote products derived from this
19  *      software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27  *   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28  *   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29  *   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31  *   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*
35  * Defines some types and macros to support newer standard or non-standard
36  * floating point numbers easily.
37  */
38 
39 #ifndef GAUCHE_FLOAT_H
40 #define GAUCHE_FLOAT_H
41 
42 #include <math.h>
43 #include <complex.h>
44 #undef I                        /* avoid unintentional conflict */
45 
46 #if defined(HAVE_FPU_CONTROL_H)
47 #include <fpu_control.h>
48 #endif
49 
50 /* assuming gauche/config.h is read. */
51 
52 /* We avoid to use C macro 'complex' for C++ extensions. */
53 typedef float _Complex ScmFloatComplex;
54 typedef double _Complex ScmDoubleComplex;
55 
56 /*
57  * Half float support
58  */
59 #ifdef HAVE_UINT16_T
60 typedef uint16_t        ScmHalfFloat;
61 #else
62 typedef unsigned short  ScmHalfFloat;
63 #endif
64 
65 #define SCM_HALF_FLOAT_SIGN_BIT(hf)  ((hf)&0x8000U)
66 #define SCM_HALF_FLOAT_EXPONENT(hf)  (((hf)&0x7c00U)>>10)
67 #define SCM_HALF_FLOAT_MANTISSA(hf)  ((hf)&0x03ffU)
68 #define SCM_HALF_FLOAT_IS_NAN(hf)                       \
69     ((((~(hf))&0x7c00U) == 0) && (((hf)&0x03ffU) != 0))
70 #define SCM_HALF_FLOAT_CMP(op, hf1, hf2)        \
71     (!SCM_HALF_FLOAT_IS_NAN(hf1)                \
72      && !SCM_HALF_FLOAT_IS_NAN(hf2)             \
73      && ((hf1) op (hf2)))
74 
75 typedef struct {
76     ScmHalfFloat r;
77     ScmHalfFloat i;
78 } ScmHalfComplex;
79 
80 #define SCM_HALF_COMPLEX_REAL(hc)  ((hc).r)
81 #define SCM_HALF_COMPLEX_IMAG(hc)  ((hc).i)
82 
83 /*
84  * Long double support
85  */
86 
87 #ifdef HAVE_LONG_DOUBLE
88 typedef long double     ScmLongDouble;
89 #else
90 typedef double          ScmLongDouble;
91 #endif
92 
93 /* NaN and Infinities.  The following works for most Unix platforms w/gcc.
94    However, Windows require a different treatment. */
95 #ifndef SCM_DBL_POSITIVE_INFINITY
96 #define SCM_DBL_POSITIVE_INFINITY  (1.0/0.0)
97 #endif
98 
99 #ifndef SCM_DBL_NEGATIVE_INFINITY
100 #define SCM_DBL_NEGATIVE_INFINITY  (-1.0/0.0)
101 #endif
102 
103 #ifndef SCM_DBL_NAN
104 #define SCM_DBL_NAN           (0.0/0.0)
105 #endif
106 
107 #ifndef SCM_FLT_POSITIVE_INFINITY
108 #define SCM_FLT_POSITIVE_INFINITY  (1.0f/0.0f)
109 #endif
110 
111 #ifndef SCM_FTL_NEGATIVE_INFINITY
112 #define SCM_FLT_NEGATIVE_INFINITY  (-1.0f/0.0f)
113 #endif
114 
115 #ifndef SCM_FTL_NAN
116 #define SCM_FLT_NAN           (0.0f/0.0f)
117 #endif
118 
119 
120 
121 #ifdef HAVE_ISNAN
122 #define SCM_IS_NAN(x)  isnan(x)
123 #else
124 #define SCM_IS_NAN(x)  (!((x)==(x)))
125 #endif
126 
127 #ifdef HAVE_ISINF
128 #define SCM_IS_INF(x)  isinf(x)
129 #else
130 #define SCM_IS_INF(x)  Scm_IsInf(x)
131 SCM_EXTERN int Scm_IsInf(double x);
132 #endif
133 
134 /*
135  * Floating pointer control register
136  *
137  *  In some places we need to make sure the FP calculations are done
138  *  with IEEE double precision, not with x87 extended double precision,
139  *  for the latter would cause inaccuracy because of double-rounding.
140  *
141  *  Unfortunately setting FP control modes differ among platforms.
142  */
143 
144 #if defined(__MINGW32__) || defined(__MINGW64__)
145 #include <float.h>
146 
147 /* Recent versions of Mingw GCC (4.6.1 and 4.7.0, afaik) has a bug that
148    Windows float.h isn't included by mingw-gcc's float.h.  This is a kludge
149    to let us use _controlfp().*/
150 #  ifndef _MCW_PC
151 extern unsigned int __cdecl _controlfp(unsigned int, unsigned int);
152 #  define _PC_53          0x00010000
153 #  define _MCW_PC         0x00030000
154 #  endif /*_MCW_PC*/
155 
156 #define SCM_FP_ENSURE_DOUBLE_PRECISION_BEGIN()        \
157     { unsigned int old_fpc_val__ = _controlfp(0, 0);  \
158       _controlfp(_PC_53, _MCW_PC);
159 
160 #define SCM_FP_ENSURE_DOUBLE_PRECISION_END() \
161       _controlfp(old_fpc_val__, _MCW_PC); }
162 
163 #elif defined(_FPU_GETCW) && defined(_FPU_EXTENDED) /* linux x86 */
164 
165 #define SCM_FP_ENSURE_DOUBLE_PRECISION_BEGIN()        \
166     { fpu_control_t old_fpc_val__, new_fpc_val__;     \
167       _FPU_GETCW(old_fpc_val__);                      \
168       new_fpc_val__ = ((old_fpc_val__ & ~_FPU_EXTENDED) | _FPU_DOUBLE); \
169       _FPU_SETCW(new_fpc_val__);
170 
171 #define SCM_FP_ENSURE_DOUBLE_PRECISION_END() \
172       _FPU_SETCW(old_fpc_val__); }
173 
174 #elif defined(__CYGWIN__)
175 
176 /* Cygwin doesn't seem to have fpu_control.h
177    We're too sloppy and don't bother restoring control word for now.
178  */
179 
180 #define SCM_FP_ENSURE_DOUBLE_PRECISION_BEGIN()  \
181     do {                                        \
182         static const u_short cw = 0x27f;        \
183         asm volatile("fldcw %0": : "m"(cw));    \
184     } while(0)
185 
186 #define SCM_FP_ENSURE_DOUBLE_PRECISION_END()
187 
188 #elif defined(__NetBSD__) && defined(__i386__) && defined(HAVE_FPSETPREC)
189 /*
190  * NetBSD 6.99.26 switched to the x87 default control word (0x037f)
191  * as initial value for new processes.
192  */
193 #include <ieeefp.h>
194 
195 #define SCM_FP_ENSURE_DOUBLE_PRECISION_BEGIN()        \
196     { fp_prec_t old_prec__ = fpsetprec(FP_PD);
197 #define SCM_FP_ENSURE_DOUBLE_PRECISION_END() \
198       fpsetprec(old_prec__); }
199 
200 #else  /* fallback */
201 #define SCM_FP_ENSURE_DOUBLE_PRECISION_BEGIN() /* nothing */
202 #define SCM_FP_ENSURE_DOUBLE_PRECISION_END()   /* nothing */
203 #endif
204 
205 
206 #endif /*GAUCHE_FLOAT_H*/
207