KiCad PCB EDA Suite
Loading...
Searching...
No Matches
util.h
Go to the documentation of this file.
1/*
2 * This program source code file is part of KICAD, a free EDA CAD application.
3 *
4 * Copyright (c) 2005 Michael Niedermayer <[email protected]>
5 * Copyright (C) CERN
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * @author Tomasz Wlostowski <[email protected]>
9 *
10 * The equals() method to compare two floating point values adapted from
11 * AlmostEqualRelativeAndAbs() on
12 * https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
13 * (C) Bruce Dawson subject to the Apache 2.0 license.
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program. If not, see <https://www.gnu.org/licenses/>.
27 */
28
29#ifndef UTIL_H
30#define UTIL_H
31
32#include <config.h>
33#include <cassert>
34#include <cmath>
35#include <cstdint>
36#include <limits>
37#include <typeinfo>
38#include <type_traits>
39#include <utility>
40#include <algorithm>
41
45void kimathLogDebug( const char* aFormatString, ... );
46
50void kimathLogOverflow( double v, const char* aTypeName );
51
52
53// Suppress an annoying warning that the explicit rounding we do is not precise
54#ifdef HAVE_WIMPLICIT_FLOAT_CONVERSION
55 _Pragma( "GCC diagnostic push" ) \
56 _Pragma( "GCC diagnostic ignored \"-Wimplicit-int-float-conversion\"" )
57#endif
58
59
65template <typename in_type = long long int, typename ret_type = int>
66inline constexpr ret_type KiCheckedCast( in_type v )
67{
68 if constexpr( std::is_same_v<in_type, long long int> && std::is_same_v<ret_type, int> )
69 {
70 if( v > std::numeric_limits<int>::max() )
71 {
72 kimathLogOverflow( double( v ), typeid( int ).name() );
73
74 return std::numeric_limits<int>::max();
75 }
76 else if( v < std::numeric_limits<int>::lowest() )
77 {
78 kimathLogOverflow( double( v ), typeid( int ).name() );
79
80 return std::numeric_limits<int>::lowest();
81 }
82
83 return int( v );
84 }
85 else
86 {
87 return v;
88 }
89}
90
91
98template <typename fp_type, typename ret_type = int>
99constexpr ret_type KiROUND( fp_type v, bool aQuiet = false )
100{
101 using limits = std::numeric_limits<ret_type>;
102
103 static_assert( limits::digits <= std::numeric_limits<long long>::digits );
104
105 auto overflow = [&]( ret_type aResult )
106 {
107 if( !aQuiet )
108 kimathLogOverflow( double( v ), typeid( ret_type ).name() );
109
110 return aResult;
111 };
112
113 // llround would convert through double and lose precision past 2^53
114 if constexpr( std::is_integral_v<fp_type> )
115 {
116 if( std::cmp_greater( v, limits::max() ) )
117 return overflow( limits::max() );
118
119 if( std::cmp_less( v, limits::lowest() ) )
120 return overflow( limits::lowest() );
121
122 return static_cast<ret_type>( v );
123 }
124 else
125 {
126 // llround is unspecified for NaN and for results beyond long long, so saturate before calling it.
127 // v != v stands in for std::isnan, which is not constexpr until C++23.
128 if constexpr( std::is_floating_point_v<fp_type> )
129 {
130 if( v != v )
131 return overflow( 0 );
132
133 if( v >= fp_type( limits::max() ) + 0.5 )
134 return overflow( limits::max() );
135
136 // lowest - 0.5 can round to lowest itself, which llround still handles exactly
137 if( v - fp_type( limits::lowest() ) <= -0.5 )
138 return overflow( limits::lowest() );
139 }
140
141 long long rounded = std::llround( v );
142 long long clamped = std::clamp<long long>( rounded, static_cast<long long>( limits::lowest() ),
143 static_cast<long long>( limits::max() ) );
144
145 if( clamped != rounded )
146 return overflow( static_cast<ret_type>( clamped ) );
147
148 return static_cast<ret_type>( clamped );
149 }
150}
151
152#ifdef HAVE_WIMPLICIT_FLOAT_CONVERSION
153 _Pragma( "GCC diagnostic pop" )
154#endif
155
159
160template <typename T>
161T rescale( T aNumerator, T aValue, T aDenominator )
162{
163 return aNumerator * aValue / aDenominator;
164}
165
166template <typename T>
167constexpr int sign( T val )
168{
169 return ( T( 0 ) < val) - ( val < T( 0 ) );
170}
171
172// explicit specializations for integer types, taking care of overflow.
173template <>
174int rescale( int aNumerator, int aValue, int aDenominator );
175
176template <>
177int64_t rescale( int64_t aNumerator, int64_t aValue, int64_t aDenominator );
178
179
180template <typename T>
181constexpr T ct_sqrt_helper( T aX, T aLo, T aHi )
182{
183 if( aLo == aHi )
184 return aLo;
185
186 const T mid = ( aLo + aHi + 1 ) / 2;
187
188 if( aX / mid < mid )
189 return ct_sqrt_helper<T>( aX, aLo, mid - 1 );
190
191 return ct_sqrt_helper<T>( aX, mid, aHi );
192}
193
197template <typename T>
198constexpr T ct_sqrt( T aX )
199{
200 return ct_sqrt_helper<T>( aX, 0, aX / 2 + 1 );
201}
202
206template <typename T>
207T isqrt( T aX )
208{
209 static_assert( std::is_integral<T>::value, "isqrt requires an integer type" );
210
211 constexpr T sqrt_max = ct_sqrt( std::numeric_limits<T>::max() );
212
213 if constexpr( std::is_signed<T>::value )
214 {
215 if( aX < 0 )
216 return sqrt_max;
217 }
218
219 T r = (T) std::sqrt( (double) aX );
220
221 // The double conversion loses precision above 2^53
222 while( r < sqrt_max && r * r < aX )
223 r++;
224
225 while( r > sqrt_max || r * r > aX )
226 r--;
227
228 return r;
229}
230
231
235constexpr uint64_t UnsignedAbs( int64_t aX )
236{
237 return aX < 0 ? 0 - uint64_t( aX ) : uint64_t( aX );
238}
239
243uint64_t RoundedHypotWide( uint64_t aX, uint64_t aY );
244
248inline uint64_t RoundedHypot( int64_t aX, int64_t aY )
249{
250 // Below this both squares are under 2^63, so their sum fits in uint64_t
251 constexpr uint64_t narrowMax = ct_sqrt<uint64_t>( std::numeric_limits<int64_t>::max() );
252
253 const uint64_t ax = UnsignedAbs( aX );
254 const uint64_t ay = UnsignedAbs( aY );
255
256 if( ax > narrowMax || ay > narrowMax )
257 return RoundedHypotWide( ax, ay );
258
259 const uint64_t n = ax * ax + ay * ay;
260 const uint64_t f = isqrt( n );
261
262 // n > f^2 + f is the same as n >= (f + 1/2)^2 for integer n
263 return f + ( n - f * f > f );
264}
265
266
275template <class T>
276typename std::enable_if<std::is_floating_point<T>::value, bool>::type
277equals( T aFirst, T aSecond, T aEpsilon = std::numeric_limits<T>::epsilon() )
278{
279 const T diff = std::abs( aFirst - aSecond );
280
281 if( diff < aEpsilon )
282 {
283 return true;
284 }
285
286 aFirst = std::abs( aFirst );
287 aSecond = std::abs( aSecond );
288 T largest = aFirst > aSecond ? aFirst : aSecond;
289
290 if( diff <= largest * aEpsilon )
291 {
292 return true;
293 }
294
295 return false;
296}
297
298
299#endif // UTIL_H
const char * name
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:437
uint64_t RoundedHypot(int64_t aX, int64_t aY)
Nearest integer to sqrt( aX^2 + aY^2 ), computed exactly.
Definition util.h:248
std::enable_if< std::is_floating_point< T >::value, bool >::type equals(T aFirst, T aSecond, T aEpsilon=std::numeric_limits< T >::epsilon())
Template to compare two floating point values for equality within a required epsilon.
Definition util.h:277
constexpr int sign(T val)
Definition util.h:167
void kimathLogOverflow(double v, const char *aTypeName)
Workaround to avoid the empty-string conversion issue in wxWidgets.
Definition util.cpp:55
constexpr uint64_t UnsignedAbs(int64_t aX)
Magnitude of a signed integer, well defined for INT64_MIN.
Definition util.h:235
constexpr T ct_sqrt(T aX)
Floor of the square root of an integer, evaluated at compile time.
Definition util.h:198
constexpr ret_type KiROUND(fp_type v, bool aQuiet=false)
Round a numeric value to an integer using "round halfway cases away from zero" and clamp the result t...
Definition util.h:99
T rescale(T aNumerator, T aValue, T aDenominator)
Scale a number (value) by rational (numerator/denominator).
Definition util.h:161
uint64_t RoundedHypotWide(uint64_t aX, uint64_t aY)
Nearest integer to sqrt( aX^2 + aY^2 ) for magnitudes of at most 2^63, using 128-bit arithmetic.
Definition util.cpp:62
void kimathLogDebug(const char *aFormatString,...)
Helper to avoid directly including wx/log.h for the templated functions in kimath.
Definition util.cpp:41
constexpr T ct_sqrt_helper(T aX, T aLo, T aHi)
Definition util.h:181
constexpr ret_type KiCheckedCast(in_type v)
Perform a cast between numerical types.
Definition util.h:66
T isqrt(T aX)
Exact floor of the square root of an integer.
Definition util.h:207