A Discrete-Event Network Simulator
API
int64x64.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.h"
20 
21 #include "assert.h"
22 #include "log.h"
23 
24 #include <iomanip> // showpos
25 #include <iostream>
26 #include <sstream>
27 #include <stdint.h>
28 
36 namespace ns3
37 {
38 
39 // Note: Logging in this file is largely avoided due to the
40 // number of calls that are made to these functions and the possibility
41 // of causing recursions leading to stack overflow
43 
51 #define HEXHILOW(hi, lo) \
52  std::hex << std::setfill('0') << std::right << " (0x" << std::setw(16) << hi << " " \
53  << std::setw(16) << lo << std::dec << std::setfill(' ') << std::left << ")"
54 
68 std::ostream&
69 operator<<(std::ostream& os, const int64x64_t& value)
70 {
71  const bool negative = (value < 0);
72  const int64x64_t absVal = (negative ? -value : value);
73 
74  int64_t hi = absVal.GetHigh();
75 
76  // Save stream format flags
77  auto precision = static_cast<std::size_t>(os.precision());
78  std::ios_base::fmtflags ff = os.flags();
79  const bool floatfield = os.flags() & std::ios_base::floatfield;
80  os << std::setw(1) << std::noshowpos;
81 
82  os << std::right << (negative ? "-" : "+");
83 
84  std::ostringstream oss;
85  oss << hi << "."; // collect the digits here so we can round properly
86 
87  int64x64_t low(0, absVal.GetLow());
88  std::size_t places = 0; // Number of decimal places printed so far
89  bool more = true; // Should we print more digits?
90 
91  NS_LOG_LOGIC(std::endl
92  << (floatfield ? " f" : " ") << "[" << precision << "] " << hi << ". "
93  << HEXHILOW(hi, low.GetLow()));
94 
95  int64_t digit;
96  do
97  {
98  low *= 10;
99  digit = low.GetHigh();
100  NS_ASSERT_MSG((0 <= digit) && (digit <= 9),
101  "digit " << digit << " out of range [0,9] "
102  << " streaming out " << HEXHILOW(value.GetHigh(), value.GetLow()));
103  low -= digit;
104 
105  oss << std::setw(1) << digit;
106 
107  ++places;
108  if (floatfield)
109  {
110  more = places < precision;
111  }
112  else // default
113  {
114  // Full resolution is 20 decimal digits
115  more = low.GetLow() && (places < 20);
116  }
117 
118  NS_LOG_LOGIC((more ? "+" : " ") << (floatfield ? "f" : " ") << "[" << places << "] "
119  << digit << HEXHILOW(low.GetHigh(), low.GetLow())
120  << std::dec << std::setfill(' ') << std::left);
121 
122  } while (more);
123 
124  // Check if we need to round the last printed digit,
125  // based on the first unprinted digit
126  std::string digits = oss.str();
127  low *= 10;
128  int64_t nextDigit = low.GetHigh();
129  if ((nextDigit > 5) || ((nextDigit == 5) && (digit % 2 == 1)))
130  {
131  // Walk backwards with the carry
132  bool carry = true;
133  for (std::string::reverse_iterator rit = digits.rbegin(); rit != digits.rend(); ++rit)
134  {
135  if (*rit == '.') // Skip over the decimal point
136  {
137  continue;
138  }
139 
140  ++(*rit); // Add the carry
141  if (*rit <= '9') // Relies on character order...
142  {
143  carry = false;
144  break; // Carry complete
145  }
146  else
147  {
148  *rit = '0'; // Continue carry to next higher digit
149  }
150  }
151  if (carry) // If we still have a carry...
152  {
153  digits.insert(digits.begin(), '1');
154  }
155  }
156  os << digits;
157 
158  os.flags(ff); // Restore stream flags
159  return os;
160 }
161 
171 static uint64_t
172 ReadHiDigits(std::string str)
173 {
174  const char* buf = str.c_str();
175  uint64_t retval = 0;
176  while (*buf != 0)
177  {
178  retval *= 10;
179  retval += *buf - '0';
180  buf++;
181  }
182  return retval;
183 }
184 
195 static uint64_t
196 ReadLoDigits(std::string str)
197 {
198  int64x64_t low;
199  const int64x64_t round(0, 5); // Round last place in division
200 
201  for (std::string::const_reverse_iterator rit = str.rbegin(); rit != str.rend(); ++rit)
202  {
203  int digit = *rit - '0';
204  NS_ASSERT_MSG((0 <= digit) && (digit <= 9),
205  "digit " << digit << " out of range [0,9]"
206  << " streaming in low digits \"" << str << "\"");
207  low = (low + digit + round) / 10;
208  }
209 
210  return low.GetLow();
211 }
212 
213 std::istream&
214 operator>>(std::istream& is, int64x64_t& value)
215 {
216  std::string str;
217 
218  is >> str;
219  bool negative;
220  // skip heading spaces
221  std::string::size_type cur;
222  cur = str.find_first_not_of(' ');
223  std::string::size_type next;
224  // first, remove the sign.
225  next = str.find('-', cur);
226  if (next != std::string::npos)
227  {
228  negative = true;
229  next++;
230  }
231  else
232  {
233  next = str.find('+', cur);
234  if (next != std::string::npos)
235  {
236  next++;
237  }
238  else
239  {
240  next = cur;
241  }
242  negative = false;
243  }
244  cur = next;
245  int64_t hi;
246  uint64_t lo;
247  next = str.find('.', cur);
248  if (next != std::string::npos)
249  {
250  hi = ReadHiDigits(str.substr(cur, next - cur));
251  lo = ReadLoDigits(str.substr(next + 1, str.size() - (next + 1)));
252  }
253  else if (cur != std::string::npos)
254  {
255  hi = ReadHiDigits(str.substr(cur, str.size() - cur));
256  lo = 0;
257  }
258  else
259  {
260  hi = 0;
261  lo = 0;
262  }
263 
264  value = int64x64_t(hi, lo);
265  value = negative ? -value : value;
266 
267  return is;
268 }
269 
270 } // namespace ns3
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.
uint64_t GetLow() const
Get the fractional portion of this value, unscaled.
#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
static uint64_t ReadHiDigits(std::string str)
Read the integer portion of a number from a string containing just the integral digits (no decimal po...
Definition: int64x64.cc:172
#define HEXHILOW(hi, lo)
Print the high and low words of an int64x64 in hex, for debugging.
Definition: int64x64.cc:51
static uint64_t ReadLoDigits(std::string str)
Read the fractional part of a number from a string containing just the decimal digits of the fraction...
Definition: int64x64.cc:196
#define NS_LOG_COMPONENT_DEFINE_MASK(name, mask)
Define a logging component with a mask.
Definition: log.h:213
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
Declaration of the ns3::int64x64_t type and associated operators.
Debug message logging.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
@ LOG_PREFIX_TIME
Prefix all trace prints with simulation time.
Definition: log.h:119
std::istream & operator>>(std::istream &is, Angles &a)
Definition: angles.cc:183
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition: angles.cc:159