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