A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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 <limits>
27#include <sstream>
28#include <stdint.h>
29
30/**
31 * \file
32 * \ingroup highprec
33 * Implementation of the streaming input and output operators for
34 * the ns3::int64x64_t type.
35 */
36
37namespace ns3
38{
39
40// Note: Logging in this file is largely avoided due to the
41// number of calls that are made to these functions and the possibility
42// of causing recursions leading to stack overflow
44
45/**
46 * \ingroup highprec
47 * Print the high and low words of an int64x64 in hex, for debugging.
48 *
49 * \param [in] hi The high (integer) word.
50 * \param [in] lo The low (fractional) work.
51 */
52#define HEXHILOW(hi, lo) \
53 std::hex << std::setfill('0') << std::right << " (0x" << std::setw(16) << hi << " " \
54 << std::setw(16) << lo << std::dec << std::setfill(' ') << std::left << ")"
55
56/**
57 * \internal
58 * This algorithm is exact to the precision requested, up to the full
59 * 64 decimal digits required to exactly represent a 64-bit fraction.
60 *
61 * Proper rounding turns out to be surprisingly hard.
62 * In `y.xxxx5|6`, where the `|` marks follows the last output digit,
63 * rounding the `5|6` to `6|` is straightforward. However,
64 * rounding `y.xxx99|6` should result in `y.xx100|`. Notice the
65 * effect of rounding percolates to higher digits.
66 * We accumulate the output digits in a string, then carry out
67 * the rounding in the string directly.
68 */
69std::ostream&
70operator<<(std::ostream& os, const int64x64_t& value)
71{
72 const bool negative = (value < 0);
73
74 uint64_t hi;
75 int64x64_t low;
76 if (value != int64x64_t(std::numeric_limits<int64_t>::min(), 0))
77 {
78 const int64x64_t absVal = (negative ? -value : value);
79 hi = absVal.GetHigh();
80 low = int64x64_t(0, absVal.GetLow());
81 }
82 else
83 {
84 hi = static_cast<uint64_t>(1) << 63;
85 }
86
87 // Save stream format flags
88 auto precision = static_cast<std::size_t>(os.precision());
89 std::ios_base::fmtflags ff = os.flags();
90 const bool floatfield = os.flags() & std::ios_base::floatfield;
91 os << std::setw(1) << std::noshowpos;
92
93 os << std::right << (negative ? "-" : "+");
94
95 std::ostringstream oss;
96 oss << hi << "."; // collect the digits here so we can round properly
97
98 std::size_t places = 0; // Number of decimal places printed so far
99 bool more = true; // Should we print more digits?
100
101 NS_LOG_LOGIC(std::endl
102 << (floatfield ? " f" : " ") << "[" << precision << "] " << hi << ". "
103 << HEXHILOW(hi, low.GetLow()));
104
105 int64_t digit;
106 do
107 {
108 low *= 10;
109 digit = low.GetHigh();
110 NS_ASSERT_MSG((0 <= digit) && (digit <= 9),
111 "digit " << digit << " out of range [0,9] "
112 << " streaming out " << HEXHILOW(value.GetHigh(), value.GetLow()));
113 low -= digit;
114
115 oss << std::setw(1) << digit;
116
117 ++places;
118 if (floatfield)
119 {
120 more = places < precision;
121 }
122 else // default
123 {
124 // Full resolution is 20 decimal digits
125 more = low.GetLow() && (places < 20);
126 }
127
128 NS_LOG_LOGIC((more ? "+" : " ") << (floatfield ? "f" : " ") << "[" << places << "] "
129 << digit << HEXHILOW(low.GetHigh(), low.GetLow())
130 << std::dec << std::setfill(' ') << std::left);
131
132 } while (more);
133
134 // Check if we need to round the last printed digit,
135 // based on the first unprinted digit
136 std::string digits = oss.str();
137 low *= 10;
138 int64_t nextDigit = low.GetHigh();
139 if ((nextDigit > 5) || ((nextDigit == 5) && (digit % 2 == 1)))
140 {
141 // Walk backwards with the carry
142 bool carry = true;
143 for (std::string::reverse_iterator rit = digits.rbegin(); rit != digits.rend(); ++rit)
144 {
145 if (*rit == '.') // Skip over the decimal point
146 {
147 continue;
148 }
149
150 ++(*rit); // Add the carry
151 if (*rit <= '9') // Relies on character order...
152 {
153 carry = false;
154 break; // Carry complete
155 }
156 else
157 {
158 *rit = '0'; // Continue carry to next higher digit
159 }
160 }
161 if (carry) // If we still have a carry...
162 {
163 digits.insert(digits.begin(), '1');
164 }
165 }
166 os << digits;
167
168 os.flags(ff); // Restore stream flags
169 return os;
170}
171
172/**
173 * \ingroup highprec
174 * Read the integer portion of a number from a string containing
175 * just the integral digits (no decimal point or fractional part).
176 *
177 * \param [in] str The string representation of the integral part
178 * of a number, with no fractional part or decimal point.
179 * \returns The integer.
180 */
181static uint64_t
182ReadHiDigits(std::string str)
183{
184 const char* buf = str.c_str();
185 uint64_t retval = 0;
186 while (*buf != 0)
187 {
188 retval *= 10;
189 retval += *buf - '0';
190 buf++;
191 }
192 return retval;
193}
194
195/**
196 * \ingroup highprec
197 * Read the fractional part of a number from a string containing
198 * just the decimal digits of the fractional part (no integral part
199 * or decimal point).
200 *
201 * \param [in] str The string representation of the fractional part
202 * of a number, without integral part or decimal point.
203 * \returns The decimal portion of the input number.
204 */
205static uint64_t
206ReadLoDigits(std::string str)
207{
208 int64x64_t low;
209 const int64x64_t round(0, 5); // Round last place in division
210
211 for (std::string::const_reverse_iterator rit = str.rbegin(); rit != str.rend(); ++rit)
212 {
213 int digit = *rit - '0';
214 NS_ASSERT_MSG((0 <= digit) && (digit <= 9),
215 "digit " << digit << " out of range [0,9]"
216 << " streaming in low digits \"" << str << "\"");
217 low = (low + digit + round) / 10;
218 }
219
220 return low.GetLow();
221}
222
223std::istream&
224operator>>(std::istream& is, int64x64_t& value)
225{
226 std::string str;
227
228 is >> str;
229 bool negative;
230 // skip heading spaces
231 std::string::size_type cur;
232 cur = str.find_first_not_of(' ');
233 std::string::size_type next;
234 // first, remove the sign.
235 next = str.find('-', cur);
236 if (next != std::string::npos)
237 {
238 negative = true;
239 next++;
240 }
241 else
242 {
243 next = str.find('+', cur);
244 if (next != std::string::npos)
245 {
246 next++;
247 }
248 else
249 {
250 next = cur;
251 }
252 negative = false;
253 }
254 cur = next;
255 int64_t hi;
256 uint64_t lo;
257 next = str.find('.', cur);
258 if (next != std::string::npos)
259 {
260 hi = ReadHiDigits(str.substr(cur, next - cur));
261 lo = ReadLoDigits(str.substr(next + 1, str.size() - (next + 1)));
262 }
263 else if (cur != std::string::npos)
264 {
265 hi = ReadHiDigits(str.substr(cur, str.size() - cur));
266 lo = 0;
267 }
268 else
269 {
270 hi = 0;
271 lo = 0;
272 }
273
274 value = int64x64_t(hi, lo);
275 value = negative ? -value : value;
276
277 return is;
278}
279
280} // namespace ns3
NS_ASSERT() and NS_ASSERT_MSG() macro definitions.
High precision numerical type, implementing Q64.64 fixed precision.
Definition: int64x64-128.h:56
int64_t GetHigh() const
Get the integer portion.
Definition: int64x64-128.h:255
uint64_t GetLow() const
Get the fractional portion of this value, unscaled.
Definition: int64x64-128.h:266
#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:182
#define HEXHILOW(hi, lo)
Print the high and low words of an int64x64 in hex, for debugging.
Definition: int64x64.cc:52
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:206
#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.
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition: angles.cc:159
std::istream & operator>>(std::istream &is, Angles &a)
Definition: angles.cc:183
@ LOG_PREFIX_TIME
Prefix all trace prints with simulation time.
Definition: log.h:119