Advertisement
Guest User

Untitled

a guest
Nov 20th, 2015
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.76 KB | None | 0 0
  1. #include <chrono>
  2. #include <cstdlib>
  3. #include <limits>
  4. #include <type_traits>
  5.  
  6. #include <assert.h>
  7. #include <stdint.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <time.h>
  11.  
  12. // ** Broken **
  13. // template <typename T>
  14. // T SaturatingMultiply1(T X, T Y) {
  15. //   // Hacker's Delight, p. 30
  16. //   T Z = X * Y;
  17. //   if (Y != 0 && Z / Y != X)
  18. //     return std::numeric_limits<T>::max();
  19. //   else
  20. //     return Z;
  21. // }
  22.  
  23. template <typename T>
  24. T SaturatingMultiply2(T X, T Y) {
  25.   const T Max = std::numeric_limits<T>::max();
  26.   if (Y != 0 && X >= Max / Y) {
  27.     return Max;
  28.   } else {
  29.     return X * Y;
  30.   }
  31. }
  32.  
  33. template <typename T>
  34. T SaturatingAdd(T X, T Y) {
  35.   // Hacker's Delight, p. 29
  36.   T Z = X + Y;
  37.   if (Z < X || Z < Y)
  38.     return std::numeric_limits<T>::max();
  39.   else
  40.     return Z;
  41. }
  42.  
  43. enum ZeroBehavior {
  44.   /// \brief The returned value is undefined.
  45.   ZB_Undefined,
  46.   /// \brief The returned value is numeric_limits<T>::max()
  47.   ZB_Max,
  48.   /// \brief The returned value is numeric_limits<T>::digits
  49.   ZB_Width
  50. };
  51.  
  52. namespace detail {
  53. template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter {
  54.   static std::size_t count(T Val, ZeroBehavior) {
  55.     if (!Val)
  56.       return std::numeric_limits<T>::digits;
  57.  
  58.     // Bisection method.
  59.     std::size_t ZeroBits = 0;
  60.     for (T Shift = std::numeric_limits<T>::digits >> 1; Shift; Shift >>= 1) {
  61.       T Tmp = Val >> Shift;
  62.       if (Tmp)
  63.         Val = Tmp;
  64.       else
  65.         ZeroBits |= Shift;
  66.     }
  67.     return ZeroBits;
  68.   }
  69. };
  70.  
  71. #if __GNUC__ >= 4 || defined(_MSC_VER)
  72. template <typename T> struct LeadingZerosCounter<T, 4> {
  73.   static std::size_t count(T Val, ZeroBehavior ZB) {
  74.     if (ZB != ZB_Undefined && Val == 0)
  75.       return 32;
  76.  
  77. #if __has_builtin(__builtin_clz)
  78.    
  79. #elif defined(_MSC_VER)
  80.     unsigned long Index;
  81.     _BitScanReverse(&Index, Val);
  82.     return Index ^ 31;
  83. #endif
  84.   }
  85. };
  86.  
  87. #if !defined(_MSC_VER)
  88. template <typename T> struct LeadingZerosCounter<T, 8> {
  89.   static std::size_t count(T Val, ZeroBehavior ZB) {
  90.     if (ZB != ZB_Undefined && Val == 0)
  91.       return 64;
  92.  
  93. #if __has_builtin(__builtin_clzll)
  94.     return __builtin_clzll(Val);
  95. #elif defined(_MSC_VER)
  96.     unsigned long Index;
  97.     _BitScanReverse64(&Index, Val);
  98.     return Index ^ 63;
  99. #endif
  100.   }
  101. };
  102. #endif
  103. #endif
  104. } // namespace detail
  105.  
  106. template <typename T>
  107. std::size_t countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
  108.   static_assert(std::numeric_limits<T>::is_integer &&
  109.                     !std::numeric_limits<T>::is_signed,
  110.                 "Only unsigned integral types are allowed.");
  111.   return detail::LeadingZerosCounter<T, sizeof(T)>::count(Val, ZB);
  112. }
  113.  
  114. /// Log2_64 - This function returns the floor log base 2 of the specified value,
  115. /// -1 if the value is zero. (64 bit edition.)
  116. inline unsigned Log2_64(uint64_t Value) {
  117.   return 63 - countLeadingZeros(Value);
  118. }
  119.  
  120. template <typename T>
  121. T SaturatingMultiply3(T X, T Y) {
  122.   // Hacker's Delight, p. 30 has a different algorithm, but
  123.   // we don't use that because it fails for uint16_t (where
  124.   // multiplcation can have UB due to promotion to int), and
  125.   // requires a division in addition to the multiplication.
  126.  
  127.   // Log2(Z) would be either Log2Z or Log2Z + 1.
  128.   // Special case: if X or Y is 0, Log2_64 gives -1, and Log2Z
  129.   // will necessarily be less than Log2Max as desired.
  130.   int Log2Z = Log2_64(X) + Log2_64(Y);
  131.   T Max = std::numeric_limits<T>::max();
  132.   int Log2Max = Log2_64(Max);
  133.   if (Log2Z < Log2Max)
  134.     return X * Y;
  135.   if (Log2Z > Log2Max)
  136.     return Max;
  137.  
  138.   // We're going to use the top bit, and maybe overflow one
  139.   // bit past it. Multiply all but the bottom bit then add
  140.   // that on at the end.
  141.   T Z = (X >> 1) * Y;
  142.   if (Z & ~(std::numeric_limits<T>::max() >> 1))
  143.     return Max;
  144.   Z <<= 1;
  145.   return (X & 1) ? SaturatingAdd(Z, Y) : Z;
  146. }
  147.  
  148. int main(int argc, char **argv)
  149. {
  150.   if (argc != 3) {
  151.     fprintf(stderr, "usage: %s <start> <end>\n", argv[0]);
  152.     return -1;
  153.   }
  154.  
  155.   uint64_t X1 = strtoull(argv[1], NULL, 10);
  156.   uint64_t X2 = strtoull(argv[2], NULL, 10);
  157.  
  158.   std::chrono::steady_clock::time_point T1, T2;
  159.  
  160.   uint64_t Ellapsed2, Ellapsed3;
  161.  
  162.   uint64_t R = 0;
  163.  
  164.   T1 = std::chrono::steady_clock::now();
  165.   for (uint64_t X = X1 ; X <= X2; X++) {
  166.     R += SaturatingMultiply2(X, X);
  167.   }
  168.   T2 = std::chrono::steady_clock::now();
  169.   printf("SaturatingMultiply2(): %ld us\n", std::chrono::duration_cast<std::chrono::microseconds>(T2 - T1).count());
  170.   fflush(stdout);
  171.  
  172.   T1 = std::chrono::steady_clock::now();
  173.   for (uint64_t X = X1 ; X <= X2; X++) {
  174.     R += SaturatingMultiply3(X, X);
  175.   }
  176.   T2 = std::chrono::steady_clock::now();
  177.   printf("SaturatingMultiply3(): %ld us\n", std::chrono::duration_cast<std::chrono::microseconds>(T2 - T1).count());
  178.   fflush(stdout);
  179.  
  180.   return int(R);
  181. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement