Submitted by timpease (Fri Jul 07 18:26:05 UTC 2006)
(0.1 + 0.2) == 0.3 => false
The comparison is obviously true, but round-off error in the processor causes the addition operation to produce an inexact number.
The first new method would be Float#=~ It would perform approximate comparison with another object, and it would follow the same semantics of Float#== i.e. perform type conversion. The Float::EPSILON constant would be used internally by this method.
The second new method would be Float#epsilon_eql? It would perform approximate comparison with another Float object, and it would allow the user to specify the epsilon. This method would follow the same semantics of Float#eql?
Syntax:
1.0 =~ 1 => true 1.0000000000000001 =~ 1.0 => true 1.000000000000001 =~ 1.0 => false (0.1 + 0.2) =~ 0.3 => true 1.0.epsilon_eql? 1 # using Float::EPSILON => false 1.0.epsilon_eql? 1.0 # using Float::EPSILON => true 1.000001.epsilon_eql?(1.0, 0.000001) => true 1.000001.epsilon_eql?(1.0, 0.0000001) => false
/* in numeric.c */ static VALUE flo_epsilon_eq(x, y) VALUE x, y; { volatile double a, b; switch (TYPE(y)) { case T_FIXNUM: b = FIX2LONG(y); break; case T_BIGNUM: b = rb_big2dbl(y); break; case T_FLOAT: b = RFLOAT(y)->value; if (isnan(b)) return Qfalse; break; default: /* defaults to normal equality check */ return num_equal(x, y); } a = RFLOAT(x)->value; if (isnan(a)) return Qfalse; if (b == 0.0) return (a <= DBL_EPSILON)?Qtrue:Qfalse; return (fabs((b-a)/b) <= DBL_EPSILON)?Qtrue:Qfalse; } static VALUE flo_epsilon_eql(argc, argv, x) int argc; VALUE* argv; VALUE x; { VALUE y, e; rb_scan_args( argc, argv, "11", &y, &e ); if (TYPE(y) == TFLOAT) { double epsilon = DBL_EPSILON; if (!NIL_P(e)) { if (TYPE(e) != TFLOAT) { rb_raise(rb_eTypeError, "epsilon must be a Float"); } epsilon = RFLOAT(e)->value; if (isnan(epsilon)) return Qfalse; epsilon = fabs(epsilon); } double a = RFLOAT(x)->value; double b = RFLOAT(y)->value; if (isnan(a) || isnan(b)) return Qfalse; if (b == 0.0) return (a <= epsilon)?Qtrue:Qfalse; return (fabs((b-a)/b) <= epsilon)?Qtrue:Qfalse; } return Qfalse; } rb_define_method(rb_cFloat, "=~", flo_epsilon_eq, 1); rb_define_method(rb_cFloat, "epsilon_eql?", flo_epsilon_eql, -1);
Comments | Current voting | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
RCRchive copyright © David Alan Black, 2003-2005.
Powered by .