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 - comparing against zero x == 0.0 x != 0.0 # 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 44 def on_send(node) lhs, _method, rhs = *node return if literal_zero?(lhs) || literal_zero?(rhs) 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 89 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 73 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 53 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
literal_zero?(node)
click to toggle source
# File lib/rubocop/cop/lint/float_comparison.rb, line 68 def literal_zero?(node) node&.numeric_type? && node.value.zero? end