I have written code in Kotlin with the objective of computing Pi in few enough lines so that it looks good on a t-shirt.
Can be cut and paste into http://try.kotlinlang.org under "My Programs" and run from browser - I just tested it with version 1.2.41 and it's working.
import kotlin.math.*
import java.math.BigInteger
fun main(args: Array<String>) {
val r = (4*(4*arccot(5) - arccot(239))).toString()
println("314 digits of Pi ${r[0]}.${r.substring(1).dropLast(5)}")
}
fun arccot(x:BigInteger):BigInteger {
var precision = 10.toBigInteger().pow(319) / x
var total = precision
var divisor = 1.toBigInteger()
while(precision.abs() >= divisor) {
precision = -precision / x.pow(2)
divisor += 2
total += precision / divisor
}
return total
}
fun arccot(x:Int) = arccot(x.toBigInteger())
operator fun Int.times(x: BigInteger) = this.toBigInteger() * x
operator fun BigInteger.plus(x: Int) = this + x.toBigInteger()
Currently it's longer than I'd like. I would like to shorten without making it less understandable. My vision is to have code that is readable enough it wouldn't be out of place in a production code base.
To give an idea, here's the significantly shorter Python version (which has been printed on a t-shirt and in my opinion looks good and is short enough but also quite readable). Can be run in browser here: https://repl.it/@sek/314-Digits - (there's also a link from there to the t-shirt if you are curious how that looks - the length in question isn't only the number of lines but also the width of the longest line as that determines the font size that can be used)
def pi():
r = 4*(4*arccot(5) - arccot(239))
return str(r)[0]+'.'+str(r)[1:-5]
def arccot(x):
total = power = 10**319 // x
divisor = 1
while abs(power) >= divisor:
power = -power // x**2
divisor += 2
total += power // divisor
return total
print("314 digits of Pi " + pi())
-
\$\begingroup\$ I'm sorry but that is wrong. Try this. \$\endgroup\$candied_orange– candied_orange2018年05月25日 22:31:48 +00:00Commented May 25, 2018 at 22:31
1 Answer 1
I noticed that you are calculating to 314 decimal places instead of 314 digits, so drop 6 instead of 5.
You really don't need the extra functions. You can remove
fun arccot(x:Int) = arccot(x.toBigInteger())
if you convert
Int
toBigInteger
inside yourarctan
method.You can remove
operator fun Int.times(x: BigInteger) = this.toBigInteger() * x
if you
shl(2)
instead of* 4
.You can remove
operator fun BigInteger.plus(x: Int) = this + x.toBigInteger()
if you change
divisor += 2
to
divisor += BigInteger("2")
You can shorten
println("314 digits of Pi ${r[0]}.${r.substring(1).dropLast(5)}")
to
println("314 digits of Pi ${r[0]}.${r.substring(1,314)}")
Now, you can change the imports to
import java.math.*
You don't have to declare the type for
val r
.
The final code I came up with by doing that is:
import java.math.*
fun main(args: Array<String>) {
val r = (acot(5).shl(2)-acot(239)).shl(2).toString()
println("314 digits of Pi ${r[0]}.${r.substring(1,314)}")
}
fun acot(x:Int):BigInteger {
var precision = BigInteger.TEN.pow(319)/x.toBigInteger()
var total = precision
var divisor = BigInteger.ONE;
while(precision.abs() >= divisor) {
precision = -precision/(x.toBigInteger().pow(2))
divisor += BigInteger("2")
total += precision / divisor
}
return total
}
I also came up with shorter code, with decreased width, by calculating a different way:
import java.math.*
fun main(args:Array<String>) {
val b4 = BigDecimal(4)
val r = ((atan(5)*b4-atan(239))*b4).toString()
println("314 digits of Pi ${r.substring(0,315)}")
}
fun atan(xInv:Int):BigDecimal {
var x = BigDecimal(1).divide(BigDecimal(xInv),330,3)
var (numer, total) = arrayOf(x, x)
for (i in 3..450 step 2) {
numer = -numer * x * x
total += numer / BigDecimal(i)
}
return total
}