Correct floating point on old MSVC

Visual Studio 6 and earlier have somewhat insane handling of comparisons
with nan values. Provide alternate (slower) versions of float comparison
functions using isnan rather than standardized comparison behaviour.
master
David Allsopp 2016-01-11 16:59:16 +00:00 committed by alainfrisch
parent 709d89b438
commit 78293a0775
3 changed files with 66 additions and 20 deletions

View File

@ -21,6 +21,10 @@
#include "caml/misc.h"
#include "caml/mlvalues.h"
#if defined(LACKS_SANE_NAN) && !defined(isnan)
#define isnan _isnan
#endif
/* Structural comparison on trees. */
struct compare_item { value * v1, * v2; mlsize_t count; };
@ -174,8 +178,19 @@ static intnat compare_val(value v1, value v2, int total)
case Double_tag: {
double d1 = Double_val(v1);
double d2 = Double_val(v2);
#ifdef LACKS_SANE_NAN
if (isnan(d2)) {
if (! total) return UNORDERED;
if (isnan(d1)) break;
return GREATER;
} else if (isnan(d1)) {
if (! total) return UNORDERED;
return LESS;
}
#endif
if (d1 < d2) return LESS;
if (d1 > d2) return GREATER;
#ifndef LACKS_SANE_NAN
if (d1 != d2) {
if (! total) return UNORDERED;
/* One or both of d1 and d2 is NaN. Order according to the
@ -184,6 +199,7 @@ static intnat compare_val(value v1, value v2, int total)
if (d2 == d2) return LESS; /* d2 is not NaN, d1 is NaN */
/* d1 and d2 are both NaN, thus equal: continue comparison */
}
#endif
break;
}
case Double_array_tag: {
@ -194,14 +210,26 @@ static intnat compare_val(value v1, value v2, int total)
for (i = 0; i < sz1; i++) {
double d1 = Double_field(v1, i);
double d2 = Double_field(v2, i);
#ifdef LACKS_SANE_NAN
if (isnan(d2)) {
if (! total) return UNORDERED;
if (isnan(d1)) break;
return GREATER;
} else if (isnan(d1)) {
if (! total) return UNORDERED;
return LESS;
}
#endif
if (d1 < d2) return LESS;
if (d1 > d2) return GREATER;
#ifndef LACKS_SANE_NAN
if (d1 != d2) {
if (! total) return UNORDERED;
/* See comment for Double_tag case */
if (d1 == d1) return GREATER;
if (d2 == d2) return LESS;
}
#endif
}
break;
}

View File

@ -555,34 +555,41 @@ CAMLprim value caml_copysign_float(value f, value g)
return caml_copy_double(caml_copysign(Double_val(f), Double_val(g)));
}
CAMLprim value caml_eq_float(value f, value g)
#ifdef LACKS_SANE_NAN
CAMLprim value caml_neq_float(value vf, value vg)
{
return Val_bool(Double_val(f) == Double_val(g));
double f = Double_val(vf);
double g = Double_val(vg);
return Val_bool(isnan(f) || isnan(g) || f != g);
}
#define DEFINE_NAN_CMP(op) (value vf, value vg) \
{ \
double f = Double_val(vf); \
double g = Double_val(vg); \
return Val_bool(!isnan(f) && !isnan(g) && f op g); \
}
intnat caml_float_compare_unboxed(double f, double g)
{
/* Insane => nan == everything && nan < everything && nan > everything */
if (isnan(f) && isnan(g)) return 0;
if (!isnan(g) && f < g) return -1;
if (f != g) return 1;
return 0;
}
#else
CAMLprim value caml_neq_float(value f, value g)
{
return Val_bool(Double_val(f) != Double_val(g));
}
CAMLprim value caml_le_float(value f, value g)
{
return Val_bool(Double_val(f) <= Double_val(g));
}
CAMLprim value caml_lt_float(value f, value g)
{
return Val_bool(Double_val(f) < Double_val(g));
}
CAMLprim value caml_ge_float(value f, value g)
{
return Val_bool(Double_val(f) >= Double_val(g));
}
CAMLprim value caml_gt_float(value f, value g)
{
return Val_bool(Double_val(f) > Double_val(g));
#define DEFINE_NAN_CMP(op) (value f, value g) \
{ \
return Val_bool(Double_val(f) op Double_val(g)); \
}
intnat caml_float_compare_unboxed(double f, double g)
@ -594,6 +601,14 @@ intnat caml_float_compare_unboxed(double f, double g)
return (f > g) - (f < g) + (f == f) - (g == g);
}
#endif
CAMLprim value caml_eq_float DEFINE_NAN_CMP(==)
CAMLprim value caml_le_float DEFINE_NAN_CMP(<=)
CAMLprim value caml_lt_float DEFINE_NAN_CMP(<)
CAMLprim value caml_ge_float DEFINE_NAN_CMP(>=)
CAMLprim value caml_gt_float DEFINE_NAN_CMP(>)
CAMLprim value caml_float_compare(value vf, value vg)
{
return Val_int(caml_float_compare_unboxed(Double_val(vf),Double_val(vg)));

View File

@ -34,3 +34,6 @@
#define HAS_IPV6
#define HAS_NICE
#define SUPPORT_DYNAMIC_LINKING
#if defined(_MSC_VER) && _MSC_VER < 1300
#define LACKS_SANE_NAN
#endif