File indexing completed on 2025-01-18 09:54:49
0001
0002
0003
0004
0005
0006
0007
0008 #pragma once
0009
0010 #include <cmath>
0011
0012 #include "corecel/Assert.hh"
0013 #include "corecel/Macros.hh"
0014 #include "corecel/Types.hh"
0015
0016 #include "detail/SoftEqualTraits.hh"
0017
0018 namespace celeritas
0019 {
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030 CELER_CONSTEXPR_FUNCTION real_type sqrt_tol()
0031 {
0032 return detail::SoftEqualTraits<real_type>::sqrt_prec();
0033 }
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053 template<class RealType = ::celeritas::real_type>
0054 class SoftEqual
0055 {
0056 public:
0057
0058
0059 using value_type = RealType;
0060
0061
0062 public:
0063
0064 CELER_CONSTEXPR_FUNCTION SoftEqual();
0065
0066
0067 explicit CELER_FUNCTION SoftEqual(value_type rel);
0068
0069
0070 CELER_FUNCTION SoftEqual(value_type rel, value_type abs);
0071
0072
0073
0074
0075 bool CELER_FUNCTION operator()(value_type a, value_type b) const;
0076
0077
0078
0079
0080 CELER_CONSTEXPR_FUNCTION value_type rel() const { return rel_; }
0081
0082
0083 CELER_CONSTEXPR_FUNCTION value_type abs() const { return abs_; }
0084
0085 private:
0086 value_type rel_;
0087 value_type abs_;
0088
0089 using SETraits = detail::SoftEqualTraits<value_type>;
0090 };
0091
0092
0093
0094
0095
0096
0097
0098 template<class F>
0099 class EqualOr : public F
0100 {
0101 public:
0102
0103 template<class... C>
0104 CELER_FUNCTION EqualOr(C&&... args) : F{std::forward<C>(args)...}
0105 {
0106 }
0107
0108
0109 template<class T, class U>
0110 bool CELER_FUNCTION operator()(T a, U b) const
0111 {
0112 return a == b || static_cast<F const&>(*this)(a, b);
0113 }
0114 };
0115
0116
0117
0118
0119
0120 template<class RealType = ::celeritas::real_type>
0121 class SoftZero
0122 {
0123 public:
0124
0125
0126 using argument_type = RealType;
0127 using value_type = RealType;
0128
0129
0130 public:
0131
0132 CELER_CONSTEXPR_FUNCTION SoftZero();
0133
0134
0135 explicit CELER_FUNCTION SoftZero(value_type abs);
0136
0137
0138
0139
0140 inline CELER_FUNCTION bool operator()(value_type actual) const;
0141
0142
0143
0144
0145 CELER_CONSTEXPR_FUNCTION value_type abs() const { return abs_; }
0146
0147 private:
0148 value_type abs_;
0149
0150 using SETraits = detail::SoftEqualTraits<value_type>;
0151 };
0152
0153
0154
0155
0156 template<class T>
0157 CELER_FUNCTION SoftEqual(T) -> SoftEqual<T>;
0158 template<class T>
0159 CELER_FUNCTION SoftEqual(T, T) -> SoftEqual<T>;
0160 template<class F>
0161 CELER_FUNCTION EqualOr(F&&) -> EqualOr<F>;
0162
0163
0164
0165
0166
0167
0168
0169 template<class RealType>
0170 CELER_CONSTEXPR_FUNCTION SoftEqual<RealType>::SoftEqual()
0171 : rel_{SETraits::rel_prec()}, abs_{SETraits::abs_thresh()}
0172 {
0173 }
0174
0175
0176
0177
0178
0179 template<class RealType>
0180 CELER_FUNCTION SoftEqual<RealType>::SoftEqual(value_type rel)
0181 : SoftEqual(rel, rel * (SETraits::abs_thresh() / SETraits::rel_prec()))
0182 {
0183 CELER_EXPECT(rel > 0);
0184 }
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195 template<class RealType>
0196 CELER_FUNCTION SoftEqual<RealType>::SoftEqual(value_type rel, value_type abs)
0197 : rel_{rel}, abs_{abs}
0198 {
0199 CELER_EXPECT(rel > 0);
0200 CELER_EXPECT(abs > 0);
0201 }
0202
0203
0204
0205
0206
0207 template<class RealType>
0208 CELER_FUNCTION bool
0209 SoftEqual<RealType>::operator()(value_type a, value_type b) const
0210 {
0211 real_type rel = rel_ * std::fmax(std::fabs(a), std::fabs(b));
0212 return std::fabs(a - b) < std::fmax(abs_, rel);
0213 }
0214
0215
0216
0217
0218
0219 template<class RealType>
0220 CELER_CONSTEXPR_FUNCTION SoftZero<RealType>::SoftZero()
0221 : abs_(SETraits::abs_thresh())
0222 {
0223 }
0224
0225
0226
0227
0228
0229
0230
0231 template<class RealType>
0232 CELER_FUNCTION SoftZero<RealType>::SoftZero(value_type abs) : abs_(abs)
0233 {
0234 CELER_EXPECT(abs > 0);
0235 }
0236
0237
0238
0239
0240
0241
0242
0243 template<class RealType>
0244 CELER_FUNCTION bool SoftZero<RealType>::operator()(value_type actual) const
0245 {
0246 return std::fabs(actual) < abs_;
0247 }
0248
0249
0250
0251 template<class RealType>
0252 inline CELER_FUNCTION bool soft_equal(RealType expected, RealType actual)
0253 {
0254 return SoftEqual<RealType>()(expected, actual);
0255 }
0256
0257
0258
0259 template<class RealType>
0260 inline CELER_FUNCTION bool
0261 soft_near(RealType expected, RealType actual, RealType rel_error)
0262 {
0263 return SoftEqual<RealType>(rel_error)(expected, actual);
0264 }
0265
0266
0267
0268 template<class RealType>
0269 inline CELER_FUNCTION bool soft_zero(RealType actual)
0270 {
0271 return SoftZero<RealType>()(actual);
0272 }
0273
0274
0275
0276 template<class RealType>
0277 inline CELER_FUNCTION bool soft_mod(RealType dividend, RealType divisor)
0278 {
0279 auto remainder = std::fmod(dividend, divisor);
0280
0281 SoftEqual<RealType> seq(detail::SoftEqualTraits<RealType>::rel_prec());
0282
0283 return seq(0, remainder) || seq(divisor, remainder);
0284 }
0285
0286
0287 }