1/*-------------------------------------------------------------------------
2 *
3 * float.h
4 * Definitions for the built-in floating-point types
5 *
6 * Portions Copyright (c) 1996-2019, 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#ifndef M_PI
21/* From my RH5.2 gcc math.h file - thomas 2000-04-03 */
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)
30static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
31
32#define NAN (*(const float8 *) nan)
33#endif
34
35extern PGDLLIMPORT int extra_float_digits;
36
37/*
38 * Utility functions in float.c
39 */
40extern int is_infinite(float8 val);
41extern float8 float8in_internal(char *num, char **endptr_p,
42 const char *type_name, const char *orig_string);
43extern float8 float8in_internal_opt_error(char *num, char **endptr_p,
44 const char *type_name, const char *orig_string,
45 bool *have_error);
46extern char *float8out_internal(float8 num);
47extern int float4_cmp_internal(float4 a, float4 b);
48extern int float8_cmp_internal(float8 a, float8 b);
49
50/*
51 * Routines to provide reasonably platform-independent handling of
52 * infinity and NaN
53 *
54 * We assume that isinf() and isnan() are available and work per spec.
55 * (On some platforms, we have to supply our own; see src/port.) However,
56 * generating an Infinity or NaN in the first place is less well standardized;
57 * pre-C99 systems tend not to have C99's INFINITY and NaN macros. We
58 * centralize our workarounds for this here.
59 */
60
61/*
62 * The funny placements of the two #pragmas is necessary because of a
63 * long lived bug in the Microsoft compilers.
64 * See http://support.microsoft.com/kb/120968/en-us for details
65 */
66#if (_MSC_VER >= 1800)
67#pragma warning(disable:4756)
68#endif
69static inline float4
70get_float4_infinity(void)
71{
72#ifdef INFINITY
73 /* C99 standard way */
74 return (float4) INFINITY;
75#else
76#if (_MSC_VER >= 1800)
77#pragma warning(default:4756)
78#endif
79
80 /*
81 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
82 * largest normal float8. We assume forcing an overflow will get us a
83 * true infinity.
84 */
85 return (float4) (HUGE_VAL * HUGE_VAL);
86#endif
87}
88
89static inline float8
90get_float8_infinity(void)
91{
92#ifdef INFINITY
93 /* C99 standard way */
94 return (float8) INFINITY;
95#else
96
97 /*
98 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
99 * largest normal float8. We assume forcing an overflow will get us a
100 * true infinity.
101 */
102 return (float8) (HUGE_VAL * HUGE_VAL);
103#endif
104}
105
106static inline float4
107get_float4_nan(void)
108{
109#ifdef NAN
110 /* C99 standard way */
111 return (float4) NAN;
112#else
113 /* Assume we can get a NAN via zero divide */
114 return (float4) (0.0 / 0.0);
115#endif
116}
117
118static inline float8
119get_float8_nan(void)
120{
121 /* (float8) NAN doesn't work on some NetBSD/MIPS releases */
122#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
123 /* C99 standard way */
124 return (float8) NAN;
125#else
126 /* Assume we can get a NaN via zero divide */
127 return (float8) (0.0 / 0.0);
128#endif
129}
130
131/*
132 * Checks to see if a float4/8 val has underflowed or overflowed
133 */
134
135static inline void
136check_float4_val(const float4 val, const bool inf_is_valid,
137 const bool zero_is_valid)
138{
139 if (!inf_is_valid && unlikely(isinf(val)))
140 ereport(ERROR,
141 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
142 errmsg("value out of range: overflow")));
143
144 if (!zero_is_valid && unlikely(val == 0.0))
145 ereport(ERROR,
146 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
147 errmsg("value out of range: underflow")));
148}
149
150static inline void
151check_float8_val(const float8 val, const bool inf_is_valid,
152 const bool zero_is_valid)
153{
154 if (!inf_is_valid && unlikely(isinf(val)))
155 ereport(ERROR,
156 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
157 errmsg("value out of range: overflow")));
158
159 if (!zero_is_valid && unlikely(val == 0.0))
160 ereport(ERROR,
161 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
162 errmsg("value out of range: underflow")));
163}
164
165/*
166 * Routines for operations with the checks above
167 *
168 * There isn't any way to check for underflow of addition/subtraction
169 * because numbers near the underflow value have already been rounded to
170 * the point where we can't detect that the two values were originally
171 * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
172 * 1.4013e-45.
173 */
174
175static inline float4
176float4_pl(const float4 val1, const float4 val2)
177{
178 float4 result;
179
180 result = val1 + val2;
181 check_float4_val(result, isinf(val1) || isinf(val2), true);
182
183 return result;
184}
185
186static inline float8
187float8_pl(const float8 val1, const float8 val2)
188{
189 float8 result;
190
191 result = val1 + val2;
192 check_float8_val(result, isinf(val1) || isinf(val2), true);
193
194 return result;
195}
196
197static inline float4
198float4_mi(const float4 val1, const float4 val2)
199{
200 float4 result;
201
202 result = val1 - val2;
203 check_float4_val(result, isinf(val1) || isinf(val2), true);
204
205 return result;
206}
207
208static inline float8
209float8_mi(const float8 val1, const float8 val2)
210{
211 float8 result;
212
213 result = val1 - val2;
214 check_float8_val(result, isinf(val1) || isinf(val2), true);
215
216 return result;
217}
218
219static inline float4
220float4_mul(const float4 val1, const float4 val2)
221{
222 float4 result;
223
224 result = val1 * val2;
225 check_float4_val(result, isinf(val1) || isinf(val2),
226 val1 == 0.0f || val2 == 0.0f);
227
228 return result;
229}
230
231static inline float8
232float8_mul(const float8 val1, const float8 val2)
233{
234 float8 result;
235
236 result = val1 * val2;
237 check_float8_val(result, isinf(val1) || isinf(val2),
238 val1 == 0.0 || val2 == 0.0);
239
240 return result;
241}
242
243static inline float4
244float4_div(const float4 val1, const float4 val2)
245{
246 float4 result;
247
248 if (val2 == 0.0f)
249 ereport(ERROR,
250 (errcode(ERRCODE_DIVISION_BY_ZERO),
251 errmsg("division by zero")));
252
253 result = val1 / val2;
254 check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
255
256 return result;
257}
258
259static inline float8
260float8_div(const float8 val1, const float8 val2)
261{
262 float8 result;
263
264 if (val2 == 0.0)
265 ereport(ERROR,
266 (errcode(ERRCODE_DIVISION_BY_ZERO),
267 errmsg("division by zero")));
268
269 result = val1 / val2;
270 check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
271
272 return result;
273}
274
275/*
276 * Routines for NaN-aware comparisons
277 *
278 * We consider all NaNs to be equal and larger than any non-NaN. This is
279 * somewhat arbitrary; the important thing is to have a consistent sort
280 * order.
281 */
282
283static inline bool
284float4_eq(const float4 val1, const float4 val2)
285{
286 return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
287}
288
289static inline bool
290float8_eq(const float8 val1, const float8 val2)
291{
292 return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
293}
294
295static inline bool
296float4_ne(const float4 val1, const float4 val2)
297{
298 return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
299}
300
301static inline bool
302float8_ne(const float8 val1, const float8 val2)
303{
304 return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
305}
306
307static inline bool
308float4_lt(const float4 val1, const float4 val2)
309{
310 return !isnan(val1) && (isnan(val2) || val1 < val2);
311}
312
313static inline bool
314float8_lt(const float8 val1, const float8 val2)
315{
316 return !isnan(val1) && (isnan(val2) || val1 < val2);
317}
318
319static inline bool
320float4_le(const float4 val1, const float4 val2)
321{
322 return isnan(val2) || (!isnan(val1) && val1 <= val2);
323}
324
325static inline bool
326float8_le(const float8 val1, const float8 val2)
327{
328 return isnan(val2) || (!isnan(val1) && val1 <= val2);
329}
330
331static inline bool
332float4_gt(const float4 val1, const float4 val2)
333{
334 return !isnan(val2) && (isnan(val1) || val1 > val2);
335}
336
337static inline bool
338float8_gt(const float8 val1, const float8 val2)
339{
340 return !isnan(val2) && (isnan(val1) || val1 > val2);
341}
342
343static inline bool
344float4_ge(const float4 val1, const float4 val2)
345{
346 return isnan(val1) || (!isnan(val2) && val1 >= val2);
347}
348
349static inline bool
350float8_ge(const float8 val1, const float8 val2)
351{
352 return isnan(val1) || (!isnan(val2) && val1 >= val2);
353}
354
355static inline float4
356float4_min(const float4 val1, const float4 val2)
357{
358 return float4_lt(val1, val2) ? val1 : val2;
359}
360
361static inline float8
362float8_min(const float8 val1, const float8 val2)
363{
364 return float8_lt(val1, val2) ? val1 : val2;
365}
366
367static inline float4
368float4_max(const float4 val1, const float4 val2)
369{
370 return float4_gt(val1, val2) ? val1 : val2;
371}
372
373static inline float8
374float8_max(const float8 val1, const float8 val2)
375{
376 return float8_gt(val1, val2) ? val1 : val2;
377}
378
379#endif /* FLOAT_H */
380