This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
We now have symbols for llrint and llround.
[perl5.git] / ext / POSIX / POSIX.xs
index 2b42a17..21f8101 100644 (file)
 #include <unistd.h>
 #endif
 
-#ifndef M_E
-#  define M_E          2.71828182845904523536028747135266250
-#endif
-#ifndef M_LOG2E
-#  define M_LOG2E      1.44269504088896340735992468100189214
-#endif
-#ifndef M_LOG10E
-#  define M_LOG10E     0.434294481903251827651128918916605082
-#endif
-#ifndef M_LN2
-#  define M_LN2                0.693147180559945309417232121458176568
-#endif
-#ifndef M_LN10
-#  define M_LN10       2.30258509299404568401799145468436421
-#endif
-#ifndef M_PI
-#  define M_PI         3.14159265358979323846264338327950288
-#endif
-#ifndef M_PI_2
-#  define M_PI_2       1.57079632679489661923132169163975144
-#endif
-#ifndef M_PI_4
-#  define M_PI_4       0.785398163397448309615660845819875721
-#endif
-#ifndef M_1_PI
-#  define M_1_PI       0.318309886183790671537767526745028724
-#endif
-#ifndef M_2_PI
-#  define M_2_PI       0.636619772367581343075535053490057448
-#endif
-#ifndef M_2_SQRTPI
-#  define M_2_SQRTPI   1.12837916709551257389615890312154517
-#endif
-#ifndef M_SQRT2
-#  define M_SQRT2      1.41421356237309504880168872420969808
-#endif
-#ifndef M_SQRT1_2
-#  define M_SQRT1_2    0.707106781186547524400844362104849039
+#if defined(USE_QUADMATH) && defined(I_QUADMATH)
+
+#  undef M_E
+#  undef M_LOG2E
+#  undef M_LOG10E
+#  undef M_LN2
+#  undef M_LN10
+#  undef M_PI
+#  undef M_PI_2
+#  undef M_PI_4
+#  undef M_1_PI
+#  undef M_2_PI
+#  undef M_2_SQRTPI
+#  undef M_SQRT2
+#  undef M_SQRT1_2
+
+#  define M_E        M_Eq
+#  define M_LOG2E    M_LOG2Eq
+#  define M_LOG10E   M_LOG10Eq
+#  define M_LN2      M_LN2q
+#  define M_LN10     M_LN10q
+#  define M_PI       M_PIq
+#  define M_PI_2     M_PI_2q
+#  define M_PI_4     M_PI_4q
+#  define M_1_PI     M_1_PIq
+#  define M_2_PI     M_2_PIq
+#  define M_2_SQRTPI M_2_SQRTPIq
+#  define M_SQRT2    M_SQRT2q
+#  define M_SQRT1_2  M_SQRT1_2q
+
+#else
+
+#  ifndef M_E
+#    define M_E                2.71828182845904523536028747135266250
+#  endif
+#  ifndef M_LOG2E
+#    define M_LOG2E    1.44269504088896340735992468100189214
+#  endif
+#  ifndef M_LOG10E
+#    define M_LOG10E   0.434294481903251827651128918916605082
+#  endif
+#  ifndef M_LN2
+#    define M_LN2      0.693147180559945309417232121458176568
+#  endif
+#  ifndef M_LN10
+#    define M_LN10     2.30258509299404568401799145468436421
+#  endif
+#  ifndef M_PI
+#    define M_PI       3.14159265358979323846264338327950288
+#  endif
+#  ifndef M_PI_2
+#    define M_PI_2     1.57079632679489661923132169163975144
+#  endif
+#  ifndef M_PI_4
+#    define M_PI_4     0.785398163397448309615660845819875721
+#  endif
+#  ifndef M_1_PI
+#    define M_1_PI     0.318309886183790671537767526745028724
+#  endif
+#  ifndef M_2_PI
+#    define M_2_PI     0.636619772367581343075535053490057448
+#  endif
+#  ifndef M_2_SQRTPI
+#    define M_2_SQRTPI 1.12837916709551257389615890312154517
+#  endif
+#  ifndef M_SQRT2
+#    define M_SQRT2    1.41421356237309504880168872420969808
+#  endif
+#  ifndef M_SQRT1_2
+#    define M_SQRT1_2  0.707106781186547524400844362104849039
+#  endif
+
 #endif
 
 #if !defined(INFINITY) && defined(NV_INF)
 #  define FP_ZERO      4
 #endif
 
+/* We will have an emulation. */
+#ifndef FE_TONEAREST
+#  define FE_TOWARDZERO        0
+#  define FE_TONEAREST 1
+#  define FE_UPWARD    2
+#  define FE_DOWNWARD  3
+#endif
+
 /* C89 math.h:
 
    acos asin atan atan2 ceil cos cosh exp fabs floor fmod frexp ldexp
    acosh asinh atanh cbrt copysign erf erfc exp2 expm1 fdim fma fmax
    fmin fpclassify hypot ilogb isfinite isgreater isgreaterequal isinf
    isless islessequal islessgreater isnan isnormal isunordered lgamma
-   log1p log2 logb lrint nan nearbyint nextafter nexttoward remainder
+   log1p log2 logb lrint lround nan nearbyint nextafter nexttoward remainder
    remquo rint round scalbn signbit tgamma trunc
 
+   See:
+   http://pubs.opengroup.org/onlinepubs/009695399/basedefs/math.h.html
+
  * Berkeley/SVID extensions:
 
    j0 j1 jn y0 y1 yn
 
- * Configure already (5.21.0) scans for:
+ * Configure already (5.21.5) scans for:
 
-   fpclassify isfinite isinf isnan ilogb*l* signbit
+   copysign*l* fpclassify isfinite isinf isnan isnan*l* ilogb*l* signbit scalbn*l*
 
  * For floating-point round mode (which matters for e.g. lrint and rint)
 
  * of missing functions doesn't seem to follow any patterns. */
 
 #ifdef HAS_ACOSH
-#  if defined(USE_LONG_DOUBLE) && defined(HAS_ILOGBL)
-/* There's already a symbol for ilogbl, we will use its truthiness
- * as the canary for all the *l variants being defined. */
+
+/* Certain AIX releases have the C99 math, but not in long double.
+ * The <math.h> has them, e.g. __expl128, but no library has them!
+ *
+ * Also see the comments in hints/aix.sh about long doubles. */
+
+#  if defined(USE_QUADMATH) && defined(I_QUADMATH)
+#    define c99_acosh  acoshq
+#    define c99_asinh  asinhq
+#    define c99_atanh  atanhq
+#    define c99_cbrt   cbrtq
+#    define c99_copysign       copysignq
+#    define c99_erf    erfq
+#    define c99_erfc   erfcq
+/* no exp2q */
+#    define c99_expm1  expm1q
+#    define c99_fdim   fdimq
+#    define c99_fma    fmaq
+#    define c99_fmax   fmaxq
+#    define c99_fmin   fminq
+#    define c99_hypot  hypotq
+#    define c99_ilogb  ilogbq
+#    define c99_lgamma lgammaq
+#    define c99_log1p  log1pq
+#    define c99_log2   log2q
+/* no logbq */
+/* no llrintq */
+/* no llroundq */
+#    define c99_lrint  lrintq
+#    define c99_lround lroundq
+#    define c99_nan    nanq
+#    define c99_nearbyint      nearbyintq
+#    define c99_nextafter      nextafterq
+/* no nexttowardq */
+#    define c99_remainder      remainderq
+#    define c99_remquo remquoq
+#    define c99_rint   rintq
+#    define c99_round  roundq
+#    define c99_scalbn scalbnq
+#    define c99_signbit        signbitq
+#    define c99_tgamma tgammaq
+#    define c99_trunc  truncq
+#    define bessel_j0 j0q
+#    define bessel_j1 j1q
+#    define bessel_jn jnq
+#    define bessel_y0 y0q
+#    define bessel_y1 y1q
+#    define bessel_yn ynq
+#  elif defined(USE_LONG_DOUBLE) && \
+  (defined(HAS_FREXPL) || defined(HAS_ILOGBL)) && defined(HAS_SQRTL)
+/* Use some of the Configure scans for long double math functions
+ * as the canary for all the C99 *l variants being defined. */
 #    define c99_acosh  acoshl
 #    define c99_asinh  asinhl
 #    define c99_atanh  atanhl
 #    else
 #      define c99_lrint        lrintl
 #    endif
+#    if defined(USE_64_BIT_INT) && QUADKIND == QUAD_IS_LONG_LONG
+#      define c99_lround       llroundl
+#    else
+#      define c99_lround       lroundl
+#    endif
 #    define c99_nan    nanl
 #    define c99_nearbyint      nearbyintl
 #    define c99_nextafter      nextafterl
 #    define c99_log1p  log1p
 #    define c99_log2   log2
 #    define c99_logb   logb
-#    if defined(USE_64_BIT_INT) && QUADKIND == QUAD_IS_LONG_LONG
+#    if defined(USE_64_BIT_INT) && QUADKIND == QUAD_IS_LONG_LONG && defined(HAS_LLRINT)
 #      define c99_lrint        llrint
 #    else
 #      define c99_lrint        lrint
 #    endif
+#    if defined(USE_64_BIT_INT) && QUADKIND == QUAD_IS_LONG_LONG && defined(HAS_LLROUND)
+#      define c99_lround       llround
+#    else
+#      define c99_lround       lround
+#    endif
 #    define c99_nan    nan
 #    define c99_nearbyint      nearbyint
 #    define c99_nextafter      nextafter
 #    define c99_trunc  trunc
 #  endif
 
+#  ifndef isunordered
+#    ifdef Perl_isnan
+#      define isunordered(x, y) (Perl_isnan(x) || Perl_isnan(y))
+#    elif defined(HAS_UNORDERED)
+#      define isunordered(x, y) unordered(x, y)
+#    endif
+#  endif
+
+/* XXX these isgreater/isnormal/isunordered macros definitions should
+ * be moved further in the file to be part of the emulations, so that
+ * platforms can e.g. #undef c99_isunordered and have it work like
+ * it does for the other interfaces. */
+
+#  if !defined(isgreater) && defined(isunordered)
+#    define isgreater(x, y)         (!isunordered((x), (y)) && (x) > (y))
+#    define isgreaterequal(x, y)    (!isunordered((x), (y)) && (x) >= (y))
+#    define isless(x, y)            (!isunordered((x), (y)) && (x) < (y))
+#    define islessequal(x, y)       (!isunordered((x), (y)) && (x) <= (y))
+#    define islessgreater(x, y)     (!isunordered((x), (y)) && \
+                                     ((x) > (y) || (y) > (x)))
+#  endif
+
 /* Check both the Configure symbol and the macro-ness (like C99 promises). */ 
 #  if defined(HAS_FPCLASSIFY) && defined(fpclassify)
 #    define c99_fpclassify     fpclassify
 
 #ifndef __GNUC__
 
-/* HP-UX on PA-RISC is missing certain C99 math functions,
- * but on IA64 (Integrity) these do exist. */
-#  if defined(__hpux) && defined(__hppa)
-#    undef c99_exp2
-#    undef c99_fdim
-#    undef c99_fma
-#    undef c99_fmax
-#    undef c99_fmin
-#    undef c99_fpclassify
-#    undef c99_lrint
-#    undef c99_nan
-#    undef c99_nearbyint
-#    undef c99_nexttoward
-#    undef c99_remquo
-#    undef c99_round
-#    undef c99_scalbn
-#    undef c99_tgamma
-#    undef c99_trunc
-#  endif
-
-#  if defined(__irix__)
-#    undef c99_ilogb
-#    undef c99_exp2
-#  endif
-
 #  if defined(__osf__) /* Tru64 */
 #    undef c99_fdim
 #    undef c99_fma
 #    undef c99_fpclassify
 #    undef c99_isfinite
 #    undef c99_isinf
-#    undef c99_isunordered
+/* Tru64 is missing isunordered but we have emulation. */
 #    undef c99_lrint
+#    undef c99_lround
+#    undef c99_nan /* in libm, but seems broken (no proto, either) */
 #    undef c99_nearbyint
 #    undef c99_nexttoward
 #    undef c99_remquo
-#    undef c99_rint
 #    undef c99_round
 #    undef c99_scalbn
 #  endif
 
 /* XXX Regarding C99 math.h, VMS seems to be missing these:
 
-  nan nearbyint round scalbn llrint
+  lround nan nearbyint round scalbn llrint
  */
 
 #ifdef __VMS
+#    undef c99_lround
 #    undef c99_nan
 #    undef c99_nearbyint
 #    undef c99_round
 
 /* XXX Regarding C99 math.h, Win32 seems to be missing these:
 
-  exp2 fdim fma fmax fmin fpclassify ilogb lgamma log1p log2 lrint
+  erf erfc exp2 fdim fma fmax fmin fpclassify ilogb lgamma log1p log2 lrint
   remquo rint signbit tgamma trunc
 
   Win32 does seem to have these:
 
-  acosh asinh atanh cbrt copysign cosh erf erfc expm1 hypot log10 nan
+  acosh asinh atanh cbrt copysign cosh expm1 hypot log10 nan
   nearbyint nextafter nexttoward remainder round scalbn
 
   And the Bessel functions are defined like _this.
 */
 
 #ifdef WIN32
+#  undef c99_erf
+#  undef c99_erfc
 #  undef c99_exp2
 #  undef c99_fdim
 #  undef c99_fma
 #  undef c99_log1p
 #  undef c99_log2
 #  undef c99_lrint
+#  undef c99_lround
 #  undef c99_remquo
 #  undef c99_rint
 #  undef c99_signbit
 
 #endif
 
+#ifdef __CYGWIN__
+#  undef c99_nexttoward
+#endif
+
 /* The Bessel functions: BSD, SVID, XPG4, and POSIX.  But not C99. */
-#ifdef HAS_J0
+#if defined(HAS_J0) && !defined(bessel_j0)
 #  if defined(USE_LONG_DOUBLE) && defined(HAS_J0L)
 #    define bessel_j0 j0l
 #    define bessel_j1 j1l
@@ -474,25 +584,23 @@ static NV my_erf(NV x)
   NV a4 = -1.453152027;
   NV a5 =  1.061405429;
   NV p  =  0.3275911;
-
+  NV t, y;
   int sign = x < 0 ? -1 : 1; /* Save the sign. */
   x = PERL_ABS(x);
 
   /* Abramowitz and Stegun formula 7.1.26 */
-  NV t = 1.0 / (1.0 + p * x);
-  NV y = 1.0 - (((((a5*t + a4)*t) + a3)*t + a2)*t + a1) * t * exp(-x*x);
+  t = 1.0 / (1.0 + p * x);
+  y = 1.0 - (((((a5*t + a4)*t) + a3)*t + a2)*t + a1) * t * Perl_exp(-x*x);
 
   return sign * y;
 }
 #  define c99_erf my_erf
 #endif
 
-/* While in theory erfc(x) is just 1-erf(x), thanks to numerical stability
- * things are not so easy. */
 #ifndef c99_erfc
 static NV my_erfc(NV x) {
-  /* Chiani, Dardari & Simon (2003), via Wikipedia */
-  return Perl_exp(-x*x) / 6.0 + Perl_exp(-4.0/3.0 * x*x) / 2.0;
+  /* This is not necessarily numerically stable, but better than nothing. */
+  return 1.0 - c99_erf(x);
 }
 #  define c99_erfc my_erfc
 #endif
@@ -510,9 +618,9 @@ static NV my_expm1(NV x)
 {
   if (PERL_ABS(x) < 1e-5)
     /* http://www.johndcook.com/cpp_expm1.html -- public domain.
-     * Also including the cubic term. */
+     * Taylor series, the first four terms (the last term quartic). */
     /* Probably not enough for long doubles. */
-    return x * (1.0 + x * (0.5 + x / 6.0)); /* Taylor series */
+    return x * (1.0 + x * (1/2.0 + x * (1/6.0 + x/24.0)));
   else
     return Perl_exp(x) - 1;
 }
@@ -557,71 +665,15 @@ static NV my_fmin(NV x, NV y)
 
 static IV my_fpclassify(NV x)
 {
-#if defined(HAS_FPCLASSIFY) && defined(FP_PLUS_INF) /* E.g. HP-UX */
-  switch (Perl_fp_class(x)) {
-  case FP_PLUS_INF:    case FP_MINUS_INF:    return FP_INFINITE;
-  case FP_SNAN:        case FP_QNAN:         return FP_NAN;
-  case FP_PLUS_NORM:   case FP_MINUS_NORM:   return FP_NORMAL;
-  case FP_PLUS_DENORM: case FP_MINUS_DENORM: return FP_SUBNORMAL;
-  case FP_PLUS_ZERO:   case FP_MINUS_ZERO:   return FP_ZERO;
-  default: return -1;
-  }
-#  define c99_fpclassify my_fpclassify
-#elif (defined(HAS_FPCLASS) || defined(HAS_FPCLASSL)) && defined(FP_CLASS_SNAN)
-  switch (Perl_fp_class(x)) {
-  case FP_CLASS_NINF:    case FP_CLASS_PINF:    return FP_INFINITE;
-  case FP_CLASS_SNAN:    case FP_CLASS_QNAN:    return FP_NAN;
-  case FP_CLASS_NNORM:   case FP_CLASS_PNORM:   return FP_NORMAL;
-  case FP_CLASS_NDENORM: case FP_CLASS_PDENORM: return FP_SUBNORMAL;
-  case FP_CLASS_NZERO:   case FP_CLASS_PZERO:   return FP_ZERO;
-  default: return -1;
-  }
-#  define c99_fpclassify my_fpclassify
-#elif (defined(HAS_FPCLASS) || defined(HAS_FP_CLASSL)) && defined(FP_SNAN)
-  switch (Perl_fp_class(x)) {
-  case FP_NINF:    case FP_PINF:    return FP_INFINITE;
-  case FP_SNAN:    case FP_QNAN:    return FP_NAN;
-  case FP_NNORM:   case FP_PNORM:   return FP_NORMAL;
-  case FP_NDENORM: case FP_PDENORM: return FP_SUBNORMAL;
-  case FP_NZERO:   case FP_PZERO:   return FP_ZERO;
-  default: return -1;
-  }
-#  define c99_fpclassify my_fpclassify
-#elif defined(HAS_FP_CLASS) && defined(FP_POS_INF)
-  switch (Perl_fp_class(x)) {
-  case FP_NEG_INF:    case FP_POS_INF:    return FP_INFINITE;
-  case FP_SNAN:       case FP_QNAN:       return FP_NAN;
-  case FP_NEG_NORM:   case FP_POS_NORM:   return FP_NORMAL;
-  case FP_NEG_DENORM: case FP_POS_DENORM: return FP_SUBNORMAL;
-  case FP_NEG_ZERO:   case FP_POS_ZERO:   return FP_ZERO;
-  default: return -1;
-  }
-#  define c99_fpclassify my_fpclassify
-#elif defined(HAS_CLASS) && defined(FP_PLUS_INF)
-  switch (Perl_fp_class(x)) {
-  case FP_MINUS_INF:    case FP_PLUS_INF:    return FP_INFINITE;
-  case FP_SNAN:         case FP_QNAN:        return FP_NAN;
-  case FP_MINUS_NORM:   case FP_PLUS_NORM:   return FP_NORMAL;
-  case FP_MINUS_DENORM: case FP_PLUS_DENORM: return FP_SUBNORMAL;
-  case FP_MINUS_ZERO:   case FP_PLUS_ZERO:   return FP_ZERO;
-  default: return -1;
-  }
-#  define c99_fpclassify my_fpclassify
-#elif defined(HAS_FP_CLASSIFY)
-  return Perl_fp_class(x);
-#  define c99_fpclassify my_fpclassify
-#elif defined(WIN32)
-  int fpclass = _fpclass(x);
+#ifdef Perl_fp_class_inf
   if (Perl_fp_class_inf(x))    return FP_INFINITE;
   if (Perl_fp_class_nan(x))    return FP_NAN;
   if (Perl_fp_class_norm(x))   return FP_NORMAL;
   if (Perl_fp_class_denorm(x)) return FP_SUBNORMAL;
   if (Perl_fp_class_zero(x))   return FP_ZERO;
-  return -1;
 #  define c99_fpclassify my_fpclassify
-#else
-  return -1;
 #endif
+  return -1;
 }
 
 #endif
@@ -643,7 +695,7 @@ static NV my_hypot(NV x, NV y)
     y = t;
   }
   t = y / x;
-  return x * sqrt(1.0 + t * t);
+  return x * Perl_sqrt(1.0 + t * t);
 }
 #  define c99_hypot my_hypot
 #endif
@@ -662,12 +714,16 @@ static IV my_ilogb(NV x)
 static NV my_log1p(NV x)
 {
   /* http://www.johndcook.com/cpp_log_one_plus_x.html -- public domain.
-   * Including also quadratic term. */
+   * Taylor series, the first four terms (the last term quartic). */
+  if (x < -1.0)
+    return NV_NAN;
+  if (x == -1.0)
+    return -NV_INF;
   if (PERL_ABS(x) > 1e-4)
     return Perl_log(1.0 + x);
   else
     /* Probably not enough for long doubles. */
-    return x * (1.0 - x * (-x / 2.0 + x / 3.0)); /* Taylor series */
+    return x * (1.0 + x * (-1/2.0 + x * (1/3.0 - x/4.0)));
 }
 #  define c99_log1p my_log1p
 #endif
@@ -688,35 +744,71 @@ static int my_fegetround()
 {
 #ifdef HAS_FEGETROUND
   return fegetround();
+#elif defined(HAS_FPGETROUND)
+  switch (fpgetround()) {
+  case FP_RN: return FE_TONEAREST;
+  case FP_RZ: return FE_TOWARDZERO;
+  case FP_RM: return FE_DOWNWARD;
+  case FP_RP: return FE_UPWARD;
+  default: return -1;
+  }
 #elif defined(FLT_ROUNDS)
-  return FLT_ROUNDS;
-  /* XXX emulate using fpgetround() (HAS_FPGETROUND):
-   * FP_RN to nearest, FP_RM down, FP_RP, up, FP_RZ truncate */
+  switch (FLT_ROUNDS) {
+  case 0: return FE_TOWARDZERO;
+  case 1: return FE_TONEAREST;
+  case 2: return FE_UPWARD;
+  case 3: return FE_DOWNWARD;
+  default: return -1;
+  }
+#elif defined(__osf__) /* Tru64 */
+  switch (read_rnd()) {
+  case FP_RND_RN: return FE_TONEAREST;
+  case FP_RND_RZ: return FE_TOWARDZERO;
+  case FP_RND_RM: return FE_DOWNWARD;
+  case FP_RND_RP: return FE_UPWARD;
+  default: return -1;
+  }
 #else
   return -1;
 #endif
 }
 
+/* Toward closest integer. */
+#define MY_ROUND_NEAREST(x) ((NV)((IV)((x) >= 0.0 ? (x) + 0.5 : (x) - 0.5)))
+
+/* Toward zero. */
+#define MY_ROUND_TRUNC(x) ((NV)((IV)(x)))
+
+/* Toward minus infinity. */
+#define MY_ROUND_DOWN(x) ((NV)((IV)((x) >= 0.0 ? (x) : (x) - 0.5)))
+
+/* Toward plus infinity. */
+#define MY_ROUND_UP(x) ((NV)((IV)((x) >= 0.0 ? (x) + 0.5 : (x))))
+
+#if (!defined(c99_nearbyint) || !defined(c99_lrint)) && defined(FE_TONEAREST)
 static NV my_rint(NV x)
 {
 #ifdef FE_TONEAREST
   switch (my_fegetround()) {
-  default:
-  case FE_TONEAREST:
-    return (NV)((IV)(x >= 0.0 ? x + 0.5 : x - 0.5)); /* like round() */
-  case FE_TOWARDZERO:
-    return (NV)((IV)(x)); /* like trunc() */
-  case FE_DOWNWARD:
-    return (NV)((IV)(x >= 0.0 ? x : x - 0.5));
-  case FE_UPWARD:
-    return (NV)((IV)(x >= 0.0 ? x + 0.5 : x));
+  case FE_TONEAREST:  return MY_ROUND_NEAREST(x);
+  case FE_TOWARDZERO: return MY_ROUND_TRUNC(x);
+  case FE_DOWNWARD:   return MY_ROUND_DOWN(x);
+  case FE_UPWARD:     return MY_ROUND_UP(x);
+  default: return NV_NAN;
+  }
+#elif defined(HAS_FPGETROUND)
+  switch (fpgetround()) {
+  case FP_RN: return MY_ROUND_NEAREST(x);
+  case FP_RZ: return MY_ROUND_TRUNC(x);
+  case FP_RM: return MY_ROUND_DOWN(x);
+  case FE_RP: return MY_ROUND_UP(x);
+  default: return NV_NAN;
   }
 #else
-  /* XXX emulate using fpsetround() (HAS_FPGETROUND):
-   * FP_RN to nearest, FP_RM down, FP_RP, up, FP_RZ truncate */
   return NV_NAN;
 #endif
 }
+#endif
 
 /* XXX nearbyint() and rint() are not really identical -- but the difference
  * is messy: nearbyint is defined NOT to raise FE_INEXACT floating point
@@ -730,7 +822,7 @@ static NV my_rint(NV x)
 
 #ifndef c99_lrint
 #  ifdef FE_TONEAREST
-static IV lrint(NV x)
+static IV my_lrint(NV x)
 {
   return (IV)my_rint(x);
 }
@@ -738,6 +830,14 @@ static IV lrint(NV x)
 #  endif
 #endif
 
+#ifndef c99_lround
+static IV my_lround(NV x)
+{
+  return (IV)MY_ROUND_NEAREST(x);
+}
+#  define c99_lround my_lround
+#endif
+
 /* XXX remainder */
 
 /* XXX remquo */
@@ -751,7 +851,7 @@ static IV lrint(NV x)
 #ifndef c99_round
 static NV my_round(NV x)
 {
-  return (NV)((IV)(x >= 0.0 ? x + 0.5 : x - 0.5));
+  return MY_ROUND_NEAREST(x);
 }
 #  define c99_round my_round
 #endif
@@ -785,7 +885,7 @@ static NV my_tgamma(NV x)
 #ifndef c99_trunc
 static NV my_trunc(NV x)
 {
-  return (NV)((IV)(x));
+  return MY_ROUND_TRUNC(x);
 }
 #  define c99_trunc my_trunc
 #endif
@@ -1082,6 +1182,14 @@ const struct lconv_offset lconv_integers[] = {
     {"n_sep_by_space",    STRUCT_OFFSET(struct lconv, n_sep_by_space)},
     {"p_sign_posn",       STRUCT_OFFSET(struct lconv, p_sign_posn)},
     {"n_sign_posn",       STRUCT_OFFSET(struct lconv, n_sign_posn)},
+#ifdef HAS_LC_MONETARY_2008
+    {"int_p_cs_precedes",  STRUCT_OFFSET(struct lconv, int_p_cs_precedes)},
+    {"int_p_sep_by_space", STRUCT_OFFSET(struct lconv, int_p_sep_by_space)},
+    {"int_n_cs_precedes",  STRUCT_OFFSET(struct lconv, int_n_cs_precedes)},
+    {"int_n_sep_by_space", STRUCT_OFFSET(struct lconv, int_n_sep_by_space)},
+    {"int_p_sign_posn",    STRUCT_OFFSET(struct lconv, int_p_sign_posn)},
+    {"int_n_sign_posn",    STRUCT_OFFSET(struct lconv, int_n_sign_posn)},
+#endif
 #endif
     {NULL, 0}
 };
@@ -1867,7 +1975,7 @@ acos(x)
        RETVAL = NV_NAN;
        switch (ix) {
        case 0:
-           RETVAL = acos(x); /* C89 math */
+           RETVAL = Perl_acos(x); /* C89 math */
            break;
        case 1:
 #ifdef c99_acosh
@@ -1877,7 +1985,7 @@ acos(x)
 #endif
            break;
        case 2:
-           RETVAL = asin(x); /* C89 math */
+           RETVAL = Perl_asin(x); /* C89 math */
            break;
        case 3:
 #ifdef c99_asinh
@@ -1887,7 +1995,7 @@ acos(x)
 #endif
            break;
        case 4:
-           RETVAL = atan(x); /* C89 math */
+           RETVAL = Perl_atan(x); /* C89 math */
            break;
        case 5:
 #ifdef c99_atanh
@@ -1904,10 +2012,10 @@ acos(x)
 #endif
            break;
        case 7:
-           RETVAL = ceil(x); /* C89 math */
+           RETVAL = Perl_ceil(x); /* C89 math */
            break;
        case 8:
-           RETVAL = cosh(x); /* C89 math */
+           RETVAL = Perl_cosh(x); /* C89 math */
            break;
        case 9:
 #ifdef c99_erf
@@ -1918,7 +2026,7 @@ acos(x)
            break;
        case 10:
 #ifdef c99_erfc
-           RETVAL = erfc(x);
+           RETVAL = c99_erfc(x);
 #else
            not_here("erfc");
 #endif
@@ -1938,7 +2046,7 @@ acos(x)
 #endif
            break;
        case 13:
-           RETVAL = floor(x); /* C89 math */
+           RETVAL = Perl_floor(x); /* C89 math */
            break;
        case 14:
 #ifdef bessel_j0
@@ -2010,13 +2118,13 @@ acos(x)
 #endif
            break;
        case 24:
-           RETVAL = sinh(x); /* C89 math */
+           RETVAL = Perl_sinh(x); /* C89 math */
            break;
        case 25:
-           RETVAL = tan(x); /* C89 math */
+           RETVAL = Perl_tan(x); /* C89 math */
            break;
        case 26:
-           RETVAL = tanh(x); /* C89 math */
+           RETVAL = Perl_tanh(x); /* C89 math */
            break;
        case 27:
         /* XXX tgamma_r -- the lgamma accesses a global variable (signgam),
@@ -2071,6 +2179,22 @@ fesetround(x)
     CODE:
 #ifdef HAS_FEGETROUND /* canary for fesetround */
        RETVAL = fesetround(x);
+#elif defined(HAS_FPGETROUND) /* canary for fpsetround */
+       switch (x) {
+       case FE_TONEAREST:  RETVAL = fpsetround(FP_RN); break;
+       case FE_TOWARDZERO: RETVAL = fpsetround(FP_RZ); break;
+       case FE_DOWNWARD:   RETVAL = fpsetround(FP_RM); break;
+       case FE_UPWARD:     RETVAL = fpsetround(FP_RP); break;
+        default: RETVAL = -1; break;
+       }
+#elif defined(__osf__) /* Tru64 */
+       switch (x) {
+       case FE_TONEAREST:  RETVAL = write_rnd(FP_RND_RN); break;
+       case FE_TOWARDZERO: RETVAL = write_rnd(FP_RND_RZ); break;
+       case FE_DOWNWARD:   RETVAL = write_rnd(FP_RND_RM); break;
+       case FE_UPWARD:     RETVAL = write_rnd(FP_RND_RP); break;
+        default: RETVAL = -1; break;
+       }
 #else
        RETVAL = -1;
        not_here("fesetround");
@@ -2088,7 +2212,8 @@ fpclassify(x)
        isnan = 4
        isnormal = 5
        lrint = 6
-        signbit = 7
+       lround = 7
+        signbit = 8
     CODE:
        RETVAL = -1;
        switch (ix) {
@@ -2130,6 +2255,13 @@ fpclassify(x)
 #endif
            break;
        case 7:
+#ifdef c99_lround
+           RETVAL = c99_lround(x);
+#else
+           not_here("lround");
+#endif
+           break;
+       case 8:
        default:
 #ifdef Perl_signbit
            RETVAL = Perl_signbit(x);
@@ -2190,7 +2322,7 @@ copysign(x,y)
 #endif
            break;
        case 4:
-           RETVAL = fmod(x, y); /* C89 math */
+           RETVAL = Perl_fmod(x, y); /* C89 math */
            break;
        case 5:
 #ifdef c99_hypot
@@ -2337,9 +2469,12 @@ nan(s = 0)
        char*   s;
     CODE:
 #ifdef c99_nan
-       RETVAL = c99_nan(s);
-#else
+       RETVAL = c99_nan(s ? s : "");
+#elif defined(NV_NAN)
+       /* XXX if s != NULL, warn about unused argument,
+         * or implement the nan payload setting. */
        RETVAL = NV_NAN;
+#else
        not_here("nan");
 #endif
     OUTPUT:
@@ -2721,6 +2856,13 @@ tmpnam()
         *
         * Then again, maybe this should be removed at some point.
         * No point in enabling dangerous interfaces. */
+        if (ckWARN_d(WARN_DEPRECATED)) {
+           HV *warned = get_hv("POSIX::_warned", GV_ADD | GV_ADDMULTI);
+            if (! hv_exists(warned, (const char *)&PL_op, sizeof(PL_op))) {
+                Perl_warner(aTHX_ packWARN(WARN_DEPRECATED), "Calling POSIX::tmpnam() is deprecated");
+                hv_store(warned, (const char *)&PL_op, sizeof(PL_op), &PL_sv_yes, 0);
+            }
+        }
        len = strlen(tmpnam(SvPV(RETVAL, i)));
        SvCUR_set(RETVAL, len);
     OUTPUT: