From 527b5d462c3de77a0fc665b03cd5ea1469e86a09 Mon Sep 17 00:00:00 2001 From: Braden MacDonald Date: Sun, 2 Jun 2024 23:55:39 -0700 Subject: [PATCH] BREAKING(assert): `assertAlmostEquals()` sets useful tolerance automatically (#4460) feat(assert): assertAlmostEquals() sets useful tolerance automatically Co-authored-by: Yoshiya Hinosawa Co-authored-by: Asher Gomez --- assert/assert_almost_equals.ts | 14 +++++++++++--- assert/assert_almost_equals_test.ts | 5 +++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/assert/assert_almost_equals.ts b/assert/assert_almost_equals.ts index 8a14fcf9c..81cce9d43 100644 --- a/assert/assert_almost_equals.ts +++ b/assert/assert_almost_equals.ts @@ -8,31 +8,39 @@ import { AssertionError } from "./assertion_error.ts"; * double-precision floating-point representation limitations. If the values * are not almost equal then throw. * + * The default tolerance is one hundred thousandth of a percent of the + * expected value. + * * @example Usage * ```ts no-eval * import { assertAlmostEquals } from "@std/assert"; * - * assertAlmostEquals(0.01, 0.02, 0.1); // Doesn't throw * assertAlmostEquals(0.01, 0.02); // Throws + * assertAlmostEquals(1e-8, 1e-9); // Throws + * assertAlmostEquals(1.000000001e-8, 1.000000002e-8); // Doesn't throw + * assertAlmostEquals(0.01, 0.02, 0.1); // Doesn't throw * assertAlmostEquals(0.1 + 0.2, 0.3, 1e-16); // Doesn't throw * assertAlmostEquals(0.1 + 0.2, 0.3, 1e-17); // Throws * ``` * * @param actual The actual value to compare. * @param expected The expected value to compare. - * @param tolerance The tolerance to consider the values almost equal. Defaults to 1e-7. (This will be changed in 1.0.0) + * @param tolerance The tolerance to consider the values almost equal. The default is one hundred thousandth of a percent of the expected value. * @param msg The optional message to include in the error. */ export function assertAlmostEquals( actual: number, expected: number, - tolerance = 1e-7, + tolerance?: number, msg?: string, ) { if (Object.is(actual, expected)) { return; } const delta = Math.abs(expected - actual); + if (tolerance === undefined) { + tolerance = isFinite(expected) ? expected * 1e-7 : 1e-7; + } if (delta <= tolerance) { return; } diff --git a/assert/assert_almost_equals_test.ts b/assert/assert_almost_equals_test.ts index ec94d7aa7..24a56cc7d 100644 --- a/assert/assert_almost_equals_test.ts +++ b/assert/assert_almost_equals_test.ts @@ -7,11 +7,16 @@ Deno.test("assertAlmostEquals() matches values within default precision range", assertAlmostEquals(0.1 + 0.2, 0.3); assertAlmostEquals(NaN, NaN); assertAlmostEquals(Number.NaN, Number.NaN); + assertAlmostEquals(9e20, 9.0000000001e20); + assertAlmostEquals(1.000000001e-8, 1.000000002e-8); }); Deno.test("assertAlmostEquals() throws values outside default precision range", () => { assertThrows(() => assertAlmostEquals(1, 2)); assertThrows(() => assertAlmostEquals(1, 1.1)); + assertThrows(() => assertAlmostEquals(9e20, 9.01e20)); + assertThrows(() => assertAlmostEquals(5e-7, 6e-7)); // approx 20% different value + assertThrows(() => assertAlmostEquals(1e-8, 1e-9)); // different order of magnitude }); Deno.test("assertAlmostEquals() matches values within higher precision range", () => {