diff --git a/.travis.yml b/.travis.yml index d84a9a1..db0ca94 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,12 @@ os: linux -dist: bionic +dist: focal language: d jobs: include: - d: dmd-nightly - d: dmd - - d: dmd-2.090.1 + - d: dmd-2.091.1 - d: ldc allow_failures: - d: dmd-nightly diff --git a/CHANGELOG.md b/CHANGELOG.md index 8485130..f796be7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# v0.3.4 + +* Update to DLang frontend 2.91 +* Using std.math.isClose instead of .approxEquals +* Added .close as alias of .approxEquals + # v0.3.3 * .throw must be @trusted, to allow to catch Errors diff --git a/README.md b/README.md index ef0debe..dee1d57 100644 --- a/README.md +++ b/README.md @@ -58,14 +58,17 @@ assertion. 255.should.equal(10); // Throws an Exception "expected 255 to equal 10" ``` -#### `T approxEqual(U)(U other, U maxRelDiff = 1e-2, U maxAbsDiff = 1e-05, string file = __FILE__, size_t line = __LINE__);` +#### `T approxEqual(U)(U other, U maxRelDiff = CommonDefaultFor!(T,U), U maxAbsDiff = 0.0, string file = __FILE__, size_t line = __LINE__);` -Asserts for aproximated equality of float types. Returns the value wrapped around the -assertion. +Asserts for approximated equality of float types. Returns the value wrapped around the +assertion. See Phobos std.math.isClose(). ```d (1.0f).should.be.approxEqual(1.00000001); -(1.0f).should.not.be.approxEqual(1.001); +(1.0f).should.not.be.approxEqual(1.01); ``` +#### `T close(U)(U other, U maxRelDiff = CommonDefaultFor!(T,U), U maxAbsDiff = 0.0, string file = __FILE__, size_t line = __LINE__);` + +Alias of approxEqual #### `T exist(string file = __FILE__, size_t line = __LINE__);` diff --git a/appveyor.yml b/appveyor.yml index 6d96f09..310e4c0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,7 +8,7 @@ environment: DVersion: stable arch: x86 - DC: dmd - DVersion: 2.090.1 + DVersion: 2.091.1 arch: x86 - DC: ldc DVersion: stable diff --git a/docs/assets/img/logo-dub.png b/docs/assets/img/logo-dub.png new file mode 100644 index 0000000..4b95461 Binary files /dev/null and b/docs/assets/img/logo-dub.png differ diff --git a/docs/changelog.md b/docs/changelog.md index c9590c5..f9ce724 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,6 +2,12 @@ layout: default title: Changelog --- +# v0.3.4 + +* Update to DLang frontend 2.91 +* Using std.math.isClose instead of .approxEquals +* Added .close as alias of .approxEquals + # v0.3.3 * .throw must be @trusted, to allow to catch Errors diff --git a/docs/index.md b/docs/index.md index ed85b14..354eede 100644 --- a/docs/index.md +++ b/docs/index.md @@ -62,14 +62,17 @@ assertion. 255.should.equal(10); // Throws an Exception "expected 255 to equal 10" ``` -#### `T approxEqual(U)(U other, U maxRelDiff = 1e-2, U maxAbsDiff = 1e-05, string file = __FILE__, size_t line = __LINE__);` +#### `T approxEqual(U)(U other, U maxRelDiff = CommonDefaultFor!(T,U), U maxAbsDiff = 0.0, string file = __FILE__, size_t line = __LINE__);` -Asserts for aproximated equality of float types. Returns the value wrapped around the -assertion. +Asserts for approximated equality of float types. Returns the value wrapped around the +assertion. See Phobos std.math.isClose(). ```d (1.0f).should.be.approxEqual(1.00000001); -(1.0f).should.not.be.approxEqual(1.001); +(1.0f).should.not.be.approxEqual(1.01); ``` +#### `T close(U)(U other, U maxRelDiff = CommonDefaultFor!(T,U), U maxAbsDiff = 0.0, string file = __FILE__, size_t line = __LINE__);` + +Alias of approxEqual #### `T exist(string file = __FILE__, size_t line = __LINE__);` diff --git a/docs/pijamas.html b/docs/pijamas.html index 99020e2..c5f7161 100644 --- a/docs/pijamas.html +++ b/docs/pijamas.html @@ -755,7 +755,7 @@

Declaration

- @trusted T approxEqual(U = double)(U other, U maxRelDiff = 0.01, U maxAbsDiff = 1e-05, string file = __FILE__, size_t line = __LINE__) if (is(T : real) && __traits(isFloating, T) && is(U : real) && __traits(isFloating, U)); + @trusted T approxEqual(U = double)(U other, U maxRelDiff = CommonDefaultFor!(T, U), U maxAbsDiff = 0.0, string file = __FILE__, size_t line = __LINE__) if (is(T : real) && __traits(isFloating, T) && is(U : real) && __traits(isFloating, U));

@@ -771,6 +771,89 @@

Declaration

+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + U other + + +
+

+ Value to compare to compare. +

+
+
+ + U maxRelDiff + + +
+

+ Maximum allowable relative difference. + Setting to 0.0 disables this check. Default depends on the type of + other and the original valie: It is approximately half the number of decimal digits of + precision of the smaller type. +

+
+
+ + U maxAbsDiff + + +
+

+ Maximum absolute difference. This is mainly usefull + for comparing values to zero. Setting to 0.0 disables this check. + Defaults to 0.0. +

+
+
+ + string file + + +
+

+ filename +

+
+
+ + size_t line + + +
+

+ line number inside of file +

+
+
+

Examples

@@ -780,7 +863,7 @@

Examples

  1. double d = 0.1; -double d2 = d + 1e-05; +double d2 = d + 1e-10; d.should.not.be.equal(d2); d.should.be.approxEqual(d2);
  2. @@ -795,6 +878,58 @@

    Examples

+
  • +
    +
    + close +
    +
    +
    +
    +

    Declaration

    +
    +

    + + alias close = approxEqual; + + +

    +
    +
    +
    +
    +
    +
    +
    +

    + Alias to approxEqual + +

    +
    +
    +

    Examples

    +

    + +

    +
    +
    +
      +
    1. double d = 0.1; +double d2 = d + 1e-10; +d.should.not.be.close(d2); +d.should.be.close(d2); +
    2. +
    +
    +
    +
    + +

    +
    +
    + +
    +
  • diff --git a/dub.json b/dub.json index e18b520..a43704e 100644 --- a/dub.json +++ b/dub.json @@ -37,7 +37,7 @@ } }, "toolchainRequirements": { - "dub": ">=1.19.0", - "frontend": ">=2.090" + "dub": ">=1.20.0", + "frontend": ">=2.091" } } diff --git a/source/pijamas.d b/source/pijamas.d index f95ef4b..b18455a 100644 --- a/source/pijamas.d +++ b/source/pijamas.d @@ -103,27 +103,82 @@ class Assertion(T) return context; } + // Ripped from std.math + private template CommonDefaultFor(T,U) + { + import std.traits : CommonType; + import std.algorithm.comparison : min; + + alias baseT = FloatingPointBaseType!T; + alias baseU = FloatingPointBaseType!U; + + enum CommonType!(baseT, baseU) CommonDefaultFor = 10.0L ^^ -((min(baseT.dig, baseU.dig) + 1) / 2 + 1); + } + + private template FloatingPointBaseType(T) + { + import std.traits : isFloatingPoint; + import std.range.primitives : ElementType; + static if (isFloatingPoint!T) + { + alias FloatingPointBaseType = Unqual!T; + } + else static if (isFloatingPoint!(ElementType!(Unqual!T))) + { + alias FloatingPointBaseType = Unqual!(ElementType!(Unqual!T)); + } + else + { + alias FloatingPointBaseType = real; + } + } + /** * Asserts that a float type is aproximated equal. Returns the valued wrapped around the assertion * + * Params: + * other = Value to compare to compare. + * maxRelDiff = Maximum allowable relative difference. + * Setting to 0.0 disables this check. Default depends on the type of + * `other` and the original valie: It is approximately half the number of decimal digits of + * precision of the smaller type. + * maxAbsDiff = Maximum absolute difference. This is mainly usefull + * for comparing values to zero. Setting to 0.0 disables this check. + * Defaults to `0.0`. + * file = filename + * line = line number inside of file + * * Examples: * ``` * double d = 0.1; - * double d2 = d + 1e-05; + * double d2 = d + 1e-10; * d.should.not.be.equal(d2); * d.should.be.approxEqual(d2); * ``` */ - T approxEqual(U = double)(U other, U maxRelDiff = 1e-2, U maxAbsDiff = 1e-05, + T approxEqual(U = double)(U other, U maxRelDiff = CommonDefaultFor!(T,U), U maxAbsDiff = 0.0, string file = __FILE__, size_t line = __LINE__) @trusted if (is(T : real) && __traits(isFloating, T) && is(U : real) && __traits(isFloating, U)) { - import std.math : approxEqual; + import std.math : isClose; operator = "be approximated equal than"; - this.ok(approxEqual(context, other, maxRelDiff, maxAbsDiff), this.message(other), file, line); + this.ok(isClose(context, other, maxRelDiff, maxAbsDiff), this.message(other), file, line); return context; } + /** + * Alias to approxEqual + * + * Examples: + * ``` + * double d = 0.1; + * double d2 = d + 1e-10; + * d.should.not.be.close(d2); + * d.should.be.close(d2); + * ``` + */ + alias close = approxEqual; + /** * Asserts whether a value exists - currently simply compares it with null, if it is a pointer, a class or a string. * Returns the value wrapped around the assertion. diff --git a/tests/pijamas_spec.d b/tests/pijamas_spec.d index c6d7fdb..76954d7 100644 --- a/tests/pijamas_spec.d +++ b/tests/pijamas_spec.d @@ -196,14 +196,15 @@ import pijamas; { float f = 0.01; f.should.be.approxEqual(f); - + f.should.be.close(f); + double d = 0.01; d.should.be.approxEqual(d); - + real r = 0.01; r.should.be.approxEqual(r); } - + // it("handles comparing diferent float types") { float f = 0.01; @@ -211,26 +212,35 @@ import pijamas; real r = 0.01; f.should.be.approxEqual(d); f.should.be.approxEqual(r); - + d.should.be.approxEqual(f); d.should.be.approxEqual(r); - + r.should.be.approxEqual(f); r.should.be.approxEqual(d); } // it("asserts that two nearly identical float values are approximated equal") { + float one = 1_000_000_000.0; + one.should.be.close(999_999_999.0); + double d = 0.1; - double d2 = d + 1e-05; + double d2 = d + 1e-10; d.should.not.be.equal(d2); d.should.be.approxEqual(d2); // and("when increase the difference, it must not be approximated equals") - d2 += 1e-2; + d2 += 1e-5; d.should.not.be.equal(d2); d.should.not.be.approxEqual(d2); assertThrown!Exception(d.should.be.approxEqual(d2)); + + // and("Different default limits for different floating point types") + float oneFloat = 1.0f; + double oneDouble = 1.0; + oneFloat.should.be.close(0.999_99f); + oneDouble.should.not.be.close(0.999_99); } }