2018-07-29 03:30:48 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* float.h
|
|
|
|
* Definitions for the built-in floating-point types
|
|
|
|
*
|
2018-07-31 17:50:28 +02:00
|
|
|
* Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
|
2018-07-29 03:30:48 +02:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2018-07-31 17:50:28 +02:00
|
|
|
* src/include/utils/float.h
|
2018-07-29 03:30:48 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#ifndef FLOAT_H
|
|
|
|
#define FLOAT_H
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#ifndef M_PI
|
|
|
|
/* From my RH5.2 gcc math.h file - thomas 2000-04-03 */
|
|
|
|
#define M_PI 3.14159265358979323846
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Radians per degree, a.k.a. PI / 180 */
|
|
|
|
#define RADIANS_PER_DEGREE 0.0174532925199432957692
|
|
|
|
|
|
|
|
/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0. */
|
|
|
|
#if defined(WIN32) && !defined(NAN)
|
|
|
|
static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
|
|
|
|
|
|
|
|
#define NAN (*(const float8 *) nan)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
extern PGDLLIMPORT int extra_float_digits;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Utility functions in float.c
|
|
|
|
*/
|
|
|
|
extern int is_infinite(float8 val);
|
|
|
|
extern float8 float8in_internal(char *num, char **endptr_p,
|
|
|
|
const char *type_name, const char *orig_string);
|
|
|
|
extern char *float8out_internal(float8 num);
|
|
|
|
extern int float4_cmp_internal(float4 a, float4 b);
|
|
|
|
extern int float8_cmp_internal(float8 a, float8 b);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Routines to provide reasonably platform-independent handling of
|
|
|
|
* infinity and NaN
|
|
|
|
*
|
|
|
|
* We assume that isinf() and isnan() are available and work per spec.
|
|
|
|
* (On some platforms, we have to supply our own; see src/port.) However,
|
|
|
|
* generating an Infinity or NaN in the first place is less well standardized;
|
|
|
|
* pre-C99 systems tend not to have C99's INFINITY and NaN macros. We
|
|
|
|
* centralize our workarounds for this here.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The funny placements of the two #pragmas is necessary because of a
|
|
|
|
* long lived bug in the Microsoft compilers.
|
|
|
|
* See http://support.microsoft.com/kb/120968/en-us for details
|
|
|
|
*/
|
|
|
|
#if (_MSC_VER >= 1800)
|
|
|
|
#pragma warning(disable:4756)
|
|
|
|
#endif
|
|
|
|
static inline float4
|
|
|
|
get_float4_infinity(void)
|
|
|
|
{
|
|
|
|
#ifdef INFINITY
|
|
|
|
/* C99 standard way */
|
|
|
|
return (float4) INFINITY;
|
|
|
|
#else
|
|
|
|
#if (_MSC_VER >= 1800)
|
|
|
|
#pragma warning(default:4756)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
|
|
|
|
* largest normal float8. We assume forcing an overflow will get us a
|
|
|
|
* true infinity.
|
|
|
|
*/
|
|
|
|
return (float4) (HUGE_VAL * HUGE_VAL);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline float8
|
|
|
|
get_float8_infinity(void)
|
|
|
|
{
|
|
|
|
#ifdef INFINITY
|
|
|
|
/* C99 standard way */
|
|
|
|
return (float8) INFINITY;
|
|
|
|
#else
|
|
|
|
|
|
|
|
/*
|
|
|
|
* On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
|
|
|
|
* largest normal float8. We assume forcing an overflow will get us a
|
|
|
|
* true infinity.
|
|
|
|
*/
|
|
|
|
return (float8) (HUGE_VAL * HUGE_VAL);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline float4
|
|
|
|
get_float4_nan(void)
|
|
|
|
{
|
|
|
|
#ifdef NAN
|
|
|
|
/* C99 standard way */
|
|
|
|
return (float4) NAN;
|
|
|
|
#else
|
|
|
|
/* Assume we can get a NAN via zero divide */
|
|
|
|
return (float4) (0.0 / 0.0);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline float8
|
|
|
|
get_float8_nan(void)
|
|
|
|
{
|
|
|
|
/* (float8) NAN doesn't work on some NetBSD/MIPS releases */
|
|
|
|
#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
|
|
|
|
/* C99 standard way */
|
|
|
|
return (float8) NAN;
|
|
|
|
#else
|
|
|
|
/* Assume we can get a NaN via zero divide */
|
|
|
|
return (float8) (0.0 / 0.0);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Checks to see if a float4/8 val has underflowed or overflowed
|
|
|
|
*/
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
check_float4_val(const float4 val, const bool inf_is_valid,
|
|
|
|
const bool zero_is_valid)
|
|
|
|
{
|
|
|
|
if (!inf_is_valid && unlikely(isinf(val)))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("value out of range: overflow")));
|
|
|
|
|
|
|
|
if (!zero_is_valid && unlikely(val == 0.0))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("value out of range: underflow")));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
check_float8_val(const float8 val, const bool inf_is_valid,
|
|
|
|
const bool zero_is_valid)
|
|
|
|
{
|
|
|
|
if (!inf_is_valid && unlikely(isinf(val)))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("value out of range: overflow")));
|
|
|
|
|
|
|
|
if (!zero_is_valid && unlikely(val == 0.0))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("value out of range: underflow")));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Routines for operations with the checks above
|
|
|
|
*
|
|
|
|
* There isn't any way to check for underflow of addition/subtraction
|
|
|
|
* because numbers near the underflow value have already been rounded to
|
|
|
|
* the point where we can't detect that the two values were originally
|
|
|
|
* different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
|
|
|
|
* 1.4013e-45.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static inline float4
|
|
|
|
float4_pl(const float4 val1, const float4 val2)
|
|
|
|
{
|
|
|
|
float4 result;
|
|
|
|
|
|
|
|
result = val1 + val2;
|
|
|
|
check_float4_val(result, isinf(val1) || isinf(val2), true);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline float8
|
|
|
|
float8_pl(const float8 val1, const float8 val2)
|
|
|
|
{
|
|
|
|
float8 result;
|
|
|
|
|
|
|
|
result = val1 + val2;
|
|
|
|
check_float8_val(result, isinf(val1) || isinf(val2), true);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline float4
|
|
|
|
float4_mi(const float4 val1, const float4 val2)
|
|
|
|
{
|
|
|
|
float4 result;
|
|
|
|
|
|
|
|
result = val1 - val2;
|
|
|
|
check_float4_val(result, isinf(val1) || isinf(val2), true);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline float8
|
|
|
|
float8_mi(const float8 val1, const float8 val2)
|
|
|
|
{
|
|
|
|
float8 result;
|
|
|
|
|
|
|
|
result = val1 - val2;
|
|
|
|
check_float8_val(result, isinf(val1) || isinf(val2), true);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline float4
|
|
|
|
float4_mul(const float4 val1, const float4 val2)
|
|
|
|
{
|
|
|
|
float4 result;
|
|
|
|
|
|
|
|
result = val1 * val2;
|
|
|
|
check_float4_val(result, isinf(val1) || isinf(val2),
|
|
|
|
val1 == 0.0f || val2 == 0.0f);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline float8
|
|
|
|
float8_mul(const float8 val1, const float8 val2)
|
|
|
|
{
|
|
|
|
float8 result;
|
|
|
|
|
|
|
|
result = val1 * val2;
|
|
|
|
check_float8_val(result, isinf(val1) || isinf(val2),
|
|
|
|
val1 == 0.0 || val2 == 0.0);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline float4
|
|
|
|
float4_div(const float4 val1, const float4 val2)
|
|
|
|
{
|
|
|
|
float4 result;
|
|
|
|
|
|
|
|
if (val2 == 0.0f)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DIVISION_BY_ZERO),
|
|
|
|
errmsg("division by zero")));
|
|
|
|
|
|
|
|
result = val1 / val2;
|
|
|
|
check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline float8
|
|
|
|
float8_div(const float8 val1, const float8 val2)
|
|
|
|
{
|
|
|
|
float8 result;
|
|
|
|
|
|
|
|
if (val2 == 0.0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DIVISION_BY_ZERO),
|
|
|
|
errmsg("division by zero")));
|
|
|
|
|
|
|
|
result = val1 / val2;
|
|
|
|
check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Routines for NaN-aware comparisons
|
|
|
|
*
|
|
|
|
* We consider all NaNs to be equal and larger than any non-NaN. This is
|
|
|
|
* somewhat arbitrary; the important thing is to have a consistent sort
|
|
|
|
* order.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
float4_eq(const float4 val1, const float4 val2)
|
|
|
|
{
|
|
|
|
return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
float8_eq(const float8 val1, const float8 val2)
|
|
|
|
{
|
|
|
|
return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
float4_ne(const float4 val1, const float4 val2)
|
|
|
|
{
|
|
|
|
return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
float8_ne(const float8 val1, const float8 val2)
|
|
|
|
{
|
|
|
|
return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
float4_lt(const float4 val1, const float4 val2)
|
|
|
|
{
|
|
|
|
return !isnan(val1) && (isnan(val2) || val1 < val2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
float8_lt(const float8 val1, const float8 val2)
|
|
|
|
{
|
|
|
|
return !isnan(val1) && (isnan(val2) || val1 < val2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
float4_le(const float4 val1, const float4 val2)
|
|
|
|
{
|
|
|
|
return isnan(val2) || (!isnan(val1) && val1 <= val2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
float8_le(const float8 val1, const float8 val2)
|
|
|
|
{
|
|
|
|
return isnan(val2) || (!isnan(val1) && val1 <= val2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
float4_gt(const float4 val1, const float4 val2)
|
|
|
|
{
|
|
|
|
return !isnan(val2) && (isnan(val1) || val1 > val2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
float8_gt(const float8 val1, const float8 val2)
|
|
|
|
{
|
|
|
|
return !isnan(val2) && (isnan(val1) || val1 > val2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
float4_ge(const float4 val1, const float4 val2)
|
|
|
|
{
|
|
|
|
return isnan(val1) || (!isnan(val2) && val1 >= val2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
float8_ge(const float8 val1, const float8 val2)
|
|
|
|
{
|
|
|
|
return isnan(val1) || (!isnan(val2) && val1 >= val2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline float4
|
|
|
|
float4_min(const float4 val1, const float4 val2)
|
|
|
|
{
|
|
|
|
return float4_lt(val1, val2) ? val1 : val2;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline float8
|
|
|
|
float8_min(const float8 val1, const float8 val2)
|
|
|
|
{
|
|
|
|
return float8_lt(val1, val2) ? val1 : val2;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline float4
|
|
|
|
float4_max(const float4 val1, const float4 val2)
|
|
|
|
{
|
|
|
|
return float4_gt(val1, val2) ? val1 : val2;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline float8
|
|
|
|
float8_max(const float8 val1, const float8 val2)
|
|
|
|
{
|
|
|
|
return float8_gt(val1, val2) ? val1 : val2;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* FLOAT_H */
|