VTK  9.7.1
vtkMathUtilities.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
2 // SPDX-License-Identifier: BSD-3-Clause
3 
18 #ifndef vtkMathUtilities_h
19 #define vtkMathUtilities_h
20 
21 #include "vtkABINamespace.h"
22 #include "vtkAssume.h"
23 
24 #include <algorithm>
25 #include <cmath>
26 #include <limits>
27 #include <tuple>
28 #include <type_traits>
29 
31 {
32 VTK_ABI_NAMESPACE_BEGIN
33 
38 template <class A>
39 bool FuzzyCompare(A a, A b, A epsilon = std::numeric_limits<A>::epsilon())
40 {
41  return fabs(a - b) < epsilon;
42 }
43 
47 template <class A>
48 A SafeDivision(A a, A b)
49 {
50  // Avoid overflow
51  if ((b < static_cast<A>(1)) && (a > b * std::numeric_limits<A>::max()))
52  {
54  }
55 
56  // Avoid underflow
57  if ((a == static_cast<A>(0)) ||
58  ((b > static_cast<A>(1)) && (a < b * std::numeric_limits<A>::min())))
59  {
60  return static_cast<A>(0);
61  }
62 
63  // safe to do the division
64  return (a / b);
65 }
66 
72 template <class A>
73 bool NearlyEqual(A a, A b, A tol = std::numeric_limits<A>::epsilon())
74 {
75  A absdiff = fabs(a - b);
76  A d1 = vtkMathUtilities::SafeDivision<A>(absdiff, fabs(a));
77  A d2 = vtkMathUtilities::SafeDivision<A>(absdiff, fabs(b));
78 
79  return ((d1 <= tol) || (d2 <= tol));
80 }
81 
105 template <class A>
106 inline void UpdateRange(A& min, A& max, const A& value)
107 {
108  if constexpr (std::is_floating_point_v<A>)
109  {
110  if (VTK_UNLIKELY(std::isnan(value)))
111  {
112  return;
113  }
114  }
115  if (value < min)
116  {
117  min = value;
118  max = std::max(max, value);
119  }
120  else if (value > max)
121  {
122  min = std::min(min, value);
123  max = value;
124  }
125 }
126 
132 template <class A>
133 inline void UpdateRangeFinite(A& min, A& max, const A& value)
134 {
135  if constexpr (std::is_floating_point_v<A>)
136  {
137  if (VTK_UNLIKELY(std::isinf(value) || std::isnan(value)))
138  {
139  return;
140  }
141  }
142  if (value < min)
143  {
144  min = value;
145  max = std::max(max, value);
146  }
147  else if (value > max)
148  {
149  min = std::min(min, value);
150  max = value;
151  }
152 }
153 
159 template <class A>
160 inline A SafeCastFromDouble(double value)
161 {
162  if constexpr (std::is_floating_point_v<A>)
163  {
164  return static_cast<A>(value);
165  }
166  else
167  {
168  constexpr double typeMin = static_cast<double>(std::numeric_limits<A>::lowest());
169  constexpr double typeMax = static_cast<double>(std::numeric_limits<A>::max());
170  // The comparisons are done in a specific way to support 64-bit ints.
171  // Explanation: casting the int64 max (equal to 2^63-1) to double gives
172  // 2^63 because double cannot exactly represent 2^63-1. So the value must
173  // be strictly less than typeMax to avoid overflow when casting to int64.
174  if (VTK_LIKELY(value >= typeMin))
175  {
176  if (VTK_LIKELY(value < typeMax))
177  {
178  return static_cast<A>(value);
179  }
181  }
182  if (VTK_UNLIKELY(std::isnan(value)))
183  {
184  return 0;
185  }
186  return std::numeric_limits<A>::lowest();
187  }
188 }
189 
190 VTK_ABI_NAMESPACE_END
191 } // End vtkMathUtilities namespace.
192 
193 #endif // vtkMathUtilities_h
194 // VTK-HeaderTest-Exclude: vtkMathUtilities.h
bool FuzzyCompare(A a, A b, A epsilon=std::numeric_limits< A >::epsilon())
Perform a fuzzy compare of floats/doubles, specify the allowed tolerance NB: this uses an absolute to...
void UpdateRangeFinite(A &min, A &max, const A &value)
Update an existing min - max range with a new prospective value.
bool NearlyEqual(A a, A b, A tol=std::numeric_limits< A >::epsilon())
A slightly different fuzzy comparator that checks if two values are "nearly" equal based on Knuth...
#define VTK_UNLIKELY(cond)
Hint that cond is expected to be false most of the time.
Definition: vtkAssume.h:201
void UpdateRange(A &min, A &max, const A &value)
Update an existing min - max range with a new prospective value.
#define VTK_LIKELY(cond)
Hint that cond is expected to be true most of the time.
Definition: vtkAssume.h:200
Compiler hint macros for assumptions and branch prediction.
A SafeDivision(A a, A b)
Performs safe division that catches overflow and underflow.
A SafeCastFromDouble(double value)
Cast from double, and clamp to output type limits to avoid overlow.
#define max(a, b)