Advertisement
Shiny_

Tetration

Oct 11th, 2023 (edited)
684
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.21 KB | Science | 0 0
  1. #include <iostream>
  2. #include <iomanip>
  3. #include <string>
  4. #include <chrono>
  5. #include <vector>
  6. #include <unordered_map>
  7.  
  8. #ifdef __has_include
  9. #   if __has_include(<boost/multiprecision/cpp_int.hpp>)
  10. #   define BOOST_AVAILABLE
  11. #   include <boost/multiprecision/cpp_int.hpp>
  12.     using cpp_int = boost::multiprecision::cpp_int;
  13. #   endif
  14. #endif
  15.  
  16. #include <emmintrin.h>
  17.  
  18. #define PRECISION 7
  19.  
  20. class Multiplier {
  21. public:    
  22.     // Using SSE2 instructions:
  23.     static std::string multiply_SSE2(const std::string& num1, const std::string& num2) {
  24.         size_t n1 = num1.size();
  25.         size_t n2 = num2.size();
  26.  
  27.         // Check if either input is empty
  28.         if (n1 == 0 || n2 == 0)
  29.             return "0";
  30.  
  31.         // Allocate memory to store the result
  32.         std::vector<int> result(n1 + n2, 0);
  33.  
  34.         int i = static_cast<int>(n1) - 1;
  35.         do {
  36.             int carry = 0;
  37.             int num1_digit = num1[i] - '0';
  38.  
  39.             int j = static_cast<int>(n2) - 1;
  40.             do {
  41.                 // int num2_digit = num2[j] - '0';
  42.                 //
  43.                 // // Multiply using SIMD (SSE2) intrinsic
  44.                 // __m128i num1_simd = _mm_set1_epi32(num1_digit);
  45.                 // __m128i num2_simd = _mm_set1_epi32(num2_digit);
  46.                 // __m128i product = _mm_mul_epu32(num1_simd, num2_simd);
  47.                 //
  48.                 // // Accumulate the product into the result
  49.                 // int index = i + j + 1;
  50.                 // __m128i result_simd = _mm_loadu_si128((__m128i*) & result[index]);
  51.                 // result_simd = _mm_add_epi32(result_simd, product);
  52.                 // _mm_storeu_si128((__m128i*) & result[index], result_simd);
  53.                 //
  54.                 // carry = _mm_extract_epi32(result_simd, 1);
  55.  
  56.                 int num2_digit = num2[j] - '0';
  57.  
  58.                 __m128i num1_simd = _mm_cvtsi32_si128(num1_digit);
  59.                 __m128i num2_simd = _mm_cvtsi32_si128(num2_digit);
  60.                 __m128i product = _mm_mul_epu32(num1_simd, num2_simd);
  61.  
  62.                 int index = i + j + 1;
  63.                 __m128i result_simd = _mm_loadu_si128((__m128i*) & result[index]);
  64.                 result_simd = _mm_add_epi64(result_simd, product);
  65.                 _mm_storeu_si128((__m128i*) & result[index], result_simd);
  66.  
  67.                 carry = static_cast<int>(_mm_extract_epi64(result_simd, 1));
  68.             } while (--j >= 0);
  69.  
  70.             // if (carry > 0)
  71.             //     result[i] += carry;
  72.  
  73.             carry > 0 ? result[i] += carry : false;
  74.  
  75.         } while (--i >= 0);
  76.  
  77.         // Handle any remaining carry and convert the result to a string
  78.         std::string s;
  79.         int carry = 0;
  80.         auto it = result.rbegin();
  81.         do {
  82.             int sum = *it + carry;
  83.             *it = sum % 10;
  84.             carry = sum / 10;
  85.             s += char(*it + '0');
  86.             ++it;
  87.         } while (it != result.rend());
  88.  
  89.         // Handle any remaining carry
  90.         while (carry) {
  91.             int digit = carry % 10;
  92.             carry /= 10;
  93.             s += char(digit + '0');
  94.         }
  95.  
  96.         // Remove leading zeros
  97.         size_t nonZeroPos = s.find_first_not_of('0');
  98.         return (nonZeroPos != std::string::npos) ? s.substr(nonZeroPos) : "0";
  99.     }
  100.  
  101.     static std::string multiply(const std::string& num1, const std::string& num2) {
  102.         size_t n1 = num1.size();
  103.         size_t n2 = num2.size();
  104.    
  105.         // Check if either input is empty
  106.         if (n1 == 0 || n2 == 0)
  107.             return "0";
  108.    
  109.         std::vector<int> result(n1 + n2, 0);
  110.    
  111.         int i = static_cast<int>(n1) - 1;
  112.         do {
  113.             int carry = 0;
  114.             int num1_digit = num1[i] - '0';
  115.    
  116.             int j = static_cast<int>(n2) - 1;
  117.             do {
  118.                 int num2_digit = num2[j] - '0';
  119.                 int sum = num1_digit * num2_digit + result[i + j + 1] + carry;
  120.                 carry = sum / 10;
  121.                 result[i + j + 1] = sum % 10;
  122.             } while (--j >= 0);
  123.    
  124.             if (carry > 0)
  125.                 result[i] += carry;
  126.         } while (--i >= 0);
  127.    
  128.         std::string s = "";
  129.         for (int i : result)
  130.             s += std::to_string(i);
  131.    
  132.         // Remove leading zeros
  133.         size_t nonZeroPos = s.find_first_not_of('0');
  134.         return (nonZeroPos != std::string::npos) ? s.substr(nonZeroPos) : "0";
  135.     }
  136.  
  137. #ifdef BOOST_AVAILABLE
  138.     static cpp_int multiply(cpp_int a, cpp_int b) {
  139.         return a * b;
  140.     }
  141. #endif
  142. };
  143.  
  144. class PowerCalculator {
  145. private:
  146.     static std::unordered_map<int, std::string> memo;
  147.  
  148. public:
  149.     static std::string power(const std::string& base, int exponent) {
  150.         switch (exponent) {
  151.         case 0:
  152.             return "1";
  153.         default:
  154.             if (memo.find(exponent) != memo.end()) {
  155.                 return memo[exponent];
  156.             }
  157.  
  158.             std::string halfPower = power(base, exponent / 2);
  159.             std::string result = Multiplier::multiply(halfPower, halfPower);
  160.  
  161.             if (exponent % 2 == 1)
  162.                 result = Multiplier::multiply(result, base);
  163.  
  164.             memo[exponent] = result;
  165.             return result;
  166.         }
  167.     }
  168.  
  169.     static std::string power_SSE2(const std::string& base, int exponent) {
  170.         switch (exponent) {
  171.         case 0:
  172.             return "1";
  173.         default:
  174.             if (memo.find(exponent) != memo.end()) {
  175.                 return memo[exponent];
  176.             }
  177.  
  178.             std::string halfPower = power_SSE2(base, exponent / 2);
  179.             std::string result = Multiplier::multiply_SSE2(halfPower, halfPower); // Use SSE2-based multiplication
  180.  
  181.             if (exponent % 2 == 1)
  182.                 result = Multiplier::multiply_SSE2(result, base); // Use SSE2-based multiplication
  183.  
  184.             memo[exponent] = result;
  185.             return result;
  186.         }
  187.     }
  188.  
  189. #ifdef BOOST_AVAILABLE
  190.     static cpp_int power(cpp_int base, int exponent) {
  191.         switch (exponent) {
  192.         case 0:
  193.             return 1;
  194.         default:
  195.             if (exponent % 2 == 0) {
  196.                 cpp_int half_power = power(base, exponent / 2);
  197.                 return Multiplier::multiply(half_power, half_power);
  198.             }
  199.             else {
  200.                 cpp_int half_power = power(base, (exponent - 1) / 2);
  201.                 return Multiplier::multiply(Multiplier::multiply(half_power, half_power), base);
  202.             }
  203.         }
  204.     }
  205. #endif
  206. };
  207.  
  208. std::unordered_map<int, std::string> PowerCalculator::memo;
  209.  
  210. class Tetrator {
  211. private:
  212.     Multiplier stringMultiplier;
  213.     PowerCalculator powerCalculator;
  214.     Multiplier sse2Multiplier;  // Use SSE2-based multiplier
  215.  
  216. public:
  217.     static std::string tetration_SSE2(const std::string& base, int height) {
  218.         switch (height) {
  219.         case 0:
  220.             return "1";
  221.         case 1:
  222.             return base;
  223.         default:
  224.             std::string result = base;
  225.  
  226.             for (int i = 1; i < height; ++i) {
  227.                 // Use SSE2-based multiplication for tetration
  228.                 result = PowerCalculator::power_SSE2(base, stoull(result));
  229.             }
  230.  
  231.             return result;
  232.         }
  233.     }
  234.    
  235.     static std::string tetration(const std::string& base, int height) {
  236.         switch (height) {
  237.         case 0:
  238.             return "1";
  239.         case 1:
  240.             return base;
  241.         default:
  242.             std::string result = base;
  243.  
  244.             for (int i = 1; i < height; ++i) {
  245.                 result = PowerCalculator::power(base, std::stoull(result));
  246.             }
  247.  
  248.             return result;
  249.         }
  250.     }
  251.  
  252. #ifdef BOOST_AVAILABLE
  253.     static cpp_int tetration(cpp_int base, int height) {
  254.         return (height == 0) ? 1 : ((height == 1) ? base : PowerCalculator::power(base, tetration(base, height - 1).convert_to<int>()));
  255.     }
  256. #endif
  257. };
  258.  
  259. void measureStringBasedPerformance() {
  260.     std::string baseInput;
  261.     int heightInput;
  262.  
  263.     std::cout << "Enter the base (a positive integer): ";
  264.     std::cin >> baseInput;
  265.     std::cout << "Enter the height (a non-negative integer): ";
  266.     std::cin >> heightInput;
  267.  
  268.     if (baseInput.empty() || heightInput < 0) {
  269.         std::cerr << "Invalid input. Please enter valid base and height values." << std::endl;
  270.         return;
  271.     }
  272.  
  273.     auto start = std::chrono::high_resolution_clock::now();
  274.     std::string result = Tetrator::tetration(baseInput, heightInput);
  275.     auto end = std::chrono::high_resolution_clock::now();
  276.  
  277.     std::chrono::duration<double> duration = end - start;
  278.     std::cout << "String-based tetration time: " << std::fixed << std::setprecision(PRECISION) << duration.count() << " seconds" << std::endl;
  279.     std::cout << "Result: " << result << std::endl;
  280. }
  281.  
  282. #ifdef BOOST_AVAILABLE
  283. void measureBoostBasedPerformance() {
  284.     cpp_int baseInput;
  285.     int heightInput;
  286.  
  287.     std::cout << "Enter the base (a positive integer): ";
  288.     std::cin >> baseInput;
  289.     std::cout << "Enter the height (a non-negative integer): ";
  290.     std::cin >> heightInput;
  291.  
  292.     if (heightInput < 0) {
  293.         std::cerr << "Invalid input. Please enter a valid non-negative height value." << std::endl;
  294.         return;
  295.     }
  296.  
  297.     auto start = std::chrono::high_resolution_clock::now();
  298.     cpp_int result = Tetrator::tetration(baseInput, heightInput);
  299.     auto end = std::chrono::high_resolution_clock::now();
  300.  
  301.     std::chrono::duration<double> duration = end - start;
  302.     std::cout << "Boost-based tetration time: " << std::fixed << std::setprecision(PRECISION) << duration.count() << " seconds" << std::endl;
  303.     std::cout << "Result: " << result << std::endl;
  304. }
  305. #endif
  306.  
  307. void measureSSE2BasedPerformance() {
  308.     std::string baseInput;
  309.     int heightInput;
  310.  
  311.     std::cout << "Enter the base (a positive integer): ";
  312.     std::cin >> baseInput;
  313.     std::cout << "Enter the height (a non-negative integer): ";
  314.     std::cin >> heightInput;
  315.  
  316.     if (baseInput.empty() || heightInput < 0) {
  317.         std::cerr << "Invalid input. Please enter valid base and height values." << std::endl;
  318.         return;
  319.     }
  320.  
  321.     // Convert heightInput to a string and call the SSE2-based tetration function
  322.     auto start = std::chrono::high_resolution_clock::now();
  323.     std::string heightStr = std::to_string(heightInput);
  324.     std::string result = Tetrator::tetration_SSE2(baseInput, stoull(heightStr));  // Call SSE2-based tetration
  325.     auto end = std::chrono::high_resolution_clock::now();
  326.  
  327.     std::chrono::duration<double> duration = end - start;
  328.     std::cout << "SSE2-based tetration time: " << std::fixed << std::setprecision(PRECISION) << duration.count() << " seconds" << std::endl;
  329.     std::cout << "Result: " << result << std::endl;
  330. }
  331.  
  332.  
  333.  
  334. int main() {
  335.     std::cout << "Measuring performance for tetration..." << std::endl;
  336.  
  337.     std::cout << "\nPerforming string-based tetration..." << std::endl;
  338.     measureStringBasedPerformance();
  339.  
  340.     std::cout << "\nPerforming SSE2-based tetration..." << std::endl;
  341.     measureSSE2BasedPerformance();
  342.  
  343. #ifdef BOOST_AVAILABLE
  344.     std::cout << "\nPerforming Boost-based tetration..." << std::endl;
  345.     measureBoostBasedPerformance();
  346. #else
  347.     std::cout << "\nBoost library not available. Boost-based tetration is disabled." << std::endl;
  348. #endif
  349.  
  350.     return 0;
  351. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement