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