Руслан Урядинский / libuavcan

Dependents:   UAVCAN UAVCAN_Subscriber

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers comparison.cpp Source File

comparison.cpp

00001 /*
00002  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
00003  */
00004 
00005 #include <gtest/gtest.h>
00006 #include <uavcan/util/comparison.hpp>
00007 
00008 TEST(Comparison, Basic)
00009 {
00010     // Basic same type floats
00011     ASSERT_TRUE(uavcan::areClose(0.1, 0.1));
00012     ASSERT_TRUE(uavcan::areClose(0.1F, 0.1F));
00013     ASSERT_TRUE(uavcan::areClose(0.1L, 0.1L));
00014 
00015     // Basic mixed type floats
00016     ASSERT_TRUE(uavcan::areClose(0.1F, 0.1));
00017     ASSERT_TRUE(uavcan::areClose(0.1,  0.1F));
00018     ASSERT_TRUE(uavcan::areClose(0.1F, 0.1L));
00019     ASSERT_TRUE(uavcan::areClose(0.1L, 0.1F));
00020     ASSERT_TRUE(uavcan::areClose(0.1,  0.1L));
00021     ASSERT_TRUE(uavcan::areClose(0.1L, 0.1));
00022 
00023     // Basic floats
00024     ASSERT_TRUE(uavcan::areClose(0x07, '\x07'));
00025     ASSERT_TRUE(uavcan::areClose(123456789LL, 123456789));
00026     ASSERT_TRUE(uavcan::areClose("123", std::string("123")));
00027 
00028     // Non-equality
00029     ASSERT_FALSE(uavcan::areClose(-0.1, 0.1));
00030     ASSERT_FALSE(uavcan::areClose(-0.1F, 0.0L));
00031     ASSERT_FALSE(uavcan::areClose("123", std::string("12")));
00032     ASSERT_FALSE(uavcan::areClose(0x07L, '\0'));
00033 }
00034 
00035 TEST(Comparison, FloatSpecialCase)
00036 {
00037     ASSERT_FALSE(uavcan::areClose(0.1, std::numeric_limits<double>::infinity()));
00038 
00039     ASSERT_TRUE(uavcan::areClose(std::numeric_limits<float>::infinity(),
00040                                  std::numeric_limits<long double>::infinity()));
00041 
00042     ASSERT_FALSE(uavcan::areClose(std::numeric_limits<float>::infinity(), -std::numeric_limits<float>::infinity()));
00043 
00044     ASSERT_FALSE(uavcan::areClose(std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()));
00045 }
00046 
00047 TEST(Comparison, FloatULP)
00048 {
00049     ASSERT_FALSE(uavcan::areClose(0.100000000000000001L, 0.1L));
00050     ASSERT_TRUE( uavcan::areClose(0.100000000000000001,  0.1L));
00051     ASSERT_TRUE( uavcan::areClose(0.100000000000000001F, 0.1L));
00052 
00053     // Near zero
00054     ASSERT_TRUE( uavcan::areClose(0.0F,  std::numeric_limits<float>::epsilon()));
00055     ASSERT_TRUE( uavcan::areClose(0.0F, -std::numeric_limits<float>::epsilon()));
00056     ASSERT_FALSE(uavcan::areClose(0.0F,  std::numeric_limits<float>::epsilon() * 2));
00057 }
00058 
00059 TEST(Comparison, BruteforceValidation)
00060 {
00061     const std::streamsize default_precision = std::cout.precision();
00062     std::cout.precision(20);
00063 
00064     float x = -uavcan::NumericTraits<float>::max();
00065 
00066     while (x < uavcan::NumericTraits<float>::max())
00067     {
00068         const float y1 = x + std::abs(x) * (uavcan::NumericTraits<float>::epsilon() * 2);                // Still equal
00069         const float y2 = x + uavcan::max(std::abs(x), 1.F) * (uavcan::NumericTraits<float>::epsilon() * 20); // Nope
00070 
00071         if (!uavcan::areClose(y1, x))
00072         {
00073             std::cout << "y1=" << y1 << " y2=" << y2 << " x=" << x << std::endl;
00074             ASSERT_TRUE(false);
00075         }
00076         if (uavcan::areClose(y2, x))
00077         {
00078             std::cout << "y1=" << y1 << " y2=" << y2 << " x=" << x << std::endl;
00079             ASSERT_TRUE(false);
00080         }
00081 
00082         x = y2;
00083     }
00084 
00085     std::cout.precision(default_precision);
00086 }
00087 
00088 
00089 struct B
00090 {
00091     long double b;
00092     B(long double val = 0.0L) : b(val) { }
00093 };
00094 
00095 struct A
00096 {
00097     float a;
00098     explicit A(float val = 0.0F) : a(val) { }
00099 
00100     bool isClose(A rhs) const
00101     {
00102         std::cout << "bool A::isClose(A) --> " << rhs.a << std::endl;
00103         return uavcan::areClose(a, rhs.a);
00104     }
00105 
00106     bool isClose(const B& rhs) const
00107     {
00108         std::cout << "bool A::isClose(const B&) --> " << rhs.b << std::endl;
00109         return uavcan::areClose(a, rhs.b);
00110     }
00111 };
00112 
00113 struct C
00114 {
00115     long long c;
00116     explicit C(long long val = 0.0L) : c(val) { }
00117 
00118     bool operator==(B rhs) const
00119     {
00120         std::cout << "bool C::operator==(B) --> " << rhs.b << std::endl;
00121         return c == static_cast<long long>(rhs.b);
00122     }
00123 };
00124 
00125 TEST(Comparison, IsCloseMethod)
00126 {
00127     B b;
00128     A a;
00129     C c;
00130 
00131     std::cout << 1 << std::endl;
00132     ASSERT_TRUE(uavcan::areClose(a, b));   // Fuzzy
00133     ASSERT_TRUE(uavcan::areClose(a, A())); // Fuzzy
00134     ASSERT_TRUE(uavcan::areClose(b, a));   // Fuzzy, reverse application
00135     ASSERT_TRUE(uavcan::areClose(c, b));   // Exact
00136 
00137     std::cout << 2 << std::endl;
00138 
00139     a.a = uavcan::NumericTraits<float>::epsilon();
00140 
00141     ASSERT_TRUE(uavcan::areClose(a, b));
00142     ASSERT_TRUE(uavcan::areClose(b, a));
00143     ASSERT_TRUE(a.isClose(b));
00144     ASSERT_TRUE(a.isClose(A()));
00145     ASSERT_TRUE(uavcan::areClose(A(), a));
00146 
00147     std::cout << 3 << std::endl;
00148 
00149     a.a = 1e-5F;
00150 
00151     ASSERT_FALSE(uavcan::areClose(a, b));
00152     ASSERT_FALSE(uavcan::areClose(b, a));
00153     ASSERT_FALSE(uavcan::areClose(A(), a));
00154 
00155     std::cout << 4 << std::endl;
00156 
00157     b.b = 1.1L;
00158     c.c = 1;
00159 
00160     ASSERT_TRUE(uavcan::areClose(c, b));      // Round to integer
00161     ASSERT_TRUE(uavcan::areClose(c, 1.0L));   // Implicit cast to B
00162     ASSERT_FALSE(uavcan::areClose(c, 0.0L));
00163 }