Age Owner Branch data 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-2024, 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
2086 tomas.vondra@postgre 74 :CBC 209039 : get_float4_infinity(void)
75 : : {
76 : : #ifdef INFINITY
77 : : /* C99 standard way */
78 : 209039 : return (float4) INFINITY;
79 : : #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
94 : 754451 : get_float8_infinity(void)
95 : : {
96 : : #ifdef INFINITY
97 : : /* C99 standard way */
98 : 754451 : return (float8) INFINITY;
99 : : #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
111 : 15 : get_float4_nan(void)
112 : : {
113 : : #ifdef NAN
114 : : /* C99 standard way */
115 : 15 : return (float4) NAN;
116 : : #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
123 : 10929 : get_float8_nan(void)
124 : : {
125 : : /* (float8) NAN doesn't work on some NetBSD/MIPS releases */
126 : : #if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
127 : : /* C99 standard way */
128 : 10929 : return (float8) NAN;
129 : : #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
146 : 27 : float4_pl(const float4 val1, const float4 val2)
147 : : {
148 : : float4 result;
149 : :
150 : 27 : result = val1 + val2;
1522 tgl@sss.pgh.pa.us 151 [ - + - - : 27 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
- - ]
1522 tgl@sss.pgh.pa.us 152 :UBC 0 : float_overflow_error();
153 : :
2086 tomas.vondra@postgre 154 :CBC 27 : return result;
155 : : }
156 : :
157 : : static inline float8
158 : 2880887 : float8_pl(const float8 val1, const float8 val2)
159 : : {
160 : : float8 result;
161 : :
162 : 2880887 : result = val1 + val2;
1522 tgl@sss.pgh.pa.us 163 [ + + + + : 2880887 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
- + ]
1522 tgl@sss.pgh.pa.us 164 :UBC 0 : float_overflow_error();
165 : :
2086 tomas.vondra@postgre 166 :CBC 2880887 : return result;
167 : : }
168 : :
169 : : static inline float4
170 : 9 : float4_mi(const float4 val1, const float4 val2)
171 : : {
172 : : float4 result;
173 : :
174 : 9 : result = val1 - val2;
1522 tgl@sss.pgh.pa.us 175 [ - + - - : 9 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
- - ]
1522 tgl@sss.pgh.pa.us 176 :UBC 0 : float_overflow_error();
177 : :
2086 tomas.vondra@postgre 178 :CBC 9 : return result;
179 : : }
180 : :
181 : : static inline float8
182 : 130382540 : float8_mi(const float8 val1, const float8 val2)
183 : : {
184 : : float8 result;
185 : :
186 : 130382540 : result = val1 - val2;
1522 tgl@sss.pgh.pa.us 187 [ + + + + : 130382540 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
- + ]
1522 tgl@sss.pgh.pa.us 188 :UBC 0 : float_overflow_error();
189 : :
2086 tomas.vondra@postgre 190 :CBC 130382540 : return result;
191 : : }
192 : :
193 : : static inline float4
194 : 18 : float4_mul(const float4 val1, const float4 val2)
195 : : {
196 : : float4 result;
197 : :
198 : 18 : result = val1 * val2;
1522 tgl@sss.pgh.pa.us 199 [ - + - - : 18 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
- - ]
1522 tgl@sss.pgh.pa.us 200 :UBC 0 : float_overflow_error();
1522 tgl@sss.pgh.pa.us 201 [ - + - - :CBC 18 : if (unlikely(result == 0.0f) && val1 != 0.0f && val2 != 0.0f)
- - ]
1522 tgl@sss.pgh.pa.us 202 :UBC 0 : float_underflow_error();
203 : :
2086 tomas.vondra@postgre 204 :CBC 18 : return result;
205 : : }
206 : :
207 : : static inline float8
208 : 56210871 : float8_mul(const float8 val1, const float8 val2)
209 : : {
210 : : float8 result;
211 : :
212 : 56210871 : result = val1 * val2;
1522 tgl@sss.pgh.pa.us 213 [ + + + + : 56210871 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
+ + ]
214 : 12 : float_overflow_error();
215 [ + + + + : 56210859 : if (unlikely(result == 0.0) && val1 != 0.0 && val2 != 0.0)
+ + ]
216 : 3 : float_underflow_error();
217 : :
2086 tomas.vondra@postgre 218 : 56210856 : return result;
219 : : }
220 : :
221 : : static inline float4
222 : 3535359 : float4_div(const float4 val1, const float4 val2)
223 : : {
224 : : float4 result;
225 : :
1364 tgl@sss.pgh.pa.us 226 [ + + + + ]: 3535359 : if (unlikely(val2 == 0.0f) && !isnan(val1))
1522 227 : 3 : float_zero_divide_error();
2086 tomas.vondra@postgre 228 : 3535356 : result = val1 / val2;
1257 tgl@sss.pgh.pa.us 229 [ - + - - ]: 3535356 : if (unlikely(isinf(result)) && !isinf(val1))
1522 tgl@sss.pgh.pa.us 230 :UBC 0 : float_overflow_error();
1257 tgl@sss.pgh.pa.us 231 [ + + + - :CBC 3535356 : if (unlikely(result == 0.0f) && val1 != 0.0f && !isinf(val2))
- + ]
1522 tgl@sss.pgh.pa.us 232 :UBC 0 : float_underflow_error();
233 : :
2086 tomas.vondra@postgre 234 :CBC 3535356 : return result;
235 : : }
236 : :
237 : : static inline float8
238 : 9714158 : float8_div(const float8 val1, const float8 val2)
239 : : {
240 : : float8 result;
241 : :
1364 tgl@sss.pgh.pa.us 242 [ + + + + ]: 9714158 : if (unlikely(val2 == 0.0) && !isnan(val1))
1522 243 : 33 : float_zero_divide_error();
2086 tomas.vondra@postgre 244 : 9714125 : result = val1 / val2;
1257 tgl@sss.pgh.pa.us 245 [ + + - + ]: 9714125 : if (unlikely(isinf(result)) && !isinf(val1))
1522 tgl@sss.pgh.pa.us 246 :UBC 0 : float_overflow_error();
1257 tgl@sss.pgh.pa.us 247 [ + + + + :CBC 9714125 : if (unlikely(result == 0.0) && val1 != 0.0 && !isinf(val2))
- + ]
1522 tgl@sss.pgh.pa.us 248 :UBC 0 : float_underflow_error();
249 : :
2086 tomas.vondra@postgre 250 :CBC 9714125 : return result;
251 : : }
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
262 : 31190 : float4_eq(const float4 val1, const float4 val2)
263 : : {
264 [ + + + - : 31190 : return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+ + ]
265 : : }
266 : :
267 : : static inline bool
268 : 8666747 : float8_eq(const float8 val1, const float8 val2)
269 : : {
270 [ + + + + : 8666747 : return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+ + ]
271 : : }
272 : :
273 : : static inline bool
274 : 15 : float4_ne(const float4 val1, const float4 val2)
275 : : {
276 [ - + + - : 15 : return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+ + ]
277 : : }
278 : :
279 : : static inline bool
280 : 9981 : float8_ne(const float8 val1, const float8 val2)
281 : : {
282 [ - + + - : 9981 : return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+ + ]
283 : : }
284 : :
285 : : static inline bool
286 : 5795695 : float4_lt(const float4 val1, const float4 val2)
287 : : {
288 [ + + + + : 5795695 : return !isnan(val1) && (isnan(val2) || val1 < val2);
+ + ]
289 : : }
290 : :
291 : : static inline bool
292 : 62514656 : float8_lt(const float8 val1, const float8 val2)
293 : : {
294 [ + + + + : 62514656 : return !isnan(val1) && (isnan(val2) || val1 < val2);
+ + ]
295 : : }
296 : :
297 : : static inline bool
298 : 1914 : float4_le(const float4 val1, const float4 val2)
299 : : {
300 [ + - + - : 1914 : return isnan(val2) || (!isnan(val1) && val1 <= val2);
+ + ]
301 : : }
302 : :
303 : : static inline bool
304 : 85226049 : float8_le(const float8 val1, const float8 val2)
305 : : {
306 [ + - + + : 85226049 : return isnan(val2) || (!isnan(val1) && val1 <= val2);
+ + ]
307 : : }
308 : :
309 : : static inline bool
310 : 5889823 : float4_gt(const float4 val1, const float4 val2)
311 : : {
312 [ + + + + : 5889823 : return !isnan(val2) && (isnan(val1) || val1 > val2);
+ + ]
313 : : }
314 : :
315 : : static inline bool
316 : 66819038 : float8_gt(const float8 val1, const float8 val2)
317 : : {
318 [ + + + + : 66819038 : return !isnan(val2) && (isnan(val1) || val1 > val2);
+ + ]
319 : : }
320 : :
321 : : static inline bool
322 : 1914 : float4_ge(const float4 val1, const float4 val2)
323 : : {
324 [ + - + - : 1914 : return isnan(val1) || (!isnan(val2) && val1 >= val2);
+ + ]
325 : : }
326 : :
327 : : static inline bool
328 : 4447857 : float8_ge(const float8 val1, const float8 val2)
329 : : {
330 [ + + + - : 4447857 : return isnan(val1) || (!isnan(val2) && val1 >= val2);
+ + ]
331 : : }
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
340 : 46829682 : float8_min(const float8 val1, const float8 val2)
341 : : {
342 [ + + ]: 46829682 : return float8_lt(val1, val2) ? val1 : val2;
343 : : }
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
352 : 46829682 : float8_max(const float8 val1, const float8 val2)
353 : : {
354 [ + + ]: 46829682 : return float8_gt(val1, val2) ? val1 : val2;
355 : : }
356 : :
357 : : #endif /* FLOAT_H */
|