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 
10 #include <iostream>
11 #include <sstream>
12 
13 #include <boost/units/quantity.hpp>
14 #include <boost/units/conversion.hpp>
15 #include <boost/units/io.hpp>
16 
17 #include <boost/units/systems/si/prefixes.hpp>
18 #include <boost/units/systems/si/time.hpp>
19 
20 // All information systems definitions
21 #include <boost/units/systems/information.hpp>
22 
23 using std::cout;
24 using std::cerr;
25 using std::endl;
26 using std::stringstream;
27 
28 namespace bu = boost::units;
29 namespace si = boost::units::si;
30 
31 using bu::quantity;
32 
33 using bu::information::bit_base_unit;
34 using bu::information::byte_base_unit;
35 using bu::information::nat_base_unit;
36 using bu::information::hartley_base_unit;
37 using bu::information::shannon_base_unit;
38 
39 
40 #define BOOST_TEST_MAIN
41 #include <boost/test/unit_test.hpp>
42 
43 
44 #include <boost/multiprecision/cpp_int.hpp>
45 
46 const double close_fraction = 0.0000001;
47 
48 // checks that cf(u2,u1) == expected
49 // also checks invariant property that cf(u2,u1) * cf(u1,u2) == 1
50 #define CHECK_DIRECT_CF(u1, u2, expected) \
51     BOOST_CHECK_CLOSE_FRACTION(bu::conversion_factor((u2), (u1)), (expected), close_fraction); \
52     BOOST_CHECK_CLOSE_FRACTION(bu::conversion_factor((u2), (u1)) * bu::conversion_factor((u1), (u2)), 1.0, close_fraction);
53 
54 // check transitive conversion factors
55 // invariant:  cf(u1,u3) = cf(u1,u2)*cf(u2,u3)
56 #define CHECK_TRANSITIVE_CF(u1, u2, u3) { \
57     double cf12 = bu::conversion_factor((u2), (u1)) ; \
58     double cf23 = bu::conversion_factor((u3), (u2)) ; \
59     double cf13 = bu::conversion_factor((u3), (u1)) ; \
60     BOOST_CHECK_CLOSE_FRACTION(cf13, cf12*cf23, close_fraction); \
61     double cf32 = bu::conversion_factor((u2), (u3)) ; \
62     double cf21 = bu::conversion_factor((u1), (u2)) ; \
63     double cf31 = bu::conversion_factor((u1), (u3)) ; \
64     BOOST_CHECK_CLOSE_FRACTION(cf31, cf32*cf21, close_fraction); \
65 }
66 
67 
BOOST_AUTO_TEST_CASE(test_cf_bit_byte)68 BOOST_AUTO_TEST_CASE(test_cf_bit_byte) {
69     CHECK_DIRECT_CF(bit_base_unit::unit_type(), byte_base_unit::unit_type(), 8.0);
70 }
71 
BOOST_AUTO_TEST_CASE(test_cf_bit_nat)72 BOOST_AUTO_TEST_CASE(test_cf_bit_nat) {
73     CHECK_DIRECT_CF(bit_base_unit::unit_type(), nat_base_unit::unit_type(), 1.442695040888964);
74 }
75 
BOOST_AUTO_TEST_CASE(test_cf_bit_hartley)76 BOOST_AUTO_TEST_CASE(test_cf_bit_hartley) {
77     CHECK_DIRECT_CF(bit_base_unit::unit_type(), hartley_base_unit::unit_type(), 3.321928094887363);
78 }
79 
BOOST_AUTO_TEST_CASE(test_cf_bit_shannon)80 BOOST_AUTO_TEST_CASE(test_cf_bit_shannon) {
81     CHECK_DIRECT_CF(bit_base_unit::unit_type(), shannon_base_unit::unit_type(), 1.0);
82 }
83 
84 /////////////////////////////////////////////////////////////////////////////////////
85 // spot-check that these are automatically transitive, thru central "hub unit" bit:
86 // basic pattern is to test invariant property:  cf(c,a) = cf(c,b)*cf(b,a)
87 
BOOST_AUTO_TEST_CASE(test_transitive_byte_nat)88 BOOST_AUTO_TEST_CASE(test_transitive_byte_nat) {
89     CHECK_TRANSITIVE_CF(byte_base_unit::unit_type(), bit_base_unit::unit_type(), nat_base_unit::unit_type());
90 }
BOOST_AUTO_TEST_CASE(test_transitive_nat_hartley)91 BOOST_AUTO_TEST_CASE(test_transitive_nat_hartley) {
92     CHECK_TRANSITIVE_CF(nat_base_unit::unit_type(), bit_base_unit::unit_type(), hartley_base_unit::unit_type());
93 }
BOOST_AUTO_TEST_CASE(test_transitive_hartley_shannon)94 BOOST_AUTO_TEST_CASE(test_transitive_hartley_shannon) {
95     CHECK_TRANSITIVE_CF(hartley_base_unit::unit_type(), bit_base_unit::unit_type(), shannon_base_unit::unit_type());
96 }
BOOST_AUTO_TEST_CASE(test_transitive_shannon_byte)97 BOOST_AUTO_TEST_CASE(test_transitive_shannon_byte) {
98     CHECK_TRANSITIVE_CF(shannon_base_unit::unit_type(), bit_base_unit::unit_type(), byte_base_unit::unit_type());
99 }
100 
101 // test transitive factors, none of which are bit, just for good measure
BOOST_AUTO_TEST_CASE(test_transitive_byte_nat_hartley)102 BOOST_AUTO_TEST_CASE(test_transitive_byte_nat_hartley) {
103     CHECK_TRANSITIVE_CF(byte_base_unit::unit_type(), nat_base_unit::unit_type(), hartley_base_unit::unit_type());
104 }
105 
BOOST_AUTO_TEST_CASE(test_byte_quantity_is_default)106 BOOST_AUTO_TEST_CASE(test_byte_quantity_is_default) {
107     using namespace bu::information;
108     quantity<info, double> qd(2 * byte);
109     BOOST_CHECK_EQUAL(qd.value(), double(2));
110     quantity<info, long> ql(2 * byte);
111     BOOST_CHECK_EQUAL(ql.value(), long(2));
112 }
113 
BOOST_AUTO_TEST_CASE(test_byte_quantity_explicit)114 BOOST_AUTO_TEST_CASE(test_byte_quantity_explicit) {
115     using namespace bu::information;
116     quantity<hu::byte::info, double> qd(2 * byte);
117     BOOST_CHECK_EQUAL(qd.value(), double(2));
118     quantity<hu::byte::info, long> ql(2 * byte);
119     BOOST_CHECK_EQUAL(ql.value(), long(2));
120 }
121 
BOOST_AUTO_TEST_CASE(test_bit_quantity)122 BOOST_AUTO_TEST_CASE(test_bit_quantity) {
123     using namespace bu::information;
124     quantity<hu::bit::info, double> qd(2 * bit);
125     BOOST_CHECK_EQUAL(qd.value(), double(2));
126     quantity<hu::bit::info, long> ql(2 * bit);
127     BOOST_CHECK_EQUAL(ql.value(), long(2));
128 }
129 
BOOST_AUTO_TEST_CASE(test_nat_quantity)130 BOOST_AUTO_TEST_CASE(test_nat_quantity) {
131     using namespace bu::information;
132     quantity<hu::nat::info, double> qd(2 * nat);
133     BOOST_CHECK_EQUAL(qd.value(), double(2));
134     quantity<hu::nat::info, long> ql(2 * nat);
135     BOOST_CHECK_EQUAL(ql.value(), long(2));
136 }
137 
BOOST_AUTO_TEST_CASE(test_hartley_quantity)138 BOOST_AUTO_TEST_CASE(test_hartley_quantity) {
139     using namespace bu::information;
140     quantity<hu::hartley::info, double> qd(2 * hartley);
141     BOOST_CHECK_EQUAL(qd.value(), double(2));
142     quantity<hu::hartley::info, long> ql(2 * hartley);
143     BOOST_CHECK_EQUAL(ql.value(), long(2));
144 }
145 
BOOST_AUTO_TEST_CASE(test_shannon_quantity)146 BOOST_AUTO_TEST_CASE(test_shannon_quantity) {
147     using namespace bu::information;
148     quantity<hu::shannon::info, double> qd(2 * shannon);
149     BOOST_CHECK_EQUAL(qd.value(), double(2));
150     quantity<hu::shannon::info, long> ql(2 * shannon);
151     BOOST_CHECK_EQUAL(ql.value(), long(2));
152 }
153 
BOOST_AUTO_TEST_CASE(test_mixed_hu)154 BOOST_AUTO_TEST_CASE(test_mixed_hu) {
155     using namespace bu::information;
156     const double cf = 0.001;
157     BOOST_CHECK_CLOSE_FRACTION((quantity<hu::bit::info>(1.0 * bits)).value(), 1.0, cf);
158     BOOST_CHECK_CLOSE_FRACTION((quantity<hu::byte::info>(1.0 * bits)).value(), 1.0/8.0, cf);
159     BOOST_CHECK_CLOSE_FRACTION((quantity<hu::nat::info>(1.0 * bits)).value(), 0.69315, cf);
160     BOOST_CHECK_CLOSE_FRACTION((quantity<hu::hartley::info>(1.0 * bits)).value(), 0.30102, cf);
161     BOOST_CHECK_CLOSE_FRACTION((quantity<hu::shannon::info>(1.0 * bits)).value(), 1.0, cf);
162 }
163 
BOOST_AUTO_TEST_CASE(test_info_prefixes)164 BOOST_AUTO_TEST_CASE(test_info_prefixes) {
165     using namespace bu::information;
166     quantity<info, long long> q10(1LL * kibi * byte);
167     BOOST_CHECK_EQUAL(q10.value(), 1024LL);
168 
169     quantity<info, long long> q20(1LL * mebi * byte);
170     BOOST_CHECK_EQUAL(q20.value(), 1048576LL);
171 
172     quantity<info, long long> q30(1LL * gibi * byte);
173     BOOST_CHECK_EQUAL(q30.value(), 1073741824LL);
174 
175     quantity<info, long long> q40(1LL * tebi * byte);
176     BOOST_CHECK_EQUAL(q40.value(), 1099511627776LL);
177 
178     quantity<info, long long> q50(1LL * pebi * byte);
179     BOOST_CHECK_EQUAL(q50.value(), 1125899906842624LL);
180 
181     quantity<info, long long> q60(1LL * exbi * byte);
182     BOOST_CHECK_EQUAL(q60.value(), 1152921504606846976LL);
183 
184     using boost::multiprecision::int128_t;
185 
186     quantity<info, int128_t> q70(1LL * zebi * byte);
187     BOOST_CHECK_EQUAL(q70.value(), int128_t("1180591620717411303424"));
188 
189     quantity<info, int128_t> q80(1LL * yobi * byte);
190     BOOST_CHECK_EQUAL(q80.value(), int128_t("1208925819614629174706176"));
191 
192     // sanity check: si prefixes should also operate
193     quantity<info, long long> q1e3(1LL * si::kilo * byte);
194     BOOST_CHECK_EQUAL(q1e3.value(), 1000LL);
195 
196     quantity<info, long long> q1e6(1LL * si::mega * byte);
197     BOOST_CHECK_EQUAL(q1e6.value(), 1000000LL);
198 }
199 
BOOST_AUTO_TEST_CASE(test_unit_constant_io)200 BOOST_AUTO_TEST_CASE(test_unit_constant_io) {
201     using namespace bu::information;
202 
203     std::stringstream ss;
204     ss << bu::symbol_format << bytes;
205     BOOST_CHECK_EQUAL(ss.str(), "B");
206 
207     ss.str("");
208     ss << bu::name_format << bytes;
209     BOOST_CHECK_EQUAL(ss.str(), "byte");
210 
211     ss.str("");
212     ss << bu::symbol_format << bits;
213     BOOST_CHECK_EQUAL(ss.str(), "b");
214 
215     ss.str("");
216     ss << bu::name_format << bits;
217     BOOST_CHECK_EQUAL(ss.str(), "bit");
218 
219     ss.str("");
220     ss << bu::symbol_format << nats;
221     BOOST_CHECK_EQUAL(ss.str(), "nat");
222 
223     ss.str("");
224     ss << bu::name_format << nats;
225     BOOST_CHECK_EQUAL(ss.str(), "nat");
226 
227     ss.str("");
228     ss << bu::symbol_format << hartleys;
229     BOOST_CHECK_EQUAL(ss.str(), "Hart");
230 
231     ss.str("");
232     ss << bu::name_format << hartleys;
233     BOOST_CHECK_EQUAL(ss.str(), "hartley");
234 
235     ss.str("");
236     ss << bu::symbol_format << shannons;
237     BOOST_CHECK_EQUAL(ss.str(), "Sh");
238 
239     ss.str("");
240     ss << bu::name_format << shannons;
241     BOOST_CHECK_EQUAL(ss.str(), "shannon");
242 }
243