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-2026, 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 : : extern PGDLLIMPORT int extra_float_digits;
29 : :
30 : : /*
31 : : * Utility functions in float.c
32 : : */
33 : : pg_noreturn extern void float_overflow_error(void);
34 : : pg_noreturn extern void float_underflow_error(void);
35 : : pg_noreturn extern void float_zero_divide_error(void);
36 : : extern float8 float_overflow_error_ext(struct Node *escontext);
37 : : extern float8 float_underflow_error_ext(struct Node *escontext);
38 : : extern float8 float_zero_divide_error_ext(struct Node *escontext);
39 : : extern int is_infinite(float8 val);
40 : : extern float8 float8in_internal(char *num, char **endptr_p,
41 : : const char *type_name, const char *orig_string,
42 : : struct Node *escontext);
43 : : extern float4 float4in_internal(char *num, char **endptr_p,
44 : : const char *type_name, const char *orig_string,
45 : : struct Node *escontext);
46 : : extern char *float8out_internal(float8 num);
47 : : extern int float4_cmp_internal(float4 a, float4 b);
48 : : extern int float8_cmp_internal(float8 a, float8 b);
49 : :
50 : : /*
51 : : * Postgres requires IEEE-standard float arithmetic, including infinities
52 : : * and NaNs. We used to support pre-C99 compilers on which <math.h> might
53 : : * not supply the standard macros INFINITY and NAN. We no longer do so,
54 : : * but these wrapper functions are still preferred over using those macros
55 : : * directly.
56 : : *
57 : : * If you change these functions, see copies in interfaces/ecpg/ecpglib/data.c.
58 : : */
59 : :
60 : : static inline float4
2837 tomas.vondra@postgre 61 :CBC 218563 : get_float4_infinity(void)
62 : : {
63 : : /* C99 standard way */
64 : 218563 : return (float4) INFINITY;
65 : : }
66 : :
67 : : static inline float8
68 : 1000914 : get_float8_infinity(void)
69 : : {
70 : : /* C99 standard way */
71 : 1000914 : return (float8) INFINITY;
72 : : }
73 : :
74 : : /* The C standard allows implementations to omit NAN, but we don't */
75 : : #ifndef NAN
76 : : #error "Postgres requires support for IEEE quiet NaNs"
77 : : #endif
78 : :
79 : : static inline float4
80 : 22 : get_float4_nan(void)
81 : : {
82 : : /* C99 standard way */
83 : 22 : return (float4) NAN;
84 : : }
85 : :
86 : : static inline float8
87 : 1526 : get_float8_nan(void)
88 : : {
89 : : /* C99 standard way */
90 : 1526 : return (float8) NAN;
91 : : }
92 : :
93 : : /*
94 : : * Floating-point arithmetic with overflow/underflow reported as errors
95 : : *
96 : : * There isn't any way to check for underflow of addition/subtraction
97 : : * because numbers near the underflow value have already been rounded to
98 : : * the point where we can't detect that the two values were originally
99 : : * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
100 : : * 1.4013e-45.
101 : : */
102 : :
103 : : static inline float4
104 : 36 : float4_pl(const float4 val1, const float4 val2)
105 : : {
106 : : float4 result;
107 : :
108 : 36 : result = val1 + val2;
2273 tgl@sss.pgh.pa.us 109 [ - + - - : 36 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
- - ]
2273 tgl@sss.pgh.pa.us 110 :UBC 0 : float_overflow_error();
111 : :
2837 tomas.vondra@postgre 112 :CBC 36 : return result;
113 : : }
114 : :
115 : : static inline float8
37 peter@eisentraut.org 116 :GNC 3841982 : float8_pl_safe(const float8 val1, const float8 val2, struct Node *escontext)
117 : : {
118 : : float8 result;
119 : :
2837 tomas.vondra@postgre 120 :CBC 3841982 : result = val1 + val2;
2273 tgl@sss.pgh.pa.us 121 [ + + + + : 3841982 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
- + ]
37 peter@eisentraut.org 122 :UNC 0 : return float_overflow_error_ext(escontext);
123 : :
2837 tomas.vondra@postgre 124 :CBC 3841982 : return result;
125 : : }
126 : :
127 : : static inline float8
37 peter@eisentraut.org 128 :GNC 3331562 : float8_pl(const float8 val1, const float8 val2)
129 : : {
130 : 3331562 : return float8_pl_safe(val1, val2, NULL);
131 : : }
132 : :
133 : : static inline float4
2837 tomas.vondra@postgre 134 :CBC 12 : float4_mi(const float4 val1, const float4 val2)
135 : : {
136 : : float4 result;
137 : :
138 : 12 : result = val1 - val2;
2273 tgl@sss.pgh.pa.us 139 [ - + - - : 12 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
- - ]
2273 tgl@sss.pgh.pa.us 140 :UBC 0 : float_overflow_error();
141 : :
2837 tomas.vondra@postgre 142 :CBC 12 : return result;
143 : : }
144 : :
145 : : static inline float8
37 peter@eisentraut.org 146 :GNC 173349725 : float8_mi_safe(const float8 val1, const float8 val2, struct Node *escontext)
147 : : {
148 : : float8 result;
149 : :
2837 tomas.vondra@postgre 150 :CBC 173349725 : result = val1 - val2;
2273 tgl@sss.pgh.pa.us 151 [ + + + + : 173349725 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
- + ]
37 peter@eisentraut.org 152 :UNC 0 : return float_overflow_error_ext(escontext);
153 : :
2837 tomas.vondra@postgre 154 :CBC 173349725 : return result;
155 : : }
156 : :
157 : : static inline float8
37 peter@eisentraut.org 158 :GNC 152140189 : float8_mi(const float8 val1, const float8 val2)
159 : : {
160 : 152140189 : return float8_mi_safe(val1, val2, NULL);
161 : : }
162 : :
163 : : static inline float4
2837 tomas.vondra@postgre 164 :CBC 24 : float4_mul(const float4 val1, const float4 val2)
165 : : {
166 : : float4 result;
167 : :
168 : 24 : result = val1 * val2;
2273 tgl@sss.pgh.pa.us 169 [ - + - - : 24 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
- - ]
2273 tgl@sss.pgh.pa.us 170 :UBC 0 : float_overflow_error();
2273 tgl@sss.pgh.pa.us 171 [ - + - - :CBC 24 : if (unlikely(result == 0.0f) && val1 != 0.0f && val2 != 0.0f)
- - ]
2273 tgl@sss.pgh.pa.us 172 :UBC 0 : float_underflow_error();
173 : :
2837 tomas.vondra@postgre 174 :CBC 24 : return result;
175 : : }
176 : :
177 : : static inline float8
37 peter@eisentraut.org 178 :GNC 75337930 : float8_mul_safe(const float8 val1, const float8 val2, struct Node *escontext)
179 : : {
180 : : float8 result;
181 : :
2837 tomas.vondra@postgre 182 :CBC 75337930 : result = val1 * val2;
2273 tgl@sss.pgh.pa.us 183 [ + + + + : 75337930 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
+ + ]
37 peter@eisentraut.org 184 :GNC 16 : return float_overflow_error_ext(escontext);
2273 tgl@sss.pgh.pa.us 185 [ + + + + :CBC 75337914 : if (unlikely(result == 0.0) && val1 != 0.0 && val2 != 0.0)
+ + ]
37 peter@eisentraut.org 186 :GNC 4 : return float_underflow_error_ext(escontext);
187 : :
2837 tomas.vondra@postgre 188 :CBC 75337910 : return result;
189 : : }
190 : :
191 : : static inline float8
37 peter@eisentraut.org 192 :GNC 73896454 : float8_mul(const float8 val1, const float8 val2)
193 : : {
194 : 73896454 : return float8_mul_safe(val1, val2, NULL);
195 : : }
196 : :
197 : : static inline float4
2837 tomas.vondra@postgre 198 :CBC 4620749 : float4_div(const float4 val1, const float4 val2)
199 : : {
200 : : float4 result;
201 : :
2115 tgl@sss.pgh.pa.us 202 [ + + + + ]: 4620749 : if (unlikely(val2 == 0.0f) && !isnan(val1))
2273 203 : 4 : float_zero_divide_error();
2837 tomas.vondra@postgre 204 : 4620745 : result = val1 / val2;
2008 tgl@sss.pgh.pa.us 205 [ - + - - ]: 4620745 : if (unlikely(isinf(result)) && !isinf(val1))
2273 tgl@sss.pgh.pa.us 206 :UBC 0 : float_overflow_error();
2008 tgl@sss.pgh.pa.us 207 [ + + + - :CBC 4620745 : if (unlikely(result == 0.0f) && val1 != 0.0f && !isinf(val2))
- + ]
2273 tgl@sss.pgh.pa.us 208 :UBC 0 : float_underflow_error();
209 : :
2837 tomas.vondra@postgre 210 :CBC 4620745 : return result;
211 : : }
212 : :
213 : : static inline float8
37 peter@eisentraut.org 214 :GNC 12914417 : float8_div_safe(const float8 val1, const float8 val2, struct Node *escontext)
215 : : {
216 : : float8 result;
217 : :
2115 tgl@sss.pgh.pa.us 218 [ + + + + ]:CBC 12914417 : if (unlikely(val2 == 0.0) && !isnan(val1))
37 peter@eisentraut.org 219 :GNC 44 : return float_zero_divide_error_ext(escontext);
2837 tomas.vondra@postgre 220 :CBC 12914373 : result = val1 / val2;
2008 tgl@sss.pgh.pa.us 221 [ + + - + ]: 12914373 : if (unlikely(isinf(result)) && !isinf(val1))
37 peter@eisentraut.org 222 :UNC 0 : return float_overflow_error_ext(escontext);
2008 tgl@sss.pgh.pa.us 223 [ + + + + :CBC 12914373 : if (unlikely(result == 0.0) && val1 != 0.0 && !isinf(val2))
- + ]
37 peter@eisentraut.org 224 :UNC 0 : return float_underflow_error_ext(escontext);
225 : :
2837 tomas.vondra@postgre 226 :CBC 12914373 : return result;
227 : : }
228 : :
229 : : static inline float8
37 peter@eisentraut.org 230 :GNC 12888641 : float8_div(const float8 val1, const float8 val2)
231 : : {
232 : 12888641 : return float8_div_safe(val1, val2, NULL);
233 : : }
234 : :
235 : : /*
236 : : * Routines for NaN-aware comparisons
237 : : *
238 : : * We consider all NaNs to be equal and larger than any non-NaN. This is
239 : : * somewhat arbitrary; the important thing is to have a consistent sort
240 : : * order.
241 : : */
242 : :
243 : : static inline bool
2837 tomas.vondra@postgre 244 :CBC 36048 : float4_eq(const float4 val1, const float4 val2)
245 : : {
246 [ + + + - : 36048 : return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+ + ]
247 : : }
248 : :
249 : : static inline bool
250 : 11343459 : float8_eq(const float8 val1, const float8 val2)
251 : : {
252 [ + + + + : 11343459 : return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
+ + ]
253 : : }
254 : :
255 : : static inline bool
256 : 20 : float4_ne(const float4 val1, const float4 val2)
257 : : {
258 [ - + + - : 20 : return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+ + ]
259 : : }
260 : :
261 : : static inline bool
262 : 21671 : float8_ne(const float8 val1, const float8 val2)
263 : : {
264 [ - + + - : 21671 : return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
+ + ]
265 : : }
266 : :
267 : : static inline bool
268 : 9051009 : float4_lt(const float4 val1, const float4 val2)
269 : : {
270 [ + + + + : 9051009 : return !isnan(val1) && (isnan(val2) || val1 < val2);
+ + ]
271 : : }
272 : :
273 : : static inline bool
274 : 82756597 : float8_lt(const float8 val1, const float8 val2)
275 : : {
276 [ + + + + : 82756597 : return !isnan(val1) && (isnan(val2) || val1 < val2);
+ + ]
277 : : }
278 : :
279 : : static inline bool
280 : 2552 : float4_le(const float4 val1, const float4 val2)
281 : : {
282 [ + - + - : 2552 : return isnan(val2) || (!isnan(val1) && val1 <= val2);
+ + ]
283 : : }
284 : :
285 : : static inline bool
286 : 113183967 : float8_le(const float8 val1, const float8 val2)
287 : : {
288 [ + - + + : 113183967 : return isnan(val2) || (!isnan(val1) && val1 <= val2);
+ + ]
289 : : }
290 : :
291 : : static inline bool
292 : 9218140 : float4_gt(const float4 val1, const float4 val2)
293 : : {
294 [ + + + + : 9218140 : return !isnan(val2) && (isnan(val1) || val1 > val2);
+ + ]
295 : : }
296 : :
297 : : static inline bool
298 : 88270962 : float8_gt(const float8 val1, const float8 val2)
299 : : {
300 [ + + + + : 88270962 : return !isnan(val2) && (isnan(val1) || val1 > val2);
+ + ]
301 : : }
302 : :
303 : : static inline bool
304 : 2552 : float4_ge(const float4 val1, const float4 val2)
305 : : {
306 [ + - + - : 2552 : return isnan(val1) || (!isnan(val2) && val1 >= val2);
+ + ]
307 : : }
308 : :
309 : : static inline bool
310 : 5814228 : float8_ge(const float8 val1, const float8 val2)
311 : : {
312 [ + + + - : 5814228 : return isnan(val1) || (!isnan(val2) && val1 >= val2);
+ + ]
313 : : }
314 : :
315 : : static inline float4
316 : : float4_min(const float4 val1, const float4 val2)
317 : : {
318 : : return float4_lt(val1, val2) ? val1 : val2;
319 : : }
320 : :
321 : : static inline float8
322 : 62272266 : float8_min(const float8 val1, const float8 val2)
323 : : {
324 [ + + ]: 62272266 : return float8_lt(val1, val2) ? val1 : val2;
325 : : }
326 : :
327 : : static inline float4
328 : : float4_max(const float4 val1, const float4 val2)
329 : : {
330 : : return float4_gt(val1, val2) ? val1 : val2;
331 : : }
332 : :
333 : : static inline float8
334 : 62272266 : float8_max(const float8 val1, const float8 val2)
335 : : {
336 [ + + ]: 62272266 : return float8_gt(val1, val2) ? val1 : val2;
337 : : }
338 : :
339 : : #endif /* FLOAT_H */
|