cpp_bin_float_conversion_performance.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. // Copyright 2018 John Maddock. Distributed under the Boost
  2. // Software License, Version 1.0. (See accompanying file
  3. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  4. #include <boost/multiprecision/cpp_bin_float.hpp>
  5. #include <boost/math/special_functions.hpp>
  6. #include <boost/chrono.hpp>
  7. #include <boost/random/mersenne_twister.hpp>
  8. #include <boost/random/uniform_int.hpp>
  9. template <class Clock>
  10. struct stopwatch
  11. {
  12. typedef typename Clock::duration duration;
  13. stopwatch()
  14. {
  15. m_start = Clock::now();
  16. }
  17. duration elapsed()
  18. {
  19. return Clock::now() - m_start;
  20. }
  21. void reset()
  22. {
  23. m_start = Clock::now();
  24. }
  25. private:
  26. typename Clock::time_point m_start;
  27. };
  28. template <class T>
  29. T generate_random()
  30. {
  31. typedef int e_type;
  32. static boost::random::mt19937 gen;
  33. T val = gen();
  34. T prev_val = -1;
  35. while (val != prev_val)
  36. {
  37. val *= (gen.max)();
  38. prev_val = val;
  39. val += gen();
  40. }
  41. e_type e;
  42. val = frexp(val, &e);
  43. static boost::random::uniform_int_distribution<e_type> ui(-20, 20);
  44. return ldexp(val, ui(gen));
  45. }
  46. template <typename T>
  47. double my_convert_to_double(const T& x)
  48. {
  49. double ret = 0;
  50. if (isfinite(x))
  51. {
  52. if (x.backend().exponent() >= -1023 - 52 && x != 0)
  53. {
  54. if (x.backend().exponent() <= 1023)
  55. {
  56. int e = x.backend().exponent();
  57. T y = ldexp(abs(x), 55 - e);
  58. T t = trunc(y);
  59. int64_t ti = t.template convert_to<int64_t>();
  60. if ((ti & 1) == 0)
  61. {
  62. if (t < y)
  63. ti |= 1;
  64. }
  65. if (e >= -1023 + 1)
  66. {
  67. ret = ldexp(double(ti), e - 55);
  68. }
  69. else
  70. {
  71. // subnormal
  72. typedef boost::multiprecision::number<boost::multiprecision::cpp_bin_float<128, boost::multiprecision::backends::digit_base_2> > cpp_bin_float128_t;
  73. cpp_bin_float128_t sx = ldexp(cpp_bin_float128_t(ti), e - 55);
  74. sx += DBL_MIN;
  75. e = -1023 + 1;
  76. cpp_bin_float128_t sy = ldexp(sx, 55 - e);
  77. cpp_bin_float128_t st = trunc(sy);
  78. ti = st.convert_to<int64_t>();
  79. if ((ti & 1) == 0)
  80. {
  81. if (st < sy)
  82. ti |= 1;
  83. }
  84. ret = ldexp(double(ti), e - 55) - DBL_MIN;
  85. }
  86. }
  87. else
  88. {
  89. // overflow
  90. ret = HUGE_VAL;
  91. }
  92. }
  93. }
  94. else
  95. {
  96. if (isnan(x))
  97. return nan("");
  98. // inf
  99. ret = HUGE_VAL;
  100. }
  101. return x.backend().sign() ? -ret : ret;
  102. }
  103. template <class T>
  104. void test_conversion_time(const char* name)
  105. {
  106. std::cout << "Testing times for type: " << name << "\n";
  107. std::vector<T> values;
  108. for (unsigned i = 0; i < 10000000; ++i)
  109. {
  110. values.push_back(generate_random<T>());
  111. }
  112. boost::chrono::duration<double> time;
  113. stopwatch<boost::chrono::high_resolution_clock> c;
  114. double total = 0;
  115. for (typename std::vector<T>::const_iterator i = values.begin(); i != values.end(); ++i)
  116. {
  117. total += my_convert_to_double(*i);
  118. }
  119. time = c.elapsed();
  120. std::cout << std::setprecision(3) << std::fixed;
  121. std::cout << "Reference time: " << std::setw(7) << std::right << time << " (total sum = " << total << ")" << std::endl;
  122. c.reset();
  123. total = 0;
  124. for (typename std::vector<T>::const_iterator i = values.begin(); i != values.end(); ++i)
  125. {
  126. total += i->template convert_to<double>();
  127. }
  128. time = c.elapsed();
  129. std::cout << "Boost time: " << std::setw(7) << std::right << time << " (total sum = " << total << ")" << std::endl;
  130. }
  131. int main()
  132. {
  133. using namespace boost::multiprecision;
  134. test_conversion_time<cpp_bin_float_double>("cpp_bin_float_double");
  135. test_conversion_time<cpp_bin_float_quad>("cpp_bin_float_quad");
  136. test_conversion_time<cpp_bin_float_oct>("cpp_bin_float_oct");
  137. test_conversion_time<cpp_bin_float_50>("cpp_bin_float_50");
  138. test_conversion_time<cpp_bin_float_100>("cpp_bin_float_100");
  139. return 0;
  140. }