LCOV - code coverage report
Current view: top level - Include/internal - pycore_pymath.h (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit acb105a7c1f] Lines: 14 15 93.3 %
Date: 2022-07-20 13:12:14 Functions: 2 2 100.0 %
Branches: 17 22 77.3 %

           Branch data     Line data    Source code
       1                 :            : #ifndef Py_INTERNAL_PYMATH_H
       2                 :            : #define Py_INTERNAL_PYMATH_H
       3                 :            : #ifdef __cplusplus
       4                 :            : extern "C" {
       5                 :            : #endif
       6                 :            : 
       7                 :            : #ifndef Py_BUILD_CORE
       8                 :            : #  error "this header requires Py_BUILD_CORE define"
       9                 :            : #endif
      10                 :            : 
      11                 :            : 
      12                 :            : /* _Py_ADJUST_ERANGE1(x)
      13                 :            :  * _Py_ADJUST_ERANGE2(x, y)
      14                 :            :  * Set errno to 0 before calling a libm function, and invoke one of these
      15                 :            :  * macros after, passing the function result(s) (_Py_ADJUST_ERANGE2 is useful
      16                 :            :  * for functions returning complex results).  This makes two kinds of
      17                 :            :  * adjustments to errno:  (A) If it looks like the platform libm set
      18                 :            :  * errno=ERANGE due to underflow, clear errno. (B) If it looks like the
      19                 :            :  * platform libm overflowed but didn't set errno, force errno to ERANGE.  In
      20                 :            :  * effect, we're trying to force a useful implementation of C89 errno
      21                 :            :  * behavior.
      22                 :            :  * Caution:
      23                 :            :  *    This isn't reliable.  C99 no longer requires libm to set errno under
      24                 :            :  *        any exceptional condition, but does require +- HUGE_VAL return
      25                 :            :  *        values on overflow.  A 754 box *probably* maps HUGE_VAL to a
      26                 :            :  *        double infinity, and we're cool if that's so, unless the input
      27                 :            :  *        was an infinity and an infinity is the expected result.  A C89
      28                 :            :  *        system sets errno to ERANGE, so we check for that too.  We're
      29                 :            :  *        out of luck if a C99 754 box doesn't map HUGE_VAL to +Inf, or
      30                 :            :  *        if the returned result is a NaN, or if a C89 box returns HUGE_VAL
      31                 :            :  *        in non-overflow cases.
      32                 :            :  */
      33                 :     254832 : static inline void _Py_ADJUST_ERANGE1(double x)
      34                 :            : {
      35         [ +  + ]:     254832 :     if (errno == 0) {
      36   [ +  -  -  + ]:     254812 :         if (x == Py_HUGE_VAL || x == -Py_HUGE_VAL) {
      37                 :          0 :             errno = ERANGE;
      38                 :            :         }
      39                 :            :     }
      40   [ +  -  +  - ]:         20 :     else if (errno == ERANGE && x == 0.0) {
      41                 :         20 :         errno = 0;
      42                 :            :     }
      43                 :     254832 : }
      44                 :            : 
      45                 :        250 : static inline void _Py_ADJUST_ERANGE2(double x, double y)
      46                 :            : {
      47   [ +  +  +  +  :        250 :     if (x == Py_HUGE_VAL || x == -Py_HUGE_VAL ||
                   +  + ]
      48         [ -  + ]:        225 :         y == Py_HUGE_VAL || y == -Py_HUGE_VAL)
      49                 :            :     {
      50         [ +  + ]:         25 :         if (errno == 0) {
      51                 :          6 :             errno = ERANGE;
      52                 :            :         }
      53                 :            :     }
      54         [ +  + ]:        225 :     else if (errno == ERANGE) {
      55                 :         58 :         errno = 0;
      56                 :            :     }
      57                 :        250 : }
      58                 :            : 
      59                 :            : // Return the maximum value of integral type *type*.
      60                 :            : #define _Py_IntegralTypeMax(type) \
      61                 :            :     (_Py_IS_TYPE_SIGNED(type) ? (((((type)1 << (sizeof(type)*CHAR_BIT - 2)) - 1) << 1) + 1) : ~(type)0)
      62                 :            : 
      63                 :            : // Return the minimum value of integral type *type*.
      64                 :            : #define _Py_IntegralTypeMin(type) \
      65                 :            :     (_Py_IS_TYPE_SIGNED(type) ? -_Py_IntegralTypeMax(type) - 1 : 0)
      66                 :            : 
      67                 :            : // Check whether *v* is in the range of integral type *type*. This is most
      68                 :            : // useful if *v* is floating-point, since demoting a floating-point *v* to an
      69                 :            : // integral type that cannot represent *v*'s integral part is undefined
      70                 :            : // behavior.
      71                 :            : #define _Py_InIntegralTypeRange(type, v) \
      72                 :            :     (_Py_IntegralTypeMin(type) <= v && v <= _Py_IntegralTypeMax(type))
      73                 :            : 
      74                 :            : 
      75                 :            : //--- HAVE_PY_SET_53BIT_PRECISION macro ------------------------------------
      76                 :            : //
      77                 :            : // The functions _Py_dg_strtod() and _Py_dg_dtoa() in Python/dtoa.c (which are
      78                 :            : // required to support the short float repr introduced in Python 3.1) require
      79                 :            : // that the floating-point unit that's being used for arithmetic operations on
      80                 :            : // C doubles is set to use 53-bit precision.  It also requires that the FPU
      81                 :            : // rounding mode is round-half-to-even, but that's less often an issue.
      82                 :            : //
      83                 :            : // If your FPU isn't already set to 53-bit precision/round-half-to-even, and
      84                 :            : // you want to make use of _Py_dg_strtod() and _Py_dg_dtoa(), then you should:
      85                 :            : //
      86                 :            : //     #define HAVE_PY_SET_53BIT_PRECISION 1
      87                 :            : //
      88                 :            : // and also give appropriate definitions for the following three macros:
      89                 :            : //
      90                 :            : // * _Py_SET_53BIT_PRECISION_HEADER: any variable declarations needed to
      91                 :            : //   use the two macros below.
      92                 :            : // * _Py_SET_53BIT_PRECISION_START: store original FPU settings, and
      93                 :            : //   set FPU to 53-bit precision/round-half-to-even
      94                 :            : // * _Py_SET_53BIT_PRECISION_END: restore original FPU settings
      95                 :            : //
      96                 :            : // The macros are designed to be used within a single C function: see
      97                 :            : // Python/pystrtod.c for an example of their use.
      98                 :            : 
      99                 :            : 
     100                 :            : // Get and set x87 control word for gcc/x86
     101                 :            : #ifdef HAVE_GCC_ASM_FOR_X87
     102                 :            : #define HAVE_PY_SET_53BIT_PRECISION 1
     103                 :            : 
     104                 :            : // Functions defined in Python/pymath.c
     105                 :            : extern unsigned short _Py_get_387controlword(void);
     106                 :            : extern void _Py_set_387controlword(unsigned short);
     107                 :            : 
     108                 :            : #define _Py_SET_53BIT_PRECISION_HEADER                                  \
     109                 :            :     unsigned short old_387controlword, new_387controlword
     110                 :            : #define _Py_SET_53BIT_PRECISION_START                                   \
     111                 :            :     do {                                                                \
     112                 :            :         old_387controlword = _Py_get_387controlword();                  \
     113                 :            :         new_387controlword = (old_387controlword & ~0x0f00) | 0x0200;   \
     114                 :            :         if (new_387controlword != old_387controlword) {                 \
     115                 :            :             _Py_set_387controlword(new_387controlword);                 \
     116                 :            :         }                                                               \
     117                 :            :     } while (0)
     118                 :            : #define _Py_SET_53BIT_PRECISION_END                                     \
     119                 :            :     do {                                                                \
     120                 :            :         if (new_387controlword != old_387controlword) {                 \
     121                 :            :             _Py_set_387controlword(old_387controlword);                 \
     122                 :            :         }                                                               \
     123                 :            :     } while (0)
     124                 :            : #endif
     125                 :            : 
     126                 :            : // Get and set x87 control word for VisualStudio/x86.
     127                 :            : // x87 is not supported in 64-bit or ARM.
     128                 :            : #if defined(_MSC_VER) && !defined(_WIN64) && !defined(_M_ARM)
     129                 :            : #define HAVE_PY_SET_53BIT_PRECISION 1
     130                 :            : 
     131                 :            : #include <float.h>                // __control87_2()
     132                 :            : 
     133                 :            : #define _Py_SET_53BIT_PRECISION_HEADER \
     134                 :            :     unsigned int old_387controlword, new_387controlword, out_387controlword
     135                 :            :     // We use the __control87_2 function to set only the x87 control word.
     136                 :            :     // The SSE control word is unaffected.
     137                 :            : #define _Py_SET_53BIT_PRECISION_START                                   \
     138                 :            :     do {                                                                \
     139                 :            :         __control87_2(0, 0, &old_387controlword, NULL);                 \
     140                 :            :         new_387controlword =                                            \
     141                 :            :           (old_387controlword & ~(_MCW_PC | _MCW_RC)) | (_PC_53 | _RC_NEAR); \
     142                 :            :         if (new_387controlword != old_387controlword) {                 \
     143                 :            :             __control87_2(new_387controlword, _MCW_PC | _MCW_RC,        \
     144                 :            :                           &out_387controlword, NULL);                   \
     145                 :            :         }                                                               \
     146                 :            :     } while (0)
     147                 :            : #define _Py_SET_53BIT_PRECISION_END                                     \
     148                 :            :     do {                                                                \
     149                 :            :         if (new_387controlword != old_387controlword) {                 \
     150                 :            :             __control87_2(old_387controlword, _MCW_PC | _MCW_RC,        \
     151                 :            :                           &out_387controlword, NULL);                   \
     152                 :            :         }                                                               \
     153                 :            :     } while (0)
     154                 :            : #endif
     155                 :            : 
     156                 :            : 
     157                 :            : // MC68881
     158                 :            : #ifdef HAVE_GCC_ASM_FOR_MC68881
     159                 :            : #define HAVE_PY_SET_53BIT_PRECISION 1
     160                 :            : #define _Py_SET_53BIT_PRECISION_HEADER \
     161                 :            :     unsigned int old_fpcr, new_fpcr
     162                 :            : #define _Py_SET_53BIT_PRECISION_START                                   \
     163                 :            :     do {                                                                \
     164                 :            :         __asm__ ("fmove.l %%fpcr,%0" : "=g" (old_fpcr));                \
     165                 :            :         /* Set double precision / round to nearest.  */                 \
     166                 :            :         new_fpcr = (old_fpcr & ~0xf0) | 0x80;                           \
     167                 :            :         if (new_fpcr != old_fpcr) {                                     \
     168                 :            :               __asm__ volatile ("fmove.l %0,%%fpcr" : : "g" (new_fpcr));\
     169                 :            :         }                                                               \
     170                 :            :     } while (0)
     171                 :            : #define _Py_SET_53BIT_PRECISION_END                                     \
     172                 :            :     do {                                                                \
     173                 :            :         if (new_fpcr != old_fpcr) {                                     \
     174                 :            :             __asm__ volatile ("fmove.l %0,%%fpcr" : : "g" (old_fpcr));  \
     175                 :            :         }                                                               \
     176                 :            :     } while (0)
     177                 :            : #endif
     178                 :            : 
     179                 :            : // Default definitions are empty
     180                 :            : #ifndef _Py_SET_53BIT_PRECISION_HEADER
     181                 :            : #  define _Py_SET_53BIT_PRECISION_HEADER
     182                 :            : #  define _Py_SET_53BIT_PRECISION_START
     183                 :            : #  define _Py_SET_53BIT_PRECISION_END
     184                 :            : #endif
     185                 :            : 
     186                 :            : 
     187                 :            : //--- _PY_SHORT_FLOAT_REPR macro -------------------------------------------
     188                 :            : 
     189                 :            : // If we can't guarantee 53-bit precision, don't use the code
     190                 :            : // in Python/dtoa.c, but fall back to standard code.  This
     191                 :            : // means that repr of a float will be long (17 significant digits).
     192                 :            : //
     193                 :            : // Realistically, there are two things that could go wrong:
     194                 :            : //
     195                 :            : // (1) doubles aren't IEEE 754 doubles, or
     196                 :            : // (2) we're on x86 with the rounding precision set to 64-bits
     197                 :            : //     (extended precision), and we don't know how to change
     198                 :            : //     the rounding precision.
     199                 :            : #if !defined(DOUBLE_IS_LITTLE_ENDIAN_IEEE754) && \
     200                 :            :     !defined(DOUBLE_IS_BIG_ENDIAN_IEEE754) && \
     201                 :            :     !defined(DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754)
     202                 :            : #  define _PY_SHORT_FLOAT_REPR 0
     203                 :            : #endif
     204                 :            : 
     205                 :            : // Double rounding is symptomatic of use of extended precision on x86.
     206                 :            : // If we're seeing double rounding, and we don't have any mechanism available
     207                 :            : // for changing the FPU rounding precision, then don't use Python/dtoa.c.
     208                 :            : #if defined(X87_DOUBLE_ROUNDING) && !defined(HAVE_PY_SET_53BIT_PRECISION)
     209                 :            : #  define _PY_SHORT_FLOAT_REPR 0
     210                 :            : #endif
     211                 :            : 
     212                 :            : #ifndef _PY_SHORT_FLOAT_REPR
     213                 :            : #  define _PY_SHORT_FLOAT_REPR 1
     214                 :            : #endif
     215                 :            : 
     216                 :            : 
     217                 :            : #ifdef __cplusplus
     218                 :            : }
     219                 :            : #endif
     220                 :            : #endif /* !Py_INTERNAL_PYMATH_H */

Generated by: LCOV version 1.14