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
74 416268 : get_float4_infinity(void)
75 : {
76 : #ifdef INFINITY
77 : /* C99 standard way */
78 416268 : 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 1506406 : get_float8_infinity(void)
95 : {
96 : #ifdef INFINITY
97 : /* C99 standard way */
98 1506406 : 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 30 : get_float4_nan(void)
112 : {
113 : #ifdef NAN
114 : /* C99 standard way */
115 30 : 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 21732 : 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 21732 : 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 54 : float4_pl(const float4 val1, const float4 val2)
147 : {
148 : float4 result;
149 :
150 54 : result = val1 + val2;
151 54 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
152 0 : float_overflow_error();
153 :
154 54 : return result;
155 : }
156 :
157 : static inline float8
158 5754352 : float8_pl(const float8 val1, const float8 val2)
159 : {
160 : float8 result;
161 :
162 5754352 : result = val1 + val2;
163 5754352 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
164 0 : float_overflow_error();
165 :
166 5754352 : return result;
167 : }
168 :
169 : static inline float4
170 18 : float4_mi(const float4 val1, const float4 val2)
171 : {
172 : float4 result;
173 :
174 18 : result = val1 - val2;
175 18 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
176 0 : float_overflow_error();
177 :
178 18 : return result;
179 : }
180 :
181 : static inline float8
182 260762112 : float8_mi(const float8 val1, const float8 val2)
183 : {
184 : float8 result;
185 :
186 260762112 : result = val1 - val2;
187 260762112 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
188 0 : float_overflow_error();
189 :
190 260762112 : return result;
191 : }
192 :
193 : static inline float4
194 36 : float4_mul(const float4 val1, const float4 val2)
195 : {
196 : float4 result;
197 :
198 36 : result = val1 * val2;
199 36 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
200 0 : float_overflow_error();
201 36 : if (unlikely(result == 0.0f) && val1 != 0.0f && val2 != 0.0f)
202 0 : float_underflow_error();
203 :
204 36 : return result;
205 : }
206 :
207 : static inline float8
208 112414052 : float8_mul(const float8 val1, const float8 val2)
209 : {
210 : float8 result;
211 :
212 112414052 : result = val1 * val2;
213 112414052 : if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
214 24 : float_overflow_error();
215 112414028 : if (unlikely(result == 0.0) && val1 != 0.0 && val2 != 0.0)
216 6 : float_underflow_error();
217 :
218 112414022 : return result;
219 : }
220 :
221 : static inline float4
222 7066482 : float4_div(const float4 val1, const float4 val2)
223 : {
224 : float4 result;
225 :
226 7066482 : if (unlikely(val2 == 0.0f) && !isnan(val1))
227 6 : float_zero_divide_error();
228 7066476 : result = val1 / val2;
229 7066476 : if (unlikely(isinf(result)) && !isinf(val1))
230 0 : float_overflow_error();
231 7066476 : if (unlikely(result == 0.0f) && val1 != 0.0f && !isinf(val2))
232 0 : float_underflow_error();
233 :
234 7066476 : return result;
235 : }
236 :
237 : static inline float8
238 19426510 : float8_div(const float8 val1, const float8 val2)
239 : {
240 : float8 result;
241 :
242 19426510 : if (unlikely(val2 == 0.0) && !isnan(val1))
243 66 : float_zero_divide_error();
244 19426444 : result = val1 / val2;
245 19426444 : if (unlikely(isinf(result)) && !isinf(val1))
246 0 : float_overflow_error();
247 19426444 : if (unlikely(result == 0.0) && val1 != 0.0 && !isinf(val2))
248 0 : float_underflow_error();
249 :
250 19426444 : 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 47974 : float4_eq(const float4 val1, const float4 val2)
263 : {
264 47974 : return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
265 : }
266 :
267 : static inline bool
268 17303394 : float8_eq(const float8 val1, const float8 val2)
269 : {
270 17303394 : return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
271 : }
272 :
273 : static inline bool
274 30 : float4_ne(const float4 val1, const float4 val2)
275 : {
276 30 : return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
277 : }
278 :
279 : static inline bool
280 36222 : float8_ne(const float8 val1, const float8 val2)
281 : {
282 36222 : return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
283 : }
284 :
285 : static inline bool
286 11883448 : float4_lt(const float4 val1, const float4 val2)
287 : {
288 11883448 : return !isnan(val1) && (isnan(val2) || val1 < val2);
289 : }
290 :
291 : static inline bool
292 124212214 : float8_lt(const float8 val1, const float8 val2)
293 : {
294 124212214 : return !isnan(val1) && (isnan(val2) || val1 < val2);
295 : }
296 :
297 : static inline bool
298 3828 : float4_le(const float4 val1, const float4 val2)
299 : {
300 3828 : return isnan(val2) || (!isnan(val1) && val1 <= val2);
301 : }
302 :
303 : static inline bool
304 170444184 : float8_le(const float8 val1, const float8 val2)
305 : {
306 170444184 : return isnan(val2) || (!isnan(val1) && val1 <= val2);
307 : }
308 :
309 : static inline bool
310 12137500 : float4_gt(const float4 val1, const float4 val2)
311 : {
312 12137500 : return !isnan(val2) && (isnan(val1) || val1 > val2);
313 : }
314 :
315 : static inline bool
316 132310082 : float8_gt(const float8 val1, const float8 val2)
317 : {
318 132310082 : return !isnan(val2) && (isnan(val1) || val1 > val2);
319 : }
320 :
321 : static inline bool
322 3828 : float4_ge(const float4 val1, const float4 val2)
323 : {
324 3828 : return isnan(val1) || (!isnan(val2) && val1 >= val2);
325 : }
326 :
327 : static inline bool
328 7926896 : float8_ge(const float8 val1, const float8 val2)
329 : {
330 7926896 : 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 93660040 : float8_min(const float8 val1, const float8 val2)
341 : {
342 93660040 : 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 93660040 : float8_max(const float8 val1, const float8 val2)
353 : {
354 93660040 : return float8_gt(val1, val2) ? val1 : val2;
355 : }
356 :
357 : #endif /* FLOAT_H */
|