A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
int64x64-cairo.cc
Go to the documentation of this file.
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 <math.h>
25 #include <iostream>
26 
27 namespace ns3 {
28 
29 #define OUTPUT_SIGN(sa,sb,ua,ub) \
30  ({ bool negA, negB; \
31  negA = _cairo_int128_negative (sa); \
32  negB = _cairo_int128_negative (sb); \
33  ua = _cairo_int128_to_uint128 (sa); \
34  ub = _cairo_int128_to_uint128 (sb); \
35  ua = negA ? _cairo_uint128_negate (ua) : ua; \
36  ub = negB ? _cairo_uint128_negate (ub) : ub; \
37  (negA && !negB) || (!negA && negB); })
38 
39 void
40 int64x64_t::Mul (int64x64_t const &o)
41 {
42  cairo_uint128_t a, b, result;
43  bool sign = OUTPUT_SIGN (_v, o._v, a, b);
44  result = Umul (a, b);
45  _v = sign ? _cairo_uint128_negate (result) : result;
46 }
47 
54 cairo_uint128_t
55 int64x64_t::Umul (cairo_uint128_t a, cairo_uint128_t b)
56 {
57  cairo_uint128_t result;
58  cairo_uint128_t hiPart,loPart,midPart;
59 
60  // Multiplying (a.h 2^64 + a.l) x (b.h 2^64 + b.l) =
61  // 2^128 a.h b.h + 2^64*(a.h b.l+b.h a.l) + a.l b.l
62  // get the low part a.l b.l
63  // multiply the fractional part
64  loPart = _cairo_uint64x64_128_mul (a.lo, b.lo);
65  // compute the middle part 2^64*(a.h b.l+b.h a.l)
66  midPart = _cairo_uint128_add (_cairo_uint64x64_128_mul (a.lo, b.hi),
67  _cairo_uint64x64_128_mul (a.hi, b.lo));
68  // truncate the low part
69  result.lo = _cairo_uint64_add (loPart.hi,midPart.lo);
70  // compute the high part 2^128 a.h b.h
71  hiPart = _cairo_uint64x64_128_mul (a.hi, b.hi);
72  // truncate the high part and only use the low part
73  result.hi = _cairo_uint64_add (hiPart.lo,midPart.hi);
74  // if the high part is not zero, put a warning
75  NS_ABORT_MSG_IF (hiPart.hi != 0,
76  "High precision 128 bits multiplication error: multiplication overflow.");
77  return result;
78 }
79 
80 void
81 int64x64_t::Div (int64x64_t const &o)
82 {
83  cairo_uint128_t a, b, result;
84  bool sign = OUTPUT_SIGN (_v, o._v, a, b);
85  result = Udiv (a, b);
86  _v = sign ? _cairo_uint128_negate (result) : result;
87 }
88 
89 cairo_uint128_t
90 int64x64_t::Udiv (cairo_uint128_t a, cairo_uint128_t b)
91 {
93  cairo_uint128_t result = _cairo_uint128_lsl (qr.quo, 64);
94  // Now, manage the remainder
95  cairo_uint128_t tmp = _cairo_uint128_rsl (qr.rem, 64);
96  cairo_uint128_t zero = _cairo_uint64_to_uint128 (0);
97  cairo_uint128_t rem, div;
98  if (_cairo_uint128_eq (tmp, zero))
99  {
100  rem = _cairo_uint128_lsl (qr.rem, 64);
101  div = b;
102  }
103  else
104  {
105  rem = qr.rem;
106  div = _cairo_uint128_rsl (b, 64);
107  }
108  qr = _cairo_uint128_divrem (rem, div);
109  result = _cairo_uint128_add (result, qr.quo);
110  return result;
111 }
112 
113 void
114 int64x64_t::MulByInvert (const int64x64_t &o)
115 {
116  bool negResult = _cairo_int128_negative (_v);
117  cairo_uint128_t a = negResult ? _cairo_int128_negate (_v) : _v;
118  cairo_uint128_t result = UmulByInvert (a, o._v);
119 
120  _v = negResult ? _cairo_int128_negate (result) : result;
121 }
122 cairo_uint128_t
123 int64x64_t::UmulByInvert (cairo_uint128_t a, cairo_uint128_t b)
124 {
125  cairo_uint128_t result;
126  cairo_uint128_t hi, mid;
127  hi = _cairo_uint64x64_128_mul (a.hi, b.hi);
128  mid = _cairo_uint128_add (_cairo_uint64x64_128_mul (a.hi, b.lo),
129  _cairo_uint64x64_128_mul (a.lo, b.hi));
130  mid.lo = mid.hi;
131  mid.hi = 0;
132  result = _cairo_uint128_add (hi,mid);
133  return result;
134 }
135 int64x64_t
136 int64x64_t::Invert (uint64_t v)
137 {
138  NS_ASSERT (v > 1);
139  cairo_uint128_t a, factor;
140  a.hi = 1;
141  a.lo = 0;
142  factor.hi = 0;
143  factor.lo = v;
144  int64x64_t result;
145  result._v = Udiv (a, factor);
146  int64x64_t tmp = int64x64_t (v, 0);
147  tmp.MulByInvert (result);
148  if (tmp.GetHigh () != 1)
149  {
150  cairo_uint128_t one = { 1, 0};
151  result._v = _cairo_uint128_add (result._v, one);
152  }
153  return result;
154 }
155 
156 
157 } // namespace ns3
158 
159 // include directly to allow optimizations within the compilation unit.
160 extern "C" {
161 #include "cairo-wideint.c"
162 }