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