A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
int64x64-128.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2010 INRIA
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 */
18
19#include "ns3/core-config.h"
20
21#if !defined(INT64X64_128_H) && defined(INT64X64_USE_128) && !defined(PYTHON_SCAN)
22/**
23 * \ingroup highprec
24 * Use uint128_t for int64x64_t implementation
25 */
26#define INT64X64_128_H
27
28#include <cmath> // pow
29#include <stdint.h>
30
31#if defined(HAVE___UINT128_T) && !defined(HAVE_UINT128_T)
32/**
33 * \ingroup highprec
34 * Some compilers do not have this defined, so we define it.
35 * @{
36 */
37typedef __uint128_t uint128_t;
38typedef __int128_t int128_t;
39/** @} */
40#endif
41
42/**
43 * \file
44 * \ingroup highprec
45 * Declaration of the ns3::int64x64_t type using a native int128_t type.
46 */
47
48namespace ns3
49{
50
51/**
52 * \internal
53 * The implementation documented here is based on native 128-bit integers.
54 */
56{
57 /// uint128_t high bit (sign bit).
58 static const uint128_t HP128_MASK_HI_BIT = (((int128_t)1) << 127);
59 /// Mask for fraction part.
60 static const uint64_t HP_MASK_LO = 0xffffffffffffffffULL;
61 /// Mask for sign + integer part.
62 static const uint64_t HP_MASK_HI = ~HP_MASK_LO;
63 /**
64 * Floating point value of HP_MASK_LO + 1.
65 * We really want:
66 * \code
67 * static const long double HP_MAX_64 = std:pow (2.0L, 64);
68 * \endcode
69 * but we can't call functions in const definitions.
70 *
71 * We could make this a static and initialize in int64x64-128.cc or
72 * int64x64.cc, but this requires handling static initialization order
73 * when most of the implementation is inline. Instead, we resort to
74 * this define.
75 */
76#define HP_MAX_64 (std::pow(2.0L, 64))
77
78 public:
79 /**
80 * Type tag for the underlying implementation.
81 *
82 * A few testcases are are sensitive to implementation,
83 * specifically the double implementation. To handle this,
84 * we expose the underlying implementation type here.
85 */
87 {
88 int128_impl, //!< Native \c int128_t implementation.
89 cairo_impl, //!< Cairo wideint implementation.
90 ld_impl, //!< `long double` implementation.
91 };
92
93 /// Type tag for this implementation.
95
96 /// Default constructor.
97 inline int64x64_t()
98 : _v(0)
99 {
100 }
101
102 /**
103 * \name Construct from a floating point value.
104 */
105 /**
106 * @{
107 * Constructor from a floating point.
108 *
109 * \param [in] value Floating value to represent.
110 */
111 inline int64x64_t(const double value)
112 {
113 const int64x64_t tmp((long double)value);
114 _v = tmp._v;
115 }
116
117 inline int64x64_t(const long double value)
118 {
119 const bool negative = value < 0;
120 const long double v = negative ? -value : value;
121
122 long double fhi;
123 long double flo = std::modf(v, &fhi);
124 // Add 0.5 to round, which improves the last count
125 // This breaks these tests:
126 // TestSuite devices-mesh-dot11s-regression
127 // TestSuite devices-mesh-flame-regression
128 // TestSuite routing-aodv-regression
129 // TestSuite routing-olsr-regression
130 // Setting round = 0; breaks:
131 // TestSuite int64x64
132 const long double round = 0.5;
133 flo = flo * HP_MAX_64 + round;
134 int128_t hi = fhi;
135 const uint64_t lo = flo;
136 if (flo >= HP_MAX_64)
137 {
138 // conversion to uint64 rolled over
139 ++hi;
140 }
141 _v = hi << 64;
142 _v |= lo;
143 _v = negative ? -_v : _v;
144 }
145
146 /**@}*/
147
148 /**
149 * \name Construct from an integral type.
150 */
151 /**@{*/
152 /**
153 * Construct from an integral type.
154 *
155 * \param [in] v Integer value to represent.
156 */
157 inline int64x64_t(const int v)
158 : _v(v)
159 {
160 _v <<= 64;
161 }
162
163 inline int64x64_t(const long int v)
164 : _v(v)
165 {
166 _v <<= 64;
167 }
168
169 inline int64x64_t(const long long int v)
170 : _v(v)
171 {
172 _v <<= 64;
173 }
174
175 inline int64x64_t(const unsigned int v)
176 : _v(v)
177 {
178 _v <<= 64;
179 }
180
181 inline int64x64_t(const unsigned long int v)
182 : _v(v)
183 {
184 _v <<= 64;
185 }
186
187 inline int64x64_t(const unsigned long long int v)
188 : _v(v)
189 {
190 _v <<= 64;
191 }
192
193 /**@}*/
194
195 /**
196 * Construct from explicit high and low values.
197 *
198 * \param [in] hi Integer portion.
199 * \param [in] lo Fractional portion, already scaled to HP_MAX_64.
200 */
201 explicit inline int64x64_t(const int64_t hi, const uint64_t lo)
202 {
203 _v = (int128_t)hi << 64;
204 _v |= lo;
205 }
206
207 /**
208 * Copy constructor.
209 *
210 * \param [in] o Value to copy.
211 */
212 inline int64x64_t(const int64x64_t& o)
213 : _v(o._v)
214 {
215 }
216
217 /**
218 * Assignment.
219 *
220 * \param [in] o Value to assign to this int64x64_t.
221 * \returns This int64x64_t.
222 */
224 {
225 _v = o._v;
226 return *this;
227 }
228
229 /** Explicit bool conversion. */
230 inline explicit operator bool() const
231 {
232 return (_v != 0);
233 }
234
235 /**
236 * Get this value as a double.
237 *
238 * \return This value in floating form.
239 */
240 inline double GetDouble() const
241 {
242 const bool negative = _v < 0;
243 const uint128_t value = negative ? -_v : _v;
244 const long double fhi = value >> 64;
245 const long double flo = (value & HP_MASK_LO) / HP_MAX_64;
246 long double retval = fhi;
247 retval += flo;
248 retval = negative ? -retval : retval;
249 return retval;
250 }
251
252 /**
253 * Get the integer portion.
254 *
255 * \return The integer portion of this value.
256 */
257 inline int64_t GetHigh() const
258 {
259 const int128_t retval = _v >> 64;
260 return retval;
261 }
262
263 /**
264 * Get the fractional portion of this value, unscaled.
265 *
266 * \return The fractional portion, unscaled, as an integer.
267 */
268 inline uint64_t GetLow() const
269 {
270 const uint128_t retval = _v & HP_MASK_LO;
271 return retval;
272 }
273
274 /**
275 * Truncate to an integer.
276 * Truncation is always toward zero,
277 * \return The value truncated toward zero.
278 */
279 int64_t GetInt() const
280 {
281 const bool negative = _v < 0;
282 const uint128_t value = negative ? -_v : _v;
283 int64_t retval = value >> 64;
284 retval = negative ? -retval : retval;
285 return retval;
286 }
287
288 /**
289 * Round to the nearest int.
290 * Similar to std::round this rounds halfway cases away from zero,
291 * regardless of the current (floating) rounding mode.
292 * \return The value rounded to the nearest int.
293 */
294 int64_t Round() const
295 {
296 const bool negative = _v < 0;
297 int64x64_t value = (negative ? -(*this) : *this);
298 const int64x64_t half(0, 1LL << 63);
299 value += half;
300 int64_t retval = value.GetHigh();
301 retval = negative ? -retval : retval;
302 return retval;
303 }
304
305 /**
306 * Multiply this value by a Q0.128 value, presumably representing an inverse,
307 * completing a division operation.
308 *
309 * \param [in] o The inverse operand.
310 *
311 * \see Invert()
312 */
313 void MulByInvert(const int64x64_t& o);
314
315 /**
316 * Compute the inverse of an integer value.
317 *
318 * Ordinary division by an integer would be limited to 64 bits of precision.
319 * Instead, we multiply by the 128-bit inverse of the divisor.
320 * This function computes the inverse to 128-bit precision.
321 * MulByInvert() then completes the division.
322 *
323 * (Really this should be a separate type representing Q0.128.)
324 *
325 * \param [in] v The value to compute the inverse of.
326 * \return A Q0.128 representation of the inverse.
327 */
328 static int64x64_t Invert(const uint64_t v);
329
330 private:
331 /**
332 * \name Arithmetic Operators
333 * Arithmetic operators for int64x64_t.
334 */
335 /**
336 * @{
337 * Arithmetic operator.
338 * \param [in] lhs Left hand argument
339 * \param [in] rhs Right hand argument
340 * \return The result of the operator.
341 */
342
343 friend inline bool operator==(const int64x64_t& lhs, const int64x64_t& rhs)
344 {
345 return lhs._v == rhs._v;
346 }
347
348 friend inline bool operator<(const int64x64_t& lhs, const int64x64_t& rhs)
349 {
350 return lhs._v < rhs._v;
351 }
352
353 friend inline bool operator>(const int64x64_t& lhs, const int64x64_t& rhs)
354 {
355 return lhs._v > rhs._v;
356 }
357
358 friend inline int64x64_t& operator+=(int64x64_t& lhs, const int64x64_t& rhs)
359 {
360 lhs._v += rhs._v;
361 return lhs;
362 }
363
364 friend inline int64x64_t& operator-=(int64x64_t& lhs, const int64x64_t& rhs)
365 {
366 lhs._v -= rhs._v;
367 return lhs;
368 }
369
370 friend inline int64x64_t& operator*=(int64x64_t& lhs, const int64x64_t& rhs)
371 {
372 lhs.Mul(rhs);
373 return lhs;
374 }
375
376 friend inline int64x64_t& operator/=(int64x64_t& lhs, const int64x64_t& rhs)
377 {
378 lhs.Div(rhs);
379 return lhs;
380 }
381
382 /**@}*/
383
384 /**
385 * \name Unary Operators
386 * Unary operators for int64x64_t.
387 */
388 /**
389 * @{
390 * Unary operator.
391 * \param [in] lhs Left hand argument
392 * \return The result of the operator.
393 */
394 friend inline int64x64_t operator+(const int64x64_t& lhs)
395 {
396 return lhs;
397 }
398
399 friend inline int64x64_t operator-(const int64x64_t& lhs)
400 {
401 int64x64_t res;
402 res._v = -lhs._v;
403 return res;
404 }
405
406 friend inline int64x64_t operator!(const int64x64_t& lhs)
407 {
408 return int64x64_t(!lhs._v);
409 }
410
411 /**@}*/
412
413 /**
414 * Implement `*=`.
415 *
416 * \param [in] o The other factor.
417 */
418 void Mul(const int64x64_t& o);
419 /**
420 * Implement `/=`.
421 *
422 * \param [in] o The divisor.
423 */
424 void Div(const int64x64_t& o);
425 /**
426 * Unsigned multiplication of Q64.64 values.
427 *
428 * Mathematically this should produce a Q128.128 value;
429 * we keep the central 128 bits, representing the Q64.64 result.
430 * We assert on integer overflow beyond the 64-bit integer portion.
431 *
432 * \param [in] a First factor.
433 * \param [in] b Second factor.
434 * \return The Q64.64 product.
435 *
436 * \internal
437 *
438 * It might be tempting to just use \pname{a} `*` \pname{b}
439 * and be done with it, but it's not that simple. With \pname{a}
440 * and \pname{b} as 128-bit integers, \pname{a} `*` \pname{b}
441 * mathematically produces a 256-bit result, which the computer
442 * truncates to the lowest 128 bits. In our case, where \pname{a}
443 * and \pname{b} are interpreted as Q64.64 fixed point numbers,
444 * the multiplication mathematically produces a Q128.128 fixed point number.
445 * We want the middle 128 bits from the result, truncating both the
446 * high and low 64 bits. To achieve this, we carry out the multiplication
447 * explicitly with 64-bit operands and 128-bit intermediate results.
448 */
449 static uint128_t Umul(const uint128_t a, const uint128_t b);
450 /**
451 * Unsigned division of Q64.64 values.
452 *
453 * \param [in] a Numerator.
454 * \param [in] b Denominator.
455 * \return The Q64.64 representation of `a / b`.
456 */
457 static uint128_t Udiv(const uint128_t a, const uint128_t b);
458 /**
459 * Unsigned multiplication of Q64.64 and Q0.128 values.
460 *
461 * \param [in] a The numerator, a Q64.64 value.
462 * \param [in] b The inverse of the denominator, a Q0.128 value
463 * \return The product `a * b`, representing the ration `a / b^-1`.
464 *
465 * \see Invert()
466 */
467 static uint128_t UmulByInvert(const uint128_t a, const uint128_t b);
468
469 int128_t _v; //!< The Q64.64 value.
470
471}; // class int64x64_t
472
473} // namespace ns3
474
475#endif /* INT64X64_128_H */
High precision numerical type, implementing Q64.64 fixed precision.
Definition: int64x64-128.h:56
int64_t GetHigh() const
Get the integer portion.
Definition: int64x64-128.h:257
friend bool operator==(const int64x64_t &lhs, const int64x64_t &rhs)
Arithmetic operator.
Definition: int64x64-128.h:343
static const uint64_t HP_MASK_LO
Mask for fraction part.
Definition: int64x64-128.h:60
static const uint128_t HP128_MASK_HI_BIT
uint128_t high bit (sign bit).
Definition: int64x64-128.h:58
impl_type
Type tag for the underlying implementation.
Definition: int64x64-128.h:87
@ int128_impl
Native int128_t implementation.
Definition: int64x64-128.h:88
@ ld_impl
long double implementation.
Definition: int64x64-128.h:90
@ cairo_impl
Cairo wideint implementation.
Definition: int64x64-128.h:89
friend int64x64_t & operator-=(int64x64_t &lhs, const int64x64_t &rhs)
Arithmetic operator.
Definition: int64x64-128.h:364
friend int64x64_t operator+(const int64x64_t &lhs)
Unary operator.
Definition: int64x64-128.h:394
int64_t Round() const
Round to the nearest int.
Definition: int64x64-128.h:294
void Mul(const int64x64_t &o)
Implement *=.
Definition: int64x64-128.cc:61
static uint128_t Udiv(const uint128_t a, const uint128_t b)
Unsigned division of Q64.64 values.
void MulByInvert(const int64x64_t &o)
Multiply this value by a Q0.128 value, presumably representing an inverse, completing a division oper...
friend bool operator<(const int64x64_t &lhs, const int64x64_t &rhs)
Arithmetic operator.
Definition: int64x64-128.h:348
int64x64_t(const long double value)
Constructor from a floating point.
Definition: int64x64-128.h:117
static const uint64_t HP_MASK_HI
Mask for sign + integer part.
Definition: int64x64-128.h:62
static uint128_t UmulByInvert(const uint128_t a, const uint128_t b)
Unsigned multiplication of Q64.64 and Q0.128 values.
static enum impl_type implementation
Type tag for this implementation.
Definition: int64x64-128.h:94
friend int64x64_t operator!(const int64x64_t &lhs)
Unary operator.
Definition: int64x64-128.h:406
int128_t _v
The Q64.64 value.
Definition: int64x64-128.h:469
friend int64x64_t & operator*=(int64x64_t &lhs, const int64x64_t &rhs)
Arithmetic operator.
Definition: int64x64-128.h:370
int64x64_t(const int64_t hi, const uint64_t lo)
Construct from explicit high and low values.
Definition: int64x64-128.h:201
void Div(const int64x64_t &o)
Implement /=.
int64x64_t(const unsigned long long int v)
Construct from an integral type.
Definition: int64x64-128.h:187
int64x64_t(const unsigned int v)
Construct from an integral type.
Definition: int64x64-128.h:175
int64x64_t(const long int v)
Construct from an integral type.
Definition: int64x64-128.h:163
int64x64_t(const long long int v)
Construct from an integral type.
Definition: int64x64-128.h:169
double GetDouble() const
Get this value as a double.
Definition: int64x64-128.h:240
friend int64x64_t & operator+=(int64x64_t &lhs, const int64x64_t &rhs)
Arithmetic operator.
Definition: int64x64-128.h:358
int64x64_t(const unsigned long int v)
Construct from an integral type.
Definition: int64x64-128.h:181
int64_t GetInt() const
Truncate to an integer.
Definition: int64x64-128.h:279
int64x64_t & operator=(const int64x64_t &o)
Assignment.
Definition: int64x64-128.h:223
friend bool operator>(const int64x64_t &lhs, const int64x64_t &rhs)
Arithmetic operator.
Definition: int64x64-128.h:353
int64x64_t(const int v)
Construct from an integral type.
Definition: int64x64-128.h:157
uint64_t GetLow() const
Get the fractional portion of this value, unscaled.
Definition: int64x64-128.h:268
friend int64x64_t operator-(const int64x64_t &lhs)
Unary operator.
Definition: int64x64-128.h:399
static int64x64_t Invert(const uint64_t v)
Compute the inverse of an integer value.
int64x64_t(const double value)
Constructor from a floating point.
Definition: int64x64-128.h:111
int64x64_t(const int64x64_t &o)
Copy constructor.
Definition: int64x64-128.h:212
friend int64x64_t & operator/=(int64x64_t &lhs, const int64x64_t &rhs)
Arithmetic operator.
Definition: int64x64-128.h:376
int64x64_t()
Default constructor.
Definition: int64x64-128.h:97
static uint128_t Umul(const uint128_t a, const uint128_t b)
Unsigned multiplication of Q64.64 values.
Definition: int64x64-128.cc:71
__uint128_t uint128_t
Some compilers do not have this defined, so we define it.
Definition: int64x64-128.h:37
__int128_t int128_t
Some compilers do not have this defined, so we define it.
Definition: int64x64-128.h:38
#define HP_MAX_64
Floating point value of HP_MASK_LO + 1.
Definition: int64x64-128.h:76
Every class exported by the ns3 library is enclosed in the ns3 namespace.