fork download
  1. #include <bitset>
  2. #include <cmath>
  3. #include <iomanip>
  4. #include <iostream>
  5. #include <limits>
  6. #include <type_traits>
  7.  
  8. using namespace std;
  9.  
  10. template <typename F, typename I>
  11. enable_if_t<is_floating_point<F>::value && is_unsigned<I>::value, void> func(const I n) {
  12. const auto d = static_cast<F>(n);
  13. auto msb = static_cast<I>(numeric_limits<I>::digits - 1);
  14.  
  15. while(((static_cast<I>(1) << msb) & n) == static_cast<I>(0)) {
  16. --msb;
  17. }
  18.  
  19. cout << "Original: " << n << endl << setprecision(50);
  20.  
  21. if(msb < numeric_limits<F>::digits)
  22. {
  23. cout << "*Lower bound: " << d << "\n*Upper bound: " << d << "\nPrecision loss: " << 0.0 << "\n\n";
  24. }
  25. else
  26. {
  27. const auto zero_based_lost_bits = static_cast<I>(msb - numeric_limits<F>::digits);
  28. const auto one_based_lost_bits = static_cast<I>(msb - numeric_limits<F>::digits + 1);
  29. const auto midway = static_cast<I>(1) << zero_based_lost_bits;
  30. const auto mask = static_cast<I>(1) << one_based_lost_bits;
  31. const auto lost_precision = ~(bitset<numeric_limits<F>::digits>().set().to_ullong() << one_based_lost_bits) & n;
  32.  
  33. if(midway > lost_precision || midway == lost_precision && (mask & n) == static_cast<I>(0)) {
  34. const auto f = nextafter(d, numeric_limits<F>::infinity());
  35.  
  36. cout << "*Lower bound: " << d << "\nUpper bound: " << f << "\nPrecision loss: " << lost_precision << "\n\n";
  37. } else {
  38. const auto f = nextafter(d, -numeric_limits<F>::infinity());
  39.  
  40. cout << "Lower bound: " << f << "\n*Upper bound: " << d << "\nPrecision loss: " << mask - lost_precision << "\n\n";
  41. }
  42. }
  43. }
  44.  
  45. int main()
  46. {
  47. func<double>(1ULL);
  48. func<double>(9007199254740991ULL);
  49. func<double>(18014398509481982ULL);
  50. func<double>(18014398509481983ULL);
  51. func<double>(9223372036854775295ULL);
  52. func<double>(9223372036854775296ULL);
  53. func<double>(numeric_limits<uint64_t>::max()); // Rounds up
  54. func<double>(numeric_limits<uint64_t>::max() - 2046); // Rounds down
  55. }
Success #stdin #stdout 0s 4368KB
stdin
Standard input is empty
stdout
Original:          1
*Lower bound:      1
*Upper bound:      1
Precision loss:    0

Original:          9007199254740991
*Lower bound:      9007199254740991
*Upper bound:      9007199254740991
Precision loss:    0

Original:          18014398509481982
*Lower bound:      18014398509481982
Upper bound:       18014398509481984
Precision loss:    0

Original:          18014398509481983
Lower bound:       18014398509481982
*Upper bound:      18014398509481984
Precision loss:    1

Original:          9223372036854775295
*Lower bound:      9223372036854774784
Upper bound:       9223372036854775808
Precision loss:    511

Original:          9223372036854775296
Lower bound:       9223372036854774784
*Upper bound:      9223372036854775808
Precision loss:    512

Original:          18446744073709551615
Lower bound:       18446744073709549568
*Upper bound:      18446744073709551616
Precision loss:    1

Original:          18446744073709549569
*Lower bound:      18446744073709549568
Upper bound:       18446744073709551616
Precision loss:    1