(root)/
Python-3.12.0/
Include/
internal/
pycore_pymath.h
       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  static inline void _Py_ADJUST_ERANGE1(double x)
      34  {
      35      if (errno == 0) {
      36          if (x == Py_HUGE_VAL || x == -Py_HUGE_VAL) {
      37              errno = ERANGE;
      38          }
      39      }
      40      else if (errno == ERANGE && x == 0.0) {
      41          errno = 0;
      42      }
      43  }
      44  
      45  static inline void _Py_ADJUST_ERANGE2(double x, double y)
      46  {
      47      if (x == Py_HUGE_VAL || x == -Py_HUGE_VAL ||
      48          y == Py_HUGE_VAL || y == -Py_HUGE_VAL)
      49      {
      50          if (errno == 0) {
      51              errno = ERANGE;
      52          }
      53      }
      54      else if (errno == ERANGE) {
      55          errno = 0;
      56      }
      57  }
      58  
      59  
      60  //--- HAVE_PY_SET_53BIT_PRECISION macro ------------------------------------
      61  //
      62  // The functions _Py_dg_strtod() and _Py_dg_dtoa() in Python/dtoa.c (which are
      63  // required to support the short float repr introduced in Python 3.1) require
      64  // that the floating-point unit that's being used for arithmetic operations on
      65  // C doubles is set to use 53-bit precision.  It also requires that the FPU
      66  // rounding mode is round-half-to-even, but that's less often an issue.
      67  //
      68  // If your FPU isn't already set to 53-bit precision/round-half-to-even, and
      69  // you want to make use of _Py_dg_strtod() and _Py_dg_dtoa(), then you should:
      70  //
      71  //     #define HAVE_PY_SET_53BIT_PRECISION 1
      72  //
      73  // and also give appropriate definitions for the following three macros:
      74  //
      75  // * _Py_SET_53BIT_PRECISION_HEADER: any variable declarations needed to
      76  //   use the two macros below.
      77  // * _Py_SET_53BIT_PRECISION_START: store original FPU settings, and
      78  //   set FPU to 53-bit precision/round-half-to-even
      79  // * _Py_SET_53BIT_PRECISION_END: restore original FPU settings
      80  //
      81  // The macros are designed to be used within a single C function: see
      82  // Python/pystrtod.c for an example of their use.
      83  
      84  
      85  // Get and set x87 control word for gcc/x86
      86  #ifdef HAVE_GCC_ASM_FOR_X87
      87  #define HAVE_PY_SET_53BIT_PRECISION 1
      88  
      89  // Functions defined in Python/pymath.c
      90  extern unsigned short _Py_get_387controlword(void);
      91  extern void _Py_set_387controlword(unsigned short);
      92  
      93  #define _Py_SET_53BIT_PRECISION_HEADER                                  \
      94      unsigned short old_387controlword, new_387controlword
      95  #define _Py_SET_53BIT_PRECISION_START                                   \
      96      do {                                                                \
      97          old_387controlword = _Py_get_387controlword();                  \
      98          new_387controlword = (old_387controlword & ~0x0f00) | 0x0200;   \
      99          if (new_387controlword != old_387controlword) {                 \
     100              _Py_set_387controlword(new_387controlword);                 \
     101          }                                                               \
     102      } while (0)
     103  #define _Py_SET_53BIT_PRECISION_END                                     \
     104      do {                                                                \
     105          if (new_387controlword != old_387controlword) {                 \
     106              _Py_set_387controlword(old_387controlword);                 \
     107          }                                                               \
     108      } while (0)
     109  #endif
     110  
     111  // Get and set x87 control word for VisualStudio/x86.
     112  // x87 is not supported in 64-bit or ARM.
     113  #if defined(_MSC_VER) && !defined(_WIN64) && !defined(_M_ARM)
     114  #define HAVE_PY_SET_53BIT_PRECISION 1
     115  
     116  #include <float.h>                // __control87_2()
     117  
     118  #define _Py_SET_53BIT_PRECISION_HEADER \
     119      unsigned int old_387controlword, new_387controlword, out_387controlword
     120      // We use the __control87_2 function to set only the x87 control word.
     121      // The SSE control word is unaffected.
     122  #define _Py_SET_53BIT_PRECISION_START                                   \
     123      do {                                                                \
     124          __control87_2(0, 0, &old_387controlword, NULL);                 \
     125          new_387controlword =                                            \
     126            (old_387controlword & ~(_MCW_PC | _MCW_RC)) | (_PC_53 | _RC_NEAR); \
     127          if (new_387controlword != old_387controlword) {                 \
     128              __control87_2(new_387controlword, _MCW_PC | _MCW_RC,        \
     129                            &out_387controlword, NULL);                   \
     130          }                                                               \
     131      } while (0)
     132  #define _Py_SET_53BIT_PRECISION_END                                     \
     133      do {                                                                \
     134          if (new_387controlword != old_387controlword) {                 \
     135              __control87_2(old_387controlword, _MCW_PC | _MCW_RC,        \
     136                            &out_387controlword, NULL);                   \
     137          }                                                               \
     138      } while (0)
     139  #endif
     140  
     141  
     142  // MC68881
     143  #ifdef HAVE_GCC_ASM_FOR_MC68881
     144  #define HAVE_PY_SET_53BIT_PRECISION 1
     145  #define _Py_SET_53BIT_PRECISION_HEADER \
     146      unsigned int old_fpcr, new_fpcr
     147  #define _Py_SET_53BIT_PRECISION_START                                   \
     148      do {                                                                \
     149          __asm__ ("fmove.l %%fpcr,%0" : "=g" (old_fpcr));                \
     150          /* Set double precision / round to nearest.  */                 \
     151          new_fpcr = (old_fpcr & ~0xf0) | 0x80;                           \
     152          if (new_fpcr != old_fpcr) {                                     \
     153                __asm__ volatile ("fmove.l %0,%%fpcr" : : "g" (new_fpcr));\
     154          }                                                               \
     155      } while (0)
     156  #define _Py_SET_53BIT_PRECISION_END                                     \
     157      do {                                                                \
     158          if (new_fpcr != old_fpcr) {                                     \
     159              __asm__ volatile ("fmove.l %0,%%fpcr" : : "g" (old_fpcr));  \
     160          }                                                               \
     161      } while (0)
     162  #endif
     163  
     164  // Default definitions are empty
     165  #ifndef _Py_SET_53BIT_PRECISION_HEADER
     166  #  define _Py_SET_53BIT_PRECISION_HEADER
     167  #  define _Py_SET_53BIT_PRECISION_START
     168  #  define _Py_SET_53BIT_PRECISION_END
     169  #endif
     170  
     171  
     172  //--- _PY_SHORT_FLOAT_REPR macro -------------------------------------------
     173  
     174  // If we can't guarantee 53-bit precision, don't use the code
     175  // in Python/dtoa.c, but fall back to standard code.  This
     176  // means that repr of a float will be long (17 significant digits).
     177  //
     178  // Realistically, there are two things that could go wrong:
     179  //
     180  // (1) doubles aren't IEEE 754 doubles, or
     181  // (2) we're on x86 with the rounding precision set to 64-bits
     182  //     (extended precision), and we don't know how to change
     183  //     the rounding precision.
     184  #if !defined(DOUBLE_IS_LITTLE_ENDIAN_IEEE754) && \
     185      !defined(DOUBLE_IS_BIG_ENDIAN_IEEE754) && \
     186      !defined(DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754)
     187  #  define _PY_SHORT_FLOAT_REPR 0
     188  #endif
     189  
     190  // Double rounding is symptomatic of use of extended precision on x86.
     191  // If we're seeing double rounding, and we don't have any mechanism available
     192  // for changing the FPU rounding precision, then don't use Python/dtoa.c.
     193  #if defined(X87_DOUBLE_ROUNDING) && !defined(HAVE_PY_SET_53BIT_PRECISION)
     194  #  define _PY_SHORT_FLOAT_REPR 0
     195  #endif
     196  
     197  #ifndef _PY_SHORT_FLOAT_REPR
     198  #  define _PY_SHORT_FLOAT_REPR 1
     199  #endif
     200  
     201  
     202  #ifdef __cplusplus
     203  }
     204  #endif
     205  #endif /* !Py_INTERNAL_PYMATH_H */