Make nan==nan true for GDScript
After discussing this with Reduz this seemed like the best way to fix #7354. This will make composite values that contain NaN in the same places as well as the same other values compare as the same. Additionally non-composite values now also compare equal if they are both NaN. This breaks IEEE specifications but this is probably what most users expect. There is a GDScript function check for NaN if the user needs this information. This fixes #7354 and probably also fixes #6947
This commit is contained in:
parent
81edda18f3
commit
adcc211feb
9 changed files with 99 additions and 26 deletions
|
@ -157,6 +157,13 @@ bool Vector2::operator!=(const Vector2& p_vec2) const {
|
|||
|
||||
return x!=p_vec2.x || y!=p_vec2.y;
|
||||
}
|
||||
bool Vector2::nan_equals(const Vector2& p_vec2) const {
|
||||
|
||||
return (x==p_vec2.x && y==p_vec2.y) ||
|
||||
(x==p_vec2.x && isnan(y) && isnan(p_vec2.y)) ||
|
||||
(isnan(x) && isnan(p_vec2.x) && y == p_vec2.y);
|
||||
}
|
||||
|
||||
Vector2 Vector2::floor() const {
|
||||
|
||||
return Vector2( Math::floor(x), Math::floor(y) );
|
||||
|
|
|
@ -133,6 +133,7 @@ struct Vector2 {
|
|||
bool operator<(const Vector2& p_vec2) const { return (x==p_vec2.x)?(y<p_vec2.y):(x<p_vec2.x); }
|
||||
bool operator<=(const Vector2& p_vec2) const { return (x==p_vec2.x)?(y<=p_vec2.y):(x<=p_vec2.x); }
|
||||
|
||||
bool nan_equals(const Vector2& p_vec2) const;
|
||||
real_t angle() const;
|
||||
|
||||
void set_rotation(real_t p_radians) {
|
||||
|
@ -319,6 +320,8 @@ struct Rect2 {
|
|||
bool operator==(const Rect2& p_rect) const { return pos==p_rect.pos && size==p_rect.size; }
|
||||
bool operator!=(const Rect2& p_rect) const { return pos!=p_rect.pos || size!=p_rect.size; }
|
||||
|
||||
bool nan_equals(const Rect2& p_rect) const { return pos.nan_equals(p_rect.pos) && size == p_rect.size; }
|
||||
|
||||
inline Rect2 grow(real_t p_by) const {
|
||||
|
||||
Rect2 g=*this;
|
||||
|
|
|
@ -164,3 +164,8 @@ Plane::operator String() const {
|
|||
|
||||
return normal.operator String() + ", " + rtos(d);
|
||||
}
|
||||
|
||||
bool Plane::nan_equals(const Plane& p_plane) const {
|
||||
|
||||
return normal.nan_equals(p_plane.normal) && d == p_plane.d;
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ public:
|
|||
|
||||
_FORCE_INLINE_ bool operator==(const Plane& p_plane) const;
|
||||
_FORCE_INLINE_ bool operator!=(const Plane& p_plane) const;
|
||||
bool nan_equals(const Plane& p_plane) const;
|
||||
operator String() const;
|
||||
|
||||
_FORCE_INLINE_ Plane() { d=0; }
|
||||
|
|
|
@ -284,3 +284,22 @@ Quat::Quat(const Vector3& axis, const real_t& angle) {
|
|||
cos_angle);
|
||||
}
|
||||
}
|
||||
|
||||
bool Quat::nan_equals(const Quat& q2) const {
|
||||
return (x == q2.x && y == q2.y && z == q2.z && w == q2.w) ||
|
||||
(x == q2.x && y == q2.y && z == q2.z && isnan(w) && isnan(q2.w)) ||
|
||||
(x == q2.x && y == q2.y && isnan(z) && isnan(q2.z) && w == q2.w) ||
|
||||
(x == q2.x && y == q2.y && isnan(z) && isnan(q2.z) && isnan(w) && isnan(q2.w)) ||
|
||||
(x == q2.x && isnan(y) && isnan(q2.y) && z == q2.z && w == q2.w) ||
|
||||
(x == q2.x && isnan(y) && isnan(q2.y) && z == q2.z && isnan(w) && isnan(q2.w)) ||
|
||||
(x == q2.x && isnan(y) && isnan(q2.y) && isnan(z) && isnan(q2.z) && w == q2.w) ||
|
||||
(x == q2.x && isnan(y) && isnan(q2.y) && isnan(z) && isnan(q2.z) && isnan(w) && isnan(q2.w)) ||
|
||||
(isnan(x) && isnan(q2.x) && y == q2.y && z == q2.z && w == q2.w) ||
|
||||
(isnan(x) && isnan(q2.x) && y == q2.y && z == q2.z && isnan(w) && isnan(q2.w)) ||
|
||||
(isnan(x) && isnan(q2.x) && y == q2.y && isnan(z) && isnan(q2.z) && w == q2.w) ||
|
||||
(isnan(x) && isnan(q2.x) && y == q2.y && isnan(z) && isnan(q2.z) && isnan(w) && isnan(q2.w)) ||
|
||||
(isnan(x) && isnan(q2.x) && isnan(y) && isnan(q2.y) && z == q2.z && w == q2.w) ||
|
||||
(isnan(x) && isnan(q2.x) && isnan(y) && isnan(q2.y) && z == q2.z && isnan(w) && isnan(q2.w)) ||
|
||||
(isnan(x) && isnan(q2.x) && isnan(y) && isnan(q2.y) && isnan(z) && isnan(q2.z) && w == q2.w) ||
|
||||
(isnan(x) && isnan(q2.x) && isnan(y) && isnan(q2.y) && isnan(z) && isnan(q2.z) && isnan(w) && isnan(q2.w));
|
||||
}
|
||||
|
|
|
@ -93,6 +93,7 @@ public:
|
|||
_FORCE_INLINE_ Quat operator*(const real_t& s) const;
|
||||
_FORCE_INLINE_ Quat operator/(const real_t& s) const;
|
||||
|
||||
bool nan_equals(const Quat& q2) const;
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const Quat& p_quat) const;
|
||||
_FORCE_INLINE_ bool operator!=(const Quat& p_quat) const;
|
||||
|
@ -193,5 +194,4 @@ bool Quat::operator!=(const Quat& p_quat) const {
|
|||
return x!=p_quat.x || y!=p_quat.y || z!=p_quat.z || w!=p_quat.w;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -176,6 +176,17 @@ Vector3 Vector3::cubic_interpolate(const Vector3& p_b,const Vector3& p_pre_a, co
|
|||
return out;
|
||||
}
|
||||
# endif
|
||||
bool Vector3::nan_equals(const Vector3& p_v) const {
|
||||
return (x == p_v.x && y == p_v.y && z == p_v.z) ||
|
||||
(x == p_v.x && y == p_v.y && isnan(z) && isnan(p_v.z)) ||
|
||||
(x == p_v.x && isnan(y) && isnan(p_v.y) && z == p_v.z) ||
|
||||
(isnan(x) && isnan(p_v.x) && y == p_v.y && z == p_v.z) ||
|
||||
(x == p_v.x && isnan(y) && isnan(p_v.y) && isnan(z) && isnan(p_v.z)) ||
|
||||
(isnan(x) && isnan(p_v.x) && y == p_v.y && isnan(z) && isnan(p_v.z)) ||
|
||||
(isnan(x) && isnan(p_v.x) && isnan(y) && isnan(p_v.y) && z == p_v.z) ||
|
||||
(isnan(x) && isnan(p_v.x) && isnan(y) && isnan(p_v.y) && isnan(z) && isnan(p_v.z));
|
||||
}
|
||||
|
||||
Vector3::operator String() const {
|
||||
|
||||
return (rtos(x)+", "+rtos(y)+", "+rtos(z));
|
||||
|
|
|
@ -134,6 +134,7 @@ struct Vector3 {
|
|||
_FORCE_INLINE_ bool operator<(const Vector3& p_v) const;
|
||||
_FORCE_INLINE_ bool operator<=(const Vector3& p_v) const;
|
||||
|
||||
bool nan_equals(const Vector3& p_v) const;
|
||||
operator String() const;
|
||||
|
||||
_FORCE_INLINE_ Vector3() { x=y=z=0; }
|
||||
|
|
|
@ -93,6 +93,18 @@ case m_name: {\
|
|||
return;\
|
||||
};
|
||||
|
||||
#define DEFAULT_OP_NUM_NAN(m_op,m_name,m_type)\
|
||||
case m_name: {\
|
||||
switch(p_b.type) {\
|
||||
case BOOL: _RETURN((p_a._data.m_type m_op p_b._data._bool) || (isnan(p_a._data.m_type) && isnan(p_a._data._bool)));\
|
||||
case INT: _RETURN((p_a._data.m_type m_op p_b._data._int) || (isnan(p_a._data.m_type) && isnan(p_a._data._int)));\
|
||||
case REAL: _RETURN((p_a._data.m_type m_op p_b._data._real) || (isnan(p_a._data.m_type) && isnan(p_a._data._real)));\
|
||||
default: {}\
|
||||
}\
|
||||
r_valid=false;\
|
||||
return;\
|
||||
};
|
||||
|
||||
#define DEFAULT_OP_NUM_NEG(m_name,m_type)\
|
||||
case m_name: {\
|
||||
\
|
||||
|
@ -132,13 +144,12 @@ case m_name: {\
|
|||
|
||||
#define DEFAULT_OP_LOCALMEM(m_op,m_name,m_type)\
|
||||
case m_name: {switch(p_b.type) {\
|
||||
case m_name: _RETURN( *reinterpret_cast<const m_type*>(p_a._data._mem) m_op *reinterpret_cast<const m_type*>(p_b._data._mem));\
|
||||
case m_name: _RETURN( (*reinterpret_cast<const m_type*>(p_a._data._mem))m_op(*reinterpret_cast<const m_type*>(p_b._data._mem)));\
|
||||
default: {}\
|
||||
}\
|
||||
r_valid=false;\
|
||||
return;}
|
||||
|
||||
|
||||
#define DEFAULT_OP_LOCALMEM_NEG(m_name,m_type)\
|
||||
case m_name: {\
|
||||
_RETURN( -*reinterpret_cast<const m_type*>(p_a._data._mem));\
|
||||
|
@ -177,12 +188,27 @@ r_valid=false;\
|
|||
return;}
|
||||
|
||||
#define DEFAULT_OP_ARRAY_EQ(m_name,m_type)\
|
||||
DEFAULT_OP_ARRAY_OP(m_name,m_type,!=,!=,true,false,false)
|
||||
DEFAULT_OP_ARRAY_OP(m_name,m_type,!=,!=,true,false,false,true)
|
||||
|
||||
#define DEFAULT_OP_ARRAY_EQ_NAN(m_name,m_type)\
|
||||
DEFAULT_ARRAY_OP_HEAD(m_name,m_type,!=,false,false)\
|
||||
if ((ra[i] != rb[i]) && (isnan(ra[i]) != isnan(rb[i])))\
|
||||
_RETURN(false);\
|
||||
DEFAULT_ARRAY_OP_FOOT(true)
|
||||
|
||||
#define DEFAULT_OP_ARRAY_EQ_NAN_V(m_name,m_type)\
|
||||
DEFAULT_OP_ARRAY_OP(m_name,m_type,!=,.nan_equals,true,false,false,false)
|
||||
|
||||
#define DEFAULT_OP_ARRAY_LT(m_name,m_type)\
|
||||
DEFAULT_OP_ARRAY_OP(m_name,m_type,<,!=,false,a_len<array_b.size(),true)
|
||||
DEFAULT_OP_ARRAY_OP(m_name,m_type,<,!=,false,a_len<array_b.size(),true,true)
|
||||
|
||||
#define DEFAULT_OP_ARRAY_OP(m_name,m_type,m_opa,m_opb,m_ret_def,m_ret_s,m_ret_f)\
|
||||
#define DEFAULT_OP_ARRAY_OP(m_name,m_type,m_opa,m_opb,m_ret_def,m_ret_s,m_ret_f,m_neg)\
|
||||
DEFAULT_ARRAY_OP_HEAD(m_name,m_type,m_opa,m_ret_s,m_ret_f)\
|
||||
if ((((ra[i])m_opb(rb[i]))==m_neg))\
|
||||
_RETURN(m_ret_f);\
|
||||
DEFAULT_ARRAY_OP_FOOT(m_ret_def)
|
||||
|
||||
#define DEFAULT_ARRAY_OP_HEAD(m_name,m_type,m_opa,m_ret_s,m_ret_f)\
|
||||
case m_name: { \
|
||||
if (p_a.type!=p_b.type) {\
|
||||
r_valid=false;\
|
||||
|
@ -200,8 +226,8 @@ case m_name: { \
|
|||
PoolVector<m_type>::Read rb = array_b.read();\
|
||||
\
|
||||
for(int i=0;i<a_len;i++) {\
|
||||
if (ra[i] m_opb rb[i])\
|
||||
_RETURN( m_ret_f);\
|
||||
|
||||
#define DEFAULT_ARRAY_OP_FOOT(m_ret_def)\
|
||||
}\
|
||||
\
|
||||
_RETURN(m_ret_def);\
|
||||
|
@ -258,16 +284,16 @@ void Variant::evaluate(const Operator& p_op, const Variant& p_a, const Variant&
|
|||
_RETURN(p_b.type==NIL || (p_b.type==Variant::OBJECT && !p_b._get_obj().obj));
|
||||
} break;
|
||||
|
||||
DEFAULT_OP_NUM(==,BOOL,_bool);
|
||||
DEFAULT_OP_NUM(==,INT,_int);
|
||||
DEFAULT_OP_NUM(==,REAL,_real);
|
||||
DEFAULT_OP_NUM_NAN(==,BOOL,_bool);
|
||||
DEFAULT_OP_NUM_NAN(==,INT,_int);
|
||||
DEFAULT_OP_NUM_NAN(==,REAL,_real);
|
||||
DEFAULT_OP_STR(==,STRING,String);
|
||||
DEFAULT_OP_LOCALMEM(==,VECTOR2,Vector2);
|
||||
DEFAULT_OP_LOCALMEM(==,RECT2,Rect2);
|
||||
DEFAULT_OP_LOCALMEM(.nan_equals,VECTOR2,Vector2);
|
||||
DEFAULT_OP_LOCALMEM(.nan_equals,RECT2,Rect2);
|
||||
DEFAULT_OP_PTRREF(==,TRANSFORM2D,_transform2d);
|
||||
DEFAULT_OP_LOCALMEM(==,VECTOR3,Vector3);
|
||||
DEFAULT_OP_LOCALMEM(==,PLANE,Plane);
|
||||
DEFAULT_OP_LOCALMEM(==,QUAT,Quat);
|
||||
DEFAULT_OP_LOCALMEM(.nan_equals,VECTOR3,Vector3);
|
||||
DEFAULT_OP_LOCALMEM(.nan_equals,PLANE,Plane);
|
||||
DEFAULT_OP_LOCALMEM(.nan_equals,QUAT,Quat);
|
||||
DEFAULT_OP_PTRREF(==,RECT3,_rect3);
|
||||
DEFAULT_OP_PTRREF(==,BASIS,_basis);
|
||||
DEFAULT_OP_PTRREF(==,TRANSFORM,_transform);
|
||||
|
@ -319,11 +345,11 @@ void Variant::evaluate(const Operator& p_op, const Variant& p_a, const Variant&
|
|||
|
||||
|
||||
DEFAULT_OP_ARRAY_EQ(POOL_BYTE_ARRAY,uint8_t);
|
||||
DEFAULT_OP_ARRAY_EQ(POOL_INT_ARRAY,int);
|
||||
DEFAULT_OP_ARRAY_EQ(POOL_REAL_ARRAY,real_t);
|
||||
DEFAULT_OP_ARRAY_EQ_NAN(POOL_INT_ARRAY,int);
|
||||
DEFAULT_OP_ARRAY_EQ_NAN(POOL_REAL_ARRAY,real_t);
|
||||
DEFAULT_OP_ARRAY_EQ(POOL_STRING_ARRAY,String);
|
||||
DEFAULT_OP_ARRAY_EQ(POOL_VECTOR2_ARRAY,Vector3);
|
||||
DEFAULT_OP_ARRAY_EQ(POOL_VECTOR3_ARRAY,Vector3);
|
||||
DEFAULT_OP_ARRAY_EQ_NAN_V(POOL_VECTOR2_ARRAY,Vector3);
|
||||
DEFAULT_OP_ARRAY_EQ_NAN_V(POOL_VECTOR3_ARRAY,Vector3);
|
||||
DEFAULT_OP_ARRAY_EQ(POOL_COLOR_ARRAY,Color);
|
||||
|
||||
case VARIANT_MAX: {
|
||||
|
@ -416,9 +442,9 @@ void Variant::evaluate(const Operator& p_op, const Variant& p_a, const Variant&
|
|||
switch(p_a.type) {
|
||||
|
||||
DEFAULT_OP_FAIL(NIL);
|
||||
DEFAULT_OP_NUM(<=,BOOL,_bool);
|
||||
DEFAULT_OP_NUM(<=,INT,_int);
|
||||
DEFAULT_OP_NUM(<=,REAL,_real);
|
||||
DEFAULT_OP_NUM_NAN(<=,BOOL,_bool);
|
||||
DEFAULT_OP_NUM_NAN(<=,INT,_int);
|
||||
DEFAULT_OP_NUM_NAN(<=,REAL,_real);
|
||||
DEFAULT_OP_STR(<=,STRING,String);
|
||||
DEFAULT_OP_LOCALMEM(<=,VECTOR2,Vector2);
|
||||
DEFAULT_OP_FAIL(RECT2);
|
||||
|
|
Loading…
Reference in a new issue