5
\$\begingroup\$

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())
\$\endgroup\$
3
\$\begingroup\$

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 to BigInteger inside your arctan 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
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.