Pikachuun

Mathologer Googol code

Jan 23rd, 2021 (edited)
534
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.50 KB | None | 0 0
  1. //How many ways are there to get a googol dollars?
  2. //Well, given enough time and a high enough precision value this'll find out, but good luck reaching it :P
  3. #include <iostream>
  4. #include <iomanip>
  5. #include <sstream>
  6. #include <string>
  7. #include <cmath>
  8. #include <cmath>
  9. #include <boost/multiprecision/gmp.hpp>
  10. using stringstream = std::stringstream;
  11. using string = std::string;
  12. using mpf_float = boost::multiprecision::mpf_float;
  13.  
  14. //Using cygwin64, compile with g++ -O3 ./googol.cpp -o ./googol.out -lgmp
  15. //I'm pretty sure you can do something similar with linux/mac since those have native g++
  16. //I'd drop a compiled version here, but i keep getting a "cannot find lgmp" error when compiling with -static. Sorry about that.
  17.  
  18. //MINI-CONFIG:
  19. u_int precision = 256; //Larger = bigger number
  20. bool intermediates = false; //Show intermediate values. Set to false to only show dollars. True will show everything, from pennies to half-dollars and everything in between.
  21. //MINI-CONFIG END
  22.  
  23. //The rest is code for you to look through. You can probably make it more efficient if you know more than me.
  24.  
  25. //What if I could do each big coin type in just 1 function, maybe even in O(n) timescale if I'm actually competent at figuring out big-O notation?
  26. //Hahaha just kidding...
  27. //Unless?
  28. mpf_float quarterSum (mpf_float d, int ID) {
  29.     mpf_float sum = 0;
  30.     mpf_float q = 0;
  31.     mpf_float mul0 = 1;
  32.     mpf_float mul1 = 1;
  33.     switch (ID) {
  34.         case 2:
  35.             do {
  36.                 sum += ceil(10*d-2.5*q+1)*floor(10*d-2.5*q+1)*mul0*mul1;
  37.                 if (fmod(q,4) == 1) { mul0++; }
  38.                 if (fmod(q,4) == 3) { mul1++; }
  39.             } while (++q <= floor(4*d));
  40.             break;
  41.         case 1:
  42.             do {
  43.                 sum += ceil(10*d-2.5*q+1)*floor(10*d-2.5*q+1)*mul0;
  44.                 if (fmod(q,2) == 1) { mul0++; }
  45.             } while (++q <= floor(4*d));
  46.             break;
  47.         default:
  48.             do {
  49.                 sum += ceil(10*d-2.5*q+1)*floor(10*d-2.5*q+1);
  50.             } while (++q <= floor(4*d));
  51.     }
  52.     return sum;
  53. }
  54.  
  55. mpf_float inputParser (string str) {
  56.     stringstream in(str);
  57.     mpf_float out = 0;
  58.     in >> out;
  59.     if (in.fail()) {
  60.         string er = "";
  61.         throw (er + "Unable to format " + str + "as a number!");
  62.    }
  63.    return out;
  64. }
  65.  
  66. int main () {
  67.     string input;
  68.     mpf_float count = 0;
  69.     mpf_float::default_precision(precision);
  70.  
  71.     std::cout << "Input the amount of dollars (Scientific notation is okay; the memetic googol value is 1e100):\n";
  72.     std::cin >> input;
  73.     count = inputParser(input);
  74.    
  75.     std::cout << std::setprecision(precision);
  76.     if (intermediates) {
  77.         std::cout << "With only pennies: 1 way. What were you expecting? :p\n";
  78.         std::cout << "Adding nickels: " << (floor(count*20)+1) << " ways.\n";
  79.         std::cout << "Adding dimes: " << pow(floor(count*10)+1, 2) << " ways.\n";
  80.         std::cout << "these three will take a bit depending on how big the number is.\n";
  81.         std::cout << "Adding quarters: " << quarterSum(count,0) << " ways.\n";
  82.         std::cout << "Adding half-dollars: " << quarterSum(count,1) << " ways.\n";
  83.         std::cout << "Adding dollars: " << quarterSum(count,2) << " ways.\n";
  84.     } else {
  85.         std::cout << "this might take a while...\n";
  86.         std::cout << "How to split change: " << quarterSum(count,2) << " ways.\n";
  87.     }
  88.     std::cout << "hope it worked ;)";
  89.     return 0;
  90. }
  91.  
  92.  
  93. //COOL TIDBITS (aka the process)
  94.     //Things that we know:
  95.     //We get n+1 values for dollars
  96.     //We get 2n+1 values for half-dollars
  97.     //We get 4n+1 values for quarters
  98.     //We get 10n+1 values for dimes
  99.     //We get 20n+1 values for nickels
  100.     //Any remainder is made up of pennies, they can be ignored
  101.    
  102.     //At the same time if we just plug in (n+1)*(4n+1)*(10n+1)*(20n+1) we certainly don't get 293, now do we?
  103.     //Technically it's the sum of all inputs that add up to 100, but we can exclude pennies. It's instead the sum of all inputs that add up to a value <= 100!
  104.    
  105.     //We COULD accomplish this with 4 nested while loops (nickels omitted for efficiency)
  106.     /*
  107.     register long double d = 0;
  108.     register long double h = 0;
  109.     register long double q = 0;
  110.     register long double i = 0;
  111.     do
  112.         do {
  113.             do {
  114.                 do {
  115.                     count += floor(2*(2.5*(2*(2*(inDoub-d)-h)-q)-i))+1;
  116.                 } while (++i <= 2.5*(2*(2*(inDoub-d)-h)-q)
  117.             } while (++q <= 2*(2*(inDoub-d)-h))
  118.         } while (++h <= 2*(inDoub-d))
  119.     } while (++d <= inDoub)
  120.     */
  121.     //Just imagine how laggy that would be at higher inputs! The key is to avoid loops as much as possible
  122.     //But it does give us insight as to how the future will perform if we count it manually...
  123.     //If we could only use dimes and nickels
  124.     //@q=0: 21 + 19 + 17 + 15 + 13 + 11 + 9 + 7 + 5 + 3 + 1 = 121
  125.     //@q=1: 16 + 14 + 12 + 10 + 8 + 6 + 4 + 2 + 0 = 72
  126.     //@q=2: 11 + 9 + 7 + 5 + 3 + 1 = 36
  127.     //@q=3: 6 + 4 + 2 + 0 = 12
  128.     //@q=4: 1 = 1
  129.     //@d=1: 1 = 1
  130.     //Total: 121 + 72 + 36 + 12 + 1 + 1 = 243, which matches expectations not counting half dollars
  131.     //A potential series. Going to 1.50 introduces a +135 for a total of 256 possibilities, so it's safe to assume that it's a +35+50i.
  132.     //In a similar vein, q=3 is equivalent to q=1 with a bit extra tacked on. This turns out to have a base of 12, and an adder of +10+50(i+1). (12 > 72 > 182, 10 > 60 > 110)
  133.    
  134.     //Notice how it's basically a sum.
  135.     //@q=0: sum(2*i+1,0,10)
  136.     //@q=1: sum(2*i,0,8)
  137.     //@q=2: sum(2*i+1,0,5)
  138.     //@q=3: sum(2*i,0,3)
  139.    
  140.     //The thing is about this while loop is that it layers them together. Is there an efficient way to get these numbers?
  141.     //Well, actually yes. q=2 is equivalent to q=0 with a bit extra tacked on, right? 85 + 36, or 85 + 35 + 1, or (35+50*1) + (35+50*0) + 1.
  142.     //A note if you're astute that allows for simplification. This (2n+1)-type sum is equal to a square of n+1.
  143.     //So for an even number of quarters, sum((5i+1)^2, 0, n/2) is a viable solution if we only deal in intervals of 25.
  144.     //Even 15 works with this, same with 5
  145.     //If it were 45 > 95, like 1.99
  146.     //@q=0: 20 + 18 + 16 + 14 + 12 + 10 + 8 + 6 + 4 + 2 + 0 = 110
  147.     //@q=2: 10 + 8 + 6 + 4 + 2 + 0 = 30
  148.     //Isn't this just n*(n-1)?
  149.     //Therefore instead of sums, we can re-summarize
  150.      
  151.     //@q=0: 11^2 = (10+1)^2
  152.     //@q=1: 9*8 = (7+2)*(7+1)
  153.     //@q=2: 6^2 = (5+1)^2
  154.     //@q=3: 4*3 = (2+2)*(2+1)
  155.     //@q=4: 1^2 = (0+1)^2
  156.     //in other words
  157.     //@q=n: ceil(10d-2.5q+1)*floor(10d-2.5q+1)
  158.     //This might be the one case we need a sum :P
  159.    
  160.     //With half-dollars, you make another instance of the sum starting 2 below (in effect, adding 1). Simple enough, after all it's just layering.
  161.     //So what about dollars? You make another instance of the half dollar sum starting 2 below and add it to the first sum.
  162.     //How do you quantify that?
  163.     //Try with 2 dollars.
  164.     //q=[0,8] represents the 0 half-dollar sum. h=0: 21^2+19*18+16^2+14*13+11^2+9*8+6^2+4*3+1^2 = 1463
  165.     //q=[2,8] represents the 1 half-dollar sum. h=1: 16^2+14*13+11^2+9*8+6^2+4*3+1^2 = 680
  166.     //q=[4,8] represents the 2 half-dollar sum. h=2: 11^2+9*8+6^2+4*3+1^2 = 242
  167.     //q=[6,8] represents the 3 half-dollar sum. h=3: 6^2+4*3+1^2 = 49
  168.     //q=[8,8] represents the 4 half-dollar sum. h=4: 1^2 = 1
  169.     //In total, q=[0,1] is counted once, q=[2,3] is counted twice, q=[4,5] is counted thrice, q=[6,7] is counted quartice, and q=[8,8] is counted... quintice? (honestly i made up quartice too)
  170.  
  171.     //Stepping up 1 layer
  172.     //h=[0,4] represents the 0 dollar sum. In other words, q=[0~8,8]. d=0: 1463+680+242+49+1 = 2435
  173.     //h=[2,4] represents the 1 dollar sum. In other words, q=[4~8,8]. d=1: 242+49+1 = 292
  174.     //h=[4,4] represents the 2 dollar sum. In other words, q=[8~8,8]. d=2: 1 = 1
  175.     //sum to get the 2 dollar total described in the video. 2728.
  176.     //In total, h=[0,1] is counted once, h=[2,3] is counted twice, h=[4,4] is counted thrice.
  177.     //In other words.
  178.     //  q=[0,1]: only in h[0,1], so 1 time
  179.     //  q=[2,3]: only in h[0,1], so 2 times
  180.     //  q=[4,5]: in both h[0,1] and h[2,3], so 3*2 = 6 times
  181.     //  q=[6,7]: in both h[0,1] and h[2,3], so 4*2 = 8 times
  182.     //  q=[8,8]: in all three, so 5*3 = 15 times
  183.     //But you probably saw a problem with your eyes the second I hit the 3rd line. It wasn't that at all.
  184.     //In fact, the pattern through manual counting is 1, 2, 4, 6, 9. That's different.
  185.     //Brief hypothesis: they both alternate in terms of incrementation. Try and see if it matches the already listed values?
  186.  
  187.     //Empirically checking, it actually does match the given examples. Huh, neat.
  188.     //Here's some other cool information that you may not know immediately because I don't just report dollars.
  189.     //Coins all actually follow a similar pattern as you multiply by 10. In essence, where {} indicates a repeating chain of the same length as every other {}
  190.     //Nickels: 2{0}1
  191.     //Dimes: 1{0}2{0}1
  192.     //Quarters: 1{3}42{3}51{0}1
  193.     //Half-dollars: 6{6}79{3}412{6}85{0}01
  194.     //Dollars: 13{3}398{3}445{3}4138{3}545{0}01
  195.  
  196.     //You also start to see this with 2*10^n (42{6}770{6}7562{6}988{6}7090{0}01 | @2e6, len=3).
  197.     //For fun, I also ran it on other values, up to 10^6, to try and find other patterns. Here's the results.
  198.     //3*10^n: 3240{0}5265{0}3024{0}072450{0}6350{0}01 | @3e6, len=2
  199.     //4*10^n: 1365{3}4997{3}40501{3}46213{3}4180{0}001 | @4e6, len=2
  200.     //5*10^n: 41{6}707291806{6}68679167250{0}1 | @5e6, len=3
  201.     //6*10^n: 10368{0}8424{0}24192{0}28980{0}1270{0}01 | @6e6, len=2
  202.     //7*10^n: 224093489398371749{3}72778{3}48150{0}01 | @7e6, len=2
  203.     //8*10^n: 436906932906724010671818{6}8360{0}01| @8e6, len=3
  204.     //9*10^n: 787320426465081648{0}65205{0}19050{0}01| @9e6, len=2
  205.     //Intriguingly, every number that repeats, regardless of whether nickels, dimes, quarters, or anything else is processed, is either a 0, a 3, or a 6.
  206.     //I should mention that this isn't every growing pattern. There are more past 1e7 that you can potentially explore, as I noticed some numbers popping up while I was figuring these out.
  207.     //Perhaps that could be a fun homework assignment?
Add Comment
Please, Sign In to add comment