Implement, test, float and double endian types.

This commit is contained in:
Beman
2013-05-25 12:16:32 -04:00
parent f8f8d90b1f
commit a7ba65f830
4 changed files with 187 additions and 7 deletions

View File

@ -177,6 +177,129 @@ application.</p>
</tr>
</table>
<h2>Timing tests</h2>
<p>These tests were run against release builds on a circa 2012 4-core little endian X64 Intel Core i5-3570K
CPU @ 3.40GHz under Windows 7.</p>
<p>See <a href="../test/speed_test.cpp">speed_test.cpp</a>,
<a href="../test/speed_test_functions.hpp">speed_test_functions.hpp</a>,
<a href="../test/speed_test_functions.cpp">speed_test_functions.cpp</a>, and
<a href="../build/Jamfile.v2">Jamfile.v2</a> for the actual code and build. The timed functions are in a separate
compilation unit to prevent being optimized away.</p>
<p>Because the timings are anomalous, particularly for those high-lighted below
in yellow, the generated code from the GNU compiler was studied in detail. <b>
Exactly the same code is being generated for by-value conversion functions,
in-place conversion functions, and the endian types. Exactly the same code is
being generated whether intrinsics are used or not for 32 and 64-bit tests.</b>
(For GCC 4.7, there are no 16-bit intrinsics, so they are emulated by using
32-bit intrinsics.)</p>
<table border="1" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
<tr>
<td bgcolor="#D7EEFF">
<p align="center"><b>Conclusions</b></p>
<p>The decision to use endian types or endian conversion functions should be
made based on application use cases, not assumptions about generated code
efficiency. Modern optimizers generate the same code for either approach,
and whether or not intrinsics are available.&nbsp; </td>
</tr>
</table>
<table border="1" cellpadding="5" cellspacing="0"style="border-collapse: collapse" bordercolor="#111111">
<tr><td colspan="6" align="center"><b>GNU g++ version 4.7.0</b></td></tr>
<tr><td colspan="6" align="center"><b> Iterations: 1,000,000,000, Intrinsics: __builtin_bswap16, etc.</b></td></tr>
<tr><td><b>Test Case</b></td>
<td align="center"><b>int<br>arg</b></td>
<td align="center"><b>int<br>value(arg)</b></td>
<td align="center"><b>int<br>in place(arg)</b></td>
<td align="center"><b>Endian<br>arg</b></td>
</tr>
<tr><td>16-bit aligned big endian</td><td align="right" bgcolor="#FFFFCC">2.71 s</td>
<td align="right">2.42 s</td><td align="right">2.42 s</td><td align="right">2.68 s</td></tr>
<tr><td>16-bit aligned little endian</td><td align="right">2.42 s</td>
<td align="right">2.40 s</td><td align="right">2.68 s</td><td align="right">2.45 s</td></tr>
<tr><td>32-bit aligned big endian</td><td align="right">2.68 s</td>
<td align="right">2.70 s</td><td align="right">2.70 s</td><td align="right">2.68 s</td></tr>
<tr><td>32-bit aligned little endian</td><td align="right">2.68 s</td>
<td align="right">2.68 s</td><td align="right">2.65 s</td><td align="right">2.68 s</td></tr>
<tr><td>64-bit aligned big endian</td><td align="right" bgcolor="#FFFFCC">2.96 s</td>
<td align="right" bgcolor="#FFFFCC">2.95 s</td>
<td align="right" bgcolor="#FFFFCC">2.95 s</td>
<td align="right" bgcolor="#FFFFCC">2.95 s</td></tr>
<tr><td>64-bit aligned little endian</td><td align="right">2.42 s</td>
<td align="right">2.40 s</td><td align="right">2.70 s</td><td align="right">2.42 s</td></tr>
<tr><td colspan="6" align="center"><b> Iterations: 1,000,000,000, Intrinsics: no byte swap intrinsics</b></td></tr>
<tr><td><b>Test Case</b></td>
<td align="center"><b>int<br>arg</b></td>
<td align="center"><b>int<br>value(arg)</b></td>
<td align="center"><b>int<br>in place(arg)</b></td>
<td align="center"><b>Endian<br>arg</b></td>
</tr>
<tr><td>16-bit aligned big endian</td><td align="right" bgcolor="#FFFFCC">2.71 s</td>
<td align="right">2.42 s</td><td align="right">2.42 s</td><td align="right">2.68 s</td></tr>
<tr><td>16-bit aligned little endian</td><td align="right">2.42 s</td>
<td align="right">2.40 s</td><td align="right">2.68 s</td><td align="right">2.42 s</td></tr>
<tr><td>32-bit aligned big endian</td><td align="right">2.68 s</td>
<td align="right">2.70 s</td><td align="right">2.67 s</td><td align="right">2.70 s</td></tr>
<tr><td>32-bit aligned little endian</td><td align="right">2.68 s</td>
<td align="right">2.67 s</td><td align="right">2.70 s</td><td align="right">2.67 s</td></tr>
<tr><td>64-bit aligned big endian</td><td align="right" bgcolor="#FFFFCC">2.96 s</td>
<td align="right" bgcolor="#FFFFCC">2.95 s</td>
<td align="right" bgcolor="#FFFFCC">2.95 s</td>
<td align="right" bgcolor="#FFFFCC">2.93 s</td></tr>
<tr><td>64-bit aligned little endian</td><td align="right">2.42 s</td>
<td align="right">2.42 s</td><td align="right">2.67 s</td><td align="right">2.40 s</td></tr>
</table>
<p></p>
<table border="1" cellpadding="5" cellspacing="0"style="border-collapse: collapse" bordercolor="#111111">
<tr><td colspan="6" align="center"><b>Microsoft Visual C++ version 11.0</b></td></tr>
<tr><td colspan="6" align="center"><b> Iterations: 1,000,000,000, Intrinsics: cstdlib _byteswap_ushort, etc.</b></td></tr>
<tr><td><b>Test Case</b></td>
<td align="center"><b>int<br>arg</b></td>
<td align="center"><b>int<br>value(arg)</b></td>
<td align="center"><b>int<br>in place(arg)</b></td>
<td align="center"><b>Endian<br>arg</b></td>
</tr>
<tr><td>16-bit aligned big endian</td><td align="right">1.90 s</td>
<td align="right">1.87 s</td><td align="right">1.89 s</td><td align="right">1.87 s</td></tr>
<tr><td>16-bit aligned little endian</td><td align="right">1.89 s</td>
<td align="right">1.87 s</td><td align="right">1.89 s</td><td align="right">1.87 s</td></tr>
<tr><td>32-bit aligned big endian</td><td align="right">1.89 s</td>
<td align="right">1.87 s</td><td align="right">1.89 s</td><td align="right">1.87 s</td></tr>
<tr><td>32-bit aligned little endian</td><td align="right">1.89 s</td>
<td align="right">1.87 s</td><td align="right">1.87 s</td><td align="right">1.89 s</td></tr>
<tr><td>64-bit aligned big endian</td><td align="right">1.87 s</td>
<td align="right">1.89 s</td><td align="right">1.87 s</td><td align="right">1.89 s</td></tr>
<tr><td>64-bit aligned little endian</td><td align="right">1.87 s</td>
<td align="right">1.87 s</td><td align="right">1.87 s</td><td align="right">1.89 s</td></tr>
<tr><td colspan="6" align="center"><b> Iterations: 1,000,000,000, Intrinsics: no byte swap intrinsics</b></td></tr>
<tr><td><b>Test Case</b></td>
<td align="center"><b>int<br>arg</b></td>
<td align="center"><b>int<br>value(arg)</b></td>
<td align="center"><b>int<br>in place(arg)</b></td>
<td align="center"><b>Endian<br>arg</b></td>
</tr>
<tr><td>16-bit aligned big endian</td><td align="right">1.90 s</td>
<td align="right">1.89 s</td><td align="right">1.87 s</td><td align="right">1.87 s</td></tr>
<tr><td>16-bit aligned little endian</td><td align="right">1.89 s</td>
<td align="right">1.87 s</td><td align="right">1.89 s</td><td align="right">1.87 s</td></tr>
<tr><td>32-bit aligned big endian</td><td align="right">1.89 s</td>
<td align="right">1.87 s</td><td align="right">1.87 s</td><td align="right">1.89 s</td></tr>
<tr><td>32-bit aligned little endian</td><td align="right">1.87 s</td>
<td align="right">1.89 s</td><td align="right">1.87 s</td><td align="right">1.89 s</td></tr>
<tr><td>64-bit aligned big endian</td><td align="right" bgcolor="#FFFFCC">2.32 s</td>
<td align="right" bgcolor="#FFFFCC">2.46 s</td>
<td align="right" bgcolor="#FFFFCC">2.45 s</td>
<td align="right" bgcolor="#FFFFCC">2.34 s</td></tr>
<tr><td>64-bit aligned little endian</td><td align="right">1.87 s</td>
<td align="right">1.87 s</td><td align="right">1.89 s</td><td align="right">1.87 s</td></tr>
</table>
<h2>Overall <a name="FAQ">FAQ</a></h2>
<p><b>Why bother with endianness?</b></p>
<blockquote>
@ -226,7 +349,7 @@ Tim Blechmann, Tim Moore, tymofey, Tomas Puverle, Vincente Botet, Yuval Ronen
and Vitaly Budovski,.</p>
<hr>
<p>Last revised:
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->22 May, 2013<!--webbot bot="Timestamp" endspan i-checksum="13980" --></p>
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->25 May, 2013<!--webbot bot="Timestamp" endspan i-checksum="13986" --></p>
<p><EFBFBD> Copyright Beman Dawes, 2011, 2013</p>
<p>Distributed under the Boost Software License, Version 1.0. See
<a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/ LICENSE_1_0.txt</a></p>

View File

@ -80,6 +80,14 @@ namespace endian
BOOST_SCOPED_ENUM(align) A = align::no>
class endian;
// aligned big endian floating point types
typedef boost::endian::endian<order::big, float, 32, align::yes> big_float32_t;
typedef boost::endian::endian<order::big, double, 64, align::yes> big_float64_t;
// aligned little endian floating point types
typedef boost::endian::endian<order::little, float, 32, align::yes> little_float32_t;
typedef boost::endian::endian<order::little, double, 64, align::yes> little_float64_t;
// aligned big endian signed integer types
typedef endian<order::big, int16_t, 16, align::yes> big_int16_t;
typedef endian<order::big, int32_t, 32, align::yes> big_int32_t;

View File

@ -223,6 +223,17 @@ namespace
little_uint32_t little_uint32 ;
little_uint64_t little_uint64 ;
big_float32_t big_float32;
big_float64_t big_float64;
little_float32_t little_float32;
little_float64_t little_float64;
VERIFY(big_float32.data() == reinterpret_cast<const char *>(&big_float32));
VERIFY(big_float64.data() == reinterpret_cast<const char *>(&big_float64));
VERIFY(little_float32.data() == reinterpret_cast<const char *>(&little_float32));
VERIFY(little_float64.data() == reinterpret_cast<const char *>(&little_float64));
VERIFY(big_8.data() == reinterpret_cast<const char *>(&big_8));
VERIFY(big_16.data() == reinterpret_cast<const char *>(&big_16));
VERIFY(big_24.data() == reinterpret_cast<const char *>(&big_24));
@ -302,6 +313,11 @@ namespace
VERIFY( numeric_limits<signed char>::digits == 7 );
VERIFY( numeric_limits<unsigned char>::digits == 8 );
VERIFY_SIZE(sizeof( big_float32_t ), 4 );
VERIFY_SIZE(sizeof( big_float64_t ), 8 );
VERIFY_SIZE(sizeof( little_float32_t ), 4 );
VERIFY_SIZE(sizeof( little_float64_t ), 8 );
VERIFY_SIZE( sizeof( big_8_t ), 1 );
VERIFY_SIZE( sizeof( big_16_t ), 2 );
VERIFY_SIZE( sizeof( big_24_t ), 3 );
@ -510,6 +526,39 @@ namespace
void check_representation_and_range_and_ops()
{
float big_float32_expected = std::numeric_limits<float>::max();
boost::endian::big_endian(big_float32_expected);
big_float32_t big_float32(std::numeric_limits<float>::max());
VERIFY(std::memcmp(big_float32.data(),
reinterpret_cast<const char*>(&big_float32_expected), sizeof(float)) == 0);
float little_float32_expected = std::numeric_limits<float>::max();
boost::endian::little_endian(little_float32_expected);
little_float32_t little_float32(std::numeric_limits<float>::max());
VERIFY(std::memcmp(little_float32.data(),
reinterpret_cast<const char*>(&little_float32_expected), sizeof(float)) == 0);
double big_float64_expected = std::numeric_limits<double>::max();
boost::endian::big_endian(big_float64_expected);
big_float64_t big_float64(std::numeric_limits<double>::max());
VERIFY(std::memcmp(big_float64.data(),
reinterpret_cast<const char*>(&big_float64_expected), sizeof(double)) == 0);
double little_float64_expected = std::numeric_limits<double>::max();
boost::endian::little_endian(little_float64_expected);
little_float64_t little_float64(std::numeric_limits<double>::max());
VERIFY(std::memcmp(little_float64.data(),
reinterpret_cast<const char*>(&little_float64_expected), sizeof(double)) == 0);
VERIFY_VALUE_AND_OPS( big_float32_t, float, std::numeric_limits<float>::max() );
VERIFY_VALUE_AND_OPS( big_float32_t, float, std::numeric_limits<float>::min() );
VERIFY_VALUE_AND_OPS( big_float64_t, double, std::numeric_limits<double>::max() );
VERIFY_VALUE_AND_OPS( big_float64_t, double, std::numeric_limits<double>::min() );
VERIFY_VALUE_AND_OPS( little_float32_t, float, std::numeric_limits<float>::max() );
VERIFY_VALUE_AND_OPS( little_float32_t, float, std::numeric_limits<float>::min() );
VERIFY_VALUE_AND_OPS( little_float64_t, double, std::numeric_limits<double>::max() );
VERIFY_VALUE_AND_OPS( little_float64_t, double, std::numeric_limits<double>::min() );
VERIFY_BIG_REPRESENTATION( big_8_t );
VERIFY_VALUE_AND_OPS( big_8_t, int_least8_t, 0x7f );

View File

@ -7,7 +7,7 @@
//--------------------------------------------------------------------------------------//
//#define BOOST_ENDIAN_NO_INTRINSICS
#define BOOST_ENDIAN_NO_INTRINSICS
//#define BOOST_ENDIAN_LOG
#include <boost/endian/detail/disable_warnings.hpp>
@ -91,7 +91,7 @@ namespace
f(x, y);
}
t.stop();
cout << "<td>" << t.format(places, "%t") << " s</td>";
cout << "<td align=\"right\">" << t.format(places, "%t") << " s</td>";
}
void test_big_int16()
@ -173,10 +173,10 @@ int cpp_main(int argc, char* argv[])
<< ", Intrinsics: " BOOST_ENDIAN_INTRINSIC_MSG
<< "</b></td></tr>\n"
<< "<tr><td><b>Test Case</b></td>\n"
"<td><b>int<br>arg</b></td>\n"
"<td><b>int<br>value(arg)</b></td>\n"
"<td><b>int<br>in place(arg)</b></td>\n"
"<td><b>Endian<br>arg</b></td>\n"
"<td align=\"center\"><b>int<br>arg</b></td>\n"
"<td align=\"center\"><b>int<br>value(arg)</b></td>\n"
"<td align=\"center\"><b>int<br>in place(arg)</b></td>\n"
"<td align=\"center\"><b>Endian<br>arg</b></td>\n"
"</tr>\n"
;