A Discrete-Event Network Simulator
API
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.
30 extern "C"
31 {
32 #include "cairo-wideint.c"
33 }
34 
41 namespace 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
47 NS_LOG_COMPONENT_DEFINE("int64x64-cairo");
48 
60 static 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);
68  ua = _cairo_int128_to_uint128(sa);
69  ub = _cairo_int128_to_uint128(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 
75 void
76 int64x64_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 
84 cairo_uint128_t
85 int64x64_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 
120 void
121 int64x64_t::Div(const int64x64_t& o)
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 
129 cairo_uint128_t
130 int64x64_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 
192 void
193 int64x64_t::MulByInvert(const int64x64_t& o)
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 
202 cairo_uint128_t
203 int64x64_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 
216 int64x64_t
217 int64x64_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.
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 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.
#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.