123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- // Copyright 2018 John Maddock. Distributed under the Boost
- // Software License, Version 1.0. (See accompanying file
- // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- #include <boost/multiprecision/cpp_bin_float.hpp>
- #include <boost/math/special_functions.hpp>
- #include <boost/chrono.hpp>
- #include <boost/random/mersenne_twister.hpp>
- #include <boost/random/uniform_int.hpp>
- template <class Clock>
- struct stopwatch
- {
- typedef typename Clock::duration duration;
- stopwatch()
- {
- m_start = Clock::now();
- }
- duration elapsed()
- {
- return Clock::now() - m_start;
- }
- void reset()
- {
- m_start = Clock::now();
- }
- private:
- typename Clock::time_point m_start;
- };
- template <class T>
- T generate_random()
- {
- typedef int e_type;
- static boost::random::mt19937 gen;
- T val = gen();
- T prev_val = -1;
- while (val != prev_val)
- {
- val *= (gen.max)();
- prev_val = val;
- val += gen();
- }
- e_type e;
- val = frexp(val, &e);
- static boost::random::uniform_int_distribution<e_type> ui(-20, 20);
- return ldexp(val, ui(gen));
- }
- template <typename T>
- double my_convert_to_double(const T& x)
- {
- double ret = 0;
- if (isfinite(x))
- {
- if (x.backend().exponent() >= -1023 - 52 && x != 0)
- {
- if (x.backend().exponent() <= 1023)
- {
- int e = x.backend().exponent();
- T y = ldexp(abs(x), 55 - e);
- T t = trunc(y);
- int64_t ti = t.template convert_to<int64_t>();
- if ((ti & 1) == 0)
- {
- if (t < y)
- ti |= 1;
- }
- if (e >= -1023 + 1)
- {
- ret = ldexp(double(ti), e - 55);
- }
- else
- {
- // subnormal
- typedef boost::multiprecision::number<boost::multiprecision::cpp_bin_float<128, boost::multiprecision::backends::digit_base_2> > cpp_bin_float128_t;
- cpp_bin_float128_t sx = ldexp(cpp_bin_float128_t(ti), e - 55);
- sx += DBL_MIN;
- e = -1023 + 1;
- cpp_bin_float128_t sy = ldexp(sx, 55 - e);
- cpp_bin_float128_t st = trunc(sy);
- ti = st.convert_to<int64_t>();
- if ((ti & 1) == 0)
- {
- if (st < sy)
- ti |= 1;
- }
- ret = ldexp(double(ti), e - 55) - DBL_MIN;
- }
- }
- else
- {
- // overflow
- ret = HUGE_VAL;
- }
- }
- }
- else
- {
- if (isnan(x))
- return nan("");
- // inf
- ret = HUGE_VAL;
- }
- return x.backend().sign() ? -ret : ret;
- }
- template <class T>
- void test_conversion_time(const char* name)
- {
- std::cout << "Testing times for type: " << name << "\n";
- std::vector<T> values;
- for (unsigned i = 0; i < 10000000; ++i)
- {
- values.push_back(generate_random<T>());
- }
- boost::chrono::duration<double> time;
- stopwatch<boost::chrono::high_resolution_clock> c;
- double total = 0;
- for (typename std::vector<T>::const_iterator i = values.begin(); i != values.end(); ++i)
- {
- total += my_convert_to_double(*i);
- }
- time = c.elapsed();
- std::cout << std::setprecision(3) << std::fixed;
- std::cout << "Reference time: " << std::setw(7) << std::right << time << " (total sum = " << total << ")" << std::endl;
- c.reset();
- total = 0;
- for (typename std::vector<T>::const_iterator i = values.begin(); i != values.end(); ++i)
- {
- total += i->template convert_to<double>();
- }
- time = c.elapsed();
- std::cout << "Boost time: " << std::setw(7) << std::right << time << " (total sum = " << total << ")" << std::endl;
- }
- int main()
- {
- using namespace boost::multiprecision;
- test_conversion_time<cpp_bin_float_double>("cpp_bin_float_double");
- test_conversion_time<cpp_bin_float_quad>("cpp_bin_float_quad");
- test_conversion_time<cpp_bin_float_oct>("cpp_bin_float_oct");
- test_conversion_time<cpp_bin_float_50>("cpp_bin_float_50");
- test_conversion_time<cpp_bin_float_100>("cpp_bin_float_100");
- return 0;
- }
|