Skip to content

Commit

Permalink
Fix float point comparisons
Browse files Browse the repository at this point in the history
- ceq IL instruction wasn't properly implemented to deal with NAN and infinite values.
- rework code to use ISO C99 floating-point macros for FP comparisons.
- Move declarations of native double to header to allow reuse on the new comparison code.

Signed-off-by: josesimoes <jose.simoes@eclo.solutions>
  • Loading branch information
josesimoes committed Apr 28, 2020
1 parent a27e35f commit 6c22546
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 52 deletions.
88 changes: 82 additions & 6 deletions src/CLR/Core/CLR_RT_HeapBlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
//
#include "Core.h"
#include <nanoHAL.h>
#include <nanoPAL_NativeDouble.h>

////////////////////////////////////////////////////////////////////////////////////////////////////

Expand Down Expand Up @@ -1336,15 +1337,90 @@ CLR_INT32 CLR_RT_HeapBlock::Compare_Values( const CLR_RT_HeapBlock& left, const
#if !defined(NANOCLR_EMULATED_FLOATINGPOINT)

case DATATYPE_R4:
if(left.NumericByRefConst().r4 > right.NumericByRefConst().r4) return 1;
if(left.NumericByRefConst().r4 < right.NumericByRefConst().r4) return -1;
/************************************************************/ return 0;

// deal with special cases:
// return 0 if the numbers are unordered (either or both are NaN)
// this is post processed in interpreter so '1' will turn into '0'
if(
__isnand(left.NumericByRefConst().r4) ||
__isnand(right.NumericByRefConst().r4))
{
return 1;
}

// The infinite values are equal to themselves.
// this is post processed in interpreter so '0' will turn into '1'
else if(
__isinfd(left.NumericByRefConst().r4) &&
__isinfd(right.NumericByRefConst().r4))
{
return 0;
}
// all the rest now
else
{
if(
isgreater(
left.NumericByRefConst().r4,
right.NumericByRefConst().r4))
{
return 1;
}
else if(
isless(
left.NumericByRefConst().r4,
right.NumericByRefConst().r4))
{
return -1;
}
else
{
return 0;
}
}

case DATATYPE_R8:

if(left.NumericByRefConst().r8 > right.NumericByRefConst().r8) return 1;
if(left.NumericByRefConst().r8 < right.NumericByRefConst().r8) return -1;
/************************************************************/ return 0;
// deal with special cases:
// return 0 if the numbers are unordered (either or both are NaN)
// this is post processed in interpreter so '1' will turn into '0'
if(
__isnand((double)left.NumericByRefConst().r8) ||
__isnand((double)right.NumericByRefConst().r8))
{
return 1;
}

// The infinite values are equal to themselves.
// this is post processed in interpreter so '0' will turn into '1'
else if(
__isinfd((double)left.NumericByRefConst().r8) &&
__isinfd((double)right.NumericByRefConst().r8))
{
return 0;
}
// all the rest now
else
{
if(
isgreater(
(double)left.NumericByRefConst().r8,
(double)right.NumericByRefConst().r8))
{
return 1;
}
else if(
isless(
(double)left.NumericByRefConst().r8,
(double)right.NumericByRefConst().r8))
{
return -1;
}
else
{
return 0;
}
}

#else
case DATATYPE_R4 :
Expand Down
46 changes: 0 additions & 46 deletions src/PAL/Double/nanoPAL_NativeDouble.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,52 +7,6 @@
#include "stdafx.h"
#include "nanoPAL_NativeDouble.h"

#include <math.h>

#ifdef WIN32
#include <float.h>

#define __isnand _isnan
#define __isinfd(x) (!_finite(x))

inline int __signbitd(double x)
{
unsigned char *ptr = (unsigned char*) &x;
return (*(ptr + (sizeof(double) - 1)) & 0x80) != 0;
}

#define rint(x) floor((x) + 0.5)
#define remainder(x,y) ((x) - ((y) * rint((x) / (y))))

#define isgreater(param0,param1) (param0 > param1)
#define isless(param0,param1) (param0 < param1)

#elif defined(__GNUC__)

#if !defined( isgreater )
#define isgreater __builtin_isgreater
#endif

#if !defined( isless )
#define isless __builtin_isless
#endif

#if !defined( __isnand )
#define __isnand __builtin_isnan
#endif

#if !defined( __isinfd )
#define __isinfd __builtin_isinf
#endif

#if !defined( __signbitd )
#define __signbitd __builtin_signbit
#endif

#endif



using namespace System;
// Summary:
// Compares this instance to a specified double-precision floating-point number
Expand Down
44 changes: 44 additions & 0 deletions src/PAL/Include/nanoPAL_NativeDouble.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,50 @@

#include <nanoHAL.h>

#include <math.h>

#ifdef WIN32
#include <float.h>

#define __isnand _isnan
#define __isinfd(x) (!_finite(x))

inline int __signbitd(double x)
{
unsigned char *ptr = (unsigned char*) &x;
return (*(ptr + (sizeof(double) - 1)) & 0x80) != 0;
}

#define rint(x) floor((x) + 0.5)
#define remainder(x,y) ((x) - ((y) * rint((x) / (y))))

#define isgreater(param0,param1) (param0 > param1)
#define isless(param0,param1) (param0 < param1)

#elif defined(__GNUC__)

#if !defined( isgreater )
#define isgreater __builtin_isgreater
#endif

#if !defined( isless )
#define isless __builtin_isless
#endif

#if !defined( __isnand )
#define __isnand __builtin_isnan
#endif

#if !defined( __isinfd )
#define __isinfd __builtin_isinf
#endif

#if !defined( __signbitd )
#define __signbitd __builtin_signbit
#endif

#endif

namespace System
{
struct Double
Expand Down

0 comments on commit 6c22546

Please sign in to comment.