Explorar el Código

Introduced a more accurate float comparison.

Marco Bambini hace 7 años
padre
commit
740b34a250
Se han modificado 2 ficheros con 33 adiciones y 0 borrados
  1. 31 0
      src/runtime/gravity_core.c
  2. 2 0
      src/shared/gravity_value.h

+ 31 - 0
src/runtime/gravity_core.c

@@ -1565,7 +1565,38 @@ static bool operator_float_cmp (gravity_vm *vm, gravity_value_t *args, uint16_t
 
 	DECLARE_2VARIABLES(v1, v2, 0, 1);
 	INTERNAL_CONVERT_FLOAT(v2);
+    
+    // simpler equality test
 	if (v1.f == v2.f) RETURN_VALUE(VALUE_FROM_INT(0), rindex);
+    
+    #if GRAVITY_ENABLE_DOUBLE
+    double diff = fabs(v1.f - v2.f);
+    #else
+    float diff = fabsf(v1.f - v2.f);
+    #endif
+    
+    // simple equality test
+    if (diff < FLOAT_EPSILON) RETURN_VALUE(VALUE_FROM_INT(0), rindex);
+    
+    // a more accurate equality test is needed for floating point numbers
+    // from https://stackoverflow.com/questions/30808556/float-vs-double-comparison
+    // and http://floating-point-gui.de/errors/comparison/
+    // check also https://bitbashing.io/comparing-floats.html
+    if (v1.f == 0 || v2.f == 0 || diff < FLOAT_MIN) {
+        if (diff < (FLOAT_EPSILON * FLOAT_MIN)) RETURN_VALUE(VALUE_FROM_INT(0), rindex);
+    } else {
+        #if GRAVITY_ENABLE_DOUBLE
+        double a = fabs((double)v1.f);
+        double b = fabs((double)v2.f);
+        double min = fmin(a + b, FLOAT_MAX);
+        #else
+        float a = fabsf((float)v1.f);
+        float b = fabsf((float)v2.f);
+        float min = fminf(a + b, FLOAT_MAX);
+        #endif
+        if (diff / min < FLOAT_EPSILON) RETURN_VALUE(VALUE_FROM_INT(0), rindex);
+    }
+    
 	if (v1.f > v2.f) RETURN_VALUE(VALUE_FROM_INT(1), rindex);
 	RETURN_VALUE(VALUE_FROM_INT(-1), rindex);
 }

+ 2 - 0
src/shared/gravity_value.h

@@ -166,10 +166,12 @@ extern "C" {
 typedef double								gravity_float_t;
 #define FLOAT_MAX                           DBL_MAX
 #define FLOAT_MIN                           DBL_MIN
+#define FLOAT_EPSILON                       0.00001
 #else
 typedef float								gravity_float_t;
 #define FLOAT_MAX                           FLT_MAX
 #define FLOAT_MIN                           FLT_MIN
+#define FLOAT_EPSILON                       0.00001
 #endif
 
 #if GRAVITY_ENABLE_INT64