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,182 @@
|
||||
-- Simple BigInt implementation using base 10^9
|
||||
local BigInt = {}
|
||||
BigInt.__index = BigInt
|
||||
|
||||
function BigInt.new(value)
|
||||
local self = setmetatable({}, BigInt)
|
||||
if type(value) == "number" then
|
||||
if value == 0 then
|
||||
self.digits = {0}
|
||||
else
|
||||
self.digits = {math.abs(value)}
|
||||
end
|
||||
else
|
||||
self.digits = {0}
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
function BigInt:add(other)
|
||||
local carry = 0
|
||||
local maxLen = math.max(#self.digits, #other.digits)
|
||||
|
||||
for i = 1, maxLen do
|
||||
local a = self.digits[i] or 0
|
||||
local b = other.digits[i] or 0
|
||||
local sum = a + b + carry
|
||||
|
||||
self.digits[i] = sum % 1000000000
|
||||
carry = math.floor(sum / 1000000000)
|
||||
end
|
||||
|
||||
if carry > 0 then
|
||||
table.insert(self.digits, carry)
|
||||
end
|
||||
end
|
||||
|
||||
function BigInt:subtract(other)
|
||||
local borrow = 0
|
||||
|
||||
for i = 1, #self.digits do
|
||||
local a = self.digits[i]
|
||||
local b = other.digits[i] or 0
|
||||
local diff = a - b - borrow
|
||||
|
||||
if diff < 0 then
|
||||
diff = diff + 1000000000
|
||||
borrow = 1
|
||||
else
|
||||
borrow = 0
|
||||
end
|
||||
|
||||
self.digits[i] = diff
|
||||
end
|
||||
|
||||
-- Remove leading zeros
|
||||
while #self.digits > 1 and self.digits[#self.digits] == 0 do
|
||||
table.remove(self.digits)
|
||||
end
|
||||
end
|
||||
|
||||
function BigInt:multiply(scalar)
|
||||
local result = BigInt.new(0)
|
||||
result.digits = {}
|
||||
|
||||
local carry = 0
|
||||
for i = 1, #self.digits do
|
||||
local prod = self.digits[i] * scalar + carry
|
||||
result.digits[i] = prod % 1000000000
|
||||
carry = math.floor(prod / 1000000000)
|
||||
end
|
||||
|
||||
if carry > 0 then
|
||||
table.insert(result.digits, carry)
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
function BigInt:divide(divisor)
|
||||
local result = BigInt.new(0)
|
||||
result.digits = {}
|
||||
|
||||
local remainder = 0
|
||||
for i = #self.digits, 1, -1 do
|
||||
local cur = remainder * 1000000000 + self.digits[i]
|
||||
result.digits[i] = math.floor(cur / divisor)
|
||||
remainder = cur % divisor
|
||||
end
|
||||
|
||||
-- Remove leading zeros
|
||||
while #result.digits > 1 and result.digits[#result.digits] == 0 do
|
||||
table.remove(result.digits)
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
function BigInt:isZero()
|
||||
return #self.digits == 1 and self.digits[1] == 0
|
||||
end
|
||||
|
||||
function BigInt:toString()
|
||||
local result = ""
|
||||
for i = #self.digits, 1, -1 do
|
||||
if i == #self.digits then
|
||||
result = result .. self.digits[i]
|
||||
else
|
||||
result = result .. string.format("%09d", self.digits[i])
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- Power of 10
|
||||
local function pow10(exp)
|
||||
local result = BigInt.new(1)
|
||||
for i = 1, exp do
|
||||
result = result:multiply(10)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- Calculate arctan(1/x) using Taylor series
|
||||
local function arctan(x, decimals)
|
||||
local scale = pow10(decimals + 10)
|
||||
local x_squared = x * x
|
||||
|
||||
local term = scale:divide(x)
|
||||
local result = BigInt.new(0)
|
||||
local n = 0
|
||||
|
||||
while not term:isZero() do
|
||||
local divisor = 2 * n + 1
|
||||
local contrib = term:divide(divisor)
|
||||
|
||||
if n % 2 == 0 then
|
||||
result:add(contrib)
|
||||
else
|
||||
result:subtract(contrib)
|
||||
end
|
||||
|
||||
term = term:divide(x_squared)
|
||||
n = n + 1
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
-- Calculate pi using Machin's formula
|
||||
local function calculate_pi(decimals)
|
||||
local atan1_5 = arctan(5, decimals)
|
||||
local atan1_239 = arctan(239, decimals)
|
||||
|
||||
-- pi = 16*arctan(1/5) - 4*arctan(1/239)
|
||||
local pi16 = atan1_5:multiply(16)
|
||||
local pi4 = atan1_239:multiply(4)
|
||||
pi16:subtract(pi4)
|
||||
|
||||
local pi_str = pi16:toString()
|
||||
|
||||
-- Format with decimal point
|
||||
local result = "3."
|
||||
local start = 2
|
||||
|
||||
for i = 0, decimals - 1 do
|
||||
if start + i <= #pi_str then
|
||||
result = result .. string.sub(pi_str, start + i, start + i)
|
||||
else
|
||||
result = result .. "0"
|
||||
end
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
-- Main
|
||||
local decimals = 100
|
||||
if #arg > 0 then
|
||||
decimals = tonumber(arg[1]) or 100
|
||||
end
|
||||
|
||||
print(calculate_pi(decimals))
|
||||
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env lua
|
||||
-- Unit tests for Lua pi calculation using busted
|
||||
|
||||
local SCRIPT_PATH = "/Users/einand/Code/test/lua/print_hej.lua"
|
||||
|
||||
local function run_script(...)
|
||||
local args = {...}
|
||||
local cmd = "lua " .. SCRIPT_PATH
|
||||
for _, arg in ipairs(args) do
|
||||
cmd = cmd .. " " .. tostring(arg)
|
||||
end
|
||||
|
||||
local handle = io.popen(cmd, "r")
|
||||
local result = handle:read("*a")
|
||||
handle:close()
|
||||
|
||||
-- Trim newline
|
||||
result = result:gsub("\n$", "")
|
||||
return result
|
||||
end
|
||||
|
||||
describe("Pi calculation", function()
|
||||
it("calculates 10 decimals", function()
|
||||
local result = run_script(10)
|
||||
local expected = "3.1415926535"
|
||||
assert.are.equal(expected, result)
|
||||
end)
|
||||
|
||||
it("calculates 5 decimals", function()
|
||||
local result = run_script(5)
|
||||
local expected = "3.14159"
|
||||
assert.are.equal(expected, result)
|
||||
end)
|
||||
|
||||
it("calculates 1 decimal", function()
|
||||
local result = run_script(1)
|
||||
local expected = "3.1"
|
||||
assert.are.equal(expected, result)
|
||||
end)
|
||||
|
||||
it("calculates 100 decimals", function()
|
||||
local result = run_script(100)
|
||||
local expected = "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679"
|
||||
assert.are.equal(expected, result)
|
||||
end)
|
||||
|
||||
it("calculates default 100 decimals", function()
|
||||
local result = run_script()
|
||||
local expected = "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679"
|
||||
assert.are.equal(expected, result)
|
||||
end)
|
||||
|
||||
it("calculates 10000 decimals", function()
|
||||
local result = run_script(10000)
|
||||
-- Check length: "3." + 10000 digits = 10002 characters
|
||||
assert.are.equal(10002, #result)
|
||||
assert.is_true(string.sub(result, 1, 7) == "3.14159")
|
||||
end)
|
||||
end)
|
||||
Reference in New Issue
Block a user