################################ ################################ St. Petersburg Paradox in 6 Lines of Code - Roland B. Stark, Integrative Statistics, June 2022 ################################ # This is companion code to the piece at https://www.integrativestatistics.com/blog # A. Initial, most concrete and transparent, but most tedious version N = 1000000 # Sets the number of trials rand = runif (N,0,1) # A uniform random number, ranging from 0 to 1, to randomize results, with sample size matching our N above pay = rep (2, N) # This initializes "pay" at the lowest possible value of $2, when the first flip is heads pay [rand < 1/2] = 2^2 # Long-term, half the time the first flip will come up tails and the 2nd (or greater), heads, paying out at least $4 pay [rand < 1/4] = 2^3 pay [rand < 1/8] = 2^4 pay [rand < 1/16] = 2^5 pay [rand < 1/32] = 2^6 pay [rand < 1/64] = 2^7 pay [rand < 1/128] = 2^8 pay [rand < 1/256] = 2^9 pay [rand < 1/512] = 2^10 pay [rand < 1/2^10] = 2^11 # Starting here we simplify our task by using exponents instead of large numbers within the brackets pay [rand < 1/2^11] = 2^12 pay [rand < 1/2^12] = 2^13 pay [rand < 1/2^13] = 2^14 pay [rand < 1/2^14] = 2^15 pay [rand < 1/2^15] = 2^16 pay [rand < 1/2^16] = 2^17 pay [rand < 1/2^17] = 2^18 pay [rand < 1/2^18] = 2^19 pay [rand < 1/2^19] = 2^20 pay [rand < 1/2^20] = 2^21 pay [rand < 1/2^21] = 2^22 pay [rand < 1/2^22] = 2^23 pay [rand < 1/2^23] = 2^24 pay [rand < 1/2^24] = 2^25 pay [rand < 1/2^25] = 2^26 pay [rand < 1/2^26] = 2^27 pay [rand < 1/2^27] = 2^28 pay [rand < 1/2^28] = 2^29 pay [rand < 1/2^29] = 2^30 pay [rand < 1/2^30] = 2^31 pay [rand < 1/2^31] = 2^32 pay [rand < 1/2^32] = 2^33 pay [rand < 1/2^33] = 2^34 pay [rand < 1/2^34] = 2^35 # 2^34 =~ 17 billion; an arbitrary stopping point mean(pay); max(pay) # For me, with 8GB of RAM and a 2.6Ghz processor, this runs in 1 second for 1M trials # The larger our N, the greater the chance of a very large payout among the trials, and the greater mean payout ################################ # B. Using a loop as a shortcut, we efficiently create the equivalent of the long set of commands in A. # For me, this loop runs in 1 second for 1M trials and about 20-40 seconds for 100M trials N = 1000000 rand = runif (N,0,1) pay = rep (2, N) for (i in 1:34) { # This loops through to compute pay for each iteration of rand, from 2^1 through 2^34 pay [rand < (1/(2^(i)))] = 2^(i+1) } # e.g., when rand = 1/2^4, pay = 2^5 mean (pay); max (pay) ################################ # C. Here's an alternative approach from George Pipis at https://predictivehacks.com/st-petersburg-paradox/ # For me, it takes much longer than the B. version to run: 1M trials required 31 minutes rather than 1 second x = Sys.time() # Records the start time payoffs=c() for (i in 1:1000000) { k=1 while (sample(c("H","T"),1)!="H") { k=k+1 } payoffs=c(payoffs, 2**k) } summary(payoffs) Sys.time() - x # Gives the time elapsed since start time ################################ # D. SPSS code (created with SPSS v21) *1st create large N of cases. new file. input program. loop #i=1 to 1000000. end case. end loop. end file. end input program. compute temp = 1. fre temp. *This confirms that 1M cases have been created. *Now for the main simulation. do repeat x=v1 v2 v3 v4 v5 v6 v7 v8 v9 v10. *One could use more variables. compute x = rv.uniform(0,1). recode x (lo thru .5 = 0) (.5 thru hi = 1). end repeat. exe. *Now each variable, v1 through v10, consists of 0s and 1s, which can stand for tails and heads. do if v1=1. compute p=2. else if v2=1. compute p=4. else if v3=1. compute p=8. else if v4=1. compute p=16. else if v5=1. compute p=32. else if v6=1. compute p=64. else if v7=1. compute p=128. else if v8=1. compute p=256. else if v9=1. compute p=512. else if v10=1. compute p=1024. end if. exe. var lab p 'Payout'. graph/barchart p. *This is a basic graph of payouts; a barchart is much more effective in this case than a histogram; see why: graph/hist p. *SPSS''s Chart Builder allows for a few more specs. GGRAPH /GRAPHDATASET NAME="graphdataset" VARIABLES=p COUNT()[name="COUNT"] MISSING=LISTWISE REPORTMISSING=NO /GRAPHSPEC SOURCE=INLINE. BEGIN GPL SOURCE: s=userSource(id("graphdataset")) DATA: p=col(source(s), name("p"), unit.category()) DATA: COUNT=col(source(s), name("COUNT")) GUIDE: axis(dim(1), label("Payout")) GUIDE: axis(dim(2), label("Percent")) SCALE: linear(dim(2), include(0)) ELEMENT: interval(position(summary.percent(p*COUNT, base.all(acrossPanels()))), shape.interior(shape.square)) END GPL. *For me this whole set of SPSS code runs in 10 seconds.