A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
int64x64-test-suite.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2011 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 "ns3/int64x64.h"
20#include "ns3/test.h"
21#include "ns3/valgrind.h" // Bug 1882
22
23#include <cfloat> // FLT_RADIX,...
24#include <cmath> // fabs, round
25#include <iomanip>
26#include <limits> // numeric_limits<>::epsilon ()
27
28#ifdef __WIN32__
29/**
30 * Indicates that Windows long doubles are 64-bit doubles
31 */
32#define RUNNING_WITH_LIMITED_PRECISION 1
33#else
34/**
35 * Checks if running on Valgrind, which assumes long doubles are 64-bit doubles
36 */
37#define RUNNING_WITH_LIMITED_PRECISION RUNNING_ON_VALGRIND
38#endif
39
40using namespace ns3;
41
42namespace ns3
43{
44
45namespace int64x64
46{
47
48namespace test
49{
50
51/**
52 * \file
53 * \ingroup int64x64-tests
54 * int64x46 test suite
55 */
56
57/**
58 * \ingroup core-tests
59 * \defgroup int64x64-tests int64x64 tests
60 */
61
62/**
63 * \ingroup int64x64-tests
64 *
65 * Pretty printer for test cases.
66 */
68{
69 public:
70 /**
71 * Construct from high and low words of Q64.64 representation.
72 *
73 * \param [in] high The integer portion.
74 * \param [in] low The fractional portion.
75 */
76 Printer(const int64_t high, const uint64_t low)
77 : m_haveInt(false),
78 m_value(0),
79 m_high(high),
80 m_low(low)
81 {
82 }
83
84 /**
85 * Construct from an \c int64x64_t Q64.64 value.
86 *
87 * \param [in] value The value.
88 */
89 Printer(const int64x64_t value)
90 : m_haveInt(true),
91 m_value(value),
92 m_high(value.GetHigh()),
93 m_low(value.GetLow())
94 {
95 }
96
97 private:
98 /**
99 * Output streamer, the main reason for this class.
100 *
101 * \param [in] os The stream.
102 * \param [in] p The value to print.
103 * \returns The stream.
104 */
105 friend std::ostream& operator<<(std::ostream& os, const Printer& p);
106
107 bool m_haveInt; /**< Do we have a full int64x64_t value? */
108 int64x64_t m_value; /**< The int64x64_t value. */
109 int64_t m_high; /**< The high (integer) word. */
110 uint64_t m_low; /**< The low (fractional) word. */
111};
112
113std::ostream&
114operator<<(std::ostream& os, const Printer& p)
115{
116 if (p.m_haveInt)
117 {
118 os << std::fixed << std::setprecision(22) << p.m_value;
119 }
120
121 os << std::hex << std::setfill('0') << " (0x" << std::setw(16) << p.m_high << " 0x"
122 << std::setw(16) << p.m_low << ")" << std::dec << std::setfill(' ');
123 return os;
124}
125
126/**
127 * \ingroup int64x64-tests
128 *
129 * Test: manipulate the high and low part of every number.
130 */
132{
133 public:
135 void DoRun() override;
136 /**
137 * Check the high and low parts for correctness.
138 * \param hi The high part of the int64x64_t.
139 * \param lo The low part of the int64x64_t.
140 */
141 void Check(const int64_t hi, const uint64_t lo);
142};
143
145 : TestCase("Manipulate the high and low part of every number")
146{
147}
148
149void
150Int64x64HiLoTestCase::Check(const int64_t hi, const uint64_t lo)
151{
152 uint64_t tolerance = 0;
154 {
155 // Darwin 12.5.0 (Mac 10.8.5) g++ 4.2.1
156 tolerance = 1;
157 }
158
159 int64x64_t value = int64x64_t(hi, lo);
160 uint64_t vLow = value.GetLow();
161 bool pass = ((value.GetHigh() == hi) && ((Max(vLow, lo) - Min(vLow, lo)) <= tolerance));
162
163 std::cout << GetParent()->GetName() << " Check: " << (pass ? "pass " : "FAIL ")
164 << Printer(value) << " from" << Printer(hi, lo) << std::endl;
165
166 NS_TEST_EXPECT_MSG_EQ(value.GetHigh(),
167 hi,
168 "High part does not match for hi:" << hi << " lo: " << lo);
169 NS_TEST_EXPECT_MSG_EQ_TOL((int64_t)vLow,
170 (int64_t)lo,
171 (int64_t)tolerance,
172 "Low part does not match for hi: " << hi << " lo: " << lo);
173}
174
175void
177{
178 std::cout << std::endl;
179 std::cout << GetParent()->GetName() << " Check: " << GetName() << std::endl;
180
181 uint64_t low = 1;
183 {
184 // Darwin 12.5.0 (Mac 10.8.5) g++ 4.2.1
185 low = static_cast<uint64_t>(HP_MAX_64 * std::numeric_limits<long double>::epsilon());
186 }
187
188 Check(0, 0);
189 Check(0, low);
190 Check(0, 0xffffffffffffffffULL - low);
191
192 Check(1, 0);
193 Check(1, low);
194 Check(1, 0xffffffffffffffffULL - low);
195
196 Check(-1, 0);
197 Check(-1, low);
198 Check(-1, 0xffffffffffffffffULL - low);
199}
200
201/**
202 * \ingroup int64x64-tests
203 *
204 * Test: check GetInt and Round.
205 */
207{
208 public:
210 void DoRun() override;
211 /**
212 * Check the int64x64 value for correctness.
213 * \param value The int64x64_t value.
214 * \param expectInt The expected integer value.
215 * \param expectRnd The expected rounding value.
216 */
217 void Check(const int64x64_t value, const int64_t expectInt, const int64_t expectRnd);
218};
219
221 : TestCase("Check GetInt and Round")
222{
223}
224
225void
227 const int64_t expectInt,
228 const int64_t expectRnd)
229{
230 int64_t vInt = value.GetInt();
231 int64_t vRnd = value.Round();
232
233 bool pass = (vInt == expectInt) && (vRnd == expectRnd);
234 std::cout << GetParent()->GetName() << " Check: " << (pass ? "pass " : "FAIL ") << value
235 << " (int)-> " << std::setw(2) << vInt << " (expected: " << std::setw(2) << expectInt
236 << "), (rnd)-> " << std::setw(2) << vRnd << " (expected " << std::setw(2) << expectRnd
237 << ")" << std::endl;
238
239 NS_TEST_EXPECT_MSG_EQ(vInt, expectInt, "Truncation to int failed");
240 NS_TEST_EXPECT_MSG_EQ(vRnd, expectRnd, "Rounding to int failed.");
241}
242
243void
245{
246 std::cout << std::endl;
247 std::cout << GetParent()->GetName() << " Check: " << GetName() << std::endl;
248
249 // Trivial cases
250 Check(0, 0, 0);
251 Check(1, 1, 1);
252 Check(-1, -1, -1);
253
254 // Both should move toward zero
255 Check(2.4, 2, 2);
256 Check(-2.4, -2, -2);
257
258 // GetInt should move toward zero; Round should move away
259 Check(3.6, 3, 4);
260 Check(-3.6, -3, -4);
261 // Boundary case
262 Check(4.5, 4, 5);
263 Check(-4.5, -4, -5);
264}
265
266/**
267 * \ingroup int64x64-tests
268 *
269 * Test: parse int64x64_t numbers as strings.
270 */
272{
273 public:
275 void DoRun() override;
276 /**
277 * Check the iont64x64 for correctness.
278 * \param str String representation of a number.
279 * \param hi The expected high part of the int64x64_t.
280 * \param lo The expected low part of the int64x64_t.
281 * \param tolerance The allowed tolerance.
282 */
283 void Check(const std::string& str,
284 const int64_t hi,
285 const uint64_t lo,
286 const int64_t tolerance = 0);
287};
288
290 : TestCase("Parse int64x64_t numbers as strings")
291{
292}
293
294void
295Int64x64InputTestCase::Check(const std::string& str,
296 const int64_t hi,
297 const uint64_t lo,
298 const int64_t tolerance /* = 0 */)
299
300{
301 std::istringstream iss;
302 iss.str(str);
303 int64x64_t value;
304 iss >> value;
305
306 std::string input = "\"" + str + "\"";
307 uint64_t vLow = value.GetLow();
308 bool pass = ((value.GetHigh() == hi) && (Max(vLow, lo) - Min(vLow, lo) <= tolerance));
309
310 std::cout << GetParent()->GetName() << " Input: " << (pass ? "pass " : "FAIL ") << std::left
311 << std::setw(28) << input << std::right << Printer(value)
312 << " expected: " << Printer(hi, lo) << " +/- " << tolerance << std::endl;
313
314 NS_TEST_EXPECT_MSG_EQ(value.GetHigh(),
315 hi,
316 "High parts do not match for input string \"" << str << "\"");
317 NS_TEST_EXPECT_MSG_EQ_TOL((int64_t)value.GetLow(),
318 (int64_t)lo,
319 tolerance,
320 "Low parts do not match for input string \"" << str << "\"");
321}
322
323void
325{
326 std::cout << std::endl;
327 std::cout << GetParent()->GetName() << " Input: " << GetName() << std::endl;
328
329 int64_t tolerance = 0;
331 {
332 // Darwin 12.5.0 (Mac 10.8.5) g++ 4.2.1
333 tolerance = 2;
334 }
335
336 Check("1", 1, 0);
337 Check("+1", 1, 0);
338 Check("-1", -1, 0);
339 Check("1.0", 1, 0);
340 Check("+1.0", 1, 0);
341 Check("001.0", 1, 0);
342 Check("+001.0", 1, 0);
343 Check("020.0", 20, 0);
344 Check("+020.0", 20, 0);
345 Check("1.0000000", 1, 0);
346 Check("-1.0", -1, 0, tolerance);
347 Check("-1.0000", -1, 0, tolerance);
348 Check(" 1.000000000000000000054", 1, 1, tolerance);
349 Check("-1.000000000000000000054", (int64_t)-2, (uint64_t)-1, tolerance);
350}
351
352/**
353 * \ingroup int64x64-tests
354 *
355 * Test: roundtrip int64x64_t numbers as strings.
356 *
357 * Prints an int64x64_t and read it back.
358 */
360{
361 public:
363 void DoRun() override;
364 /**
365 * Check the iont64x64 for correctness.
366 * \param str String representation of a number.
367 * \param tolerance The allowed tolerance.
368 */
369 void Check(const std::string& str, const int64_t tolerance = 0);
370};
371
373 : TestCase("Roundtrip int64x64_t numbers as strings")
374{
375}
376
377void
378Int64x64InputOutputTestCase::Check(const std::string& str, const int64_t tolerance /* = 0 */)
379{
380 std::stringstream iss(str);
381 int64x64_t expect;
382 iss >> expect;
383
384 std::stringstream oss;
385 oss << std::scientific << std::setprecision(21) << expect;
386 int64x64_t value;
387 oss >> value;
388
389 bool pass = Abs(value - expect) <= int64x64_t(0, tolerance + 1);
390
391 std::string input = "\"" + str + "\"";
392 std::string output = "\"" + oss.str() + "\"";
393
394 if (pass)
395 {
396 std::cout << GetParent()->GetName() << " InputOutput: " << (pass ? "pass " : "FAIL ")
397 << " in: " << std::left << std::setw(28) << input << " out: " << std::left
398 << std::setw(28) << output << std::right << std::endl;
399 }
400 else
401 {
402 std::cout << GetParent()->GetName() << " InputOutput: " << (pass ? "pass " : "FAIL ")
403 << " in: " << std::left << std::setw(28) << input << std::right
404 << Printer(expect) << std::endl;
405 std::cout << GetParent()->GetName() << std::setw(19) << " "
406 << " out: " << std::left << std::setw(28) << output << std::right
407 << Printer(value) << std::endl;
408 }
409
411 expect,
412 int64x64_t(0, tolerance),
413 "Converted string does not match expected string");
414}
415
416void
418{
419 std::cout << std::endl;
420 std::cout << GetParent()->GetName() << " InputOutput: " << GetName() << std::endl;
421
422 int64_t tolerance = 0;
424 {
425 // Darwin 12.5.0 (Mac 10.8.5) g++ 4.2.1
426 tolerance = 1;
427 }
428
429 Check("+1.000000000000000000000");
430 Check("+20.000000000000000000000");
431 Check("+0.000000000000000000000", tolerance);
432 Check("-1.000000000000000000000", tolerance);
433 Check("+1.084467440737095516158", tolerance);
434 Check("-2.084467440737095516158", tolerance);
435 Check("+3.184467440737095516179", tolerance);
436 Check("-4.184467440737095516179", tolerance);
437}
438
439/**
440 * \ingroup int64x64-tests
441 *
442 * Test: basic arithmetic operations.
443 */
445{
446 public:
448 void DoRun() override;
449 /**
450 * Check the int64x64 for correctness.
451 * \param test The test number.
452 * \param value The actual value.
453 * \param expect The expected value.
454 * \param tolerance The allowed tolerance.
455 */
456 void Check(const int test,
457 const int64x64_t value,
458 const int64x64_t expect,
459 const int64x64_t tolerance = int64x64_t(0, 0));
460};
461
463 : TestCase("Basic arithmetic operations")
464{
465}
466
467void
469 const int64x64_t value,
470 const int64x64_t expect,
471 const int64x64_t tolerance)
472{
473 bool pass = Abs(value - expect) <= tolerance;
474
475 std::cout << GetParent()->GetName() << " Arithmetic: " << (pass ? "pass " : "FAIL ") << test
476 << ": " << value << " == " << expect << " (+/- " << tolerance << ")" << std::endl;
477
478 NS_TEST_ASSERT_MSG_EQ_TOL(value, expect, tolerance, "Arithmetic failure in test case " << test);
479}
480
481void
483{
484 const int64x64_t tol1(0, 1);
485 const int64x64_t zero(0, 0);
486 const int64x64_t one(1, 0);
487 const int64x64_t two(2, 0);
488 const int64x64_t three(3, 0);
489
490 std::cout << std::endl;
491 std::cout << GetParent()->GetName() << " Arithmetic: " << GetName() << std::endl;
492
493 // NOLINTBEGIN(misc-redundant-expression)
494 Check(0, zero - zero, zero);
495 Check(1, zero - one, -one);
496 Check(2, one - one, zero);
497 Check(3, one - two, -one);
498 Check(4, one - (-one), two);
499 Check(5, (-one) - (-two), one);
500 Check(6, (-one) - two, -three);
501
502 Check(7, zero + zero, zero);
503 Check(8, zero + one, one);
504 Check(9, one + one, two);
505 Check(10, one + two, three);
506 Check(11, one + (-one), zero);
507 Check(12, (-one) + (-two), -three);
508 Check(13, (-one) + two, one);
509
510 Check(14, zero * zero, zero);
511 Check(15, zero * one, zero);
512 Check(16, zero * (-one), zero);
513 Check(17, one * one, one);
514 Check(18, one * (-one), -one);
515 Check(19, (-one) * (-one), one);
516
517 Check(20, (two * three) / three, two);
518 // NOLINTEND(misc-redundant-expression)
519
520 const int64x64_t frac = int64x64_t(0, 0xc000000000000000ULL); // 0.75
521 const int64x64_t fplf2 = frac + frac * frac; // 1.3125
522
523 Check(21, frac, 0.75);
524 Check(22, fplf2, 1.3125);
525
526 const int64x64_t zerof = zero + frac;
527 const int64x64_t onef = one + frac;
528 const int64x64_t twof = two + frac;
529 const int64x64_t thref = three + frac;
530
531 // NOLINTBEGIN(misc-redundant-expression)
532 Check(23, zerof, frac);
533
534 Check(24, zerof - zerof, zero);
535 Check(25, zerof - onef, -one);
536 Check(26, onef - onef, zero);
537 Check(27, onef - twof, -one);
538 Check(28, onef - (-onef), twof + frac);
539 Check(29, (-onef) - (-twof), one);
540 Check(30, (-onef) - twof, -thref - frac);
541
542 Check(31, zerof + zerof, zerof + frac);
543 Check(32, zerof + onef, onef + frac);
544 Check(33, onef + onef, twof + frac);
545 Check(34, onef + twof, thref + frac);
546 Check(35, onef + (-onef), zero);
547 Check(36, (-onef) + (-twof), -thref - frac);
548 Check(37, (-onef) + twof, one);
549
550 Check(38, zerof * zerof, frac * frac);
551 Check(39, zero * onef, zero);
552 Check(40, zerof * one, frac);
553
554 Check(41, zerof * onef, fplf2);
555 Check(42, zerof * (-onef), -fplf2);
556 Check(43, onef * onef, onef + fplf2);
557 Check(44, onef * (-onef), -onef - fplf2);
558 Check(45, (-onef) * (-onef), onef + fplf2);
559 // NOLINTEND(misc-redundant-expression)
560
561 // Multiplication followed by division is exact:
562 Check(46, (two * three) / three, two);
563 Check(47, (twof * thref) / thref, twof);
564
565 // Division followed by multiplication loses a bit or two:
566 Check(48, (two / three) * three, two, 2 * tol1);
567 Check(49, (twof / thref) * thref, twof, 3 * tol1);
568
569 // The example below shows that we really do not lose
570 // much precision internally: it is almost always the
571 // final conversion which loses precision.
572 Check(50,
573 (int64x64_t(2000000000) / int64x64_t(3)) * int64x64_t(3),
574 int64x64_t(1999999999, 0xfffffffffffffffeULL));
575
576 // Check special values
577 Check(51, int64x64_t(0, 0x159fa87f8aeaad21ULL) * 10, int64x64_t(0, 0xd83c94fb6d2ac34aULL));
578 {
579 auto x = int64x64_t(std::numeric_limits<int64_t>::min(), 0);
580 Check(52, x * 1, x);
581 Check(53, 1 * x, x);
582 }
583 {
584 int64x64_t x(1 << 30, (static_cast<uint64_t>(1) << 63) + 1);
585 auto ret = x * x;
586 int64x64_t expected(1152921505680588800, 4611686020574871553);
587 // The real difference between ret and expected is 2^-128.
588 int64x64_t tolerance = 0;
590 {
591 tolerance = tol1;
592 }
593 Check(54, ret, expected, tolerance);
594 }
595
596 // The following triggers an assert in int64x64-128.cc:Umul():117
597 /*
598 {
599 auto x = int64x64_t(1LL << 31); // 2^31
600 auto y = 2 * x; // 2^32
601 Check(55, x, x);
602 Check(56, y, y);
603 auto z [[maybe_unused]] = x * y; // 2^63 < 0, triggers assert
604 Check(57, z, z);
605 }
606 */
607}
608
609/**
610 * \ingroup int64x64-tests
611 *
612 * Test case for bug 455.
613 *
614 * See \bugid{455}
615 */
617{
618 public:
620 void DoRun() override;
621 /**
622 * Check the int64x64 for correctness.
623 * \param result The actual value.
624 * \param expect The expected value.
625 * \param msg The error message to print.
626 */
627 void Check(const double result, const double expect, const std::string& msg);
628};
629
631 : TestCase("Test case for bug 455")
632{
633}
634
635void
636Int64x64Bug455TestCase::Check(const double result, const double expect, const std::string& msg)
637{
638 bool pass = result == expect;
639
640 std::cout << GetParent()->GetName() << " Bug 455: " << (pass ? "pass " : "FAIL ")
641 << "res: " << result << " exp: " << expect << ": " << msg << std::endl;
642
643 NS_TEST_ASSERT_MSG_EQ(result, expect, msg);
644}
645
646void
648{
649 std::cout << std::endl;
650 std::cout << GetParent()->GetName() << " Bug 455: " << GetName() << std::endl;
651
652 int64x64_t a(0.1);
653 a /= int64x64_t(1.25);
654 Check(a.GetDouble(), 0.08, "The original testcase");
655
656 a = int64x64_t(0.5);
657 a *= int64x64_t(5);
658 Check(a.GetDouble(), 2.5, "Simple test for multiplication");
659
660 a = int64x64_t(-0.5);
661 a *= int64x64_t(5);
662 Check(a.GetDouble(), -2.5, "Test sign, first operation negative");
663
664 a = int64x64_t(-0.5);
665 a *= int64x64_t(-5);
666 Check(a.GetDouble(), 2.5, "both operands negative");
667
668 a = int64x64_t(0.5);
669 a *= int64x64_t(-5);
670 Check(a.GetDouble(), -2.5, "only second operand negative");
671}
672
673/**
674 * \ingroup int64x64-tests
675 *
676 * Test case for bug 455.
677 *
678 * See \bugid{863}
679 */
681{
682 public:
684 void DoRun() override;
685 /**
686 * Check the int64x64 for correctness.
687 * \param result The actual value.
688 * \param expect The expected value.
689 * \param msg The error message to print.
690 */
691 void Check(const double result, const double expect, const std::string& msg);
692};
693
695 : TestCase("Test case for bug 863")
696{
697}
698
699void
700Int64x64Bug863TestCase::Check(const double result, const double expect, const std::string& msg)
701{
702 bool pass = result == expect;
703
704 std::cout << GetParent()->GetName() << " Bug 863: " << (pass ? "pass " : "FAIL ")
705 << "res: " << result << " exp: " << expect << ": " << msg << std::endl;
706
707 NS_TEST_ASSERT_MSG_EQ(result, expect, msg);
708}
709
710void
712{
713 std::cout << std::endl;
714 std::cout << GetParent()->GetName() << " Bug 863: " << GetName() << std::endl;
715
716 int64x64_t a(0.9);
717 a /= int64x64_t(1);
718 Check(a.GetDouble(), 0.9, "The original testcase");
719
720 a = int64x64_t(0.5);
721 a /= int64x64_t(0.5);
722 Check(a.GetDouble(), 1.0, "Simple test for division");
723
724 a = int64x64_t(-0.5);
725 Check(a.GetDouble(), -0.5, "Check that we actually convert doubles correctly");
726
727 a /= int64x64_t(0.5);
728 Check(a.GetDouble(), -1.0, "first argument negative");
729
730 a = int64x64_t(0.5);
731 a /= int64x64_t(-0.5);
732 Check(a.GetDouble(), -1.0, "second argument negative");
733
734 a = int64x64_t(-0.5);
735 a /= int64x64_t(-0.5);
736 Check(a.GetDouble(), 1.0, "both arguments negative");
737}
738
739/**
740 * \ingroup int64x64-tests
741 *
742 * Test case for bug 455.
743 *
744 * See \bugid{1786}
745 */
747{
748 public:
750 void DoRun() override;
751 /**
752 * Check the int64x64 for correctness.
753 * \param low The actual low value.
754 * \param value The expected low part printed value.
755 * \param tolerance The allowed tolerance.
756 */
757 void Check(const uint64_t low, const std::string& value, const int64_t tolerance = 0);
758};
759
761 : TestCase("Test case for bug 1786")
762{
763}
764
765void
767 const std::string& str,
768 const int64_t tolerance /* = 0 */)
769{
770 int64x64_t value(0, low);
771 std::ostringstream oss;
772 oss << std::scientific << std::setprecision(22) << value;
773
774 if (tolerance == 0)
775 {
776 bool pass = oss.str() == str;
777
778 std::cout << GetParent()->GetName() << " Bug 1786: " << (pass ? "pass " : "FAIL ")
779 << " 0x" << std::hex << std::setw(16) << low << std::dec << " = " << oss.str();
780 if (!pass)
781 {
782 std::cout << ", expected " << str;
783 }
784 std::cout << std::endl;
785
786 NS_TEST_EXPECT_MSG_EQ(oss.str(), str, "Fraction string not correct");
787 }
788 else
789 {
790 // No obvious way to implement a tolerance on the strings
791
792 std::cout << GetParent()->GetName() << " Bug 1786: "
793 << "skip "
794 << " 0x" << std::hex << std::setw(16) << low << std::dec << " = " << oss.str()
795 << ", expected " << str << std::endl;
796 }
797}
798
799void
801{
802 std::cout << std::endl;
803 std::cout << GetParent()->GetName() << " But 1786: " << GetName() << std::endl;
804
805 int64_t tolerance = 0;
807 {
808 // Darwin 12.5.0 (Mac 10.8.5) g++ 4.2.1
809 tolerance = 1;
810 }
811
812 // Some of these values differ from the DoubleTestCase
813 // by one count in the last place
814 // because operator<< truncates the last output digit,
815 // instead of rounding.
816
817 // NOLINTBEGIN(misc-redundant-expression)
818 // clang-format off
819 Check( 1ULL, "+0.0000000000000000000542");
820 Check( 2ULL, "+0.0000000000000000001084");
821 Check( 3ULL, "+0.0000000000000000001626");
822 Check( 4ULL, "+0.0000000000000000002168");
823 Check( 5ULL, "+0.0000000000000000002710");
824 Check( 6ULL, "+0.0000000000000000003253");
825 Check( 7ULL, "+0.0000000000000000003795");
826 Check( 8ULL, "+0.0000000000000000004337");
827 Check( 9ULL, "+0.0000000000000000004879");
828 Check( 0xAULL, "+0.0000000000000000005421");
829 Check( 0xFULL, "+0.0000000000000000008132");
830 Check( 0xF0ULL, "+0.0000000000000000130104");
831 Check( 0xF00ULL, "+0.0000000000000002081668");
832 Check( 0xF000ULL, "+0.0000000000000033306691");
833 Check( 0xF0000ULL, "+0.0000000000000532907052");
834 Check( 0xF00000ULL, "+0.0000000000008526512829");
835 Check( 0xF000000ULL, "+0.0000000000136424205266");
836 Check( 0xF0000000ULL, "+0.0000000002182787284255");
837 Check( 0xF00000000ULL, "+0.0000000034924596548080");
838 Check( 0xF000000000ULL, "+0.0000000558793544769287");
839 Check( 0xF0000000000ULL, "+0.0000008940696716308594");
840 Check( 0xF00000000000ULL, "+0.0000143051147460937500");
841 Check( 0xF000000000000ULL, "+0.0002288818359375000000");
842 Check( 0xF0000000000000ULL, "+0.0036621093750000000000");
843 Check( 0xF00000000000000ULL, "+0.0585937500000000000000");
844 std::cout << std::endl;
845 Check(0x7FFFFFFFFFFFFFFDULL, "+0.4999999999999999998374", tolerance);
846 Check(0x7FFFFFFFFFFFFFFEULL, "+0.4999999999999999998916", tolerance);
847 Check(0x7FFFFFFFFFFFFFFFULL, "+0.4999999999999999999458", tolerance);
848 Check(0x8000000000000000ULL, "+0.5000000000000000000000");
849 Check(0x8000000000000001ULL, "+0.5000000000000000000542", tolerance);
850 Check(0x8000000000000002ULL, "+0.5000000000000000001084", tolerance);
851 Check(0x8000000000000003ULL, "+0.5000000000000000001626", tolerance);
852 std::cout << std::endl;
853 Check(0xF000000000000000ULL, "+0.9375000000000000000000");
854 Check(0xFF00000000000000ULL, "+0.9960937500000000000000");
855 Check(0xFFF0000000000000ULL, "+0.9997558593750000000000");
856 Check(0xFFFF000000000000ULL, "+0.9999847412109375000000");
857 Check(0xFFFFF00000000000ULL, "+0.9999990463256835937500");
858 Check(0xFFFFFF0000000000ULL, "+0.9999999403953552246094");
859 Check(0xFFFFFFF000000000ULL, "+0.9999999962747097015381");
860 Check(0xFFFFFFFF00000000ULL, "+0.9999999997671693563461");
861 Check(0xFFFFFFFFF0000000ULL, "+0.9999999999854480847716");
862 Check(0xFFFFFFFFFF000000ULL, "+0.9999999999990905052982");
863 Check(0xFFFFFFFFFFF00000ULL, "+0.9999999999999431565811");
864 Check(0xFFFFFFFFFFFF0000ULL, "+0.9999999999999964472863");
865 Check(0xFFFFFFFFFFFFF000ULL, "+0.9999999999999997779554");
866 Check(0xFFFFFFFFFFFFFF00ULL, "+0.9999999999999999861222");
867 Check(0xFFFFFFFFFFFFFFF0ULL, "+0.9999999999999999991326");
868 Check(0xFFFFFFFFFFFFFFF5ULL, "+0.9999999999999999994037", tolerance);
869 Check(0xFFFFFFFFFFFFFFF6ULL, "+0.9999999999999999994579", tolerance);
870 Check(0xFFFFFFFFFFFFFFF7ULL, "+0.9999999999999999995121", tolerance);
871 Check(0xFFFFFFFFFFFFFFF8ULL, "+0.9999999999999999995663", tolerance);
872 Check(0xFFFFFFFFFFFFFFF9ULL, "+0.9999999999999999996205", tolerance);
873 Check(0xFFFFFFFFFFFFFFFAULL, "+0.9999999999999999996747", tolerance);
874 Check(0xFFFFFFFFFFFFFFFBULL, "+0.9999999999999999997289", tolerance);
875 Check(0xFFFFFFFFFFFFFFFCULL, "+0.9999999999999999997832", tolerance);
876 Check(0xFFFFFFFFFFFFFFFDULL, "+0.9999999999999999998374", tolerance);
877 Check(0xFFFFFFFFFFFFFFFEULL, "+0.9999999999999999998916", tolerance);
878 Check(0xFFFFFFFFFFFFFFFFULL, "+0.9999999999999999999458", tolerance);
879 // clang-format on
880 // NOLINTEND(misc-redundant-expression)
881}
882
883/**
884 * \ingroup int64x64-tests
885 *
886 * Test: basic compare operations.
887 */
889{
890 public:
892 void DoRun() override;
893
894 /**
895 * Check the int64x64 for correctness.
896 * \param result The actual value.
897 * \param expect The expected value.
898 * \param msg The error message to print.
899 */
900 void Check(const bool result, const bool expect, const std::string& msg);
901};
902
904 : TestCase("Basic compare operations")
905{
906}
907
908void
909Int64x64CompareTestCase::Check(const bool result, const bool expect, const std::string& msg)
910{
911 bool pass = result == expect;
912
913 std::cout << GetParent()->GetName() << " Compare: " << (pass ? "pass " : "FAIL ") << msg
914 << std::endl;
915
916 NS_TEST_ASSERT_MSG_EQ(result, expect, msg);
917}
918
919void
921{
922 std::cout << std::endl;
923 std::cout << GetParent()->GetName() << " Compare: " << GetName() << std::endl;
924
925 const int64x64_t zero(0, 0);
926 const int64x64_t one(1, 0);
927 const int64x64_t two(2, 0);
928 const int64x64_t mone(-1, 0);
929 const int64x64_t mtwo(-2, 0);
930 const int64x64_t frac = int64x64_t(0, 0xc000000000000000ULL); // 0.75
931 const int64x64_t zerof = zero + frac;
932 const int64x64_t onef = one + frac;
933 const int64x64_t monef = mone - frac;
934 const int64x64_t mtwof = mtwo - frac;
935
936 // NOLINTBEGIN(misc-redundant-expression)
937 Check(zerof == zerof, true, "equality, zero");
938 Check(onef == onef, true, "equality, positive");
939 Check(mtwof == mtwof, true, "equality, negative");
940 Check(zero == one, false, "equality false, zero");
941 Check(one == two, false, "equality false, unsigned");
942 Check(one == mone, false, "equality false, signed");
943 Check(onef == one, false, "equality false, fraction");
944 std::cout << std::endl;
945
946 Check(zerof != zerof, false, "inequality, zero");
947 Check(onef != onef, false, "inequality, positive");
948 Check(mtwof != mtwof, false, "inequality, negative");
949 Check(zero != one, true, "inequality true, zero");
950 Check(one != two, true, "inequality true, unsigned");
951 Check(one != mone, true, "inequality true, signed");
952 Check(onef != one, true, "inequality true, fraction");
953 std::cout << std::endl;
954
955 Check(zerof < onef, true, "less, zerof");
956 Check(zero < zerof, true, "less, zero");
957 Check(one < onef, true, "less, positive");
958 Check(monef < mone, true, "less, negative");
959 Check(onef < one, false, "less, false, positive");
960 Check(mtwo < mtwof, false, "less, false, negative");
961 std::cout << std::endl;
962
963 Check(zerof <= zerof, true, "less equal, equal, zerof");
964 Check(zero <= zerof, true, "less equal, less, zero");
965 Check(onef <= onef, true, "less equal, equal, positive");
966 Check(monef <= mone, true, "less equal, less, negative");
967 Check(onef <= one, false, "less equal, false, positive");
968 Check(mtwo <= mtwof, false, "less equal, false, negative");
969 std::cout << std::endl;
970
971 Check(onef > zerof, true, "greater, zerof");
972 Check(zerof > zero, true, "greater, zero");
973 Check(onef > one, true, "greater, positive");
974 Check(mone > monef, true, "greater, negative");
975 Check(one > onef, false, "greater, false, positive");
976 Check(mtwof > mtwo, false, "greater, false, negative");
977 std::cout << std::endl;
978
979 Check(zerof >= zerof, true, "greater equal, equal, zerof");
980 Check(zerof >= zero, true, "greater equal, greater, zero");
981 Check(onef >= onef, true, "greater equal, equal, positive");
982 Check(mone >= monef, true, "greater equal, greater, negative");
983 Check(one >= onef, false, "greater equal, false, positive");
984 Check(mtwof >= mtwo, false, "greater equal, false, negative");
985 std::cout << std::endl;
986
987 Check(zero == false, true, "zero == false");
988 Check(one == true, true, "one == true");
989 Check(zerof != false, true, "zerof != false");
990 Check((!zero) == true, true, "!zero == true");
991 Check((!zerof) == false, true, "!zerof == false");
992 Check((!one) == false, true, "!one == false");
993 Check((+onef) == onef, true, "unary positive");
994 Check((-onef) == monef, true, "unary negative");
995 // NOLINTEND(misc-redundant-expression)
996}
997
998/**
999 * \ingroup int64x64-tests
1000 *
1001 * Test: Invert and MulByInvert.
1002 */
1004{
1005 public:
1007 void DoRun() override;
1008 /**
1009 * Check the int64x64 for correctness.
1010 * \param factor The factor used to invert the number.
1011 */
1012 void Check(const int64_t factor);
1013 /**
1014 * Check the int64x64 for correctness.
1015 * \param factor The factor used to invert the number.
1016 * \param result The value.
1017 * \param expect The expected value.
1018 * \param msg The error message to print.
1019 * \param tolerance The allowed tolerance.
1020 */
1021 void CheckCase(const uint64_t factor,
1022 const int64x64_t result,
1023 const int64x64_t expect,
1024 const std::string& msg,
1025 const double tolerance = 0);
1026};
1027
1029 : TestCase("Invert and MulByInvert")
1030{
1031}
1032
1033void
1035 const int64x64_t result,
1036 const int64x64_t expect,
1037 const std::string& msg,
1038 const double tolerance /* = 0 */)
1039{
1040 bool pass = Abs(result - expect) <= tolerance;
1041
1042 std::cout << GetParent()->GetName() << " Invert: ";
1043
1044 if (pass)
1045 {
1046 std::cout << "pass: " << factor << ": ";
1047 }
1048 else
1049 {
1050 std::cout << "FAIL: " << factor << ": "
1051 << "(res: " << result << " exp: " << expect << " tol: " << tolerance << ") ";
1052 }
1053 std::cout << msg << std::endl;
1054
1055 NS_TEST_ASSERT_MSG_EQ_TOL(result, expect, int64x64_t(tolerance), msg);
1056}
1057
1058void
1060{
1061 const int64x64_t one(1, 0);
1062 const int64x64_t factorI = one / int64x64_t(factor);
1063
1064 const int64x64_t a = int64x64_t::Invert(factor);
1065 int64x64_t b(factor);
1066
1067 double tolerance = 0;
1069 {
1070 // Darwin 12.5.0 (Mac 10.8.5) g++ 4.2.1
1071 tolerance = 0.000000000000000001L;
1072 }
1073
1074 b.MulByInvert(a);
1075 CheckCase(factor, b, one, "x * x^-1 == 1", tolerance);
1076
1077 int64x64_t c(1);
1078 c.MulByInvert(a);
1079 CheckCase(factor, c, factorI, "1 * x^-1 == 1 / x");
1080
1081 int64x64_t d(1);
1082 d /= (int64x64_t(factor));
1083 CheckCase(factor, d, c, "1/x == x^-1");
1084
1085 int64x64_t e(-factor);
1086 e.MulByInvert(a);
1087 CheckCase(factor, e, -one, "-x * x^-1 == -1", tolerance);
1088}
1089
1090void
1092{
1093 std::cout << std::endl;
1094 std::cout << GetParent()->GetName() << " Invert: " << GetName() << std::endl;
1095
1096 Check(2);
1097 Check(3);
1098 Check(4);
1099 Check(5);
1100 Check(6);
1101 Check(10);
1102 Check(99);
1103 Check(100);
1104 Check(1000);
1105 Check(10000);
1106 Check(100000);
1107 Check(100000);
1108 Check(1000000);
1109 Check(10000000);
1110 Check(100000000);
1111 Check(1000000000);
1112 Check(10000000000LL);
1113 Check(100000000000LL);
1114 Check(1000000000000LL);
1115 Check(10000000000000LL);
1116 Check(100000000000000LL);
1117 Check(1000000000000000LL);
1118}
1119
1120/**
1121 * \ingroup int64x64-tests
1122 *
1123 * Test: construct from floating point.
1124 */
1126{
1127 public:
1129 void DoRun() override;
1130
1131 /**
1132 * Check the int64x64 for correctness.
1133 * \param intPart The expected integer part value of the int64x64.
1134 */
1135 void Check(const int64_t intPart);
1136 /**
1137 * Check the int64x64 for correctness.
1138 * \param dec The integer part of the value to test.
1139 * \param frac The fractional part of the value to test.x
1140 * \param intPart The expected integer part value of the int64x64.
1141 * \param lo The expected low part value of the int64x64.
1142 */
1143 void Check(const long double dec,
1144 const long double frac,
1145 const int64_t intPart,
1146 const uint64_t lo);
1147
1148 private:
1149 /**
1150 * Compute a multiplier to match the mantissa size on this platform
1151 *
1152 * Since we will store the fractional part of a double
1153 * in the low word (64 bits) of our Q64.64
1154 * the most mantissa bits we can take advantage of is
1155 *
1156 * EFF_MANT_DIG = std::min (64, LDBL_MANT_DIG)
1157 *
1158 * We have to bound this for platforms with LDBL_MANT_DIG > 64.
1159 *
1160 * The number of "missing" bits in the mantissa is
1161 *
1162 * MISS_MANT_DIG = 64 - EFF_MANT_DIG = std::max (0, 64 - LDBL_MANT_DIG)
1163 *
1164 * This will lie in the closed interval [0, 64]
1165 */
1166 static constexpr int MISS_MANT_DIG = std::max(0, 64 - LDBL_MANT_DIG);
1167
1168 /**
1169 * The smallest low word we expect to get from a conversion.
1170 *
1171 * MIN_LOW = 2^MISS_MANT_DIG
1172 *
1173 * which will be in [1, 2^64].
1174 */
1175 static constexpr long double MIN_LOW = 1 << MISS_MANT_DIG;
1176
1177 /**
1178 * Smallest mantissa we expect to convert to a non-zero low word.
1179 *
1180 * MIN_MANT = MIN_LOW / 2^64
1181 * = 2^(MISS_MANT_DIG - 64)
1182 * = 2^(-EFF_MANT_DIG)
1183 *
1184 * We scale and round this value to match the
1185 * hard-coded fractional values in Check(intPart)
1186 * which have 22 decimal digits.
1187 *
1188 * Since we use std::round() which isn't constexpr,
1189 * just declare this const and initialize below.
1190 */
1191 static const long double MIN_MANT;
1192
1193 // Member variables
1194 long double m_last; //!< The last value tested.
1196 m_deltaMax; //!< The maximum observed difference between expected and computed values.
1197 int m_deltaCount; //!< The number of times a delta was recorded.
1198};
1199
1200/* static */
1201const long double Int64x64DoubleTestCase::MIN_MANT =
1202 std::round(1e22 / std::pow(2.0L, std::min(64, LDBL_MANT_DIG))) / 1e22;
1203
1205 : TestCase("Construct from floating point."),
1206 m_last{0},
1207 m_deltaMax{0},
1208 m_deltaCount{0}
1209{
1210}
1211
1212void
1213Int64x64DoubleTestCase::Check(const long double dec,
1214 const long double frac,
1215 const int64_t intPart,
1216 const uint64_t lo)
1217{
1218 // 1. The double value we're going to convert
1219 long double value = dec + frac;
1220
1221 // 2. The expected value of the conversion
1222 int64x64_t expect(intPart, lo);
1223
1224 // 1a, 2a. Handle lower-precision architectures by scaling up the fractional part
1225 // We assume MISS_MANT_DIG is much less than 64, MIN_MANT much less than 0.5
1226 // Could check lo < MIN_LOW instead...
1227
1228 /*
1229 This approach works for real values with mantissa very near zero,
1230 but isn't ideal. For values near 0.5, say, the low order bits
1231 are completely lost, since they exceed the precision of the
1232 double representation. This shows up on M1 and ARM architectures
1233 as the x.5... values all skipped, because they are indistinguishable
1234 from x.5 exactly.
1235
1236 A more involved alternative would be to separate the
1237 "frac" and "low" values in the caller. Then the underflow
1238 rescaling could be applied to the low bits only,
1239 before adding to the frac part.
1240
1241 To do this the signature of this function would have to be
1242 Check (cld dec, cld frac, int64_t intPart, int64_t low);
1243 ^- Note this signed
1244 The caller Check (intPart) would look like
1245
1246 Check (v, 0.0L, intPart, 0x0LL);
1247 Check (v, 0.0L, intPart, 0x1LL);
1248 Check (v, 0.0L, intPart, 0x2LL);
1249 ...
1250 Check (v, 0.5L, intPart, -0xFLL);
1251 Check (v, 0.5L, intPart, -0xELL);
1252 ...
1253 Check (v, 0.5L, intPart, 0x0LL);
1254 Check (v, 0.5L, intPart, 0x1LL);
1255
1256 Here we would construct value as
1257 long double lowLd = (double)low / std::pow(2.0L, 64);
1258 value = dec + frac + lowLd;
1259
1260 For underflow cases:
1261 value = dec + frac + std::max::(lowLd, MIN_MANT);
1262 */
1263
1264 bool under = false;
1265 if (frac && (frac < MIN_MANT))
1266 {
1267 under = true;
1268 value = dec + std::max(frac * MIN_LOW, MIN_MANT);
1269 expect = int64x64_t(intPart, lo * MIN_LOW);
1270 }
1271
1272 // 3. The actual value of the conversion
1273 const int64x64_t result = int64x64_t(value);
1274
1275 // 4. Absolute error in the conversion
1276 const int64x64_t delta = Abs(result - expect);
1277
1278 // Mark repeats (no change in input floating value) as "skip" (but not integers)
1279 const bool skip = (frac && (value == m_last));
1280 // Save the value to detect unchanged values next time
1281 m_last = value;
1282
1283 // 5. Tolerance for the test, scaled to the magnitude of value
1284 // Tolerance will be computed from the value, epsilon and margin
1285 int64x64_t tolerance;
1286
1287 // Default epsilon
1288 long double epsilon = std::numeric_limits<long double>::epsilon();
1289
1290 // A few cases need extra tolerance
1291 // If you add cases please thoroughly document the configuration
1292 long double margin = 0;
1293
1295 {
1296 // Darwin 12.5.0 (Mac 10.8.5) g++ 4.2.1
1297 margin = 1.0;
1298 }
1300 {
1301 // Valgrind and Windows use 64-bit doubles for long doubles
1302 // See ns-3 bug 1882
1303 // Need non-zero margin to ensure final tolerance is non-zero
1304 margin = 1.0;
1305 epsilon = std::numeric_limits<double>::epsilon();
1306 }
1307
1308 // Final tolerance amount
1309 tolerance = std::max(1.0L, std::fabs(value)) * epsilon + margin * epsilon;
1310
1311 // 6. Is the conversion acceptably close to the expected value?
1312 const bool pass = delta <= tolerance;
1313
1314 // 7. Show the result of this check
1315
1316 // Save stream format flags
1317 std::ios_base::fmtflags ff = std::cout.flags();
1318 std::cout << std::fixed << std::setprecision(22);
1319
1320 std::cout << GetParent()->GetName()
1321 << " Double: " << (skip ? "skip " : (pass ? "pass " : "FAIL ")) << std::showpos
1322 << value << " == " << Printer(result) << (under ? " (underflow)" : "") << std::endl;
1323
1324 if (delta)
1325 {
1326 // There was a difference, show the expected value
1327 std::cout << GetParent()->GetName() << std::left << std::setw(43) << " expected"
1328 << std::right << Printer(expect) << std::endl;
1329
1330 if (delta == tolerance)
1331 {
1332 // Short form: show the delta, and note it equals the tolerance
1333 std::cout << GetParent()->GetName() << std::left << std::setw(43)
1334 << " delta = tolerance" << std::right << Printer(delta) << std::endl;
1335 }
1336 else
1337 {
1338 // Long form, show both delta and tolerance
1339 std::cout << GetParent()->GetName() << std::left << std::setw(43) << " delta"
1340 << std::right << Printer(delta) << std::endl;
1341 std::cout << GetParent()->GetName() << std::left << std::setw(43)
1342 << " tolerance" << std::right << Printer(tolerance)
1343 << " eps: " << epsilon << ", margin: " << margin << std::endl;
1344 }
1345
1346 // Record number and max delta
1347 ++m_deltaCount;
1348
1349 if (delta > m_deltaMax)
1350 {
1351 m_deltaMax = delta;
1352 }
1353 }
1354
1355 // Report pass/fail
1356 NS_TEST_ASSERT_MSG_EQ_TOL(result, expect, tolerance, "int64x64_t (long double) failed");
1357 std::cout.flags(ff);
1358}
1359
1360void
1361Int64x64DoubleTestCase::Check(const int64_t intPart)
1362{
1363 std::cout << std::endl;
1364 std::cout << GetParent()->GetName() << " Double: "
1365 << "integer: " << intPart << std::endl;
1366 // Reset last value for new intPart
1367 m_last = intPart;
1368 // Save current number and max delta, so we can report max from just this intPart
1369 int64x64_t deltaMaxPrior = m_deltaMax;
1370 m_deltaMax = 0;
1371 int deltaCountPrior = m_deltaCount;
1372 m_deltaCount = 0;
1373
1374 // Nudging the integer part eliminates deltas around 0
1375 long double v = intPart;
1376
1377 Check(v, 0.0L, intPart, 0x0ULL);
1378 Check(v, 0.0000000000000000000542L, intPart, 0x1ULL);
1379 Check(v, 0.0000000000000000001084L, intPart, 0x2ULL);
1380 Check(v, 0.0000000000000000001626L, intPart, 0x3ULL);
1381 Check(v, 0.0000000000000000002168L, intPart, 0x4ULL);
1382 Check(v, 0.0000000000000000002711L, intPart, 0x5ULL);
1383 Check(v, 0.0000000000000000003253L, intPart, 0x6ULL);
1384 Check(v, 0.0000000000000000003795L, intPart, 0x7ULL);
1385 Check(v, 0.0000000000000000004337L, intPart, 0x8ULL);
1386 Check(v, 0.0000000000000000004879L, intPart, 0x9ULL);
1387 Check(v, 0.0000000000000000005421L, intPart, 0xAULL);
1388 Check(v, 0.0000000000000000005963L, intPart, 0xBULL);
1389 Check(v, 0.0000000000000000006505L, intPart, 0xCULL);
1390 Check(v, 0.0000000000000000007047L, intPart, 0xDULL);
1391 Check(v, 0.0000000000000000007589L, intPart, 0xEULL);
1392 Check(v, 0.0000000000000000008132L, intPart, 0xFULL);
1393 Check(v, 0.0000000000000000130104L, intPart, 0xF0ULL);
1394 Check(v, 0.0000000000000002081668L, intPart, 0xF00ULL);
1395 Check(v, 0.0000000000000033306691L, intPart, 0xF000ULL);
1396 Check(v, 0.0000000000000532907052L, intPart, 0xF0000ULL);
1397 Check(v, 0.0000000000008526512829L, intPart, 0xF00000ULL);
1398 Check(v, 0.0000000000136424205266L, intPart, 0xF000000ULL);
1399 Check(v, 0.0000000002182787284255L, intPart, 0xF0000000ULL);
1400 Check(v, 0.0000000034924596548080L, intPart, 0xF00000000ULL);
1401 Check(v, 0.0000000558793544769287L, intPart, 0xF000000000ULL);
1402 Check(v, 0.0000008940696716308594L, intPart, 0xF0000000000ULL);
1403 Check(v, 0.0000143051147460937500L, intPart, 0xF00000000000ULL);
1404 Check(v, 0.0002288818359375000000L, intPart, 0xF000000000000ULL);
1405 Check(v, 0.0036621093750000000000L, intPart, 0xF0000000000000ULL);
1406 Check(v, 0.0585937500000000000000L, intPart, 0xF00000000000000ULL);
1407 std::cout << std::endl;
1408 Check(v, 0.4999999999999999991326L, intPart, 0x7FFFFFFFFFFFFFF0ULL);
1409 Check(v, 0.4999999999999999991868L, intPart, 0x7FFFFFFFFFFFFFF1ULL);
1410 Check(v, 0.4999999999999999992411L, intPart, 0x7FFFFFFFFFFFFFF2ULL);
1411 Check(v, 0.4999999999999999992953L, intPart, 0x7FFFFFFFFFFFFFF3ULL);
1412 Check(v, 0.4999999999999999993495L, intPart, 0x7FFFFFFFFFFFFFF4ULL);
1413 Check(v, 0.4999999999999999994037L, intPart, 0x7FFFFFFFFFFFFFF5ULL);
1414 Check(v, 0.4999999999999999994579L, intPart, 0x7FFFFFFFFFFFFFF6ULL);
1415 Check(v, 0.4999999999999999995121L, intPart, 0x7FFFFFFFFFFFFFF7ULL);
1416 Check(v, 0.4999999999999999995663L, intPart, 0x7FFFFFFFFFFFFFF8ULL);
1417 Check(v, 0.4999999999999999996205L, intPart, 0x7FFFFFFFFFFFFFF9ULL);
1418 Check(v, 0.4999999999999999996747L, intPart, 0x7FFFFFFFFFFFFFFAULL);
1419 Check(v, 0.4999999999999999997289L, intPart, 0x7FFFFFFFFFFFFFFBULL);
1420 Check(v, 0.4999999999999999997832L, intPart, 0x7FFFFFFFFFFFFFFCULL);
1421 Check(v, 0.4999999999999999998374L, intPart, 0x7FFFFFFFFFFFFFFDULL);
1422 Check(v, 0.4999999999999999998916L, intPart, 0x7FFFFFFFFFFFFFFEULL);
1423 Check(v, 0.4999999999999999999458L, intPart, 0x7FFFFFFFFFFFFFFFULL);
1424 Check(v, 0.5000000000000000000000L, intPart, 0x8000000000000000ULL);
1425 Check(v, 0.5000000000000000000542L, intPart, 0x8000000000000001ULL);
1426 Check(v, 0.5000000000000000001084L, intPart, 0x8000000000000002ULL);
1427 Check(v, 0.5000000000000000001626L, intPart, 0x8000000000000003ULL);
1428 Check(v, 0.5000000000000000002168L, intPart, 0x8000000000000004ULL);
1429 Check(v, 0.5000000000000000002711L, intPart, 0x8000000000000005ULL);
1430 Check(v, 0.5000000000000000003253L, intPart, 0x8000000000000006ULL);
1431 Check(v, 0.5000000000000000003795L, intPart, 0x8000000000000007ULL);
1432 Check(v, 0.5000000000000000004337L, intPart, 0x8000000000000008ULL);
1433 Check(v, 0.5000000000000000004879L, intPart, 0x8000000000000009ULL);
1434 Check(v, 0.5000000000000000005421L, intPart, 0x800000000000000AULL);
1435 Check(v, 0.5000000000000000005963L, intPart, 0x800000000000000BULL);
1436 Check(v, 0.5000000000000000006505L, intPart, 0x800000000000000CULL);
1437 Check(v, 0.5000000000000000007047L, intPart, 0x800000000000000DULL);
1438 Check(v, 0.5000000000000000007589L, intPart, 0x800000000000000EULL);
1439 Check(v, 0.5000000000000000008132L, intPart, 0x800000000000000FULL);
1440 std::cout << std::endl;
1441 Check(v, 0.9375000000000000000000L, intPart, 0xF000000000000000ULL);
1442 Check(v, 0.9960937500000000000000L, intPart, 0xFF00000000000000ULL);
1443 Check(v, 0.9997558593750000000000L, intPart, 0xFFF0000000000000ULL);
1444 Check(v, 0.9999847412109375000000L, intPart, 0xFFFF000000000000ULL);
1445 Check(v, 0.9999990463256835937500L, intPart, 0xFFFFF00000000000ULL);
1446 Check(v, 0.9999999403953552246094L, intPart, 0xFFFFFF0000000000ULL);
1447 Check(v, 0.9999999962747097015381L, intPart, 0xFFFFFFF000000000ULL);
1448 Check(v, 0.9999999997671693563461L, intPart, 0xFFFFFFFF00000000ULL);
1449 Check(v, 0.9999999999854480847716L, intPart, 0xFFFFFFFFF0000000ULL);
1450 Check(v, 0.9999999999990905052982L, intPart, 0xFFFFFFFFFF000000ULL);
1451 Check(v, 0.9999999999999431565811L, intPart, 0xFFFFFFFFFFF00000ULL);
1452 Check(v, 0.9999999999999964472863L, intPart, 0xFFFFFFFFFFFF0000ULL);
1453 Check(v, 0.9999999999999997779554L, intPart, 0xFFFFFFFFFFFFF000ULL);
1454 Check(v, 0.9999999999999999861222L, intPart, 0xFFFFFFFFFFFFFF00ULL);
1455 Check(v, 0.9999999999999999991326L, intPart, 0xFFFFFFFFFFFFFFF0ULL);
1456 Check(v, 0.9999999999999999991868L, intPart, 0xFFFFFFFFFFFFFFF1ULL);
1457 Check(v, 0.9999999999999999992411L, intPart, 0xFFFFFFFFFFFFFFF2ULL);
1458 Check(v, 0.9999999999999999992943L, intPart, 0xFFFFFFFFFFFFFFF3ULL);
1459 Check(v, 0.9999999999999999993495L, intPart, 0xFFFFFFFFFFFFFFF4ULL);
1460 Check(v, 0.9999999999999999994037L, intPart, 0xFFFFFFFFFFFFFFF5ULL);
1461 Check(v, 0.9999999999999999994579L, intPart, 0xFFFFFFFFFFFFFFF6ULL);
1462 Check(v, 0.9999999999999999995121L, intPart, 0xFFFFFFFFFFFFFFF7ULL);
1463 Check(v, 0.9999999999999999995663L, intPart, 0xFFFFFFFFFFFFFFF8ULL);
1464 Check(v, 0.9999999999999999996205L, intPart, 0xFFFFFFFFFFFFFFF9ULL);
1465 Check(v, 0.9999999999999999996747L, intPart, 0xFFFFFFFFFFFFFFFAULL);
1466 Check(v, 0.9999999999999999997289L, intPart, 0xFFFFFFFFFFFFFFFBULL);
1467 Check(v, 0.9999999999999999997832L, intPart, 0xFFFFFFFFFFFFFFFCULL);
1468 Check(v, 0.9999999999999999998374L, intPart, 0xFFFFFFFFFFFFFFFDULL);
1469 Check(v, 0.9999999999999999998916L, intPart, 0xFFFFFFFFFFFFFFFEULL);
1470 Check(v, 0.9999999999999999999458L, intPart, 0xFFFFFFFFFFFFFFFFULL);
1471
1472 std::cout << GetParent()->GetName() << " Double: "
1473 << "integer:" << std::setw(4) << intPart << ": deltas:" << std::setw(4)
1474 << m_deltaCount << ", max: " << Printer(m_deltaMax) << std::endl;
1475
1476 // Add the count, max from this intPart to the grand totals
1477 m_deltaCount += deltaCountPrior;
1478 m_deltaMax = Max(m_deltaMax, deltaMaxPrior);
1479}
1480
1481void
1483{
1484 std::cout << std::endl;
1485 std::cout << GetParent()->GetName() << " Double: " << GetName() << std::endl;
1486
1487 // Save stream format flags
1488 std::ios_base::fmtflags ff = std::cout.flags();
1489
1490 std::cout << GetParent()->GetName() << " Double: "
1491 << "FLT_RADIX: " << FLT_RADIX
1492 << "\n LDBL_MANT_DIG: " << LDBL_MANT_DIG
1493 << "\n MISS_MANT_DIG: " << MISS_MANT_DIG
1494 << "\n MIN_LOW: " << Printer(MIN_LOW) << " (" << std::hexfloat
1495 << MIN_LOW << ")" << std::defaultfloat
1496 << "\n MIN_MANT: " << Printer(MIN_MANT) << std::endl;
1497
1498 std::cout << std::scientific << std::setprecision(21);
1499
1500 Check(-2);
1501 Check(-1);
1502 Check(0);
1503 Check(1);
1504 Check(2);
1505
1506 std::cout << GetParent()->GetName() << " Double: "
1507 << "Total deltas:" << std::setw(7) << m_deltaCount
1508 << ", max delta: " << Printer(m_deltaMax) << std::endl;
1509
1510 std::cout.flags(ff);
1511}
1512
1513/**
1514 * \ingroup int64x64-tests
1515 *
1516 * Test: print the implementation
1517 */
1519{
1520 public:
1522 void DoRun() override;
1523};
1524
1526 : TestCase("Print the implementation")
1527{
1528}
1529
1530void
1532{
1533 std::cout << std::endl;
1534 std::cout << GetParent()->GetName() << " Impl: " << GetName() << std::endl;
1535
1536 std::cout << "int64x64_t::implementation: ";
1538 {
1540 std::cout << "int128_impl";
1541 break;
1543 std::cout << "cairo_impl";
1544 break;
1545 case (int64x64_t::ld_impl):
1546 std::cout << "ld_impl";
1547 break;
1548 default:
1549 std::cout << "unknown!";
1550 }
1551 std::cout << std::endl;
1552
1553#if defined(INT64X64_USE_CAIRO) && !defined(PYTHON_SCAN)
1554 std::cout << "cairo_impl64: " << cairo_impl64 << std::endl;
1555 std::cout << "cairo_impl128: " << cairo_impl128 << std::endl;
1556#endif
1557
1559 {
1560 std::cout << "Running with 64-bit long doubles" << std::endl;
1561 }
1562}
1563
1564/**
1565 * \ingroup int64x64-tests
1566 * \internal
1567 *
1568 * The int64x64 Test Suite.
1569 *
1570 * Some of these tests are a little unusual for ns-3 in that they
1571 * are sensitive to implementation, specifically the resolution
1572 * of the double and long double implementations.
1573 *
1574 * To handle this, where needed we define a tolerance to use in the
1575 * test comparisons. If you need to increase the tolerance,
1576 * please append the system and compiler version. For example:
1577 *
1578 * \code
1579 * // Darwin 12.5.0 (Mac 10.8.5) g++ 4.2.1
1580 * tolerance = 1;
1581 * // System Foo gcc 3.9
1582 * tolerance = 3;
1583 * \endcode
1584 */
1586{
1587 public:
1589 : TestSuite("int64x64", Type::UNIT)
1590 {
1603 }
1604};
1605
1606static Int64x64TestSuite g_int64x64TestSuite; //!< Static variable for test initialization
1607
1608} // namespace test
1609
1610} // namespace int64x64
1611
1612} // namespace ns3
#define Max(a, b)
#define Min(a, b)
const char * cairo_impl64
Definition: cairo-wideint.c:64
const char * cairo_impl128
encapsulates test code
Definition: test.h:1061
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:302
TestCase * GetParent() const
Get the parent of this TestCase.
Definition: test.cc:383
std::string GetName() const
Definition: test.cc:376
A suite of tests to run.
Definition: test.h:1273
Type
Type of test.
Definition: test.h:1280
static constexpr auto UNIT
Definition: test.h:1291
void DoRun() override
Implementation to actually run this TestCase.
void Check(const int test, const int64x64_t value, const int64x64_t expect, const int64x64_t tolerance=int64x64_t(0, 0))
Check the int64x64 for correctness.
void Check(const uint64_t low, const std::string &value, const int64_t tolerance=0)
Check the int64x64 for correctness.
void DoRun() override
Implementation to actually run this TestCase.
void DoRun() override
Implementation to actually run this TestCase.
void Check(const double result, const double expect, const std::string &msg)
Check the int64x64 for correctness.
void Check(const double result, const double expect, const std::string &msg)
Check the int64x64 for correctness.
void DoRun() override
Implementation to actually run this TestCase.
void DoRun() override
Implementation to actually run this TestCase.
void Check(const bool result, const bool expect, const std::string &msg)
Check the int64x64 for correctness.
Test: construct from floating point.
static constexpr long double MIN_LOW
The smallest low word we expect to get from a conversion.
static constexpr int MISS_MANT_DIG
Compute a multiplier to match the mantissa size on this platform.
void DoRun() override
Implementation to actually run this TestCase.
void Check(const int64_t intPart)
Check the int64x64 for correctness.
int m_deltaCount
The number of times a delta was recorded.
long double m_last
The last value tested.
static const long double MIN_MANT
Smallest mantissa we expect to convert to a non-zero low word.
int64x64_t m_deltaMax
The maximum observed difference between expected and computed values.
Test: manipulate the high and low part of every number.
void DoRun() override
Implementation to actually run this TestCase.
void Check(const int64_t hi, const uint64_t lo)
Check the high and low parts for correctness.
void DoRun() override
Implementation to actually run this TestCase.
Test: roundtrip int64x64_t numbers as strings.
void Check(const std::string &str, const int64_t tolerance=0)
Check the iont64x64 for correctness.
void DoRun() override
Implementation to actually run this TestCase.
Test: parse int64x64_t numbers as strings.
void Check(const std::string &str, const int64_t hi, const uint64_t lo, const int64_t tolerance=0)
Check the iont64x64 for correctness.
void DoRun() override
Implementation to actually run this TestCase.
void Check(const int64x64_t value, const int64_t expectInt, const int64_t expectRnd)
Check the int64x64 value for correctness.
void DoRun() override
Implementation to actually run this TestCase.
void CheckCase(const uint64_t factor, const int64x64_t result, const int64x64_t expect, const std::string &msg, const double tolerance=0)
Check the int64x64 for correctness.
void DoRun() override
Implementation to actually run this TestCase.
void Check(const int64_t factor)
Check the int64x64 for correctness.
Pretty printer for test cases.
int64x64_t m_value
The int64x64_t value.
friend std::ostream & operator<<(std::ostream &os, const Printer &p)
Output streamer, the main reason for this class.
bool m_haveInt
Do we have a full int64x64_t value?
int64_t m_high
The high (integer) word.
Printer(const int64x64_t value)
Construct from an int64x64_t Q64.64 value.
Printer(const int64_t high, const uint64_t low)
Construct from high and low words of Q64.64 representation.
uint64_t m_low
The low (fractional) word.
High precision numerical type, implementing Q64.64 fixed precision.
Definition: int64x64-128.h:56
@ int128_impl
Native int128_t implementation.
Definition: int64x64-128.h:86
@ ld_impl
long double implementation.
Definition: int64x64-128.h:88
@ cairo_impl
Cairo wideint implementation.
Definition: int64x64-128.h:87
void MulByInvert(const int64x64_t &o)
Multiply this value by a Q0.128 value, presumably representing an inverse, completing a division oper...
static enum impl_type implementation
Type tag for this implementation.
Definition: int64x64-128.h:92
double GetDouble() const
Get this value as a double.
Definition: int64x64-128.h:238
static int64x64_t Invert(const uint64_t v)
Compute the inverse of an integer value.
static double zero
int64x64_t Abs(const int64x64_t &value)
Absolute value.
Definition: int64x64.h:215
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition: test.h:145
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition: test.h:252
#define NS_TEST_EXPECT_MSG_EQ_TOL(actual, limit, tol, msg)
Test that actual and expected (limit) values are equal to plus or minus some tolerance and report if ...
Definition: test.h:511
#define NS_TEST_ASSERT_MSG_EQ_TOL(actual, limit, tol, msg)
Test that actual and expected (limit) values are equal to plus or minus some tolerance and report and...
Definition: test.h:338
#define HP_MAX_64
Floating point value of HP_MASK_LO + 1.
Definition: int64x64-128.h:74
#define RUNNING_WITH_LIMITED_PRECISION
Checks if running on Valgrind, which assumes long doubles are 64-bit doubles.
std::ostream & operator<<(std::ostream &os, const Printer &p)
static Int64x64TestSuite g_int64x64TestSuite
Static variable for test initialization.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
-ns3 Test suite for the ns3 wrapper script
-ray-to-three-gpp-ch-calibration