A Discrete-Event Network Simulator
API
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 
31 namespace 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
37 NS_LOG_COMPONENT_DEFINE("int64x64-128");
38 
50 static inline bool
51 output_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 
60 void
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 
70 uint128_t
71 int64x64_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 
113 void
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 
123 uint128_t
124 int64x64_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 
188 void
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 
198 uint128_t
199 int64x64_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 
220 int64x64_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(v, 0);
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.
#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.