From 85c05b3cf01215b91b0e8db7ea81f0ce0c70cd3e Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Tue, 2 May 2023 16:55:17 +0200
Subject: [PATCH] algo::almostEqual gets 3rd argument ulp

---
 Base/Py/PyFmt.cpp                             | 4 ++--
 Base/Util/Algorithms.h                        | 6 +++---
 Device/Mask/Line.cpp                          | 4 ++--
 Sim/Export/SimulationToPython.cpp             | 6 ++----
 Tests/Unit/Device/RectangularDetectorTest.cpp | 6 +++---
 Tests/Unit/GUI/TestFormFactorItems.cpp        | 2 +-
 6 files changed, 13 insertions(+), 15 deletions(-)

diff --git a/Base/Py/PyFmt.cpp b/Base/Py/PyFmt.cpp
index 1f343ffd335..9217267dd83 100644
--- a/Base/Py/PyFmt.cpp
+++ b/Base/Py/PyFmt.cpp
@@ -183,12 +183,12 @@ std::string Py::Fmt::printFunction(const std::string& name, double value1, const
 
 bool Py::Fmt::isSquare(double length1, double length2, double angle)
 {
-    return length1 == length2 && BaseUtils::algo::almostEqual(angle, (pi / 2));
+    return length1 == length2 && BaseUtils::algo::almostEqual(angle, (pi / 2), 2);
 }
 
 bool Py::Fmt::isHexagonal(double length1, double length2, double angle)
 {
-    return length1 == length2 && BaseUtils::algo::almostEqual(angle, (2 * pi) / 3.0);
+    return length1 == length2 && BaseUtils::algo::almostEqual(angle, (2 * pi) / 3.0, 2);
 }
 
 std::string Py::Fmt::printKvector(const R3 value)
diff --git a/Base/Util/Algorithms.h b/Base/Util/Algorithms.h
index ed71de382e4..a450c5b9377 100644
--- a/Base/Util/Algorithms.h
+++ b/Base/Util/Algorithms.h
@@ -27,11 +27,11 @@
 
 namespace BaseUtils::algo {
 
-//! Returns true if two doubles agree within machine epsilon.
-inline bool almostEqual(double a, double b)
+//! Returns true if two doubles agree within machine epsilon times ulp (units in the last place).
+inline bool almostEqual(double a, double b, int ulp)
 {
     constexpr double eps = std::numeric_limits<double>::epsilon();
-    return std::abs(a - b) <= eps * std::max(eps, (std::abs(a) + std::abs(b)) / 2);
+    return std::abs(a - b) <= eps * ulp * (std::abs(a) + std::abs(b)) / 2;
 }
 
 //! Returns the minimum value of function evaluate as applied to the elements of an iterator range.
diff --git a/Device/Mask/Line.cpp b/Device/Mask/Line.cpp
index ec8f9daae52..d45719468af 100644
--- a/Device/Mask/Line.cpp
+++ b/Device/Mask/Line.cpp
@@ -73,7 +73,7 @@ VerticalLine::VerticalLine(double x)
 
 bool VerticalLine::contains(double x, double /*y*/) const
 {
-    return BaseUtils::algo::almostEqual(x, m_x);
+    return BaseUtils::algo::almostEqual(x, m_x, 2);
 }
 
 bool VerticalLine::contains(const Bin1D& binx, const Bin1D& /*biny*/) const
@@ -92,7 +92,7 @@ HorizontalLine::HorizontalLine(double y)
 
 bool HorizontalLine::contains(double /*x*/, double y) const
 {
-    return BaseUtils::algo::almostEqual(y, m_y);
+    return BaseUtils::algo::almostEqual(y, m_y, 2);
 }
 
 bool HorizontalLine::contains(const Bin1D& /*binx*/, const Bin1D& biny) const
diff --git a/Sim/Export/SimulationToPython.cpp b/Sim/Export/SimulationToPython.cpp
index 796c0a6a90e..76ab922ea6c 100644
--- a/Sim/Export/SimulationToPython.cpp
+++ b/Sim/Export/SimulationToPython.cpp
@@ -15,7 +15,6 @@
 #include "Sim/Export/SimulationToPython.h"
 #include "Base/Axis/IAxis.h"
 #include "Base/Py/PyFmt.h"
-#include "Base/Util/Algorithms.h"
 #include "Base/Util/Assert.h"
 #include "Device/Beam/Beam.h"
 #include "Device/Beam/FootprintGauss.h"
@@ -65,9 +64,8 @@ bool isQuadraticDetector(const IDetector& det)
 //! Returns true if it is (0, -1, 0) vector
 bool isDefaultDirection(const R3 direction)
 {
-    return BaseUtils::algo::almostEqual(direction.x(), 0.0)
-           && BaseUtils::algo::almostEqual(direction.y(), -1.0)
-           && BaseUtils::algo::almostEqual(direction.z(), 0.0);
+    return fabs(direction.x()) < 5e-16 && fabs(direction.y() + 1) < 1e-15
+           && fabs(direction.z()) < 5e-16;
 }
 
 std::string defineFootprintFactor(const IFootprintFactor& foot)
diff --git a/Tests/Unit/Device/RectangularDetectorTest.cpp b/Tests/Unit/Device/RectangularDetectorTest.cpp
index 8a04f7950ac..6ebc889925f 100644
--- a/Tests/Unit/Device/RectangularDetectorTest.cpp
+++ b/Tests/Unit/Device/RectangularDetectorTest.cpp
@@ -17,9 +17,9 @@ double alpha(R3 k)
 
 bool isEqual(const R3 lhs, const R3 rhs)
 {
-    bool is_equal = BaseUtils::algo::almostEqual(lhs.x(), rhs.x())
-                    && BaseUtils::algo::almostEqual(lhs.y(), rhs.y())
-                    && BaseUtils::algo::almostEqual(lhs.z(), rhs.z());
+    bool is_equal = BaseUtils::algo::almostEqual(lhs.x(), rhs.x(), 2)
+                    && BaseUtils::algo::almostEqual(lhs.y(), rhs.y(), 2)
+                    && BaseUtils::algo::almostEqual(lhs.z(), rhs.z(), 2);
     if (!is_equal)
         std::cout << "lhs:" << lhs << " rhs:" << rhs << " diff:" << (lhs - rhs) << std::endl;
     return is_equal;
diff --git a/Tests/Unit/GUI/TestFormFactorItems.cpp b/Tests/Unit/GUI/TestFormFactorItems.cpp
index 7a20ecf3821..7435739935e 100644
--- a/Tests/Unit/GUI/TestFormFactorItems.cpp
+++ b/Tests/Unit/GUI/TestFormFactorItems.cpp
@@ -18,5 +18,5 @@ TEST(TestFormFactorItems, Pyramid2Item)
     EXPECT_EQ(p_ff->length(), 20.0);
     EXPECT_EQ(p_ff->width(), 16.0);
     EXPECT_EQ(p_ff->height(), 13.0);
-    EXPECT_TRUE(BaseUtils::algo::almostEqual(p_ff->alpha(), Units::deg2rad(60.0)));
+    EXPECT_TRUE(BaseUtils::algo::almostEqual(p_ff->alpha(), Units::deg2rad(60.0), 2));
 }
-- 
GitLab