LCOV - code coverage report
Current view: top level - src/include/utils - float.h (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 78 88 88.6 %
Date: 2024-04-19 18:11:10 Functions: 26 26 100.0 %
Legend: Lines: hit not hit

          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      433800 : get_float4_infinity(void)
      75             : {
      76             : #ifdef INFINITY
      77             :     /* C99 standard way */
      78      433800 :     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     1506308 : get_float8_infinity(void)
      95             : {
      96             : #ifdef INFINITY
      97             :     /* C99 standard way */
      98     1506308 :     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     5762794 : float8_pl(const float8 val1, const float8 val2)
     159             : {
     160             :     float8      result;
     161             : 
     162     5762794 :     result = val1 + val2;
     163     5762794 :     if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
     164           0 :         float_overflow_error();
     165             : 
     166     5762794 :     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   260597084 : float8_mi(const float8 val1, const float8 val2)
     183             : {
     184             :     float8      result;
     185             : 
     186   260597084 :     result = val1 - val2;
     187   260597084 :     if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
     188           0 :         float_overflow_error();
     189             : 
     190   260597084 :     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   112357066 : float8_mul(const float8 val1, const float8 val2)
     209             : {
     210             :     float8      result;
     211             : 
     212   112357066 :     result = val1 * val2;
     213   112357066 :     if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
     214          24 :         float_overflow_error();
     215   112357042 :     if (unlikely(result == 0.0) && val1 != 0.0 && val2 != 0.0)
     216           6 :         float_underflow_error();
     217             : 
     218   112357036 :     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    19426536 : float8_div(const float8 val1, const float8 val2)
     239             : {
     240             :     float8      result;
     241             : 
     242    19426536 :     if (unlikely(val2 == 0.0) && !isnan(val1))
     243          66 :         float_zero_divide_error();
     244    19426470 :     result = val1 / val2;
     245    19426470 :     if (unlikely(isinf(result)) && !isinf(val1))
     246           0 :         float_overflow_error();
     247    19426470 :     if (unlikely(result == 0.0) && val1 != 0.0 && !isinf(val2))
     248           0 :         float_underflow_error();
     249             : 
     250    19426470 :     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       44854 : float4_eq(const float4 val1, const float4 val2)
     263             : {
     264       44854 :     return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
     265             : }
     266             : 
     267             : static inline bool
     268    16927738 : float8_eq(const float8 val1, const float8 val2)
     269             : {
     270    16927738 :     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       19962 : float8_ne(const float8 val1, const float8 val2)
     281             : {
     282       19962 :     return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
     283             : }
     284             : 
     285             : static inline bool
     286    10891400 : float4_lt(const float4 val1, const float4 val2)
     287             : {
     288    10891400 :     return !isnan(val1) && (isnan(val2) || val1 < val2);
     289             : }
     290             : 
     291             : static inline bool
     292   124141588 : float8_lt(const float8 val1, const float8 val2)
     293             : {
     294   124141588 :     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   170311968 : float8_le(const float8 val1, const float8 val2)
     305             : {
     306   170311968 :     return isnan(val2) || (!isnan(val1) && val1 <= val2);
     307             : }
     308             : 
     309             : static inline bool
     310    11111776 : float4_gt(const float4 val1, const float4 val2)
     311             : {
     312    11111776 :     return !isnan(val2) && (isnan(val1) || val1 > val2);
     313             : }
     314             : 
     315             : static inline bool
     316   132221694 : float8_gt(const float8 val1, const float8 val2)
     317             : {
     318   132221694 :     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     7926670 : float8_ge(const float8 val1, const float8 val2)
     329             : {
     330     7926670 :     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    93594060 : float8_min(const float8 val1, const float8 val2)
     341             : {
     342    93594060 :     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    93594060 : float8_max(const float8 val1, const float8 val2)
     353             : {
     354    93594060 :     return float8_gt(val1, val2) ? val1 : val2;
     355             : }
     356             : 
     357             : #endif                          /* FLOAT_H */

Generated by: LCOV version 1.14