Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * float.h
4 : * Definitions for the built-in floating-point types
5 : *
6 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/include/utils/float.h
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : #ifndef FLOAT_H
16 : #define FLOAT_H
17 :
18 : #include <math.h>
19 :
20 : /* X/Open (XSI) requires <math.h> to provide M_PI, but core POSIX does not */
21 : #ifndef M_PI
22 : #define M_PI 3.14159265358979323846
23 : #endif
24 :
25 : /* Radians per degree, a.k.a. PI / 180 */
26 : #define RADIANS_PER_DEGREE 0.0174532925199432957692
27 :
28 : /* Visual C++ etc lacks NAN, and won't accept 0.0/0.0. */
29 : #if defined(WIN32) && !defined(NAN)
30 : static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
31 :
32 : #define NAN (*(const float8 *) nan)
33 : #endif
34 :
35 : extern PGDLLIMPORT int extra_float_digits;
36 :
37 : /*
38 : * Utility functions in float.c
39 : */
40 : extern void float_overflow_error(void) pg_attribute_noreturn();
41 : extern void float_underflow_error(void) pg_attribute_noreturn();
42 : extern void float_zero_divide_error(void) pg_attribute_noreturn();
43 : extern int is_infinite(float8 val);
44 : extern float8 float8in_internal(char *num, char **endptr_p,
45 : const char *type_name, const char *orig_string,
46 : struct Node *escontext);
47 : extern float4 float4in_internal(char *num, char **endptr_p,
48 : const char *type_name, const char *orig_string,
49 : struct Node *escontext);
50 : extern char *float8out_internal(float8 num);
51 : extern int float4_cmp_internal(float4 a, float4 b);
52 : extern int float8_cmp_internal(float8 a, float8 b);
53 :
54 : /*
55 : * Routines to provide reasonably platform-independent handling of
56 : * infinity and NaN
57 : *
58 : * We assume that isinf() and isnan() are available and work per spec.
59 : * (On some platforms, we have to supply our own; see src/port.) However,
60 : * generating an Infinity or NaN in the first place is less well standardized;
61 : * pre-C99 systems tend not to have C99's INFINITY and NaN macros. We
62 : * centralize our workarounds for this here.
63 : */
64 :
65 : /*
66 : * The funny placements of the two #pragmas is necessary because of a
67 : * long lived bug in the Microsoft compilers.
68 : * See http://support.microsoft.com/kb/120968/en-us for details
69 : */
70 : #ifdef _MSC_VER
71 : #pragma warning(disable:4756)
72 : #endif
73 : static inline float4
1715 tomas.vondra 74 GIC 207542 : get_float4_infinity(void)
1715 tomas.vondra 75 ECB : {
76 : #ifdef INFINITY
77 : /* C99 standard way */
1715 tomas.vondra 78 GIC 207542 : return (float4) INFINITY;
1715 tomas.vondra 79 ECB : #else
80 : #ifdef _MSC_VER
81 : #pragma warning(default:4756)
82 : #endif
83 :
84 : /*
85 : * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
86 : * largest normal float8. We assume forcing an overflow will get us a
87 : * true infinity.
88 : */
89 : return (float4) (HUGE_VAL * HUGE_VAL);
90 : #endif
91 : }
92 :
93 : static inline float8
1715 tomas.vondra 94 GIC 753921 : get_float8_infinity(void)
1715 tomas.vondra 95 ECB : {
96 : #ifdef INFINITY
97 : /* C99 standard way */
1715 tomas.vondra 98 GIC 753921 : return (float8) INFINITY;
1715 tomas.vondra 99 ECB : #else
100 :
101 : /*
102 : * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
103 : * largest normal float8. We assume forcing an overflow will get us a
104 : * true infinity.
105 : */
106 : return (float8) (HUGE_VAL * HUGE_VAL);
107 : #endif
108 : }
109 :
110 : static inline float4
1715 tomas.vondra 111 GIC 15 : get_float4_nan(void)
1715 tomas.vondra 112 ECB : {
113 : #ifdef NAN
114 : /* C99 standard way */
1715 tomas.vondra 115 GIC 15 : return (float4) NAN;
1715 tomas.vondra 116 ECB : #else
117 : /* Assume we can get a NAN via zero divide */
118 : return (float4) (0.0 / 0.0);
119 : #endif
120 : }
121 :
122 : static inline float8
1715 tomas.vondra 123 GIC 10866 : get_float8_nan(void)
1715 tomas.vondra 124 ECB : {
125 : /* (float8) NAN doesn't work on some NetBSD/MIPS releases */
126 : #if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
127 : /* C99 standard way */
1715 tomas.vondra 128 GIC 10866 : return (float8) NAN;
1715 tomas.vondra 129 ECB : #else
130 : /* Assume we can get a NaN via zero divide */
131 : return (float8) (0.0 / 0.0);
132 : #endif
133 : }
134 :
135 : /*
136 : * Floating-point arithmetic with overflow/underflow reported as errors
137 : *
138 : * There isn't any way to check for underflow of addition/subtraction
139 : * because numbers near the underflow value have already been rounded to
140 : * the point where we can't detect that the two values were originally
141 : * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
142 : * 1.4013e-45.
143 : */
144 :
145 : static inline float4
1715 tomas.vondra 146 GIC 27 : float4_pl(const float4 val1, const float4 val2)
1715 tomas.vondra 147 ECB : {
148 : float4 result;
149 :
1715 tomas.vondra 150 GIC 27 : result = val1 + val2;
1151 tgl 151 CBC 27 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
1151 tgl 152 LBC 0 : float_overflow_error();
1715 tomas.vondra 153 EUB :
1715 tomas.vondra 154 GIC 27 : return result;
1715 tomas.vondra 155 ECB : }
156 :
157 : static inline float8
1715 tomas.vondra 158 GIC 2866988 : float8_pl(const float8 val1, const float8 val2)
1715 tomas.vondra 159 ECB : {
160 : float8 result;
161 :
1715 tomas.vondra 162 GIC 2866988 : result = val1 + val2;
1151 tgl 163 CBC 2866988 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
1151 tgl 164 LBC 0 : float_overflow_error();
1715 tomas.vondra 165 EUB :
1715 tomas.vondra 166 GIC 2866988 : return result;
1715 tomas.vondra 167 ECB : }
168 :
169 : static inline float4
1715 tomas.vondra 170 GIC 9 : float4_mi(const float4 val1, const float4 val2)
1715 tomas.vondra 171 ECB : {
172 : float4 result;
173 :
1715 tomas.vondra 174 GIC 9 : result = val1 - val2;
1151 tgl 175 CBC 9 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
1151 tgl 176 LBC 0 : float_overflow_error();
1715 tomas.vondra 177 EUB :
1715 tomas.vondra 178 GIC 9 : return result;
1715 tomas.vondra 179 ECB : }
180 :
181 : static inline float8
1715 tomas.vondra 182 GIC 130288673 : float8_mi(const float8 val1, const float8 val2)
1715 tomas.vondra 183 ECB : {
184 : float8 result;
185 :
1715 tomas.vondra 186 GIC 130288673 : result = val1 - val2;
1151 tgl 187 CBC 130288673 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
1151 tgl 188 LBC 0 : float_overflow_error();
1715 tomas.vondra 189 EUB :
1715 tomas.vondra 190 GIC 130288673 : return result;
1715 tomas.vondra 191 ECB : }
192 :
193 : static inline float4
1715 tomas.vondra 194 GIC 18 : float4_mul(const float4 val1, const float4 val2)
1715 tomas.vondra 195 ECB : {
196 : float4 result;
197 :
1715 tomas.vondra 198 GIC 18 : result = val1 * val2;
1151 tgl 199 CBC 18 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
1151 tgl 200 LBC 0 : float_overflow_error();
1151 tgl 201 GBC 18 : if (unlikely(result == 0.0f) && val1 != 0.0f && val2 != 0.0f)
1151 tgl 202 LBC 0 : float_underflow_error();
1715 tomas.vondra 203 EUB :
1715 tomas.vondra 204 GIC 18 : return result;
1715 tomas.vondra 205 ECB : }
206 :
207 : static inline float8
1715 tomas.vondra 208 GIC 56153160 : float8_mul(const float8 val1, const float8 val2)
1715 tomas.vondra 209 ECB : {
210 : float8 result;
211 :
1715 tomas.vondra 212 GIC 56153160 : result = val1 * val2;
1151 tgl 213 CBC 56153160 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
214 9 : float_overflow_error();
215 56153151 : if (unlikely(result == 0.0) && val1 != 0.0 && val2 != 0.0)
216 3 : float_underflow_error();
1715 tomas.vondra 217 ECB :
1715 tomas.vondra 218 GIC 56153148 : return result;
1715 tomas.vondra 219 ECB : }
220 :
221 : static inline float4
1715 tomas.vondra 222 GIC 3525265 : float4_div(const float4 val1, const float4 val2)
1715 tomas.vondra 223 ECB : {
224 : float4 result;
225 :
993 tgl 226 GIC 3525265 : if (unlikely(val2 == 0.0f) && !isnan(val1))
1151 tgl 227 CBC 3 : float_zero_divide_error();
1715 tomas.vondra 228 3525262 : result = val1 / val2;
886 tgl 229 3525262 : if (unlikely(isinf(result)) && !isinf(val1))
1151 tgl 230 LBC 0 : float_overflow_error();
886 tgl 231 GBC 3525262 : if (unlikely(result == 0.0f) && val1 != 0.0f && !isinf(val2))
1151 tgl 232 LBC 0 : float_underflow_error();
1715 tomas.vondra 233 EUB :
1715 tomas.vondra 234 GIC 3525262 : return result;
1715 tomas.vondra 235 ECB : }
236 :
237 : static inline float8
1715 tomas.vondra 238 GIC 9709887 : float8_div(const float8 val1, const float8 val2)
1715 tomas.vondra 239 ECB : {
240 : float8 result;
241 :
993 tgl 242 GIC 9709887 : if (unlikely(val2 == 0.0) && !isnan(val1))
1151 tgl 243 CBC 33 : float_zero_divide_error();
1715 tomas.vondra 244 9709854 : result = val1 / val2;
886 tgl 245 9709854 : if (unlikely(isinf(result)) && !isinf(val1))
1151 tgl 246 LBC 0 : float_overflow_error();
886 tgl 247 GBC 9709854 : if (unlikely(result == 0.0) && val1 != 0.0 && !isinf(val2))
1151 tgl 248 LBC 0 : float_underflow_error();
1715 tomas.vondra 249 EUB :
1715 tomas.vondra 250 GIC 9709854 : return result;
1715 tomas.vondra 251 ECB : }
252 :
253 : /*
254 : * Routines for NaN-aware comparisons
255 : *
256 : * We consider all NaNs to be equal and larger than any non-NaN. This is
257 : * somewhat arbitrary; the important thing is to have a consistent sort
258 : * order.
259 : */
260 :
261 : static inline bool
1715 tomas.vondra 262 GIC 31166 : float4_eq(const float4 val1, const float4 val2)
1715 tomas.vondra 263 ECB : {
1715 tomas.vondra 264 GIC 31166 : return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
1715 tomas.vondra 265 ECB : }
266 :
267 : static inline bool
1715 tomas.vondra 268 GIC 8464387 : float8_eq(const float8 val1, const float8 val2)
1715 tomas.vondra 269 ECB : {
1715 tomas.vondra 270 GIC 8464387 : return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
1715 tomas.vondra 271 ECB : }
272 :
273 : static inline bool
1715 tomas.vondra 274 GIC 15 : float4_ne(const float4 val1, const float4 val2)
1715 tomas.vondra 275 ECB : {
1715 tomas.vondra 276 GIC 15 : return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
1715 tomas.vondra 277 ECB : }
278 :
279 : static inline bool
1715 tomas.vondra 280 GIC 9912 : float8_ne(const float8 val1, const float8 val2)
1715 tomas.vondra 281 ECB : {
1715 tomas.vondra 282 GIC 9912 : return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
1715 tomas.vondra 283 ECB : }
284 :
285 : static inline bool
1715 tomas.vondra 286 GIC 24738422 : float4_lt(const float4 val1, const float4 val2)
1715 tomas.vondra 287 ECB : {
1715 tomas.vondra 288 GIC 24738422 : return !isnan(val1) && (isnan(val2) || val1 < val2);
1715 tomas.vondra 289 ECB : }
290 :
291 : static inline bool
1715 tomas.vondra 292 GIC 62399573 : float8_lt(const float8 val1, const float8 val2)
1715 tomas.vondra 293 ECB : {
1715 tomas.vondra 294 GIC 62399573 : return !isnan(val1) && (isnan(val2) || val1 < val2);
1715 tomas.vondra 295 ECB : }
296 :
297 : static inline bool
1715 tomas.vondra 298 GIC 1914 : float4_le(const float4 val1, const float4 val2)
1715 tomas.vondra 299 ECB : {
1715 tomas.vondra 300 GIC 1914 : return isnan(val2) || (!isnan(val1) && val1 <= val2);
1715 tomas.vondra 301 ECB : }
302 :
303 : static inline bool
1715 tomas.vondra 304 GIC 85143552 : float8_le(const float8 val1, const float8 val2)
1715 tomas.vondra 305 ECB : {
1715 tomas.vondra 306 GIC 85143552 : return isnan(val2) || (!isnan(val1) && val1 <= val2);
1715 tomas.vondra 307 ECB : }
308 :
309 : static inline bool
1715 tomas.vondra 310 GIC 25269094 : float4_gt(const float4 val1, const float4 val2)
1715 tomas.vondra 311 ECB : {
1715 tomas.vondra 312 GIC 25269094 : return !isnan(val2) && (isnan(val1) || val1 > val2);
1715 tomas.vondra 313 ECB : }
314 :
315 : static inline bool
1715 tomas.vondra 316 GIC 66649997 : float8_gt(const float8 val1, const float8 val2)
1715 tomas.vondra 317 ECB : {
1715 tomas.vondra 318 GIC 66649997 : return !isnan(val2) && (isnan(val1) || val1 > val2);
1715 tomas.vondra 319 ECB : }
320 :
321 : static inline bool
1715 tomas.vondra 322 GIC 1914 : float4_ge(const float4 val1, const float4 val2)
1715 tomas.vondra 323 ECB : {
1715 tomas.vondra 324 GIC 1914 : return isnan(val1) || (!isnan(val2) && val1 >= val2);
1715 tomas.vondra 325 ECB : }
326 :
327 : static inline bool
1715 tomas.vondra 328 GIC 4433507 : float8_ge(const float8 val1, const float8 val2)
1715 tomas.vondra 329 ECB : {
1715 tomas.vondra 330 GIC 4433507 : return isnan(val1) || (!isnan(val2) && val1 >= val2);
1715 tomas.vondra 331 ECB : }
332 :
333 : static inline float4
334 : float4_min(const float4 val1, const float4 val2)
335 : {
336 : return float4_lt(val1, val2) ? val1 : val2;
337 : }
338 :
339 : static inline float8
1715 tomas.vondra 340 GIC 46795660 : float8_min(const float8 val1, const float8 val2)
1715 tomas.vondra 341 ECB : {
1715 tomas.vondra 342 GIC 46795660 : return float8_lt(val1, val2) ? val1 : val2;
1715 tomas.vondra 343 ECB : }
344 :
345 : static inline float4
346 : float4_max(const float4 val1, const float4 val2)
347 : {
348 : return float4_gt(val1, val2) ? val1 : val2;
349 : }
350 :
351 : static inline float8
1715 tomas.vondra 352 GIC 46795660 : float8_max(const float8 val1, const float8 val2)
1715 tomas.vondra 353 ECB : {
1715 tomas.vondra 354 GIC 46795660 : return float8_gt(val1, val2) ? val1 : val2;
1715 tomas.vondra 355 ECB : }
356 :
357 : #endif /* FLOAT_H */
|