Skip to content

File almostequal.h

File List > code_source > templat > include > TempLat > util > almostequal.h

Go to the documentation of this file

#ifndef TEMPLAT_UTIL_ALMOSTEQUAL_H
#define TEMPLAT_UTIL_ALMOSTEQUAL_H

/* This file is part of TempLat, available at https://cosmolattice.github.io/templat .
   Copyright 2021-2026 The TempLat authors, see AUTHORS.md.
   Released under the MIT license, see LICENSE.md. */

// File info: Main contributor(s): Wessel Valkenburg, Year: 2019

#include <limits> 
#include "TempLat/parallel/device.h"

namespace TempLat
{
  template <typename T1, typename T2, typename T3 = T1>
    requires(std::is_arithmetic_v<T1> && std::is_arithmetic_v<T2> && std::is_arithmetic_v<T3>)
  DEVICE_FUNCTION bool AlmostEqual(const T1 &a, const T2 &b,
                                   const T3 &epsilon = std::sqrt(std::numeric_limits<T3>::epsilon()))
  {
    if (std::isnan(a) || std::isnan(b)) return false;
    if (a == b) return true;
    if (std::abs(a) < epsilon)
      return std::abs(b) < epsilon;
    else if (std::abs(b) < epsilon)
      return std::abs(a) < epsilon;
    else
      // I added a test of absolute difference to catch the edge-case where both values are effectively zero.
      return std::abs(a / b - 1) < epsilon || std::abs(a - b) < std::numeric_limits<T3>::epsilon() * 2;
  };

  template <typename T>
  DEVICE_FUNCTION bool AlmostEqual(const complex<T> &a, const complex<T> &b,
                                   const T epsilon = std::sqrt(std::numeric_limits<T>::epsilon()))
  {
    return AlmostEqual(a.real(), b.real(), epsilon) && AlmostEqual(a.imag(), b.imag(), epsilon);
  };

  template <typename T, size_t N>
  DEVICE_FUNCTION bool AlmostEqual(const std::array<T, N> &a, const std::array<T, N> &b,
                                   const T epsilon = std::sqrt(std::numeric_limits<T>::epsilon()))
  {
    bool result = true;
    for (ptrdiff_t i = 0; i < (ptrdiff_t)N; ++i) {
      result = result && AlmostEqual(a[i], b[i], epsilon);
    }
    return result;
  };

} // namespace TempLat

#endif