54d2fecee0
- 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
182 lines
4.0 KiB
Lua
182 lines
4.0 KiB
Lua
-- 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)) |