A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
int64x64-cairo.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2006 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 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
18 */
19#include "int64x64-cairo.h"
20
21#include "abort.h"
22#include "assert.h"
23#include "log.h"
24#include "test.h"
25
26#include <cmath>
27#include <iostream>
28
29// Include directly to allow optimizations within this compilation unit.
30extern "C"
31{
32#include "cairo-wideint.c"
33}
34
35/**
36 * \file
37 * \ingroup highprec
38 * Implementation of the ns3::int64x64_t type using the Cairo implementation.
39 */
40
41namespace ns3
42{
43
44// Note: Logging in this file is largely avoided due to the
45// number of calls that are made to these functions and the possibility
46// of causing recursions leading to stack overflow
47NS_LOG_COMPONENT_DEFINE("int64x64-cairo");
48
49/**
50 * \ingroup highprec
51 * Compute the sign of the result of multiplying or dividing
52 * Q64.64 fixed precision operands.
53 *
54 * \param [in] sa The signed value of the first operand.
55 * \param [in] sb The signed value of the second operand.
56 * \param [out] ua The unsigned magnitude of the first operand.
57 * \param [out] ub The unsigned magnitude of the second operand.
58 * \returns True if the result will be negative.
59 */
60static inline bool
62 const cairo_int128_t sb,
63 cairo_uint128_t& ua,
64 cairo_uint128_t& ub)
65{
66 bool negA = _cairo_int128_negative(sa);
67 bool negB = _cairo_int128_negative(sb);
70 ua = negA ? _cairo_uint128_negate(ua) : ua;
71 ub = negB ? _cairo_uint128_negate(ub) : ub;
72 return (negA && !negB) || (!negA && negB);
73}
74
75void
76int64x64_t::Mul(const int64x64_t& o)
77{
78 cairo_uint128_t a, b;
79 bool sign = output_sign(_v, o._v, a, b);
80 cairo_uint128_t result = Umul(a, b);
81 _v = sign ? _cairo_uint128_negate(result) : result;
82}
83
84cairo_uint128_t
85int64x64_t::Umul(const cairo_uint128_t a, const cairo_uint128_t b)
86{
87 cairo_uint128_t result;
88 cairo_uint128_t hiPart, loPart, midPart;
89 cairo_uint128_t res1, res2;
90
91 // Multiplying (a.h 2^64 + a.l) x (b.h 2^64 + b.l) =
92 // 2^128 a.h b.h + 2^64*(a.h b.l+b.h a.l) + a.l b.l
93 // get the low part a.l b.l
94 // multiply the fractional part
95 loPart = _cairo_uint64x64_128_mul(a.lo, b.lo);
96 // compute the middle part 2^64*(a.h b.l+b.h a.l)
97 midPart = _cairo_uint128_add(_cairo_uint64x64_128_mul(a.lo, b.hi),
98 _cairo_uint64x64_128_mul(a.hi, b.lo));
99 // compute the high part 2^128 a.h b.h
100 hiPart = _cairo_uint64x64_128_mul(a.hi, b.hi);
101 // if the high part is not zero, put a warning
102 NS_ABORT_MSG_IF(hiPart.hi != 0,
103 "High precision 128 bits multiplication error: multiplication overflow.");
104
105 // Adding 64-bit terms to get 128-bit results, with carries
106 res1 = _cairo_uint64_to_uint128(loPart.hi);
107 res2 = _cairo_uint64_to_uint128(midPart.lo);
108 result = _cairo_uint128_add(res1, res2);
109
110 res1 = _cairo_uint64_to_uint128(midPart.hi);
111 res2 = _cairo_uint64_to_uint128(hiPart.lo);
112 res1 = _cairo_uint128_add(res1, res2);
113 res1 = _cairo_uint128_lsl(res1, 64);
114
115 result = _cairo_uint128_add(result, res1);
116
117 return result;
118}
119
120void
122{
123 cairo_uint128_t a, b;
124 bool sign = output_sign(_v, o._v, a, b);
125 cairo_uint128_t result = Udiv(a, b);
126 _v = sign ? _cairo_uint128_negate(result) : result;
127}
128
129cairo_uint128_t
130int64x64_t::Udiv(const cairo_uint128_t a, const cairo_uint128_t b)
131{
132 cairo_uint128_t den = b;
134 cairo_uint128_t result = qr.quo;
135 cairo_uint128_t rem = qr.rem;
136
137 // Now, manage the remainder
138 const uint64_t DIGITS = 64; // Number of fraction digits (bits) we need
139 const cairo_uint128_t ZERO = _cairo_uint32_to_uint128((uint32_t)0);
140
141 NS_ASSERT_MSG(_cairo_uint128_lt(rem, den), "Remainder not less than divisor");
142
143 uint64_t digis = 0; // Number of digits we have already
144 uint64_t shift = 0; // Number we are going to get this round
145
146 // Skip trailing zeros in divisor
147 while ((shift < DIGITS) && !(den.lo & 0x1))
148 {
149 ++shift;
150 den = _cairo_uint128_rsl(den, 1);
151 }
152
153 while ((digis < DIGITS) && !(_cairo_uint128_eq(rem, ZERO)))
154 {
155 // Skip leading zeros in remainder
156 while ((digis + shift < DIGITS) && !(rem.hi & HPCAIRO_MASK_HI_BIT))
157 {
158 ++shift;
159 rem = _cairo_int128_lsl(rem, 1);
160 }
161
162 // Cast off denominator bits if:
163 // Need more digits and
164 // LSB is zero or
165 // rem < den
166 while ((digis + shift < DIGITS) && (!(den.lo & 0x1) || _cairo_uint128_lt(rem, den)))
167 {
168 ++shift;
169 den = _cairo_uint128_rsl(den, 1);
170 }
171
172 // Do the division
173 qr = _cairo_uint128_divrem(rem, den);
174
175 // Add in the quotient as shift bits of the fraction
176 result = _cairo_uint128_lsl(result, static_cast<int>(shift));
177 result = _cairo_uint128_add(result, qr.quo);
178 rem = qr.rem;
179 digis += shift;
180 shift = 0;
181 }
182 // Did we run out of remainder?
183 if (digis < DIGITS)
184 {
185 shift = DIGITS - digis;
186 result = _cairo_uint128_lsl(result, static_cast<int>(shift));
187 }
188
189 return result;
190}
191
192void
194{
195 bool sign = _cairo_int128_negative(_v);
196 cairo_uint128_t a = sign ? _cairo_int128_negate(_v) : _v;
197 cairo_uint128_t result = UmulByInvert(a, o._v);
198
199 _v = sign ? _cairo_int128_negate(result) : result;
200}
201
202cairo_uint128_t
203int64x64_t::UmulByInvert(const cairo_uint128_t a, const cairo_uint128_t b)
204{
205 cairo_uint128_t result;
206 cairo_uint128_t hi, mid;
207 hi = _cairo_uint64x64_128_mul(a.hi, b.hi);
209 _cairo_uint64x64_128_mul(a.lo, b.hi));
210 mid.lo = mid.hi;
211 mid.hi = 0;
212 result = _cairo_uint128_add(hi, mid);
213 return result;
214}
215
217int64x64_t::Invert(const uint64_t v)
218{
219 NS_ASSERT(v > 1);
220 cairo_uint128_t a, factor;
221 a.hi = 1;
222 a.lo = 0;
223 factor.hi = 0;
224 factor.lo = v;
225 int64x64_t result;
226 result._v = Udiv(a, factor);
227 int64x64_t tmp = int64x64_t(v, 0);
228 tmp.MulByInvert(result);
229 if (tmp.GetHigh() != 1)
230 {
231 cairo_uint128_t one = {1, 0};
232 result._v = _cairo_uint128_add(result._v, one);
233 }
234 return result;
235}
236
237} // namespace ns3
NS_ABORT_x macro definitions.
NS_ASSERT() and NS_ASSERT_MSG() macro definitions.
cairo_uint128_t cairo_I _cairo_uint128_negate(cairo_uint128_t a)
int cairo_I _cairo_uint128_eq(cairo_uint128_t a, cairo_uint128_t b)
cairo_uint128_t cairo_I _cairo_uint128_add(cairo_uint128_t a, cairo_uint128_t b)
#define _cairo_int128_lsl(a, b)
#define _cairo_int128_to_uint128(i)
cairo_uint128_t cairo_I _cairo_uint32_to_uint128(uint32_t i)
cairo_uint128_t cairo_I _cairo_uint64x64_128_mul(cairo_uint64_t a, cairo_uint64_t b)
cairo_uint128_t cairo_I _cairo_uint128_lsl(cairo_uint128_t a, int shift)
#define _cairo_int128_negative(a)
cairo_uint128_t cairo_I _cairo_uint128_rsl(cairo_uint128_t a, int shift)
int cairo_I _cairo_uint128_lt(cairo_uint128_t a, cairo_uint128_t b)
cairo_uquorem128_t cairo_I _cairo_uint128_divrem(cairo_uint128_t num, cairo_uint128_t den)
#define _cairo_int128_negate(a)
cairo_uint128_t cairo_I _cairo_uint64_to_uint128(cairo_uint64_t i)
Implementation of the cairo_x functions which implement high precision arithmetic.
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
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...
static uint128_t UmulByInvert(const uint128_t a, const uint128_t b)
Unsigned multiplication of Q64.64 and Q0.128 values.
int128_t _v
The Q64.64 value.
Definition: int64x64-128.h:469
void Div(const int64x64_t &o)
Implement /=.
static const uint64_t HPCAIRO_MASK_HI_BIT
High bit of fractional part.
static int64x64_t Invert(const uint64_t v)
Compute the inverse of an integer value.
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
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
static bool output_sign(const int128_t sa, const int128_t sb, uint128_t &ua, uint128_t &ub)
Compute the sign of the result of multiplying or dividing Q64.64 fixed precision operands.
Definition: int64x64-128.cc:51
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
Declaration of the ns3::int64x64_t type using the Cairo implementation.
Debug message logging.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
ns3::TestCase, ns3::TestSuite, ns3::TestRunner declarations, and NS_TEST_ASSERT macro definitions.