Forráskód Böngészése

Better handling of nan/infinity. Previously, these weren't working on Windows in config strings.

rdb 11 éve
szülő
commit
515f93a0b8
3 módosított fájl, 158 hozzáadás és 88 törlés
  1. 67 37
      dtool/src/dtoolbase/cmath.I
  2. 6 2
      dtool/src/dtoolbase/cmath.h
  3. 85 49
      dtool/src/dtoolbase/pstrtod.cxx

+ 67 - 37
dtool/src/dtoolbase/cmath.I

@@ -16,11 +16,11 @@
 // see float.h
 #define FPU_CONTROLWORD_WRITEMASK    0xFFFFF        // if you look at defn of _CW_DEFAULT, all settings fall within 0xFFFFF
 #define FPU_CONTROLWORD_NEW_SETTING  _CW_DEFAULT
-#endif  
+#endif
 
 ////////////////////////////////////////////////////////////////////
 //     Function: csqrt
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE float
 csqrt(float v) {
@@ -29,7 +29,7 @@ csqrt(float v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: csin
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE float
 csin(float v) {
@@ -38,7 +38,7 @@ csin(float v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ccos
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE float
 ccos(float v) {
@@ -47,7 +47,7 @@ ccos(float v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ctan
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE float ctan(float v) {
   return tanf(v);
@@ -55,7 +55,7 @@ INLINE float ctan(float v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: csincos
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE void
 csincos(float v, float *sin_result, float *cos_result) {
@@ -80,7 +80,7 @@ csincos(float v, float *sin_result, float *cos_result) {
 //     Function: csin_over_x
 //  Description: Computes sin(x) / x, well-behaved as x approaches 0.
 ////////////////////////////////////////////////////////////////////
-INLINE float 
+INLINE float
 csin_over_x(float v) {
   if (1.0f + v * v == 1.0f) {
     return 1.0f;
@@ -91,7 +91,7 @@ csin_over_x(float v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: cabs
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE float
 cabs(float v) {
@@ -100,7 +100,7 @@ cabs(float v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: catan
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE float
 catan(float v) {
@@ -109,7 +109,7 @@ catan(float v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: catan2
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE float
 catan2(float y, float x) {
@@ -118,7 +118,7 @@ catan2(float y, float x) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: casin
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE float
 casin(float v) {
@@ -127,7 +127,7 @@ casin(float v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: cacos
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE float
 cacos(float v) {
@@ -147,7 +147,7 @@ cmod(float x, float y) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: cpow
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE float
 cpow(float x, float y) {
@@ -157,7 +157,7 @@ cpow(float x, float y) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: cfloor
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 cfloor(double f) {
@@ -169,13 +169,13 @@ cfloor(double f) {
     _controlfp(saved_fpu_control_word,FPU_CONTROLWORD_WRITEMASK);
     return retval;
   #else
-    return floor(f);  
+    return floor(f);
   #endif
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: cceil
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 cceil(double f) {
@@ -187,7 +187,7 @@ cceil(double f) {
     _controlfp(saved_fpu_control_word,FPU_CONTROLWORD_WRITEMASK);
     return retval;
   #else
-    return ceil(f);  
+    return ceil(f);
   #endif
 }
 
@@ -202,7 +202,7 @@ cfrac(double f) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: csqrt
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 csqrt(double v) {
@@ -211,7 +211,7 @@ csqrt(double v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: csin
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 csin(double v) {
@@ -220,7 +220,7 @@ csin(double v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ccos
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 ccos(double v) {
@@ -229,7 +229,7 @@ ccos(double v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ctan
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 ctan(double v) {
@@ -238,7 +238,7 @@ ctan(double v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: csincos
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE void
 csincos(double v, double *sin_result, double *cos_result) {
@@ -262,7 +262,7 @@ csincos(double v, double *sin_result, double *cos_result) {
 //     Function: csin_over_x
 //  Description: Computes sin(x) / x, well-behaved as x approaches 0.
 ////////////////////////////////////////////////////////////////////
-INLINE double 
+INLINE double
 csin_over_x(double v) {
   if (1.0 + v * v == 1.0) {
     return 1.0;
@@ -273,7 +273,7 @@ csin_over_x(double v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: cabs
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 cabs(double v) {
@@ -282,7 +282,7 @@ cabs(double v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: catan
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 catan(double v) {
@@ -291,7 +291,7 @@ catan(double v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: catan2
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 catan2(double y, double x) {
@@ -300,7 +300,7 @@ catan2(double y, double x) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: casin
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 casin(double v) {
@@ -309,7 +309,7 @@ casin(double v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: cacos
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 cacos(double v) {
@@ -329,7 +329,7 @@ cmod(double x, double y) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: cpow
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 cpow(double x, double y) {
@@ -338,7 +338,7 @@ cpow(double x, double y) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: cpow
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE int
 cpow(int x, int y) {
@@ -360,43 +360,73 @@ cpow(int x, int y) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: cnan
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE bool
 cnan(double v) {
 #ifndef _WIN32
-  return (std::isnan(v) != 0);
+  return std::isnan(v);
 #else
   return (_isnan(v) != 0);
 #endif
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: cinf
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool
+cinf(double v) {
+#ifndef _WIN32
+  return std::isinf(v);
+#else
+  return (_isnan(v) == 0 && _finite(v) == 0);
+#endif
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: make_nan
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE float
 make_nan(float) {
 #ifndef _WIN32
   return nanf("");
 #else
-  return numeric_limits<float>::quiet_NaN();
+  return std::numeric_limits<float>::quiet_NaN();
 #endif
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: make_nan
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE double 
+INLINE double
 make_nan(double) {
 #ifndef _WIN32
   return nan("");
 #else
-  return numeric_limits<double>::quiet_NaN();
+  return std::numeric_limits<double>::quiet_NaN();
 #endif
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: make_inf
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE float
+make_inf(float) {
+  return std::numeric_limits<float>::infinity();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: make_inf
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE double
+make_inf(double) {
+  return std::numeric_limits<double>::infinity();
+}
 
 ////////////////////////////////////////////////////////////////////
 //     Function: cmod

+ 6 - 2
dtool/src/dtoolbase/cmath.h

@@ -68,13 +68,17 @@ INLINE int cpow(int x, int y);
 // or infinity.
 INLINE bool cnan(double v);
 
-// Returns NaN.
+// Returns true if the number is infinity.
+INLINE bool cinf(double v);
+
+// Return NaN and infinity, respectively.
 INLINE float make_nan(float);
 INLINE double make_nan(double);
+INLINE float make_inf(float);
+INLINE double make_inf(double);
 
 INLINE int cmod(int x, int y);
 
 #include "cmath.I"
 
 #endif
-

+ 85 - 49
dtool/src/dtoolbase/pstrtod.cxx

@@ -17,6 +17,9 @@
 #include <ctype.h>
 #include <math.h>
 
+#ifdef _WIN32
+#define strncasecmp _strnicmp
+#endif
 
 ////////////////////////////////////////////////////////////////////
 //     Function: pstrtod
@@ -45,67 +48,100 @@ pstrtod(const char *nptr, char **endptr) {
   double value = 0.0;
 
   if (isalpha(*p)) {
-    // For special cases like "inf" and "nan", pass these up to the
-    // system implementation of strtod.
-    return strtod(nptr, endptr);
-  }
+    // Windows' implementation of strtod doesn't support "inf" or
+    // "nan", so check for those here.
+    if (strncasecmp(p, "inf", 3) == 0) {
+      p += 3;
+      if (strncasecmp(p, "inity", 5) == 0) {
+        p += 5;
+      }
+      value = std::numeric_limits<double>::infinity();
 
-  // Start reading decimal digits to the left of the decimal point.
-  bool found_digits = false;
-  while (isdigit(*p)) {
-    value = (value * 10.0) + (*p - '0');
-    found_digits = true;
-    ++p;
-  }
-  
-  if (*p == '.') {
-    ++p;
-    // Read decimal digits to the right of the decimal point.
-    double multiplicand = 0.1;
+    } else if (strncasecmp(p, "nan", 3) == 0) {
+      p += 3;
+
+      if (*p == 's' || *p == 'S') {
+        value = std::numeric_limits<double>::signaling_NaN();
+        ++p;
+      } else {
+        if (*p == 'q' || *p == 'Q') {
+          ++p;
+        }
+        value = std::numeric_limits<double>::quiet_NaN();
+      }
+
+      // It is optionally possible to include a character sequence
+      // between parentheses after "nan", to be passed to the new
+      // nan() function.  Since it isn't supported universally, we
+      // will only accept a pair of empty parentheses.
+      if (strncmp(p, "()", 2) == 0) {
+        p += 2;
+      }
+
+    } else {
+      // Pass it up to the system implementation of strtod;
+      // perhaps it knows how to deal with this string.
+      return strtod(nptr, endptr);
+    }
+
+  } else {
+    // Start reading decimal digits to the left of the decimal point.
+    bool found_digits = false;
     while (isdigit(*p)) {
-      value += (*p - '0') * multiplicand;
-      ++p;
+      value = (value * 10.0) + (*p - '0');
       found_digits = true;
-      multiplicand *= 0.1;
-    }
-  }
-  
-  if (!found_digits) {
-    // Not a valid float.
-    if (endptr != NULL) {
-      *endptr = (char *)nptr;
-    }
-    return 0.0;
-  }
-  
-  if (tolower(*p) == 'e') {
-    // There's an exponent.
-    ++p;
-    
-    char esign = '+';
-    if (*p == '+' || *p == '-') {
-      esign = *p;
       ++p;
     }
-    
-    // Start reading decimal digits to the left of the decimal point.
-    double evalue = 0.0;
-    while (isdigit(*p)) {
-      evalue = (evalue * 10.0) + (*p - '0');
+
+    if (*p == '.') {
       ++p;
+      // Read decimal digits to the right of the decimal point.
+      double multiplicand = 0.1;
+      while (isdigit(*p)) {
+        value += (*p - '0') * multiplicand;
+        ++p;
+        found_digits = true;
+        multiplicand *= 0.1;
+      }
     }
-    
-    if (esign == '-') {
-      value /= pow(evalue, 10.0);
-    } else {
-      value *= pow(evalue, 10.0);
+
+    if (!found_digits) {
+      // Not a valid float.
+      if (endptr != NULL) {
+        *endptr = (char *)nptr;
+      }
+      return 0.0;
     }
-  }        
+
+    if (tolower(*p) == 'e') {
+      // There's an exponent.
+      ++p;
+
+      char esign = '+';
+      if (*p == '+' || *p == '-') {
+        esign = *p;
+        ++p;
+      }
+
+      // Start reading decimal digits to the left of the decimal point.
+      double evalue = 0.0;
+      while (isdigit(*p)) {
+        evalue = (evalue * 10.0) + (*p - '0');
+        ++p;
+      }
+
+      if (esign == '-') {
+        value /= pow(evalue, 10.0);
+      } else {
+        value *= pow(evalue, 10.0);
+      }
+    }
+  }
 
   if (sign == '-') {
     value = -value;
   }
-  
+
   if (endptr != NULL) {
     *endptr = (char *)p;
   }