KiCad PCB EDA Suite
Loading...
Searching...
No Matches
wide_int.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#pragma once
21
29
30#include <bit>
31#include <cmath>
32#include <cstdint>
33
34#include <math/vector2d.h>
35
36#if defined( _MSC_VER )
37// The standard has no 128-bit integer; this is the STL's own integer-class type (it backs iota_view).
38// Also used for clang-cl, whose __int128 cannot convert to double without compiler-rt.
39#include <__msvc_int128.hpp>
40#endif
41
42
43namespace KIGEOM_WIDE
44{
46inline double WordsToDouble( int64_t aHi, uint64_t aLo )
47{
48 const bool negative = aHi < 0;
49 uint64_t hi = static_cast<uint64_t>( aHi );
50 uint64_t lo = aLo;
51
52 if( negative )
53 {
54 lo = ~lo + 1;
55 hi = ~hi + ( lo == 0 ? 1 : 0 );
56 }
57
58 double magnitude;
59
60 if( hi == 0 )
61 {
62 magnitude = static_cast<double>( lo );
63 }
64 else
65 {
66 // Fold the discarded low bits into a sticky bit so the single uint64 to double rounding
67 // matches rounding the full 128-bit value
68 int shift = std::countl_zero( hi );
69 uint64_t top = shift == 0 ? hi : ( hi << shift ) | ( lo >> ( 64 - shift ) );
70
71 if( ( lo << shift ) != 0 )
72 top |= 1;
73
74 magnitude = std::ldexp( static_cast<double>( top ), 64 - shift );
75 }
76
77 return negative ? -magnitude : magnitude;
78}
79} // namespace KIGEOM_WIDE
80
81
82#if defined( _MSC_VER )
83using KI_INT128 = std::_Signed128;
84using KI_UINT128 = std::_Unsigned128;
85
86inline double ToDouble( const KI_INT128& aValue )
87{
88 return KIGEOM_WIDE::WordsToDouble( static_cast<int64_t>( aValue._Word[1] ), aValue._Word[0] );
89}
90#else
91using KI_INT128 = __int128;
92using KI_UINT128 = unsigned __int128;
93
94inline double ToDouble( KI_INT128 aValue )
95{
96 return static_cast<double>( aValue );
97}
98#endif
99
100
104constexpr KI_INT128 CrossWide( const VECTOR2L& aA, const VECTOR2L& aB )
105{
106 return KI_INT128( aA.x ) * aB.y - KI_INT128( aA.y ) * aB.x;
107}
108
109
113constexpr KI_INT128 DotWide( const VECTOR2L& aA, const VECTOR2L& aB )
114{
115 return KI_INT128( aA.x ) * aB.x + KI_INT128( aA.y ) * aB.y;
116}
double WordsToDouble(int64_t aHi, uint64_t aLo)
Nearest double to hi * 2^64 + lo, ties to even.
Definition wide_int.h:46
KIBIS top(path, &reporter)
VECTOR2< int64_t > VECTOR2L
Definition vector2d.h:709
unsigned __int128 KI_UINT128
Definition wide_int.h:92
constexpr KI_INT128 DotWide(const VECTOR2L &aA, const VECTOR2L &aB)
Exact aA.x * aB.x + aA.y * aB.y.
Definition wide_int.h:113
double ToDouble(KI_INT128 aValue)
Definition wide_int.h:94
constexpr KI_INT128 CrossWide(const VECTOR2L &aA, const VECTOR2L &aB)
Exact aA.x * aB.y - aA.y * aB.x.
Definition wide_int.h:104
__int128 KI_INT128
Definition wide_int.h:91