Test cases for the relatively equality comparision method
require 'rails_helper' | |
require 'rantly/rspec_extensions' | |
require_relative '../../app/lib/math.rb' | |
RSpec.describe Math do | |
describe 'close?' do | |
context 'non numeric arguments' do | |
it 'raises exception' do | |
expect { Math.close?(nil, 0) }.to raise_error(ArgumentError) | |
expect { Math.close?(0, nil) }.to raise_error(ArgumentError) | |
end | |
end | |
context 'negative tolerance values' do | |
it 'raises exception' do | |
expect { Math.close?(0, 0, rel_tol: -1) }.to raise_error(ArgumentError) | |
expect { Math.close?(0, 0, abs_tol: -1) }.to raise_error(ArgumentError) | |
end | |
end | |
context 'Infinite values' do | |
it 'returns false when a is either side of Infinite value' do | |
expect(Math.close?(Float::INFINITY, 0)).to be_falsey | |
expect(Math.close?(-Float::INFINITY, 0)).to be_falsey | |
end | |
end | |
context 'integers' do | |
it 'returns true for same numbers' do | |
expect(Math.close?(0, 0)).to be_truthy | |
expect(Math.close?(10, 10)).to be_truthy | |
end | |
it 'returns false for different numbers' do | |
expect(Math.close?(10, 11)).to be_falsey | |
expect(Math.close?(0, 1)).to be_falsey | |
end | |
end | |
context 'large numbers' do | |
let (:exp10) { 1.0E10 } | |
it 'returns true for same positive numbers' do | |
expect(Math.close?(exp10, exp10 + 1)).to be_truthy | |
expect(Math.close?(exp10 + 1, exp10)).to be_truthy | |
end | |
it 'returns true for same negative numbers' do | |
expect(Math.close?(-exp10, -(exp10 + 1))).to be_truthy | |
expect(Math.close?(-(exp10 + 1), -exp10)).to be_truthy | |
end | |
it 'returns false for different positive numbers' do | |
expect(Math.close?(1000_000.0, 1000_001.0)).to be_falsey | |
expect(Math.close?(1000_001.0, 1000_000.0)).to be_falsey | |
end | |
it 'returns false for different negative numbers' do | |
expect(Math.close?(-1000_000.0, -1000_001.0)).to be_falsey | |
expect(Math.close?(-1000_001.0, -1000_000.0)).to be_falsey | |
end | |
end | |
context 'Numbers around ' do | |
it '1 returns true for same positive numbers' do | |
expect(Math.close?(1.000000001, 1.000000002)).to be_truthy | |
expect(Math.close?(1.000000002, 1.000000001)).to be_truthy | |
end | |
it '-1 returns true for same negative numbers' do | |
expect(Math.close?(-1.000000001, -1.000000002)).to be_truthy | |
expect(Math.close?(-1.000000002, -1.000000001)).to be_truthy | |
end | |
it '1 returns false for different positive numbers' do | |
expect(Math.close?(1.00000002, 1.00000001)).to be_falsey | |
expect(Math.close?(1.00000001, 1.00000002)).to be_falsey | |
end | |
it '-1 returns false for different negative numbers' do | |
expect(Math.close?(-1.00000002, -1.00000001)).to be_falsey | |
expect(Math.close?(-1.00000001, -1.00000002)).to be_falsey | |
end | |
end | |
context 'Numbers between 1 and 0' do | |
let (:absolute_tolerance) { 1.0E-14 } | |
it 'returns true for same positive numbers' do | |
expect(Math.close?(1000001.0E-15, 1000002.0E-15, abs_tol: absolute_tolerance)).to be_truthy | |
expect(Math.close?(1000002.0E-15, 1000001.0E-15, abs_tol: absolute_tolerance)).to be_truthy | |
end | |
it 'returns true for same negative numbers' do | |
expect(Math.close?(-1000001.0E-15, -1000002.0E-15, abs_tol: absolute_tolerance)).to be_truthy | |
expect(Math.close?(-1000002.0E-15, -1000001.0E-15, abs_tol: absolute_tolerance)).to be_truthy | |
end | |
it 'returns false for different positive numbers' do | |
expect(Math.close?(1000010.0E-15, 1000020.0E-15, abs_tol: absolute_tolerance)).to be_falsey | |
expect(Math.close?(1000020.0E-15, 1000010.0E-15, abs_tol: absolute_tolerance)).to be_falsey | |
end | |
it 'returns false for different negative numbers' do | |
expect(Math.close?(-1000010.0E-15, -1000020.0E-15, abs_tol: absolute_tolerance)).to be_falsey | |
expect(Math.close?(-1000020.0E-15, -1000010.0E-15, abs_tol: absolute_tolerance)).to be_falsey | |
end | |
end | |
context 'Numbers with small differences away from 0' do | |
let (:absolute_tolerance) { 1.0E-7 } | |
it 'returns true' do | |
expect(Math.close?(0.3, 0.30000003, abs_tol: absolute_tolerance)).to be_truthy | |
expect(Math.close?(-0.3, -0.30000003, abs_tol: absolute_tolerance)).to be_truthy | |
end | |
end | |
context 'Involving zero' do | |
let (:high_absolute_tolerance) { 1.0E-41 } | |
let (:low_absolute_tolerance) { 1.0E-2 } | |
it 'returns true in case of zero absolute value' do | |
expect(Math.close?(0.0, 0.0)).to be_truthy | |
expect(Math.close?(0.0, -0.0)).to be_truthy | |
expect(Math.close?(-0.0, 0.0)).to be_truthy | |
end | |
it 'returns true in case of low accuracy required' do | |
# with low absolute tolerance - low accuracy | |
expect(Math.close?(0.00000001, 0.0, abs_tol: low_absolute_tolerance)).to be_truthy | |
expect(Math.close?(0.0, 0.00000001, abs_tol: low_absolute_tolerance)).to be_truthy | |
expect(Math.close?(-0.00000001, 0.0, abs_tol: low_absolute_tolerance)).to be_truthy | |
expect(Math.close?(0.0, -0.00000001, abs_tol: low_absolute_tolerance)).to be_truthy | |
expect(Math.close?(0.0, 1E-40, abs_tol: low_absolute_tolerance)).to be_truthy | |
expect(Math.close?(1E-40, 0.0, abs_tol: low_absolute_tolerance)).to be_truthy | |
end | |
it 'return false in case of high accuracy required' do | |
# with high absolute tolerance - high accuracy | |
expect(Math.close?(0.00000001, 0.0, abs_tol: high_absolute_tolerance)).to be_falsey | |
expect(Math.close?(0.0, 0.00000001, abs_tol: high_absolute_tolerance)).to be_falsey | |
expect(Math.close?(-0.00000001, 0.0, abs_tol: high_absolute_tolerance)).to be_falsey | |
expect(Math.close?(0.0, -0.00000001, abs_tol: high_absolute_tolerance)).to be_falsey | |
expect(Math.close?(0.0, 1E-40, abs_tol: high_absolute_tolerance)).to be_falsey | |
expect(Math.close?(1E-40, 0.0, abs_tol: high_absolute_tolerance)).to be_falsey | |
end | |
end | |
context 'Numbers on opposite sides of 0' do | |
let (:minus_exp9) { 1.0E-9 } | |
let (:min_value) { 10**Float::MIN_EXP } | |
let (:high_absolute_tolerance) { 1.0E-307 } | |
it 'returns false' do | |
expect(Math.close?(1 + minus_exp9, -1.0)).to be_falsey | |
expect(Math.close?(-1.0, 1 + minus_exp9)).to be_falsey | |
expect(Math.close?(-(1 + minus_exp9), 1.0)).to be_falsey | |
expect(Math.close?(1.0, -(1 + minus_exp9))).to be_falsey | |
end | |
it 'return true in case of numbers near zero' do | |
expect(Math.close?(10 * min_value, 10 * -min_value, abs_tol: high_absolute_tolerance)).to be_truthy | |
end | |
end | |
context 'Numbers very close to zero' do | |
let (:min_value) { 10**Float::MIN_EXP } | |
let (:minus_exp9) { 1.0E-9 } | |
let (:high_absolute_tolerance) { 1.0E-40 } | |
it 'return true' do | |
expect(Math.close?(min_value, min_value, abs_tol: high_absolute_tolerance)).to be_truthy | |
expect(Math.close?(min_value, -min_value, abs_tol: high_absolute_tolerance)).to be_truthy | |
expect(Math.close?(-min_value, min_value, abs_tol: high_absolute_tolerance)).to be_truthy | |
expect(Math.close?(min_value, 0, abs_tol: high_absolute_tolerance)).to be_truthy | |
expect(Math.close?(0, min_value, abs_tol: high_absolute_tolerance)).to be_truthy | |
expect(Math.close?(-min_value, 0, abs_tol: high_absolute_tolerance)).to be_truthy | |
expect(Math.close?(0, -min_value, abs_tol: high_absolute_tolerance)).to be_truthy | |
end | |
it 'returns false' do | |
expect(Math.close?(min_value, minus_exp9, abs_tol: high_absolute_tolerance)).to be_falsey | |
expect(Math.close?(-min_value, minus_exp9, abs_tol: high_absolute_tolerance)).to be_falsey | |
expect(Math.close?(minus_exp9, -min_value, abs_tol: high_absolute_tolerance)).to be_falsey | |
expect(Math.close?(minus_exp9, min_value, abs_tol: high_absolute_tolerance)).to be_falsey | |
end | |
end | |
context 'Exact number pairs' do | |
let (:exact_pairs) { [ | |
[2.0, 2.0], | |
[0.1E200, 0.1E200], | |
[1.123E-300, 1.123E-300], | |
[0.0, -0.0], | |
[345667, 345667], | |
[BigDecimal('1.0001'), BigDecimal('1.0001')] | |
] } | |
it 'return true' do | |
exact_pairs.each do |pair| | |
expect(Math.close?(pair[0], pair[1])).to be_truthy | |
end | |
end | |
end | |
context 'BigDecimal number pairs' do | |
let (:big_decimal_pairs) { [ | |
[BigDecimal('1.000000001'), BigDecimal('1.0')], | |
[BigDecimal('1.000000001e-20'), BigDecimal('1.0e-20')], | |
[BigDecimal('1.000000001e-100'), BigDecimal('1.0e-100')], | |
] } | |
it 'return true' do | |
big_decimal_pairs.each do |pair| | |
expect(Math.close?(pair[0], pair[1])).to be_truthy | |
end | |
end | |
it 'return false with higher accuracy' do | |
big_decimal_pairs.each do |pair| | |
expect(Math.close?(pair[0], pair[1], rel_tol: 1E-10)).to be_falsey | |
end | |
end | |
end | |
context 'Fraction number pairs' do | |
let (:fraction_pairs) { [ | |
[Rational(1, 1E9) + 1, Rational(1)], | |
[Rational(1, 3), Rational(0.3333333333)] | |
] } | |
it 'return true' do | |
fraction_pairs.each do |pair| | |
expect(Math.close?(pair[0], pair[1])).to be_truthy | |
end | |
end | |
it 'return false with higher accuracy' do | |
fraction_pairs.each do |pair| | |
expect(Math.close?(pair[0], pair[1], rel_tol: 1E-10)).to be_falsey | |
end | |
end | |
end | |
context 'randomly generated sorted integers' do | |
let(:candidates) do | |
Rantly { array(100) { [integer, integer] } } | |
end | |
it 'return false in case of 2 random integers' do | |
candidates.each do |pair| | |
a, b = [pair.max, pair.min] # biggest number first | |
expect(Math.close?(a, b)).to be_falsey | |
end | |
end | |
it 'return true in case of 2 identical integers' do | |
candidates.each do |pair| | |
a, b = [pair.max, pair.max] # biggest number first | |
expect(Math.close?(a, b)).to be_truthy | |
end | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment