comparison.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /*
  2. * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
  3. */
  4. #include <gtest/gtest.h>
  5. #include <uavcan/util/comparison.hpp>
  6. TEST(Comparison, Basic)
  7. {
  8. // Basic same type floats
  9. ASSERT_TRUE(uavcan::areClose(0.1, 0.1));
  10. ASSERT_TRUE(uavcan::areClose(0.1F, 0.1F));
  11. ASSERT_TRUE(uavcan::areClose(0.1L, 0.1L));
  12. // Basic mixed type floats
  13. ASSERT_TRUE(uavcan::areClose(0.1F, 0.1));
  14. ASSERT_TRUE(uavcan::areClose(0.1, 0.1F));
  15. ASSERT_TRUE(uavcan::areClose(0.1F, 0.1L));
  16. ASSERT_TRUE(uavcan::areClose(0.1L, 0.1F));
  17. ASSERT_TRUE(uavcan::areClose(0.1, 0.1L));
  18. ASSERT_TRUE(uavcan::areClose(0.1L, 0.1));
  19. // Basic floats
  20. ASSERT_TRUE(uavcan::areClose(0x07, '\x07'));
  21. ASSERT_TRUE(uavcan::areClose(123456789LL, 123456789));
  22. ASSERT_TRUE(uavcan::areClose("123", std::string("123")));
  23. // Non-equality
  24. ASSERT_FALSE(uavcan::areClose(-0.1, 0.1));
  25. ASSERT_FALSE(uavcan::areClose(-0.1F, 0.0L));
  26. ASSERT_FALSE(uavcan::areClose("123", std::string("12")));
  27. ASSERT_FALSE(uavcan::areClose(0x07L, '\0'));
  28. }
  29. TEST(Comparison, FloatSpecialCase)
  30. {
  31. ASSERT_FALSE(uavcan::areClose(0.1, std::numeric_limits<double>::infinity()));
  32. ASSERT_TRUE(uavcan::areClose(std::numeric_limits<float>::infinity(),
  33. std::numeric_limits<long double>::infinity()));
  34. ASSERT_FALSE(uavcan::areClose(std::numeric_limits<float>::infinity(), -std::numeric_limits<float>::infinity()));
  35. ASSERT_FALSE(uavcan::areClose(std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()));
  36. }
  37. TEST(Comparison, FloatULP)
  38. {
  39. ASSERT_FALSE(uavcan::areClose(0.100000000000000001L, 0.1L));
  40. ASSERT_TRUE( uavcan::areClose(0.100000000000000001, 0.1L));
  41. ASSERT_TRUE( uavcan::areClose(0.100000000000000001F, 0.1L));
  42. // Near zero
  43. ASSERT_TRUE( uavcan::areClose(0.0F, std::numeric_limits<float>::epsilon()));
  44. ASSERT_TRUE( uavcan::areClose(0.0F, -std::numeric_limits<float>::epsilon()));
  45. ASSERT_FALSE(uavcan::areClose(0.0F, std::numeric_limits<float>::epsilon() * 2));
  46. }
  47. TEST(Comparison, BruteforceValidation)
  48. {
  49. const std::streamsize default_precision = std::cout.precision();
  50. std::cout.precision(20);
  51. float x = -uavcan::NumericTraits<float>::max();
  52. while (x < uavcan::NumericTraits<float>::max())
  53. {
  54. const float y1 = x + std::abs(x) * (uavcan::NumericTraits<float>::epsilon() * 2); // Still equal
  55. const float y2 = x + uavcan::max(std::abs(x), 1.F) * (uavcan::NumericTraits<float>::epsilon() * 20); // Nope
  56. if (!uavcan::areClose(y1, x))
  57. {
  58. std::cout << "y1=" << y1 << " y2=" << y2 << " x=" << x << std::endl;
  59. ASSERT_TRUE(false);
  60. }
  61. if (uavcan::areClose(y2, x))
  62. {
  63. std::cout << "y1=" << y1 << " y2=" << y2 << " x=" << x << std::endl;
  64. ASSERT_TRUE(false);
  65. }
  66. x = y2;
  67. }
  68. std::cout.precision(default_precision);
  69. }
  70. struct B
  71. {
  72. long double b;
  73. B(long double val = 0.0L) : b(val) { }
  74. };
  75. struct A
  76. {
  77. float a;
  78. explicit A(float val = 0.0F) : a(val) { }
  79. bool isClose(A rhs) const
  80. {
  81. std::cout << "bool A::isClose(A) --> " << rhs.a << std::endl;
  82. return uavcan::areClose(a, rhs.a);
  83. }
  84. bool isClose(const B& rhs) const
  85. {
  86. std::cout << "bool A::isClose(const B&) --> " << rhs.b << std::endl;
  87. return uavcan::areClose(a, rhs.b);
  88. }
  89. };
  90. struct C
  91. {
  92. long long c;
  93. explicit C(long long val = 0.0L) : c(val) { }
  94. bool operator==(B rhs) const
  95. {
  96. std::cout << "bool C::operator==(B) --> " << rhs.b << std::endl;
  97. return c == static_cast<long long>(rhs.b);
  98. }
  99. };
  100. TEST(Comparison, IsCloseMethod)
  101. {
  102. B b;
  103. A a;
  104. C c;
  105. std::cout << 1 << std::endl;
  106. ASSERT_TRUE(uavcan::areClose(a, b)); // Fuzzy
  107. ASSERT_TRUE(uavcan::areClose(a, A())); // Fuzzy
  108. ASSERT_TRUE(uavcan::areClose(b, a)); // Fuzzy, reverse application
  109. ASSERT_TRUE(uavcan::areClose(c, b)); // Exact
  110. std::cout << 2 << std::endl;
  111. a.a = uavcan::NumericTraits<float>::epsilon();
  112. ASSERT_TRUE(uavcan::areClose(a, b));
  113. ASSERT_TRUE(uavcan::areClose(b, a));
  114. ASSERT_TRUE(a.isClose(b));
  115. ASSERT_TRUE(a.isClose(A()));
  116. ASSERT_TRUE(uavcan::areClose(A(), a));
  117. std::cout << 3 << std::endl;
  118. a.a = 1e-5F;
  119. ASSERT_FALSE(uavcan::areClose(a, b));
  120. ASSERT_FALSE(uavcan::areClose(b, a));
  121. ASSERT_FALSE(uavcan::areClose(A(), a));
  122. std::cout << 4 << std::endl;
  123. b.b = 1.1L;
  124. c.c = 1;
  125. ASSERT_TRUE(uavcan::areClose(c, b)); // Round to integer
  126. ASSERT_TRUE(uavcan::areClose(c, 1.0L)); // Implicit cast to B
  127. ASSERT_FALSE(uavcan::areClose(c, 0.0L));
  128. }