test_cpp_int_import_export.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // Copyright John Maddock 2015.
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt
  5. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #ifdef _MSC_VER
  7. #define _SCL_SECURE_NO_WARNINGS
  8. #endif
  9. #include <boost/multiprecision/cpp_int.hpp>
  10. #include <boost/algorithm/string/case_conv.hpp>
  11. #include <boost/random/mersenne_twister.hpp>
  12. #include <boost/random/uniform_int.hpp>
  13. #include "test.hpp"
  14. #include <iostream>
  15. #include <iomanip>
  16. #ifdef BOOST_MSVC
  17. #pragma warning(disable : 4127)
  18. #endif
  19. template <class T>
  20. struct unchecked_type
  21. {
  22. typedef T type;
  23. };
  24. template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
  25. struct unchecked_type<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >
  26. {
  27. typedef boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, boost::multiprecision::unchecked, Allocator>, ExpressionTemplates> type;
  28. };
  29. template <class T>
  30. T generate_random()
  31. {
  32. typedef typename unchecked_type<T>::type unchecked_T;
  33. static const unsigned limbs = std::numeric_limits<T>::is_specialized && std::numeric_limits<T>::is_bounded ? std::numeric_limits<T>::digits / std::numeric_limits<unsigned>::digits + 3 : 20;
  34. static boost::random::uniform_int_distribution<unsigned> ui(0, limbs);
  35. static boost::random::mt19937 gen;
  36. unchecked_T val = gen();
  37. unsigned lim = ui(gen);
  38. for (unsigned i = 0; i < lim; ++i)
  39. {
  40. val *= (gen.max)();
  41. val += gen();
  42. }
  43. return val;
  44. }
  45. template <class T>
  46. void test_round_trip_neg(T val, const boost::mpl::true_&)
  47. {
  48. // Try some negative values:
  49. std::vector<unsigned char> cv;
  50. T newval;
  51. val = -val;
  52. export_bits(val, std::back_inserter(cv), 8, false);
  53. import_bits(newval, cv.begin(), cv.end(), 8, false);
  54. BOOST_CHECK_EQUAL(-val, newval);
  55. }
  56. template <class T>
  57. void test_round_trip_neg(const T&, const boost::mpl::false_&)
  58. {
  59. }
  60. template <class T>
  61. void test_round_trip(T val)
  62. {
  63. std::vector<unsigned char> cv;
  64. export_bits(val, std::back_inserter(cv), 8);
  65. T newval;
  66. import_bits(newval, cv.begin(), cv.end());
  67. BOOST_CHECK_EQUAL(val, newval);
  68. // Should get the same value if we reverse the bytes:
  69. std::reverse(cv.begin(), cv.end());
  70. newval = 0;
  71. import_bits(newval, cv.begin(), cv.end(), 8, false);
  72. BOOST_CHECK_EQUAL(val, newval);
  73. // Also try importing via pointers as these may memcpy:
  74. newval = 0;
  75. import_bits(newval, &cv[0], &cv[0] + cv.size(), 8, false);
  76. BOOST_CHECK_EQUAL(val, newval);
  77. cv.clear();
  78. export_bits(val, std::back_inserter(cv), 8, false);
  79. import_bits(newval, cv.begin(), cv.end(), 8, false);
  80. BOOST_CHECK_EQUAL(val, newval);
  81. std::reverse(cv.begin(), cv.end());
  82. newval = 0;
  83. import_bits(newval, cv.begin(), cv.end(), 8, true);
  84. BOOST_CHECK_EQUAL(val, newval);
  85. std::vector<boost::uintmax_t> bv;
  86. export_bits(val, std::back_inserter(bv), std::numeric_limits<boost::uintmax_t>::digits);
  87. import_bits(newval, bv.begin(), bv.end());
  88. BOOST_CHECK_EQUAL(val, newval);
  89. // Should get the same value if we reverse the values:
  90. std::reverse(bv.begin(), bv.end());
  91. newval = 0;
  92. import_bits(newval, bv.begin(), bv.end(), std::numeric_limits<boost::uintmax_t>::digits, false);
  93. BOOST_CHECK_EQUAL(val, newval);
  94. // Also try importing via pointers as these may memcpy:
  95. newval = 0;
  96. import_bits(newval, &bv[0], &bv[0] + bv.size(), std::numeric_limits<boost::uintmax_t>::digits, false);
  97. BOOST_CHECK_EQUAL(val, newval);
  98. bv.clear();
  99. export_bits(val, std::back_inserter(bv), std::numeric_limits<boost::uintmax_t>::digits, false);
  100. import_bits(newval, bv.begin(), bv.end(), std::numeric_limits<boost::uintmax_t>::digits, false);
  101. BOOST_CHECK_EQUAL(val, newval);
  102. //
  103. // Try with an unconventional number of bits, to model some machine with guard bits:
  104. //
  105. bv.clear();
  106. export_bits(val, std::back_inserter(bv), std::numeric_limits<boost::uintmax_t>::digits - 3);
  107. import_bits(newval, bv.begin(), bv.end(), std::numeric_limits<boost::uintmax_t>::digits - 3);
  108. BOOST_CHECK_EQUAL(val, newval);
  109. bv.clear();
  110. export_bits(val, std::back_inserter(bv), std::numeric_limits<boost::uintmax_t>::digits - 3, false);
  111. import_bits(newval, bv.begin(), bv.end(), std::numeric_limits<boost::uintmax_t>::digits - 3, false);
  112. BOOST_CHECK_EQUAL(val, newval);
  113. cv.clear();
  114. export_bits(val, std::back_inserter(cv), 6);
  115. import_bits(newval, cv.begin(), cv.end(), 6);
  116. BOOST_CHECK_EQUAL(val, newval);
  117. cv.clear();
  118. export_bits(val, std::back_inserter(cv), 6, false);
  119. import_bits(newval, cv.begin(), cv.end(), 6, false);
  120. BOOST_CHECK_EQUAL(val, newval);
  121. test_round_trip_neg(val, boost::mpl::bool_<std::numeric_limits<T>::is_signed>());
  122. }
  123. template <class T>
  124. void test_round_trip()
  125. {
  126. std::cout << std::hex;
  127. std::cerr << std::hex;
  128. for (unsigned i = 0; i < 1000; ++i)
  129. {
  130. T val = generate_random<T>();
  131. test_round_trip(val);
  132. }
  133. //
  134. // Bug cases.
  135. // See https://github.com/boostorg/multiprecision/issues/21
  136. T bug(1);
  137. bug << std::numeric_limits<T>::digits - 1;
  138. --bug;
  139. test_round_trip(bug);
  140. }
  141. int main()
  142. {
  143. test_round_trip<boost::multiprecision::cpp_int>();
  144. test_round_trip<boost::multiprecision::checked_int1024_t>();
  145. test_round_trip<boost::multiprecision::checked_uint512_t>();
  146. test_round_trip<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<64, 64, boost::multiprecision::unsigned_magnitude, boost::multiprecision::checked, void> > >();
  147. test_round_trip<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<23, 23, boost::multiprecision::unsigned_magnitude, boost::multiprecision::checked, void> > >();
  148. return boost::report_errors();
  149. }