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)

rubocop:disable Metrics/PerceivedComplexity
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