From a7ba65f830cf2f44bd8c2167505c97baf38e6385 Mon Sep 17 00:00:00 2001 From: Beman Date: Sat, 25 May 2013 12:16:32 -0400 Subject: [PATCH] Implement, test, float and double endian types. --- doc/index.html | 125 ++++++++++++++++++++++++++++++++- include/boost/endian/types.hpp | 8 +++ test/endian_test.cpp | 49 +++++++++++++ test/speed_test.cpp | 12 ++-- 4 files changed, 187 insertions(+), 7 deletions(-) diff --git a/doc/index.html b/doc/index.html index bd192a5..ba1a3c7 100644 --- a/doc/index.html +++ b/doc/index.html @@ -177,6 +177,129 @@ application.

+

Timing tests

+

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.

+ +

See speed_test.cpp, +speed_test_functions.hpp, +speed_test_functions.cpp, and +Jamfile.v2 for the actual code and build. The timed functions are in a separate +compilation unit to prevent being optimized away.

+ +

Because the timings are anomalous, particularly for those high-lighted below +in yellow, the generated code from the GNU compiler was studied in detail. +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. +(For GCC 4.7, there are no 16-bit intrinsics, so they are emulated by using +32-bit intrinsics.)

+ + + + + +
+

Conclusions

+

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. 

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
GNU g++ version 4.7.0
Iterations: 1,000,000,000, Intrinsics: __builtin_bswap16, etc.
Test Caseint
arg
int
value(arg)
int
in place(arg)
Endian
arg
16-bit aligned big endian2.71 s2.42 s2.42 s2.68 s
16-bit aligned little endian2.42 s2.40 s2.68 s2.45 s
32-bit aligned big endian2.68 s2.70 s2.70 s2.68 s
32-bit aligned little endian2.68 s2.68 s2.65 s2.68 s
64-bit aligned big endian2.96 s2.95 s2.95 s2.95 s
64-bit aligned little endian2.42 s2.40 s2.70 s2.42 s
Iterations: 1,000,000,000, Intrinsics: no byte swap intrinsics
Test Caseint
arg
int
value(arg)
int
in place(arg)
Endian
arg
16-bit aligned big endian2.71 s2.42 s2.42 s2.68 s
16-bit aligned little endian2.42 s2.40 s2.68 s2.42 s
32-bit aligned big endian2.68 s2.70 s2.67 s2.70 s
32-bit aligned little endian2.68 s2.67 s2.70 s2.67 s
64-bit aligned big endian2.96 s2.95 s2.95 s2.93 s
64-bit aligned little endian2.42 s2.42 s2.67 s2.40 s
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Microsoft Visual C++ version 11.0
Iterations: 1,000,000,000, Intrinsics: cstdlib _byteswap_ushort, etc.
Test Caseint
arg
int
value(arg)
int
in place(arg)
Endian
arg
16-bit aligned big endian1.90 s1.87 s1.89 s1.87 s
16-bit aligned little endian1.89 s1.87 s1.89 s1.87 s
32-bit aligned big endian1.89 s1.87 s1.89 s1.87 s
32-bit aligned little endian1.89 s1.87 s1.87 s1.89 s
64-bit aligned big endian1.87 s1.89 s1.87 s1.89 s
64-bit aligned little endian1.87 s1.87 s1.87 s1.89 s
Iterations: 1,000,000,000, Intrinsics: no byte swap intrinsics
Test Caseint
arg
int
value(arg)
int
in place(arg)
Endian
arg
16-bit aligned big endian1.90 s1.89 s1.87 s1.87 s
16-bit aligned little endian1.89 s1.87 s1.89 s1.87 s
32-bit aligned big endian1.89 s1.87 s1.87 s1.89 s
32-bit aligned little endian1.87 s1.89 s1.87 s1.89 s
64-bit aligned big endian2.32 s2.46 s2.45 s2.34 s
64-bit aligned little endian1.87 s1.87 s1.89 s1.87 s
+ +

Overall FAQ

Why bother with endianness?

@@ -226,7 +349,7 @@ Tim Blechmann, Tim Moore, tymofey, Tomas Puverle, Vincente Botet, Yuval Ronen and Vitaly Budovski,.


Last revised: -22 May, 2013

+25 May, 2013

© Copyright Beman Dawes, 2011, 2013

Distributed under the Boost Software License, Version 1.0. See www.boost.org/ LICENSE_1_0.txt

diff --git a/include/boost/endian/types.hpp b/include/boost/endian/types.hpp index bdbd1c2..3c9d642 100644 --- a/include/boost/endian/types.hpp +++ b/include/boost/endian/types.hpp @@ -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 big_float32_t; + typedef boost::endian::endian big_float64_t; + + // aligned little endian floating point types + typedef boost::endian::endian little_float32_t; + typedef boost::endian::endian little_float64_t; + // aligned big endian signed integer types typedef endian big_int16_t; typedef endian big_int32_t; diff --git a/test/endian_test.cpp b/test/endian_test.cpp index 5688008..7307796 100644 --- a/test/endian_test.cpp +++ b/test/endian_test.cpp @@ -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(&big_float32)); + VERIFY(big_float64.data() == reinterpret_cast(&big_float64)); + + VERIFY(little_float32.data() == reinterpret_cast(&little_float32)); + VERIFY(little_float64.data() == reinterpret_cast(&little_float64)); + VERIFY(big_8.data() == reinterpret_cast(&big_8)); VERIFY(big_16.data() == reinterpret_cast(&big_16)); VERIFY(big_24.data() == reinterpret_cast(&big_24)); @@ -302,6 +313,11 @@ namespace VERIFY( numeric_limits::digits == 7 ); VERIFY( numeric_limits::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::max(); + boost::endian::big_endian(big_float32_expected); + big_float32_t big_float32(std::numeric_limits::max()); + VERIFY(std::memcmp(big_float32.data(), + reinterpret_cast(&big_float32_expected), sizeof(float)) == 0); + + float little_float32_expected = std::numeric_limits::max(); + boost::endian::little_endian(little_float32_expected); + little_float32_t little_float32(std::numeric_limits::max()); + VERIFY(std::memcmp(little_float32.data(), + reinterpret_cast(&little_float32_expected), sizeof(float)) == 0); + + double big_float64_expected = std::numeric_limits::max(); + boost::endian::big_endian(big_float64_expected); + big_float64_t big_float64(std::numeric_limits::max()); + VERIFY(std::memcmp(big_float64.data(), + reinterpret_cast(&big_float64_expected), sizeof(double)) == 0); + + double little_float64_expected = std::numeric_limits::max(); + boost::endian::little_endian(little_float64_expected); + little_float64_t little_float64(std::numeric_limits::max()); + VERIFY(std::memcmp(little_float64.data(), + reinterpret_cast(&little_float64_expected), sizeof(double)) == 0); + + VERIFY_VALUE_AND_OPS( big_float32_t, float, std::numeric_limits::max() ); + VERIFY_VALUE_AND_OPS( big_float32_t, float, std::numeric_limits::min() ); + VERIFY_VALUE_AND_OPS( big_float64_t, double, std::numeric_limits::max() ); + VERIFY_VALUE_AND_OPS( big_float64_t, double, std::numeric_limits::min() ); + + VERIFY_VALUE_AND_OPS( little_float32_t, float, std::numeric_limits::max() ); + VERIFY_VALUE_AND_OPS( little_float32_t, float, std::numeric_limits::min() ); + VERIFY_VALUE_AND_OPS( little_float64_t, double, std::numeric_limits::max() ); + VERIFY_VALUE_AND_OPS( little_float64_t, double, std::numeric_limits::min() ); VERIFY_BIG_REPRESENTATION( big_8_t ); VERIFY_VALUE_AND_OPS( big_8_t, int_least8_t, 0x7f ); diff --git a/test/speed_test.cpp b/test/speed_test.cpp index 1f630e8..b07e40a 100644 --- a/test/speed_test.cpp +++ b/test/speed_test.cpp @@ -7,7 +7,7 @@ //--------------------------------------------------------------------------------------// -//#define BOOST_ENDIAN_NO_INTRINSICS +#define BOOST_ENDIAN_NO_INTRINSICS //#define BOOST_ENDIAN_LOG #include @@ -91,7 +91,7 @@ namespace f(x, y); } t.stop(); - cout << "" << t.format(places, "%t") << " s"; + cout << "" << t.format(places, "%t") << " s"; } void test_big_int16() @@ -173,10 +173,10 @@ int cpp_main(int argc, char* argv[]) << ", Intrinsics: " BOOST_ENDIAN_INTRINSIC_MSG << "\n" << "Test Case\n" - "int
arg
\n" - "int
value(arg)
\n" - "int
in place(arg)
\n" - "Endian
arg
\n" + "int
arg
\n" + "int
value(arg)
\n" + "int
in place(arg)
\n" + "Endian
arg
\n" "\n" ;