A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
int64x64-cairo.cc
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2006 INRIA
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19  */
20 #include "int64x64-cairo.h"
21 #include "test.h"
22 #include "abort.h"
23 #include "assert.h"
24 #include "log.h"
25 #include <cmath>
26 #include <iostream>
27 
28 // Note: Logging in this file is largely avoided due to the
29 // number of calls that are made to these functions and the possibility
30 // of causing recursions leading to stack overflow
31 
32 NS_LOG_COMPONENT_DEFINE ("int64x64-cairo");
33 
34 namespace ns3 {
35 
36 #define OUTPUT_SIGN(sa,sb,ua,ub) \
37  ({ bool negA, negB; \
38  negA = _cairo_int128_negative (sa); \
39  negB = _cairo_int128_negative (sb); \
40  ua = _cairo_int128_to_uint128 (sa); \
41  ub = _cairo_int128_to_uint128 (sb); \
42  ua = negA ? _cairo_uint128_negate (ua) : ua; \
43  ub = negB ? _cairo_uint128_negate (ub) : ub; \
44  (negA && !negB) || (!negA && negB); })
45 
46 void
47 int64x64_t::Mul (int64x64_t const &o)
48 {
49  cairo_uint128_t a, b, result;
50  bool sign = OUTPUT_SIGN (_v, o._v, a, b);
51  result = Umul (a, b);
52  _v = sign ? _cairo_uint128_negate (result) : result;
53 }
54 
61 cairo_uint128_t
62 int64x64_t::Umul (cairo_uint128_t a, cairo_uint128_t b)
63 {
64  cairo_uint128_t result;
65  cairo_uint128_t hiPart,loPart,midPart;
66 
67  // Multiplying (a.h 2^64 + a.l) x (b.h 2^64 + b.l) =
68  // 2^128 a.h b.h + 2^64*(a.h b.l+b.h a.l) + a.l b.l
69  // get the low part a.l b.l
70  // multiply the fractional part
71  loPart = _cairo_uint64x64_128_mul (a.lo, b.lo);
72  // compute the middle part 2^64*(a.h b.l+b.h a.l)
73  midPart = _cairo_uint128_add (_cairo_uint64x64_128_mul (a.lo, b.hi),
74  _cairo_uint64x64_128_mul (a.hi, b.lo));
75  // truncate the low part
76  result.lo = _cairo_uint64_add (loPart.hi,midPart.lo);
77  // compute the high part 2^128 a.h b.h
78  hiPart = _cairo_uint64x64_128_mul (a.hi, b.hi);
79  // truncate the high part and only use the low part
80  result.hi = _cairo_uint64_add (hiPart.lo,midPart.hi);
81  // if the high part is not zero, put a warning
82  NS_ABORT_MSG_IF (hiPart.hi != 0,
83  "High precision 128 bits multiplication error: multiplication overflow.");
84  return result;
85 }
86 
87 void
88 int64x64_t::Div (int64x64_t const &o)
89 {
90  cairo_uint128_t a, b, result;
91  bool sign = OUTPUT_SIGN (_v, o._v, a, b);
92  result = Udiv (a, b);
93  _v = sign ? _cairo_uint128_negate (result) : result;
94 }
95 
96 cairo_uint128_t
97 int64x64_t::Udiv (cairo_uint128_t a, cairo_uint128_t b)
98 {
99  cairo_uquorem128_t qr = _cairo_uint128_divrem (a, b);
100  cairo_uint128_t result = _cairo_uint128_lsl (qr.quo, 64);
101  // Now, manage the remainder
102  cairo_uint128_t tmp = _cairo_uint128_rsl (qr.rem, 64);
103  cairo_uint128_t zero = _cairo_uint64_to_uint128 (0);
104  cairo_uint128_t rem, div;
105  if (_cairo_uint128_eq (tmp, zero))
106  {
107  rem = _cairo_uint128_lsl (qr.rem, 64);
108  div = b;
109  }
110  else
111  {
112  rem = qr.rem;
113  div = _cairo_uint128_rsl (b, 64);
114  }
115  qr = _cairo_uint128_divrem (rem, div);
116  result = _cairo_uint128_add (result, qr.quo);
117  return result;
118 }
119 
120 void
121 int64x64_t::MulByInvert (const int64x64_t &o)
122 {
123  bool negResult = _cairo_int128_negative (_v);
124  cairo_uint128_t a = negResult ? _cairo_int128_negate (_v) : _v;
125  cairo_uint128_t result = UmulByInvert (a, o._v);
126 
127  _v = negResult ? _cairo_int128_negate (result) : result;
128 }
129 cairo_uint128_t
130 int64x64_t::UmulByInvert (cairo_uint128_t a, cairo_uint128_t b)
131 {
132  cairo_uint128_t result;
133  cairo_uint128_t hi, mid;
134  hi = _cairo_uint64x64_128_mul (a.hi, b.hi);
135  mid = _cairo_uint128_add (_cairo_uint64x64_128_mul (a.hi, b.lo),
136  _cairo_uint64x64_128_mul (a.lo, b.hi));
137  mid.lo = mid.hi;
138  mid.hi = 0;
139  result = _cairo_uint128_add (hi,mid);
140  return result;
141 }
142 int64x64_t
143 int64x64_t::Invert (uint64_t v)
144 {
145  NS_ASSERT (v > 1);
146  cairo_uint128_t a, factor;
147  a.hi = 1;
148  a.lo = 0;
149  factor.hi = 0;
150  factor.lo = v;
151  int64x64_t result;
152  result._v = Udiv (a, factor);
153  int64x64_t tmp = int64x64_t (v, 0);
154  tmp.MulByInvert (result);
155  if (tmp.GetHigh () != 1)
156  {
157  cairo_uint128_t one = { 1, 0};
158  result._v = _cairo_uint128_add (result._v, one);
159  }
160  return result;
161 }
162 
163 
164 } // namespace ns3
165 
166 // include directly to allow optimizations within the compilation unit.
167 extern "C" {
168 #include "cairo-wideint.c"
169 }
#define NS_ASSERT(condition)
Definition: assert.h:64
#define NS_LOG_COMPONENT_DEFINE(name)
Definition: log.h:122
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if cond is true.
Definition: abort.h:98