Initial commit: Pi calculation benchmark with 34 languages
- Added implementations for: bash, brainfuck, c, cpp, crystal, csharp, d, dart, elixir, erlang, fortran, go, haskell, java, javascript, julia, kotlin, objective-c, scala, typescript, lua, nim, odin, perl, php, python, r, ruby, rust, swift, zig, assembly, vimscript, wolfram - All implementations use Machin's formula: π/4 = 4*arctan(1/5) - arctan(1/239) - Build system with ./build.sh, test system with ./test.sh - Performance testing with ./run_all.sh - Comprehensive README.md explaining performance differences - Test framework verifies correctness against known π values
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
// swift-tools-version:5.5
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "print_hej",
|
||||
targets: [
|
||||
.executableTarget(
|
||||
name: "print_hej",
|
||||
path: "."),
|
||||
.testTarget(
|
||||
name: "PiTests",
|
||||
dependencies: ["print_hej"],
|
||||
path: "."),
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,75 @@
|
||||
import XCTest
|
||||
@testable import print_hej
|
||||
|
||||
class PiTests: XCTestCase {
|
||||
let scriptPath = "/Users/einand/Code/test/swift/print_hej"
|
||||
|
||||
func runScript(_ args: String? = nil) -> String {
|
||||
let process = Process()
|
||||
process.executableURL = URL(fileURLWithPath: scriptPath)
|
||||
|
||||
if let args = args {
|
||||
process.arguments = [args]
|
||||
}
|
||||
|
||||
let pipe = Pipe()
|
||||
process.standardOutput = pipe
|
||||
process.standardError = pipe
|
||||
|
||||
do {
|
||||
try process.run()
|
||||
process.waitUntilExit()
|
||||
|
||||
let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||
return String(data: data, encoding: .utf8)?.trimmingCharacters(in: .newlines) ?? ""
|
||||
} catch {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func test10Decimals() {
|
||||
let result = runScript("10")
|
||||
let expected = "3.1415926535"
|
||||
XCTAssertEqual(result, expected)
|
||||
}
|
||||
|
||||
func test5Decimals() {
|
||||
let result = runScript("5")
|
||||
let expected = "3.14159"
|
||||
XCTAssertEqual(result, expected)
|
||||
}
|
||||
|
||||
func test1Decimal() {
|
||||
let result = runScript("1")
|
||||
let expected = "3.1"
|
||||
XCTAssertEqual(result, expected)
|
||||
}
|
||||
|
||||
func test100Decimals() {
|
||||
let result = runScript("100")
|
||||
let expected = "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679"
|
||||
XCTAssertEqual(result, expected)
|
||||
}
|
||||
|
||||
func testDefault100Decimals() {
|
||||
let result = runScript()
|
||||
let expected = "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679"
|
||||
XCTAssertEqual(result, expected)
|
||||
}
|
||||
|
||||
func test10000Decimals() {
|
||||
let result = runScript("10000")
|
||||
// Check length: "3." + 10000 digits = 10002 characters
|
||||
XCTAssertEqual(result.count, 10002)
|
||||
XCTAssertTrue(result.hasPrefix("3.14159"))
|
||||
}
|
||||
|
||||
static var allTests = [
|
||||
("test10Decimals", test10Decimals),
|
||||
("test5Decimals", test5Decimals),
|
||||
("test1Decimal", test1Decimal),
|
||||
("test100Decimals", test100Decimals),
|
||||
("testDefault100Decimals", testDefault100Decimals),
|
||||
("test10000Decimals", test10000Decimals),
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
import Foundation
|
||||
|
||||
// Simple BigInt implementation for arbitrary precision
|
||||
class BigInt {
|
||||
var digits: [UInt64]
|
||||
|
||||
init(_ value: Int = 0) {
|
||||
if value == 0 {
|
||||
digits = [0]
|
||||
} else {
|
||||
digits = [UInt64(abs(value))]
|
||||
}
|
||||
}
|
||||
|
||||
init(_ value: UInt64) {
|
||||
digits = [value]
|
||||
}
|
||||
|
||||
func add(_ other: BigInt) {
|
||||
var carry: UInt64 = 0
|
||||
let maxLen = max(digits.count, other.digits.count)
|
||||
|
||||
for i in 0..<maxLen {
|
||||
let a = i < digits.count ? digits[i] : 0
|
||||
let b = i < other.digits.count ? other.digits[i] : 0
|
||||
let sum = a + b + carry
|
||||
|
||||
if i < digits.count {
|
||||
digits[i] = sum % 1_000_000_000
|
||||
} else {
|
||||
digits.append(sum % 1_000_000_000)
|
||||
}
|
||||
carry = sum / 1_000_000_000
|
||||
}
|
||||
|
||||
if carry > 0 {
|
||||
digits.append(carry)
|
||||
}
|
||||
}
|
||||
|
||||
func subtract(_ other: BigInt) {
|
||||
var borrow: Int64 = 0
|
||||
|
||||
for i in 0..<digits.count {
|
||||
let a = Int64(digits[i])
|
||||
let b = i < other.digits.count ? Int64(other.digits[i]) : 0
|
||||
var diff = a - b - borrow
|
||||
|
||||
if diff < 0 {
|
||||
diff += 1_000_000_000
|
||||
borrow = 1
|
||||
} else {
|
||||
borrow = 0
|
||||
}
|
||||
|
||||
digits[i] = UInt64(diff)
|
||||
}
|
||||
|
||||
// Remove leading zeros
|
||||
while digits.count > 1 && digits.last! == 0 {
|
||||
digits.removeLast()
|
||||
}
|
||||
}
|
||||
|
||||
func multiply(_ other: BigInt) -> BigInt {
|
||||
let result = BigInt()
|
||||
result.digits = Array(repeating: 0, count: digits.count + other.digits.count)
|
||||
|
||||
for i in 0..<digits.count {
|
||||
var carry: UInt64 = 0
|
||||
for j in 0..<other.digits.count {
|
||||
let prod = digits[i] * other.digits[j] + result.digits[i + j] + carry
|
||||
result.digits[i + j] = prod % 1_000_000_000
|
||||
carry = prod / 1_000_000_000
|
||||
}
|
||||
if carry > 0 {
|
||||
result.digits[i + other.digits.count] += carry
|
||||
}
|
||||
}
|
||||
|
||||
// Remove leading zeros
|
||||
while result.digits.count > 1 && result.digits.last! == 0 {
|
||||
result.digits.removeLast()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func divide(_ divisor: UInt64) -> BigInt {
|
||||
let result = BigInt()
|
||||
result.digits = Array(repeating: 0, count: digits.count)
|
||||
|
||||
var remainder: UInt64 = 0
|
||||
for i in (0..<digits.count).reversed() {
|
||||
let cur = remainder * 1_000_000_000 + digits[i]
|
||||
result.digits[i] = cur / divisor
|
||||
remainder = cur % divisor
|
||||
}
|
||||
|
||||
// Remove leading zeros
|
||||
while result.digits.count > 1 && result.digits.last! == 0 {
|
||||
result.digits.removeLast()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func toString() -> String {
|
||||
var result = ""
|
||||
for i in (0..<digits.count).reversed() {
|
||||
if i == digits.count - 1 {
|
||||
result += String(digits[i])
|
||||
} else {
|
||||
result += String(format: "%09d", digits[i])
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
func pow10(_ exp: Int) -> BigInt {
|
||||
let result = BigInt(1)
|
||||
for _ in 0..<exp {
|
||||
let temp = result.multiply(BigInt(10))
|
||||
result.digits = temp.digits
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func arctan(_ x: UInt64, decimals: Int) -> BigInt {
|
||||
let scale = pow10(decimals + 10)
|
||||
let xSquared = x * x
|
||||
|
||||
var term = scale.divide(x)
|
||||
var result = BigInt(0)
|
||||
var n = 0
|
||||
|
||||
while term.digits.count > 1 || term.digits[0] > 0 {
|
||||
let divisor = UInt64(2 * n + 1)
|
||||
let contrib = term.divide(divisor)
|
||||
|
||||
if n % 2 == 0 {
|
||||
result.add(contrib)
|
||||
} else {
|
||||
result.subtract(contrib)
|
||||
}
|
||||
|
||||
term = term.divide(xSquared)
|
||||
n += 1
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func calculatePi(_ decimals: Int) -> String {
|
||||
let atan1_5 = arctan(5, decimals: decimals)
|
||||
let atan1_239 = arctan(239, decimals: decimals)
|
||||
|
||||
// pi = 16*arctan(1/5) - 4*arctan(1/239)
|
||||
let pi16 = atan1_5.multiply(BigInt(16))
|
||||
let pi4 = atan1_239.multiply(BigInt(4))
|
||||
pi16.subtract(pi4)
|
||||
|
||||
let piStr = pi16.toString()
|
||||
|
||||
// Format with decimal point
|
||||
var result = "3."
|
||||
let start = piStr.index(piStr.startIndex, offsetBy: 1)
|
||||
let digits = piStr[start...]
|
||||
|
||||
var i = 0
|
||||
for char in digits {
|
||||
if i >= decimals { break }
|
||||
result.append(char)
|
||||
i += 1
|
||||
}
|
||||
|
||||
// Pad with zeros if needed
|
||||
while i < decimals {
|
||||
result.append("0")
|
||||
i += 1
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Main
|
||||
let decimals: Int
|
||||
if CommandLine.arguments.count > 1 {
|
||||
decimals = Int(CommandLine.arguments[1]) ?? 100
|
||||
} else {
|
||||
decimals = 100
|
||||
}
|
||||
|
||||
let pi = calculatePi(decimals)
|
||||
print(pi)
|
||||
Reference in New Issue
Block a user