class RuboCop::Cop::Lint::FloatComparison
Checks for the presence of precise comparison of floating point numbers.
Floating point values are inherently inaccurate, and comparing them for exact equality is almost never the desired semantics. Comparison via the `==/!=` operators checks floating-point value representation to be exactly the same, which is very unlikely if you perform any arithmetic operations involving precision loss.
@example
# bad x == 0.1 x != 0.1 # good - using BigDecimal x.to_d == 0.1.to_d # good (x - 0.1).abs < Float::EPSILON # good tolerance = 0.0001 (x - 0.1).abs < tolerance # Or some other epsilon based type of comparison: # https://www.embeddeduse.com/2019/08/26/qt-compare-two-floats/
Constants
- EQUALITY_METHODS
- FLOAT_INSTANCE_METHODS
- FLOAT_RETURNING_METHODS
- MSG
- RESTRICT_ON_SEND
Public Instance Methods
on_send(node)
click to toggle source
# File lib/rubocop/cop/lint/float_comparison.rb, line 40 def on_send(node) lhs, _method, rhs = *node add_offense(node) if float?(lhs) || float?(rhs) end
Private Instance Methods
check_numeric_returning_method(node)
click to toggle source
rubocop:enable Metrics/PerceivedComplexity
# File lib/rubocop/cop/lint/float_comparison.rb, line 79 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
check_send(node)
click to toggle source
rubocop:disable Metrics/PerceivedComplexity
# File lib/rubocop/cop/lint/float_comparison.rb, line 63 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
float?(node)
click to toggle source
# File lib/rubocop/cop/lint/float_comparison.rb, line 47 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