Skip to content

Instantly share code, notes, and snippets.

@yennguyenh yennguyenh/isClose_spec.rb Secret
Last active Apr 29, 2019

Embed
What would you like to do?
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
You can’t perform that action at this time.