Skip to content

Instantly share code, notes, and snippets.

@bram-inniger
Created March 22, 2023 12:12
Show Gist options
  • Save bram-inniger/c33cc5b2fe91ad77b2a5d82b1cd92a2b to your computer and use it in GitHub Desktop.
Save bram-inniger/c33cc5b2fe91ad77b2a5d82b1cd92a2b to your computer and use it in GitHub Desktop.
Monte Carlo estimation of Pi
import kotlin.math.PI
import kotlin.math.abs
import kotlin.math.sqrt
import kotlin.random.Random
import kotlin.time.ExperimentalTime
import kotlin.time.measureTimedValue
object MonteCarlo {
fun estimatePi(nrPicks: Int = 1_000_000_000) =
generateSequence { pickRandomPoint() }
.take(nrPicks)
.filter { it.distanceFromCenter <= 1 }
.count()
.toDouble()
.let { it / nrPicks * 4 }
private fun pickRandomPoint() =
UnitSquarePosition(
Random.nextDouble(-1.0, 1.0),
Random.nextDouble(-1.0, 1.0),
)
private data class UnitSquarePosition(private val x: Double, private val y: Double) {
init {
if (x !in -1.0..1.0) error("X coordinate outside the unit square: $x")
if (y !in -1.0..1.0) error("Y coordinate outside the unit square: $y")
}
val distanceFromCenter = sqrt(x * x + y * y)
}
}
/*
* Sample output:
*
* Running the estimation with 500.000.000 picks...
* Monte Carlo: 3,14144
* Real value: 3,14159
* The estimation took 14 seconds to complete
* The estimation was 99,99504% close to Pi
*/
@OptIn(ExperimentalTime::class)
fun main() {
val nrPicks = 500_000_000
println("Running the estimation with ${"%,d".format(nrPicks)} picks...")
val estimation = measureTimedValue { MonteCarlo.estimatePi(nrPicks) }
val proximity = 100 * (1 - abs((PI - estimation.value) / PI))
println("Monte Carlo: ${"%.5f".format(estimation.value)}")
println("Real value: ${"%.5f".format(PI)}")
println("The estimation took ${estimation.duration.inWholeSeconds} seconds to complete")
println("The estimation was ${"%.5f".format(proximity)}% close to Pi")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment