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