A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
int64x64-128.cc
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 "int64x64-128.h"
20
21#include "abort.h"
22#include "assert.h"
23#include "log.h"
24
31namespace ns3
32{
33
34// Note: Logging in this file is largely avoided due to the
35// number of calls that are made to these functions and the possibility
36// of causing recursions leading to stack overflow
37NS_LOG_COMPONENT_DEFINE("int64x64-128");
38
50static inline bool
51output_sign(const int128_t sa, const int128_t sb, uint128_t& ua, uint128_t& ub)
52{
53 bool negA = sa < 0;
54 bool negB = sb < 0;
55 ua = negA ? -sa : sa;
56 ub = negB ? -sb : sb;
57 return negA != negB;
58}
59
60void
62{
63 uint128_t a;
64 uint128_t b;
65 bool negative = output_sign(_v, o._v, a, b);
66 uint128_t result = Umul(a, b);
67 _v = negative ? -result : result;
68}
69
70uint128_t
71int64x64_t::Umul(const uint128_t a, const uint128_t b)
72{
73 uint128_t aL = a & HP_MASK_LO;
74 uint128_t bL = b & HP_MASK_LO;
75 uint128_t aH = (a >> 64) & HP_MASK_LO;
76 uint128_t bH = (b >> 64) & HP_MASK_LO;
77
78 uint128_t result;
79 uint128_t hiPart;
80 uint128_t loPart;
81 uint128_t midPart;
82 uint128_t res1;
83 uint128_t res2;
84
85 // Multiplying (a.h 2^64 + a.l) x (b.h 2^64 + b.l) =
86 // 2^128 a.h b.h + 2^64*(a.h b.l+b.h a.l) + a.l b.l
87 // get the low part a.l b.l
88 // multiply the fractional part
89 loPart = aL * bL;
90 // compute the middle part 2^64*(a.h b.l+b.h a.l)
91 midPart = aL * bH + aH * bL;
92 // compute the high part 2^128 a.h b.h
93 hiPart = aH * bH;
94 // if the high part is not zero, put a warning
95 NS_ABORT_MSG_IF((hiPart & HP_MASK_HI) != 0,
96 "High precision 128 bits multiplication error: multiplication overflow.");
97
98 // Adding 64-bit terms to get 128-bit results, with carries
99 res1 = loPart >> 64;
100 res2 = midPart & HP_MASK_LO;
101 result = res1 + res2;
102
103 res1 = midPart >> 64;
104 res2 = hiPart & HP_MASK_LO;
105 res1 += res2;
106 res1 <<= 64;
107
108 result += res1;
109
110 return result;
111}
112
113void
115{
116 uint128_t a;
117 uint128_t b;
118 bool negative = output_sign(_v, o._v, a, b);
119 int128_t result = Udiv(a, b);
120 _v = negative ? -result : result;
121}
122
123uint128_t
124int64x64_t::Udiv(const uint128_t a, const uint128_t b)
125{
126 uint128_t rem = a;
127 uint128_t den = b;
128 uint128_t quo = rem / den;
129 rem = rem % den;
130 uint128_t result = quo;
131
132 // Now, manage the remainder
133 const uint64_t DIGITS = 64; // Number of fraction digits (bits) we need
134 const uint128_t ZERO = 0;
135
136 NS_ASSERT_MSG(rem < den, "Remainder not less than divisor");
137
138 uint64_t digis = 0; // Number of digits we have already
139 uint64_t shift = 0; // Number we are going to get this round
140
141 // Skip trailing zeros in divisor
142 while ((shift < DIGITS) && !(den & 0x1))
143 {
144 ++shift;
145 den >>= 1;
146 }
147
148 while ((digis < DIGITS) && (rem != ZERO))
149 {
150 // Skip leading zeros in remainder
151 while ((digis + shift < DIGITS) && !(rem & HP128_MASK_HI_BIT))
152 {
153 ++shift;
154 rem <<= 1;
155 }
156
157 // Cast off denominator bits if:
158 // Need more digits and
159 // LSB is zero or
160 // rem < den
161 while ((digis + shift < DIGITS) && (!(den & 0x1) || (rem < den)))
162 {
163 ++shift;
164 den >>= 1;
165 }
166
167 // Do the division
168 quo = rem / den;
169 rem = rem % den;
170
171 // Add in the quotient as shift bits of the fraction
172 result <<= shift;
173 result += quo;
174
175 digis += shift;
176 shift = 0;
177 }
178 // Did we run out of remainder?
179 if (digis < DIGITS)
180 {
181 shift = DIGITS - digis;
182 result <<= shift;
183 }
184
185 return result;
186}
187
188void
190{
191 bool negResult = _v < 0;
192 uint128_t a = negResult ? -_v : _v;
193 uint128_t result = UmulByInvert(a, o._v);
194
195 _v = negResult ? -result : result;
196}
197
198uint128_t
199int64x64_t::UmulByInvert(const uint128_t a, const uint128_t b)
200{
201 uint128_t result;
202 uint128_t ah;
203 uint128_t bh;
204 uint128_t al;
205 uint128_t bl;
206 uint128_t hi;
207 uint128_t mid;
208 ah = a >> 64;
209 bh = b >> 64;
210 al = a & HP_MASK_LO;
211 bl = b & HP_MASK_LO;
212 hi = ah * bh;
213 mid = ah * bl + al * bh;
214 mid >>= 64;
215 result = hi + mid;
216 return result;
217}
218
220int64x64_t::Invert(const uint64_t v)
221{
222 NS_ASSERT(v > 1);
223 uint128_t a;
224 a = 1;
225 a <<= 64;
226 int64x64_t result;
227 result._v = Udiv(a, v);
228 int64x64_t tmp = int64x64_t(v, false);
229 tmp.MulByInvert(result);
230 if (tmp.GetHigh() != 1)
231 {
232 result._v += 1;
233 }
234 return result;
235}
236
237} // namespace ns3
NS_ABORT_x macro definitions.
NS_ASSERT() and NS_ASSERT_MSG() macro definitions.
High precision numerical type, implementing Q64.64 fixed precision.
int64_t GetHigh() const
Get the integer portion.
static const uint64_t HP_MASK_LO
Mask for fraction part.
static cairo_uint128_t Umul(const cairo_uint128_t a, const cairo_uint128_t b)
Unsigned multiplication of Q64.64 values.
Definition: int64x64-128.cc:71
static cairo_uint128_t UmulByInvert(const cairo_uint128_t a, const cairo_uint128_t b)
Unsigned multiplication of Q64.64 and Q0.128 values.
void Mul(const int64x64_t &o)
Implement *=.
Definition: int64x64-128.cc:61
void MulByInvert(const int64x64_t &o)
Multiply this value by a Q0.128 value, presumably representing an inverse, completing a division oper...
static cairo_uint128_t Udiv(const cairo_uint128_t a, const cairo_uint128_t b)
Unsigned division of Q64.64 values.
cairo_int128_t _v
The Q64.64 value.
void Div(const int64x64_t &o)
Implement /=.
static int64x64_t Invert(const uint64_t v)
Compute the inverse of an integer value.
int64x64_t()
Default constructor.
#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
Debug message logging.
Every class exported by the ns3 library is enclosed in the ns3 namespace.