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
580/**
581 * \ingroup int64x64-tests
582 *
583 * Test case for bug 455.
584 *
585 * See \bugid{455}
586 */
588{
589 public:
591 void DoRun() override;
592 /**
593 * Check the int64x64 for correctness.
594 * \param result The actual value.
595 * \param expect The expected value.
596 * \param msg The error message to print.
597 */
598 void Check(const double result, const double expect, const std::string& msg);
599};
600
602 : TestCase("Test case for bug 455")
603{
604}
605
606void
607Int64x64Bug455TestCase::Check(const double result, const double expect, const std::string& msg)
608{
609 bool pass = result == expect;
610
611 std::cout << GetParent()->GetName() << " Bug 455: " << (pass ? "pass " : "FAIL ")
612 << "res: " << result << " exp: " << expect << ": " << msg << std::endl;
613
614 NS_TEST_ASSERT_MSG_EQ(result, expect, msg);
615}
616
617void
619{
620 std::cout << std::endl;
621 std::cout << GetParent()->GetName() << " Bug 455: " << GetName() << std::endl;
622
623 int64x64_t a(0.1);
624 a /= int64x64_t(1.25);
625 Check(a.GetDouble(), 0.08, "The original testcase");
626
627 a = int64x64_t(0.5);
628 a *= int64x64_t(5);
629 Check(a.GetDouble(), 2.5, "Simple test for multiplication");
630
631 a = int64x64_t(-0.5);
632 a *= int64x64_t(5);
633 Check(a.GetDouble(), -2.5, "Test sign, first operation negative");
634
635 a = int64x64_t(-0.5);
636 a *= int64x64_t(-5);
637 Check(a.GetDouble(), 2.5, "both operands negative");
638
639 a = int64x64_t(0.5);
640 a *= int64x64_t(-5);
641 Check(a.GetDouble(), -2.5, "only second operand negative");
642}
643
644/**
645 * \ingroup int64x64-tests
646 *
647 * Test case for bug 455.
648 *
649 * See \bugid{863}
650 */
652{
653 public:
655 void DoRun() override;
656 /**
657 * Check the int64x64 for correctness.
658 * \param result The actual value.
659 * \param expect The expected value.
660 * \param msg The error message to print.
661 */
662 void Check(const double result, const double expect, const std::string& msg);
663};
664
666 : TestCase("Test case for bug 863")
667{
668}
669
670void
671Int64x64Bug863TestCase::Check(const double result, const double expect, const std::string& msg)
672{
673 bool pass = result == expect;
674
675 std::cout << GetParent()->GetName() << " Bug 863: " << (pass ? "pass " : "FAIL ")
676 << "res: " << result << " exp: " << expect << ": " << msg << std::endl;
677
678 NS_TEST_ASSERT_MSG_EQ(result, expect, msg);
679}
680
681void
683{
684 std::cout << std::endl;
685 std::cout << GetParent()->GetName() << " Bug 863: " << GetName() << std::endl;
686
687 int64x64_t a(0.9);
688 a /= int64x64_t(1);
689 Check(a.GetDouble(), 0.9, "The original testcase");
690
691 a = int64x64_t(0.5);
692 a /= int64x64_t(0.5);
693 Check(a.GetDouble(), 1.0, "Simple test for division");
694
695 a = int64x64_t(-0.5);
696 Check(a.GetDouble(), -0.5, "Check that we actually convert doubles correctly");
697
698 a /= int64x64_t(0.5);
699 Check(a.GetDouble(), -1.0, "first argument negative");
700
701 a = int64x64_t(0.5);
702 a /= int64x64_t(-0.5);
703 Check(a.GetDouble(), -1.0, "second argument negative");
704
705 a = int64x64_t(-0.5);
706 a /= int64x64_t(-0.5);
707 Check(a.GetDouble(), 1.0, "both arguments negative");
708}
709
710/**
711 * \ingroup int64x64-tests
712 *
713 * Test case for bug 455.
714 *
715 * See \bugid{1786}
716 */
718{
719 public:
721 void DoRun() override;
722 /**
723 * Check the int64x64 for correctness.
724 * \param low The actual low value.
725 * \param value The expected low part printed value.
726 * \param tolerance The allowed tolerance.
727 */
728 void Check(const uint64_t low, const std::string& value, const int64_t tolerance = 0);
729};
730
732 : TestCase("Test case for bug 1786")
733{
734}
735
736void
738 const std::string& str,
739 const int64_t tolerance /* = 0 */)
740{
741 int64x64_t value(0, low);
742 std::ostringstream oss;
743 oss << std::scientific << std::setprecision(22) << value;
744
745 if (tolerance == 0)
746 {
747 bool pass = oss.str() == str;
748
749 std::cout << GetParent()->GetName() << " Bug 1786: " << (pass ? "pass " : "FAIL ")
750 << " 0x" << std::hex << std::setw(16) << low << std::dec << " = " << oss.str();
751 if (!pass)
752 {
753 std::cout << ", expected " << str;
754 }
755 std::cout << std::endl;
756
757 NS_TEST_EXPECT_MSG_EQ(oss.str(), str, "Fraction string not correct");
758 }
759 else
760 {
761 // No obvious way to implement a tolerance on the strings
762
763 std::cout << GetParent()->GetName() << " Bug 1786: "
764 << "skip "
765 << " 0x" << std::hex << std::setw(16) << low << std::dec << " = " << oss.str()
766 << ", expected " << str << std::endl;
767 }
768}
769
770void
772{
773 std::cout << std::endl;
774 std::cout << GetParent()->GetName() << " But 1786: " << GetName() << std::endl;
775
776 int64_t tolerance = 0;
778 {
779 // Darwin 12.5.0 (Mac 10.8.5) g++ 4.2.1
780 tolerance = 1;
781 }
782
783 // Some of these values differ from the DoubleTestCase
784 // by one count in the last place
785 // because operator<< truncates the last output digit,
786 // instead of rounding.
787
788 // NOLINTBEGIN(misc-redundant-expression)
789 // clang-format off
790 Check( 1ULL, "+0.0000000000000000000542");
791 Check( 2ULL, "+0.0000000000000000001084");
792 Check( 3ULL, "+0.0000000000000000001626");
793 Check( 4ULL, "+0.0000000000000000002168");
794 Check( 5ULL, "+0.0000000000000000002710");
795 Check( 6ULL, "+0.0000000000000000003253");
796 Check( 7ULL, "+0.0000000000000000003795");
797 Check( 8ULL, "+0.0000000000000000004337");
798 Check( 9ULL, "+0.0000000000000000004879");
799 Check( 0xAULL, "+0.0000000000000000005421");
800 Check( 0xFULL, "+0.0000000000000000008132");
801 Check( 0xF0ULL, "+0.0000000000000000130104");
802 Check( 0xF00ULL, "+0.0000000000000002081668");
803 Check( 0xF000ULL, "+0.0000000000000033306691");
804 Check( 0xF0000ULL, "+0.0000000000000532907052");
805 Check( 0xF00000ULL, "+0.0000000000008526512829");
806 Check( 0xF000000ULL, "+0.0000000000136424205266");
807 Check( 0xF0000000ULL, "+0.0000000002182787284255");
808 Check( 0xF00000000ULL, "+0.0000000034924596548080");
809 Check( 0xF000000000ULL, "+0.0000000558793544769287");
810 Check( 0xF0000000000ULL, "+0.0000008940696716308594");
811 Check( 0xF00000000000ULL, "+0.0000143051147460937500");
812 Check( 0xF000000000000ULL, "+0.0002288818359375000000");
813 Check( 0xF0000000000000ULL, "+0.0036621093750000000000");
814 Check( 0xF00000000000000ULL, "+0.0585937500000000000000");
815 std::cout << std::endl;
816 Check(0x7FFFFFFFFFFFFFFDULL, "+0.4999999999999999998374", tolerance);
817 Check(0x7FFFFFFFFFFFFFFEULL, "+0.4999999999999999998916", tolerance);
818 Check(0x7FFFFFFFFFFFFFFFULL, "+0.4999999999999999999458", tolerance);
819 Check(0x8000000000000000ULL, "+0.5000000000000000000000");
820 Check(0x8000000000000001ULL, "+0.5000000000000000000542", tolerance);
821 Check(0x8000000000000002ULL, "+0.5000000000000000001084", tolerance);
822 Check(0x8000000000000003ULL, "+0.5000000000000000001626", tolerance);
823 std::cout << std::endl;
824 Check(0xF000000000000000ULL, "+0.9375000000000000000000");
825 Check(0xFF00000000000000ULL, "+0.9960937500000000000000");
826 Check(0xFFF0000000000000ULL, "+0.9997558593750000000000");
827 Check(0xFFFF000000000000ULL, "+0.9999847412109375000000");
828 Check(0xFFFFF00000000000ULL, "+0.9999990463256835937500");
829 Check(0xFFFFFF0000000000ULL, "+0.9999999403953552246094");
830 Check(0xFFFFFFF000000000ULL, "+0.9999999962747097015381");
831 Check(0xFFFFFFFF00000000ULL, "+0.9999999997671693563461");
832 Check(0xFFFFFFFFF0000000ULL, "+0.9999999999854480847716");
833 Check(0xFFFFFFFFFF000000ULL, "+0.9999999999990905052982");
834 Check(0xFFFFFFFFFFF00000ULL, "+0.9999999999999431565811");
835 Check(0xFFFFFFFFFFFF0000ULL, "+0.9999999999999964472863");
836 Check(0xFFFFFFFFFFFFF000ULL, "+0.9999999999999997779554");
837 Check(0xFFFFFFFFFFFFFF00ULL, "+0.9999999999999999861222");
838 Check(0xFFFFFFFFFFFFFFF0ULL, "+0.9999999999999999991326");
839 Check(0xFFFFFFFFFFFFFFF5ULL, "+0.9999999999999999994037", tolerance);
840 Check(0xFFFFFFFFFFFFFFF6ULL, "+0.9999999999999999994579", tolerance);
841 Check(0xFFFFFFFFFFFFFFF7ULL, "+0.9999999999999999995121", tolerance);
842 Check(0xFFFFFFFFFFFFFFF8ULL, "+0.9999999999999999995663", tolerance);
843 Check(0xFFFFFFFFFFFFFFF9ULL, "+0.9999999999999999996205", tolerance);
844 Check(0xFFFFFFFFFFFFFFFAULL, "+0.9999999999999999996747", tolerance);
845 Check(0xFFFFFFFFFFFFFFFBULL, "+0.9999999999999999997289", tolerance);
846 Check(0xFFFFFFFFFFFFFFFCULL, "+0.9999999999999999997832", tolerance);
847 Check(0xFFFFFFFFFFFFFFFDULL, "+0.9999999999999999998374", tolerance);
848 Check(0xFFFFFFFFFFFFFFFEULL, "+0.9999999999999999998916", tolerance);
849 Check(0xFFFFFFFFFFFFFFFFULL, "+0.9999999999999999999458", tolerance);
850 // clang-format on
851 // NOLINTEND(misc-redundant-expression)
852}
853
854/**
855 * \ingroup int64x64-tests
856 *
857 * Test: basic compare operations.
858 */
860{
861 public:
863 void DoRun() override;
864
865 /**
866 * Check the int64x64 for correctness.
867 * \param result The actual value.
868 * \param expect The expected value.
869 * \param msg The error message to print.
870 */
871 void Check(const bool result, const bool expect, const std::string& msg);
872};
873
875 : TestCase("Basic compare operations")
876{
877}
878
879void
880Int64x64CompareTestCase::Check(const bool result, const bool expect, const std::string& msg)
881{
882 bool pass = result == expect;
883
884 std::cout << GetParent()->GetName() << " Compare: " << (pass ? "pass " : "FAIL ") << msg
885 << std::endl;
886
887 NS_TEST_ASSERT_MSG_EQ(result, expect, msg);
888}
889
890void
892{
893 std::cout << std::endl;
894 std::cout << GetParent()->GetName() << " Compare: " << GetName() << std::endl;
895
896 const int64x64_t zero(0, 0);
897 const int64x64_t one(1, 0);
898 const int64x64_t two(2, 0);
899 const int64x64_t mone(-1, 0);
900 const int64x64_t mtwo(-2, 0);
901 const int64x64_t frac = int64x64_t(0, 0xc000000000000000ULL); // 0.75
902 const int64x64_t zerof = zero + frac;
903 const int64x64_t onef = one + frac;
904 const int64x64_t monef = mone - frac;
905 const int64x64_t mtwof = mtwo - frac;
906
907 // NOLINTBEGIN(misc-redundant-expression)
908 Check(zerof == zerof, true, "equality, zero");
909 Check(onef == onef, true, "equality, positive");
910 Check(mtwof == mtwof, true, "equality, negative");
911 Check(zero == one, false, "equality false, zero");
912 Check(one == two, false, "equality false, unsigned");
913 Check(one == mone, false, "equality false, signed");
914 Check(onef == one, false, "equality false, fraction");
915 std::cout << std::endl;
916
917 Check(zerof != zerof, false, "inequality, zero");
918 Check(onef != onef, false, "inequality, positive");
919 Check(mtwof != mtwof, false, "inequality, negative");
920 Check(zero != one, true, "inequality true, zero");
921 Check(one != two, true, "inequality true, unsigned");
922 Check(one != mone, true, "inequality true, signed");
923 Check(onef != one, true, "inequality true, fraction");
924 std::cout << std::endl;
925
926 Check(zerof < onef, true, "less, zerof");
927 Check(zero < zerof, true, "less, zero");
928 Check(one < onef, true, "less, positive");
929 Check(monef < mone, true, "less, negative");
930 Check(onef < one, false, "less, false, positive");
931 Check(mtwo < mtwof, false, "less, false, negative");
932 std::cout << std::endl;
933
934 Check(zerof <= zerof, true, "less equal, equal, zerof");
935 Check(zero <= zerof, true, "less equal, less, zero");
936 Check(onef <= onef, true, "less equal, equal, positive");
937 Check(monef <= mone, true, "less equal, less, negative");
938 Check(onef <= one, false, "less equal, false, positive");
939 Check(mtwo <= mtwof, false, "less equal, false, negative");
940 std::cout << std::endl;
941
942 Check(onef > zerof, true, "greater, zerof");
943 Check(zerof > zero, true, "greater, zero");
944 Check(onef > one, true, "greater, positive");
945 Check(mone > monef, true, "greater, negative");
946 Check(one > onef, false, "greater, false, positive");
947 Check(mtwof > mtwo, false, "greater, false, negative");
948 std::cout << std::endl;
949
950 Check(zerof >= zerof, true, "greater equal, equal, zerof");
951 Check(zerof >= zero, true, "greater equal, greater, zero");
952 Check(onef >= onef, true, "greater equal, equal, positive");
953 Check(mone >= monef, true, "greater equal, greater, negative");
954 Check(one >= onef, false, "greater equal, false, positive");
955 Check(mtwof >= mtwo, false, "greater equal, false, negative");
956 std::cout << std::endl;
957
958 Check(zero == false, true, "zero == false");
959 Check(one == true, true, "one == true");
960 Check(zerof != false, true, "zerof != false");
961 Check((!zero) == true, true, "!zero == true");
962 Check((!zerof) == false, true, "!zerof == false");
963 Check((!one) == false, true, "!one == false");
964 Check((+onef) == onef, true, "unary positive");
965 Check((-onef) == monef, true, "unary negative");
966 // NOLINTEND(misc-redundant-expression)
967}
968
969/**
970 * \ingroup int64x64-tests
971 *
972 * Test: Invert and MulByInvert.
973 */
975{
976 public:
978 void DoRun() override;
979 /**
980 * Check the int64x64 for correctness.
981 * \param factor The factor used to invert the number.
982 */
983 void Check(const int64_t factor);
984 /**
985 * Check the int64x64 for correctness.
986 * \param factor The factor used to invert the number.
987 * \param result The value.
988 * \param expect The expected value.
989 * \param msg The error message to print.
990 * \param tolerance The allowed tolerance.
991 */
992 void CheckCase(const uint64_t factor,
993 const int64x64_t result,
994 const int64x64_t expect,
995 const std::string& msg,
996 const double tolerance = 0);
997};
998
1000 : TestCase("Invert and MulByInvert")
1001{
1002}
1003
1004void
1006 const int64x64_t result,
1007 const int64x64_t expect,
1008 const std::string& msg,
1009 const double tolerance /* = 0 */)
1010{
1011 bool pass = Abs(result - expect) <= tolerance;
1012
1013 std::cout << GetParent()->GetName() << " Invert: ";
1014
1015 if (pass)
1016 {
1017 std::cout << "pass: " << factor << ": ";
1018 }
1019 else
1020 {
1021 std::cout << "FAIL: " << factor << ": "
1022 << "(res: " << result << " exp: " << expect << " tol: " << tolerance << ") ";
1023 }
1024 std::cout << msg << std::endl;
1025
1026 NS_TEST_ASSERT_MSG_EQ_TOL(result, expect, int64x64_t(tolerance), msg);
1027}
1028
1029void
1031{
1032 const int64x64_t one(1, 0);
1033 const int64x64_t factorI = one / int64x64_t(factor);
1034
1035 const int64x64_t a = int64x64_t::Invert(factor);
1036 int64x64_t b(factor);
1037
1038 double tolerance = 0;
1040 {
1041 // Darwin 12.5.0 (Mac 10.8.5) g++ 4.2.1
1042 tolerance = 0.000000000000000001L;
1043 }
1044
1045 b.MulByInvert(a);
1046 CheckCase(factor, b, one, "x * x^-1 == 1", tolerance);
1047
1048 int64x64_t c(1);
1049 c.MulByInvert(a);
1050 CheckCase(factor, c, factorI, "1 * x^-1 == 1 / x");
1051
1052 int64x64_t d(1);
1053 d /= (int64x64_t(factor));
1054 CheckCase(factor, d, c, "1/x == x^-1");
1055
1056 int64x64_t e(-factor);
1057 e.MulByInvert(a);
1058 CheckCase(factor, e, -one, "-x * x^-1 == -1", tolerance);
1059}
1060
1061void
1063{
1064 std::cout << std::endl;
1065 std::cout << GetParent()->GetName() << " Invert: " << GetName() << std::endl;
1066
1067 Check(2);
1068 Check(3);
1069 Check(4);
1070 Check(5);
1071 Check(6);
1072 Check(10);
1073 Check(99);
1074 Check(100);
1075 Check(1000);
1076 Check(10000);
1077 Check(100000);
1078 Check(100000);
1079 Check(1000000);
1080 Check(10000000);
1081 Check(100000000);
1082 Check(1000000000);
1083 Check(10000000000LL);
1084 Check(100000000000LL);
1085 Check(1000000000000LL);
1086 Check(10000000000000LL);
1087 Check(100000000000000LL);
1088 Check(1000000000000000LL);
1089}
1090
1091/**
1092 * \ingroup int64x64-tests
1093 *
1094 * Test: construct from floating point.
1095 */
1097{
1098 public:
1100 void DoRun() override;
1101
1102 /**
1103 * Check the int64x64 for correctness.
1104 * \param intPart The expected integer part value of the int64x64.
1105 */
1106 void Check(const int64_t intPart);
1107 /**
1108 * Check the int64x64 for correctness.
1109 * \param dec The integer part of the value to test.
1110 * \param frac The fractional part of the value to test.x
1111 * \param intPart The expected integer part value of the int64x64.
1112 * \param lo The expected low part value of the int64x64.
1113 */
1114 void Check(const long double dec,
1115 const long double frac,
1116 const int64_t intPart,
1117 const uint64_t lo);
1118
1119 private:
1120 /**
1121 * Compute a multiplier to match the mantissa size on this platform
1122 *
1123 * Since we will store the fractional part of a double
1124 * in the low word (64 bits) of our Q64.64
1125 * the most mantissa bits we can take advantage of is
1126 *
1127 * EFF_MANT_DIG = std::min (64, LDBL_MANT_DIG)
1128 *
1129 * We have to bound this for platforms with LDBL_MANT_DIG > 64.
1130 *
1131 * The number of "missing" bits in the mantissa is
1132 *
1133 * MISS_MANT_DIG = 64 - EFF_MANT_DIG = std::max (0, 64 - LDBL_MANT_DIG)
1134 *
1135 * This will lie in the closed interval [0, 64]
1136 */
1137 static constexpr int MISS_MANT_DIG = std::max(0, 64 - LDBL_MANT_DIG);
1138
1139 /**
1140 * The smallest low word we expect to get from a conversion.
1141 *
1142 * MIN_LOW = 2^MISS_MANT_DIG
1143 *
1144 * which will be in [1, 2^64].
1145 */
1146 static constexpr long double MIN_LOW = 1 << MISS_MANT_DIG;
1147
1148 /**
1149 * Smallest mantissa we expect to convert to a non-zero low word.
1150 *
1151 * MIN_MANT = MIN_LOW / 2^64
1152 * = 2^(MISS_MANT_DIG - 64)
1153 * = 2^(-EFF_MANT_DIG)
1154 *
1155 * We scale and round this value to match the
1156 * hard-coded fractional values in Check(intPart)
1157 * which have 22 decimal digits.
1158 *
1159 * Since we use std::round() which isn't constexpr,
1160 * just declare this const and initialize below.
1161 */
1162 static const long double MIN_MANT;
1163
1164 // Member variables
1165 long double m_last; //!< The last value tested.
1167 m_deltaMax; //!< The maximum observed difference between expected and computed values.
1168 int m_deltaCount; //!< The number of times a delta was recorded.
1169};
1170
1171/* static */
1172const long double Int64x64DoubleTestCase::MIN_MANT =
1173 std::round(1e22 / std::pow(2.0L, std::min(64, LDBL_MANT_DIG))) / 1e22;
1174
1176 : TestCase("Construct from floating point."),
1177 m_last{0},
1178 m_deltaMax{0},
1179 m_deltaCount{0}
1180{
1181}
1182
1183void
1184Int64x64DoubleTestCase::Check(const long double dec,
1185 const long double frac,
1186 const int64_t intPart,
1187 const uint64_t lo)
1188{
1189 // 1. The double value we're going to convert
1190 long double value = dec + frac;
1191
1192 // 2. The expected value of the conversion
1193 int64x64_t expect(intPart, lo);
1194
1195 // 1a, 2a. Handle lower-precision architectures by scaling up the fractional part
1196 // We assume MISS_MANT_DIG is much less than 64, MIN_MANT much less than 0.5
1197 // Could check lo < MIN_LOW instead...
1198
1199 /*
1200 This approach works for real values with mantissa very near zero,
1201 but isn't ideal. For values near 0.5, say, the low order bits
1202 are completely lost, since they exceed the precision of the
1203 double representation. This shows up on M1 and ARM architectures
1204 as the x.5... values all skipped, because they are indistinguishable
1205 from x.5 exactly.
1206
1207 A more involved alternative would be to separate the
1208 "frac" and "low" values in the caller. Then the underflow
1209 rescaling could be applied to the low bits only,
1210 before adding to the frac part.
1211
1212 To do this the signature of this function would have to be
1213 Check (cld dec, cld frac, int64_t intPart, int64_t low);
1214 ^- Note this signed
1215 The caller Check (intPart) would look like
1216
1217 Check (v, 0.0L, intPart, 0x0LL);
1218 Check (v, 0.0L, intPart, 0x1LL);
1219 Check (v, 0.0L, intPart, 0x2LL);
1220 ...
1221 Check (v, 0.5L, intPart, -0xFLL);
1222 Check (v, 0.5L, intPart, -0xELL);
1223 ...
1224 Check (v, 0.5L, intPart, 0x0LL);
1225 Check (v, 0.5L, intPart, 0x1LL);
1226
1227 Here we would construct value as
1228 long double lowLd = (double)low / std::pow(2.0L, 64);
1229 value = dec + frac + lowLd;
1230
1231 For underflow cases:
1232 value = dec + frac + std::max::(lowLd, MIN_MANT);
1233 */
1234
1235 bool under = false;
1236 if (frac && (frac < MIN_MANT))
1237 {
1238 under = true;
1239 value = dec + std::max(frac * MIN_LOW, MIN_MANT);
1240 expect = int64x64_t(intPart, lo * MIN_LOW);
1241 }
1242
1243 // 3. The actual value of the conversion
1244 const int64x64_t result = int64x64_t(value);
1245
1246 // 4. Absolute error in the conversion
1247 const int64x64_t delta = Abs(result - expect);
1248
1249 // Mark repeats (no change in input floating value) as "skip" (but not integers)
1250 const bool skip = (frac && (value == m_last));
1251 // Save the value to detect unchanged values next time
1252 m_last = value;
1253
1254 // 5. Tolerance for the test, scaled to the magnitude of value
1255 // Tolerance will be computed from the value, epsilon and margin
1256 int64x64_t tolerance;
1257
1258 // Default epsilon
1259 long double epsilon = std::numeric_limits<long double>::epsilon();
1260
1261 // A few cases need extra tolerance
1262 // If you add cases please thoroughly document the configuration
1263 long double margin = 0;
1264
1266 {
1267 // Darwin 12.5.0 (Mac 10.8.5) g++ 4.2.1
1268 margin = 1.0;
1269 }
1271 {
1272 // Valgrind and Windows use 64-bit doubles for long doubles
1273 // See ns-3 bug 1882
1274 // Need non-zero margin to ensure final tolerance is non-zero
1275 margin = 1.0;
1276 epsilon = std::numeric_limits<double>::epsilon();
1277 }
1278
1279 // Final tolerance amount
1280 tolerance = std::max(1.0L, std::fabs(value)) * epsilon + margin * epsilon;
1281
1282 // 6. Is the conversion acceptably close to the expected value?
1283 const bool pass = delta <= tolerance;
1284
1285 // 7. Show the result of this check
1286
1287 // Save stream format flags
1288 std::ios_base::fmtflags ff = std::cout.flags();
1289 std::cout << std::fixed << std::setprecision(22);
1290
1291 std::cout << GetParent()->GetName()
1292 << " Double: " << (skip ? "skip " : (pass ? "pass " : "FAIL ")) << std::showpos
1293 << value << " == " << Printer(result) << (under ? " (underflow)" : "") << std::endl;
1294
1295 if (delta)
1296 {
1297 // There was a difference, show the expected value
1298 std::cout << GetParent()->GetName() << std::left << std::setw(43) << " expected"
1299 << std::right << Printer(expect) << std::endl;
1300
1301 if (delta == tolerance)
1302 {
1303 // Short form: show the delta, and note it equals the tolerance
1304 std::cout << GetParent()->GetName() << std::left << std::setw(43)
1305 << " delta = tolerance" << std::right << Printer(delta) << std::endl;
1306 }
1307 else
1308 {
1309 // Long form, show both delta and tolerance
1310 std::cout << GetParent()->GetName() << std::left << std::setw(43) << " delta"
1311 << std::right << Printer(delta) << std::endl;
1312 std::cout << GetParent()->GetName() << std::left << std::setw(43)
1313 << " tolerance" << std::right << Printer(tolerance)
1314 << " eps: " << epsilon << ", margin: " << margin << std::endl;
1315 }
1316
1317 // Record number and max delta
1318 ++m_deltaCount;
1319
1320 if (delta > m_deltaMax)
1321 {
1322 m_deltaMax = delta;
1323 }
1324 }
1325
1326 // Report pass/fail
1327 NS_TEST_ASSERT_MSG_EQ_TOL(result, expect, tolerance, "int64x64_t (long double) failed");
1328 std::cout.flags(ff);
1329}
1330
1331void
1332Int64x64DoubleTestCase::Check(const int64_t intPart)
1333{
1334 std::cout << std::endl;
1335 std::cout << GetParent()->GetName() << " Double: "
1336 << "integer: " << intPart << std::endl;
1337 // Reset last value for new intPart
1338 m_last = intPart;
1339 // Save current number and max delta, so we can report max from just this intPart
1340 int64x64_t deltaMaxPrior = m_deltaMax;
1341 m_deltaMax = 0;
1342 int deltaCountPrior = m_deltaCount;
1343 m_deltaCount = 0;
1344
1345 // Nudging the integer part eliminates deltas around 0
1346 long double v = intPart;
1347
1348 Check(v, 0.0L, intPart, 0x0ULL);
1349 Check(v, 0.0000000000000000000542L, intPart, 0x1ULL);
1350 Check(v, 0.0000000000000000001084L, intPart, 0x2ULL);
1351 Check(v, 0.0000000000000000001626L, intPart, 0x3ULL);
1352 Check(v, 0.0000000000000000002168L, intPart, 0x4ULL);
1353 Check(v, 0.0000000000000000002711L, intPart, 0x5ULL);
1354 Check(v, 0.0000000000000000003253L, intPart, 0x6ULL);
1355 Check(v, 0.0000000000000000003795L, intPart, 0x7ULL);
1356 Check(v, 0.0000000000000000004337L, intPart, 0x8ULL);
1357 Check(v, 0.0000000000000000004879L, intPart, 0x9ULL);
1358 Check(v, 0.0000000000000000005421L, intPart, 0xAULL);
1359 Check(v, 0.0000000000000000005963L, intPart, 0xBULL);
1360 Check(v, 0.0000000000000000006505L, intPart, 0xCULL);
1361 Check(v, 0.0000000000000000007047L, intPart, 0xDULL);
1362 Check(v, 0.0000000000000000007589L, intPart, 0xEULL);
1363 Check(v, 0.0000000000000000008132L, intPart, 0xFULL);
1364 Check(v, 0.0000000000000000130104L, intPart, 0xF0ULL);
1365 Check(v, 0.0000000000000002081668L, intPart, 0xF00ULL);
1366 Check(v, 0.0000000000000033306691L, intPart, 0xF000ULL);
1367 Check(v, 0.0000000000000532907052L, intPart, 0xF0000ULL);
1368 Check(v, 0.0000000000008526512829L, intPart, 0xF00000ULL);
1369 Check(v, 0.0000000000136424205266L, intPart, 0xF000000ULL);
1370 Check(v, 0.0000000002182787284255L, intPart, 0xF0000000ULL);
1371 Check(v, 0.0000000034924596548080L, intPart, 0xF00000000ULL);
1372 Check(v, 0.0000000558793544769287L, intPart, 0xF000000000ULL);
1373 Check(v, 0.0000008940696716308594L, intPart, 0xF0000000000ULL);
1374 Check(v, 0.0000143051147460937500L, intPart, 0xF00000000000ULL);
1375 Check(v, 0.0002288818359375000000L, intPart, 0xF000000000000ULL);
1376 Check(v, 0.0036621093750000000000L, intPart, 0xF0000000000000ULL);
1377 Check(v, 0.0585937500000000000000L, intPart, 0xF00000000000000ULL);
1378 std::cout << std::endl;
1379 Check(v, 0.4999999999999999991326L, intPart, 0x7FFFFFFFFFFFFFF0ULL);
1380 Check(v, 0.4999999999999999991868L, intPart, 0x7FFFFFFFFFFFFFF1ULL);
1381 Check(v, 0.4999999999999999992411L, intPart, 0x7FFFFFFFFFFFFFF2ULL);
1382 Check(v, 0.4999999999999999992953L, intPart, 0x7FFFFFFFFFFFFFF3ULL);
1383 Check(v, 0.4999999999999999993495L, intPart, 0x7FFFFFFFFFFFFFF4ULL);
1384 Check(v, 0.4999999999999999994037L, intPart, 0x7FFFFFFFFFFFFFF5ULL);
1385 Check(v, 0.4999999999999999994579L, intPart, 0x7FFFFFFFFFFFFFF6ULL);
1386 Check(v, 0.4999999999999999995121L, intPart, 0x7FFFFFFFFFFFFFF7ULL);
1387 Check(v, 0.4999999999999999995663L, intPart, 0x7FFFFFFFFFFFFFF8ULL);
1388 Check(v, 0.4999999999999999996205L, intPart, 0x7FFFFFFFFFFFFFF9ULL);
1389 Check(v, 0.4999999999999999996747L, intPart, 0x7FFFFFFFFFFFFFFAULL);
1390 Check(v, 0.4999999999999999997289L, intPart, 0x7FFFFFFFFFFFFFFBULL);
1391 Check(v, 0.4999999999999999997832L, intPart, 0x7FFFFFFFFFFFFFFCULL);
1392 Check(v, 0.4999999999999999998374L, intPart, 0x7FFFFFFFFFFFFFFDULL);
1393 Check(v, 0.4999999999999999998916L, intPart, 0x7FFFFFFFFFFFFFFEULL);
1394 Check(v, 0.4999999999999999999458L, intPart, 0x7FFFFFFFFFFFFFFFULL);
1395 Check(v, 0.5000000000000000000000L, intPart, 0x8000000000000000ULL);
1396 Check(v, 0.5000000000000000000542L, intPart, 0x8000000000000001ULL);
1397 Check(v, 0.5000000000000000001084L, intPart, 0x8000000000000002ULL);
1398 Check(v, 0.5000000000000000001626L, intPart, 0x8000000000000003ULL);
1399 Check(v, 0.5000000000000000002168L, intPart, 0x8000000000000004ULL);
1400 Check(v, 0.5000000000000000002711L, intPart, 0x8000000000000005ULL);
1401 Check(v, 0.5000000000000000003253L, intPart, 0x8000000000000006ULL);
1402 Check(v, 0.5000000000000000003795L, intPart, 0x8000000000000007ULL);
1403 Check(v, 0.5000000000000000004337L, intPart, 0x8000000000000008ULL);
1404 Check(v, 0.5000000000000000004879L, intPart, 0x8000000000000009ULL);
1405 Check(v, 0.5000000000000000005421L, intPart, 0x800000000000000AULL);
1406 Check(v, 0.5000000000000000005963L, intPart, 0x800000000000000BULL);
1407 Check(v, 0.5000000000000000006505L, intPart, 0x800000000000000CULL);
1408 Check(v, 0.5000000000000000007047L, intPart, 0x800000000000000DULL);
1409 Check(v, 0.5000000000000000007589L, intPart, 0x800000000000000EULL);
1410 Check(v, 0.5000000000000000008132L, intPart, 0x800000000000000FULL);
1411 std::cout << std::endl;
1412 Check(v, 0.9375000000000000000000L, intPart, 0xF000000000000000ULL);
1413 Check(v, 0.9960937500000000000000L, intPart, 0xFF00000000000000ULL);
1414 Check(v, 0.9997558593750000000000L, intPart, 0xFFF0000000000000ULL);
1415 Check(v, 0.9999847412109375000000L, intPart, 0xFFFF000000000000ULL);
1416 Check(v, 0.9999990463256835937500L, intPart, 0xFFFFF00000000000ULL);
1417 Check(v, 0.9999999403953552246094L, intPart, 0xFFFFFF0000000000ULL);
1418 Check(v, 0.9999999962747097015381L, intPart, 0xFFFFFFF000000000ULL);
1419 Check(v, 0.9999999997671693563461L, intPart, 0xFFFFFFFF00000000ULL);
1420 Check(v, 0.9999999999854480847716L, intPart, 0xFFFFFFFFF0000000ULL);
1421 Check(v, 0.9999999999990905052982L, intPart, 0xFFFFFFFFFF000000ULL);
1422 Check(v, 0.9999999999999431565811L, intPart, 0xFFFFFFFFFFF00000ULL);
1423 Check(v, 0.9999999999999964472863L, intPart, 0xFFFFFFFFFFFF0000ULL);
1424 Check(v, 0.9999999999999997779554L, intPart, 0xFFFFFFFFFFFFF000ULL);
1425 Check(v, 0.9999999999999999861222L, intPart, 0xFFFFFFFFFFFFFF00ULL);
1426 Check(v, 0.9999999999999999991326L, intPart, 0xFFFFFFFFFFFFFFF0ULL);
1427 Check(v, 0.9999999999999999991868L, intPart, 0xFFFFFFFFFFFFFFF1ULL);
1428 Check(v, 0.9999999999999999992411L, intPart, 0xFFFFFFFFFFFFFFF2ULL);
1429 Check(v, 0.9999999999999999992943L, intPart, 0xFFFFFFFFFFFFFFF3ULL);
1430 Check(v, 0.9999999999999999993495L, intPart, 0xFFFFFFFFFFFFFFF4ULL);
1431 Check(v, 0.9999999999999999994037L, intPart, 0xFFFFFFFFFFFFFFF5ULL);
1432 Check(v, 0.9999999999999999994579L, intPart, 0xFFFFFFFFFFFFFFF6ULL);
1433 Check(v, 0.9999999999999999995121L, intPart, 0xFFFFFFFFFFFFFFF7ULL);
1434 Check(v, 0.9999999999999999995663L, intPart, 0xFFFFFFFFFFFFFFF8ULL);
1435 Check(v, 0.9999999999999999996205L, intPart, 0xFFFFFFFFFFFFFFF9ULL);
1436 Check(v, 0.9999999999999999996747L, intPart, 0xFFFFFFFFFFFFFFFAULL);
1437 Check(v, 0.9999999999999999997289L, intPart, 0xFFFFFFFFFFFFFFFBULL);
1438 Check(v, 0.9999999999999999997832L, intPart, 0xFFFFFFFFFFFFFFFCULL);
1439 Check(v, 0.9999999999999999998374L, intPart, 0xFFFFFFFFFFFFFFFDULL);
1440 Check(v, 0.9999999999999999998916L, intPart, 0xFFFFFFFFFFFFFFFEULL);
1441 Check(v, 0.9999999999999999999458L, intPart, 0xFFFFFFFFFFFFFFFFULL);
1442
1443 std::cout << GetParent()->GetName() << " Double: "
1444 << "integer:" << std::setw(4) << intPart << ": deltas:" << std::setw(4)
1445 << m_deltaCount << ", max: " << Printer(m_deltaMax) << std::endl;
1446
1447 // Add the count, max from this intPart to the grand totals
1448 m_deltaCount += deltaCountPrior;
1449 m_deltaMax = Max(m_deltaMax, deltaMaxPrior);
1450}
1451
1452void
1454{
1455 std::cout << std::endl;
1456 std::cout << GetParent()->GetName() << " Double: " << GetName() << std::endl;
1457
1458 // Save stream format flags
1459 std::ios_base::fmtflags ff = std::cout.flags();
1460
1461 std::cout << GetParent()->GetName() << " Double: "
1462 << "FLT_RADIX: " << FLT_RADIX
1463 << "\n LDBL_MANT_DIG: " << LDBL_MANT_DIG
1464 << "\n MISS_MANT_DIG: " << MISS_MANT_DIG
1465 << "\n MIN_LOW: " << Printer(MIN_LOW) << " (" << std::hexfloat
1466 << MIN_LOW << ")" << std::defaultfloat
1467 << "\n MIN_MANT: " << Printer(MIN_MANT) << std::endl;
1468
1469 std::cout << std::scientific << std::setprecision(21);
1470
1471 Check(-2);
1472 Check(-1);
1473 Check(0);
1474 Check(1);
1475 Check(2);
1476
1477 std::cout << GetParent()->GetName() << " Double: "
1478 << "Total deltas:" << std::setw(7) << m_deltaCount
1479 << ", max delta: " << Printer(m_deltaMax) << std::endl;
1480
1481 std::cout.flags(ff);
1482}
1483
1484/**
1485 * \ingroup int64x64-tests
1486 *
1487 * Test: print the implementation
1488 */
1490{
1491 public:
1493 void DoRun() override;
1494};
1495
1497 : TestCase("Print the implementation")
1498{
1499}
1500
1501void
1503{
1504 std::cout << std::endl;
1505 std::cout << GetParent()->GetName() << " Impl: " << GetName() << std::endl;
1506
1507 std::cout << "int64x64_t::implementation: ";
1509 {
1511 std::cout << "int128_impl";
1512 break;
1514 std::cout << "cairo_impl";
1515 break;
1516 case (int64x64_t::ld_impl):
1517 std::cout << "ld_impl";
1518 break;
1519 default:
1520 std::cout << "unknown!";
1521 }
1522 std::cout << std::endl;
1523
1524#if defined(INT64X64_USE_CAIRO) && !defined(PYTHON_SCAN)
1525 std::cout << "cairo_impl64: " << cairo_impl64 << std::endl;
1526 std::cout << "cairo_impl128: " << cairo_impl128 << std::endl;
1527#endif
1528
1530 {
1531 std::cout << "Running with 64-bit long doubles" << std::endl;
1532 }
1533}
1534
1535/**
1536 * \ingroup int64x64-tests
1537 * \internal
1538 *
1539 * The int64x64 Test Suite.
1540 *
1541 * Some of these tests are a little unusual for ns-3 in that they
1542 * are sensitive to implementation, specifically the resolution
1543 * of the double and long double implementations.
1544 *
1545 * To handle this, where needed we define a tolerance to use in the
1546 * test comparisons. If you need to increase the tolerance,
1547 * please append the system and compiler version. For example:
1548 *
1549 * \code
1550 * // Darwin 12.5.0 (Mac 10.8.5) g++ 4.2.1
1551 * tolerance = 1;
1552 * // System Foo gcc 3.9
1553 * tolerance = 3;
1554 * \endcode
1555 */
1557{
1558 public:
1560 : TestSuite("int64x64", Type::UNIT)
1561 {
1574 }
1575};
1576
1577static Int64x64TestSuite g_int64x64TestSuite; //!< Static variable for test initialization
1578
1579} // namespace test
1580
1581} // namespace int64x64
1582
1583} // 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:301
TestCase * GetParent() const
Get the parent of this TestCase.
Definition: test.cc:380
std::string GetName() const
Definition: test.cc:373
A suite of tests to run.
Definition: test.h:1268
Type
Type of test.
Definition: test.h:1275
static constexpr auto UNIT
Definition: test.h:1286
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:88
@ ld_impl
long double implementation.
Definition: int64x64-128.h:90
@ cairo_impl
Cairo wideint implementation.
Definition: int64x64-128.h:89
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:94
double GetDouble() const
Get this value as a double.
Definition: int64x64-128.h:240
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:76
#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