test_information_units.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. // Boost.Units - A C++ library for zero-overhead dimensional analysis and
  2. // unit/quantity manipulation and conversion
  3. //
  4. // Copyright (C) 2014 Erik Erlandson
  5. //
  6. // Distributed under the Boost Software License, Version 1.0. (See
  7. // accompanying file LICENSE_1_0.txt or copy at
  8. // http://www.boost.org/LICENSE_1_0.txt)
  9. #include <iostream>
  10. #include <sstream>
  11. #include <boost/units/quantity.hpp>
  12. #include <boost/units/conversion.hpp>
  13. #include <boost/units/io.hpp>
  14. #include <boost/units/systems/si/prefixes.hpp>
  15. #include <boost/units/systems/si/time.hpp>
  16. // All information systems definitions
  17. #include <boost/units/systems/information.hpp>
  18. using std::cout;
  19. using std::cerr;
  20. using std::endl;
  21. using std::stringstream;
  22. namespace bu = boost::units;
  23. namespace si = boost::units::si;
  24. using bu::quantity;
  25. using bu::information::bit_base_unit;
  26. using bu::information::byte_base_unit;
  27. using bu::information::nat_base_unit;
  28. using bu::information::hartley_base_unit;
  29. using bu::information::shannon_base_unit;
  30. #define BOOST_TEST_MAIN
  31. #include <boost/test/unit_test.hpp>
  32. #include <boost/multiprecision/cpp_int.hpp>
  33. const double close_fraction = 0.0000001;
  34. // checks that cf(u2,u1) == expected
  35. // also checks invariant property that cf(u2,u1) * cf(u1,u2) == 1
  36. #define CHECK_DIRECT_CF(u1, u2, expected) \
  37. BOOST_CHECK_CLOSE_FRACTION(bu::conversion_factor((u2), (u1)), (expected), close_fraction); \
  38. BOOST_CHECK_CLOSE_FRACTION(bu::conversion_factor((u2), (u1)) * bu::conversion_factor((u1), (u2)), 1.0, close_fraction);
  39. // check transitive conversion factors
  40. // invariant: cf(u1,u3) = cf(u1,u2)*cf(u2,u3)
  41. #define CHECK_TRANSITIVE_CF(u1, u2, u3) { \
  42. BOOST_CONSTEXPR_OR_CONST double cf12 = bu::conversion_factor((u2), (u1)) ; \
  43. BOOST_CONSTEXPR_OR_CONST double cf23 = bu::conversion_factor((u3), (u2)) ; \
  44. BOOST_CONSTEXPR_OR_CONST double cf13 = bu::conversion_factor((u3), (u1)) ; \
  45. BOOST_CHECK_CLOSE_FRACTION(cf13, cf12*cf23, close_fraction); \
  46. BOOST_CONSTEXPR_OR_CONST double cf32 = bu::conversion_factor((u2), (u3)) ; \
  47. BOOST_CONSTEXPR_OR_CONST double cf21 = bu::conversion_factor((u1), (u2)) ; \
  48. BOOST_CONSTEXPR_OR_CONST double cf31 = bu::conversion_factor((u1), (u3)) ; \
  49. BOOST_CHECK_CLOSE_FRACTION(cf31, cf32*cf21, close_fraction); \
  50. }
  51. BOOST_AUTO_TEST_CASE(test_cf_bit_byte) {
  52. CHECK_DIRECT_CF(bit_base_unit::unit_type(), byte_base_unit::unit_type(), 8.0);
  53. }
  54. BOOST_AUTO_TEST_CASE(test_cf_bit_nat) {
  55. CHECK_DIRECT_CF(bit_base_unit::unit_type(), nat_base_unit::unit_type(), 1.442695040888964);
  56. }
  57. BOOST_AUTO_TEST_CASE(test_cf_bit_hartley) {
  58. CHECK_DIRECT_CF(bit_base_unit::unit_type(), hartley_base_unit::unit_type(), 3.321928094887363);
  59. }
  60. BOOST_AUTO_TEST_CASE(test_cf_bit_shannon) {
  61. CHECK_DIRECT_CF(bit_base_unit::unit_type(), shannon_base_unit::unit_type(), 1.0);
  62. }
  63. /////////////////////////////////////////////////////////////////////////////////////
  64. // spot-check that these are automatically transitive, thru central "hub unit" bit:
  65. // basic pattern is to test invariant property: cf(c,a) = cf(c,b)*cf(b,a)
  66. BOOST_AUTO_TEST_CASE(test_transitive_byte_nat) {
  67. CHECK_TRANSITIVE_CF(byte_base_unit::unit_type(), bit_base_unit::unit_type(), nat_base_unit::unit_type());
  68. }
  69. BOOST_AUTO_TEST_CASE(test_transitive_nat_hartley) {
  70. CHECK_TRANSITIVE_CF(nat_base_unit::unit_type(), bit_base_unit::unit_type(), hartley_base_unit::unit_type());
  71. }
  72. BOOST_AUTO_TEST_CASE(test_transitive_hartley_shannon) {
  73. CHECK_TRANSITIVE_CF(hartley_base_unit::unit_type(), bit_base_unit::unit_type(), shannon_base_unit::unit_type());
  74. }
  75. BOOST_AUTO_TEST_CASE(test_transitive_shannon_byte) {
  76. CHECK_TRANSITIVE_CF(shannon_base_unit::unit_type(), bit_base_unit::unit_type(), byte_base_unit::unit_type());
  77. }
  78. // test transitive factors, none of which are bit, just for good measure
  79. BOOST_AUTO_TEST_CASE(test_transitive_byte_nat_hartley) {
  80. CHECK_TRANSITIVE_CF(byte_base_unit::unit_type(), nat_base_unit::unit_type(), hartley_base_unit::unit_type());
  81. }
  82. BOOST_AUTO_TEST_CASE(test_byte_quantity_is_default) {
  83. using namespace bu::information;
  84. BOOST_CONSTEXPR_OR_CONST quantity<info, double> qd(2 * byte);
  85. BOOST_CHECK_EQUAL(qd.value(), double(2));
  86. BOOST_CONSTEXPR_OR_CONST quantity<info, long> ql(2 * byte);
  87. BOOST_CHECK_EQUAL(ql.value(), long(2));
  88. }
  89. BOOST_AUTO_TEST_CASE(test_byte_quantity_explicit) {
  90. using namespace bu::information;
  91. BOOST_CONSTEXPR_OR_CONST quantity<hu::byte::info, double> qd(2 * byte);
  92. BOOST_CHECK_EQUAL(qd.value(), double(2));
  93. BOOST_CONSTEXPR_OR_CONST quantity<hu::byte::info, long> ql(2 * byte);
  94. BOOST_CHECK_EQUAL(ql.value(), long(2));
  95. }
  96. BOOST_AUTO_TEST_CASE(test_bit_quantity) {
  97. using namespace bu::information;
  98. BOOST_CONSTEXPR_OR_CONST quantity<hu::bit::info, double> qd(2 * bit);
  99. BOOST_CHECK_EQUAL(qd.value(), double(2));
  100. BOOST_CONSTEXPR_OR_CONST quantity<hu::bit::info, long> ql(2 * bit);
  101. BOOST_CHECK_EQUAL(ql.value(), long(2));
  102. }
  103. BOOST_AUTO_TEST_CASE(test_nat_quantity) {
  104. using namespace bu::information;
  105. BOOST_CONSTEXPR_OR_CONST quantity<hu::nat::info, double> qd(2 * nat);
  106. BOOST_CHECK_EQUAL(qd.value(), double(2));
  107. BOOST_CONSTEXPR_OR_CONST quantity<hu::nat::info, long> ql(2 * nat);
  108. BOOST_CHECK_EQUAL(ql.value(), long(2));
  109. }
  110. BOOST_AUTO_TEST_CASE(test_hartley_quantity) {
  111. using namespace bu::information;
  112. BOOST_CONSTEXPR_OR_CONST quantity<hu::hartley::info, double> qd(2 * hartley);
  113. BOOST_CHECK_EQUAL(qd.value(), double(2));
  114. BOOST_CONSTEXPR_OR_CONST quantity<hu::hartley::info, long> ql(2 * hartley);
  115. BOOST_CHECK_EQUAL(ql.value(), long(2));
  116. }
  117. BOOST_AUTO_TEST_CASE(test_shannon_quantity) {
  118. using namespace bu::information;
  119. BOOST_CONSTEXPR_OR_CONST quantity<hu::shannon::info, double> qd(2 * shannon);
  120. BOOST_CHECK_EQUAL(qd.value(), double(2));
  121. BOOST_CONSTEXPR_OR_CONST quantity<hu::shannon::info, long> ql(2 * shannon);
  122. BOOST_CHECK_EQUAL(ql.value(), long(2));
  123. }
  124. BOOST_AUTO_TEST_CASE(test_mixed_hu) {
  125. using namespace bu::information;
  126. BOOST_CONSTEXPR_OR_CONST double cf = 0.001;
  127. BOOST_CHECK_CLOSE_FRACTION((quantity<hu::bit::info>(1.0 * bits)).value(), 1.0, cf);
  128. BOOST_CHECK_CLOSE_FRACTION((quantity<hu::byte::info>(1.0 * bits)).value(), 1.0/8.0, cf);
  129. BOOST_CHECK_CLOSE_FRACTION((quantity<hu::nat::info>(1.0 * bits)).value(), 0.69315, cf);
  130. BOOST_CHECK_CLOSE_FRACTION((quantity<hu::hartley::info>(1.0 * bits)).value(), 0.30102, cf);
  131. BOOST_CHECK_CLOSE_FRACTION((quantity<hu::shannon::info>(1.0 * bits)).value(), 1.0, cf);
  132. }
  133. BOOST_AUTO_TEST_CASE(test_info_prefixes) {
  134. using namespace bu::information;
  135. BOOST_CONSTEXPR_OR_CONST quantity<info, long long> q10(1LL * kibi * byte);
  136. BOOST_CHECK_EQUAL(q10.value(), 1024LL);
  137. BOOST_CONSTEXPR_OR_CONST quantity<info, long long> q20(1LL * mebi * byte);
  138. BOOST_CHECK_EQUAL(q20.value(), 1048576LL);
  139. BOOST_CONSTEXPR_OR_CONST quantity<info, long long> q30(1LL * gibi * byte);
  140. BOOST_CHECK_EQUAL(q30.value(), 1073741824LL);
  141. BOOST_CONSTEXPR_OR_CONST quantity<info, long long> q40(1LL * tebi * byte);
  142. BOOST_CHECK_EQUAL(q40.value(), 1099511627776LL);
  143. BOOST_CONSTEXPR_OR_CONST quantity<info, long long> q50(1LL * pebi * byte);
  144. BOOST_CHECK_EQUAL(q50.value(), 1125899906842624LL);
  145. BOOST_CONSTEXPR_OR_CONST quantity<info, long long> q60(1LL * exbi * byte);
  146. BOOST_CHECK_EQUAL(q60.value(), 1152921504606846976LL);
  147. using boost::multiprecision::int128_t;
  148. const quantity<info, int128_t> q70(1LL * zebi * byte);
  149. BOOST_CHECK_EQUAL(q70.value(), int128_t("1180591620717411303424"));
  150. const quantity<info, int128_t> q80(1LL * yobi * byte);
  151. BOOST_CHECK_EQUAL(q80.value(), int128_t("1208925819614629174706176"));
  152. // sanity check: si prefixes should also operate
  153. BOOST_CONSTEXPR_OR_CONST quantity<info, long long> q1e3(1LL * si::kilo * byte);
  154. BOOST_CHECK_EQUAL(q1e3.value(), 1000LL);
  155. BOOST_CONSTEXPR_OR_CONST quantity<info, long long> q1e6(1LL * si::mega * byte);
  156. BOOST_CHECK_EQUAL(q1e6.value(), 1000000LL);
  157. }
  158. BOOST_AUTO_TEST_CASE(test_unit_constant_io) {
  159. using namespace bu::information;
  160. std::stringstream ss;
  161. ss << bu::symbol_format << bytes;
  162. BOOST_CHECK_EQUAL(ss.str(), "B");
  163. ss.str("");
  164. ss << bu::name_format << bytes;
  165. BOOST_CHECK_EQUAL(ss.str(), "byte");
  166. ss.str("");
  167. ss << bu::symbol_format << bits;
  168. BOOST_CHECK_EQUAL(ss.str(), "b");
  169. ss.str("");
  170. ss << bu::name_format << bits;
  171. BOOST_CHECK_EQUAL(ss.str(), "bit");
  172. ss.str("");
  173. ss << bu::symbol_format << nats;
  174. BOOST_CHECK_EQUAL(ss.str(), "nat");
  175. ss.str("");
  176. ss << bu::name_format << nats;
  177. BOOST_CHECK_EQUAL(ss.str(), "nat");
  178. ss.str("");
  179. ss << bu::symbol_format << hartleys;
  180. BOOST_CHECK_EQUAL(ss.str(), "Hart");
  181. ss.str("");
  182. ss << bu::name_format << hartleys;
  183. BOOST_CHECK_EQUAL(ss.str(), "hartley");
  184. ss.str("");
  185. ss << bu::symbol_format << shannons;
  186. BOOST_CHECK_EQUAL(ss.str(), "Sh");
  187. ss.str("");
  188. ss << bu::name_format << shannons;
  189. BOOST_CHECK_EQUAL(ss.str(), "shannon");
  190. }