Skip to content

Instantly share code, notes, and snippets.

@yennguyenh
Last active April 29, 2019 09:50
Show Gist options
  • Save yennguyenh/2e81dc72b310cb9d886a82faf3d536ef to your computer and use it in GitHub Desktop.
Save yennguyenh/2e81dc72b310cb9d886a82faf3d536ef to your computer and use it in GitHub Desktop.
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