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
125 // llround is unspecified for NaN and for results beyond long long, so saturate before calling it.
126 // v != v stands in for std::isnan, which is not constexpr until C++23.
127 if constexpr( std::is_floating_point_v<fp_type> )
128 {
129 if( v != v )
130 return overflow( 0 );
131
132 if( v >= fp_type( limits::max() ) + 0.5 )
133 return overflow( limits::max() );
134
135 // lowest - 0.5 can round to lowest itself, which llround still handles exactly
136 if( v - fp_type( limits::lowest() ) <= -0.5 )
137 return overflow( limits::lowest() );
138 }
139
140 long long rounded = std::llround( v );
141 long long clamped = std::clamp<long long>( rounded,
142 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#ifdef HAVE_WIMPLICIT_FLOAT_CONVERSION
152 _Pragma( "GCC diagnostic pop" )
153#endif
154
158
159template <typename T>
160T rescale( T aNumerator, T aValue, T aDenominator )
161{
162 return aNumerator * aValue / aDenominator;
163}
164
165template <typename T>
166constexpr int sign( T val )
167{
168 return ( T( 0 ) < val) - ( val < T( 0 ) );
169}
170
171// explicit specializations for integer types, taking care of overflow.
172template <>
173int rescale( int aNumerator, int aValue, int aDenominator );
174
175template <>
176int64_t rescale( int64_t aNumerator, int64_t aValue, int64_t aDenominator );
177
178
179template <typename T>
180constexpr T ct_sqrt_helper( T aX, T aLo, T aHi )
181{
182 if( aLo == aHi )
183 return aLo;
184
185 const T mid = ( aLo + aHi + 1 ) / 2;
186
187 if( aX / mid < mid )
188 return ct_sqrt_helper<T>( aX, aLo, mid - 1 );
189
190 return ct_sqrt_helper<T>( aX, mid, aHi );
191}
192
196template <typename T>
197constexpr T ct_sqrt( T aX )
198{
199 return ct_sqrt_helper<T>( aX, 0, aX / 2 + 1 );
200}
201
205template <typename T>
206T isqrt( T aX )
207{
208 static_assert( std::is_integral<T>::value, "isqrt requires an integer type" );
209
210 constexpr T sqrt_max = ct_sqrt( std::numeric_limits<T>::max() );
211
212 if constexpr( std::is_signed<T>::value )
213 {
214 if( aX < 0 )
215 return sqrt_max;
216 }
217
218 T r = (T) std::sqrt( (double) aX );
219
220 // The double conversion loses precision above 2^53
221 while( r < sqrt_max && r * r < aX )
222 r++;
223
224 while( r > sqrt_max || r * r > aX )
225 r--;
226
227 return r;
228}
229
230
234constexpr uint64_t UnsignedAbs( int64_t aX )
235{
236 return aX < 0 ? 0 - uint64_t( aX ) : uint64_t( aX );
237}
238
242uint64_t RoundedHypotWide( uint64_t aX, uint64_t aY );
243
247inline uint64_t RoundedHypot( int64_t aX, int64_t aY )
248{
249 // Below this both squares are under 2^63, so their sum fits in uint64_t
250 constexpr uint64_t narrowMax = ct_sqrt<uint64_t>( std::numeric_limits<int64_t>::max() );
251
252 const uint64_t ax = UnsignedAbs( aX );
253 const uint64_t ay = UnsignedAbs( aY );
254
255 if( ax > narrowMax || ay > narrowMax )
256 return RoundedHypotWide( ax, ay );
257
258 const uint64_t n = ax * ax + ay * ay;
259 const uint64_t f = isqrt( n );
260
261 // n > f^2 + f is the same as n >= (f + 1/2)^2 for integer n
262 return f + ( n - f * f > f );
263}
264
265
274template <class T>
275typename std::enable_if<std::is_floating_point<T>::value, bool>::type
276equals( T aFirst, T aSecond, T aEpsilon = std::numeric_limits<T>::epsilon() )
277{
278 const T diff = std::abs( aFirst - aSecond );
279
280 if( diff < aEpsilon )
281 {
282 return true;
283 }
284
285 aFirst = std::abs( aFirst );
286 aSecond = std::abs( aSecond );
287 T largest = aFirst > aSecond ? aFirst : aSecond;
288
289 if( diff <= largest * aEpsilon )
290 {
291 return true;
292 }
293
294 return false;
295}
296
297
298#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:247
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:276
constexpr int sign(T val)
Definition util.h:166
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:234
constexpr T ct_sqrt(T aX)
Floor of the square root of an integer, evaluated at compile time.
Definition util.h:197
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:160
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:180
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:206