@@ -1017,6 +1017,20 @@ private IRubyObject float_cmp(ThreadContext context, RubyFloat y) {
10171017 return RubyFixnum .minus_one (runtime );
10181018 }
10191019
1020+ // mri : rb_integer_float_eq
1021+ private boolean float_eq (ThreadContext context , RubyFloat y ) {
1022+ double yd = y .value ;
1023+
1024+ if (Double .isNaN (yd ) || Double .isInfinite (yd )) return false ;
1025+
1026+ // if yd has a fractional part, it can't equal an integer
1027+ if (Math .floor (yd ) != yd ) return false ;
1028+
1029+ // compare as integers to avoid precision loss
1030+ IRubyObject rel = op_cmp (context , newBignorm (context .runtime , yd ));
1031+ return rel instanceof RubyFixnum fix && fix .getLongValue () == 0 ;
1032+ }
1033+
10201034 @ Override
10211035 public final int compareTo (IRubyObject other ) {
10221036 if (other instanceof RubyBignum bignum ) return value .compareTo (bignum .value );
@@ -1045,9 +1059,7 @@ public IRubyObject op_cmp(ThreadContext context, IRubyObject other) {
10451059 } else if (other instanceof RubyBignum big ) {
10461060 otherValue = big .value ;
10471061 } else if (other instanceof RubyFloat flt ) {
1048- return flt .isInfinite () ?
1049- asFixnum (context , flt .value > 0.0 ? -1 : 1 ) :
1050- dbl_cmp (context .runtime , big2dbl (this ), flt .value );
1062+ return float_cmp (context , flt );
10511063 } else {
10521064 return coerceCmp (context , sites (context ).op_cmp , other );
10531065 }
@@ -1067,9 +1079,7 @@ public IRubyObject op_equal(ThreadContext context, IRubyObject other) {
10671079 } else if (other instanceof RubyBignum bignum ) {
10681080 otherValue = bignum .value ;
10691081 } else if (other instanceof RubyFloat flote ) {
1070- double a = flote .value ;
1071- if (Double .isNaN (a ) || Double .isInfinite (a )) return context .fals ;
1072- return asBoolean (context , a == big2dbl (this ));
1082+ return asBoolean (context , float_eq (context , flote ));
10731083 } else {
10741084 return other .op_eqq (context , this );
10751085 }
0 commit comments