class RuboCop::Cop::Lint::FloatComparison
# www.embeddeduse.com/2019/08/26/qt-compare-two-floats/
# Or some other epsilon based type of comparison:
(x - 0.1).abs < tolerance
tolerance = 0.0001
# good
(x - 0.1).abs < Float::EPSILON
# good
x.to_d == 0.1.to_d
# good - using BigDecimal
x != 0.1
x == 0.1
# bad
@example
if you perform any arithmetic operations involving precision loss.
floating-point value representation to be exactly the same, which is very unlikely
is almost never the desired semantics. Comparison via the ‘==/!=` operators checks
Floating point values are inherently inaccurate, and comparing them for exact equality
This cop checks for the presence of precise comparison of floating point numbers.
def check_numeric_returning_method(node)
def check_numeric_returning_method(node) return false unless node.receiver case node.method_name when :angle, :arg, :phase Float(node.receiver.source).negative? when :ceil, :floor, :round, :truncate precision = node.first_argument precision&.int_type? && Integer(precision.source).positive? end end
def check_send(node)
def check_send(node) if node.arithmetic_operation? lhs, _operation, rhs = *node float?(lhs) || float?(rhs) elsif FLOAT_RETURNING_METHODS.include?(node.method_name) true elsif node.receiver&.float_type? if FLOAT_INSTANCE_METHODS.include?(node.method_name) true else check_numeric_returning_method(node) end end end
def float?(node)
def float?(node) return false unless node case node.type when :float true when :send check_send(node) when :begin float?(node.children.first) else false end end
def on_send(node)
def on_send(node) lhs, _method, rhs = *node add_offense(node) if float?(lhs) || float?(rhs) end