From c274d9aed637af05f7acf553edb57721bd91d021 Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Fri, 30 Oct 2020 10:56:28 +0200 Subject: [PATCH] add approxequal (#15766) * add approxequal * Address review comments, tests that pass * more wikipedia links [ci skip] * forgot since Co-authored-by: b3liever Co-authored-by: Andreas Rumpf --- changelog.md | 2 ++ lib/pure/math.nim | 25 ++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 552e1e8df4..6bff75a447 100644 --- a/changelog.md +++ b/changelog.md @@ -7,6 +7,7 @@ - `prelude` now works with the JavaScript target. - Added `ioutils` module containing `duplicate` and `duplicateTo` to duplicate `FileHandle` using C function `dup` and `dup2`. +- Added `almostEqual` in `math` for comparing two float values using a machine epsilon. - The JSON module can now handle integer literals and floating point literals of arbitrary length and precision. Numbers that do not fit the underlying `BiggestInt` or `BiggestFloat` fields are kept as string literals and @@ -16,6 +17,7 @@ - Added `randState` template that exposes the default random number generator. Useful for library authors. + ## Language changes diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 21d614270a..2a26605242 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -56,7 +56,7 @@ import std/private/since {.push debugger: off.} # the user does not want to trace a part # of the standard library! -import bitops +import bitops, fenv proc binom*(n, k: int): int {.noSideEffect.} = ## Computes the `binomial coefficient `_. @@ -158,6 +158,29 @@ proc classify*(x: float): FloatClass = return fcSubnormal return fcNormal +proc almostEqual*[T: SomeFloat](x, y: T; unitsInLastPlace: Natural = 4): bool {. + since: (1, 5), inline, noSideEffect.} = + ## Checks if two float values are almost equal, using + ## `machine epsilon `_. + ## + ## `unitsInLastPlace` is the max number of + ## `units in last place `_ + ## difference tolerated when comparing two numbers. The larger the value, the + ## more error is allowed. A ``0`` value means that two numbers must be exactly the + ## same to be considered equal. + ## + ## The machine epsilon has to be scaled to the magnitude of the values used + ## and multiplied by the desired precision in ULPs unless the difference is + ## subnormal. + ## + # taken from: https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon + runnableExamples: + doAssert almostEqual(3.141592653589793, 3.1415926535897936) + doAssert almostEqual(1.6777215e7'f32, 1.6777216e7'f32) + let diff = abs(x - y) + result = diff <= epsilon(T) * abs(x + y) * T(unitsInLastPlace) or + diff < minimumPositiveValue(T) + proc isPowerOfTwo*(x: int): bool {.noSideEffect.} = ## Returns ``true``, if ``x`` is a power of two, ``false`` otherwise. ##