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
228 lines
5.4 KiB
Odin
228 lines
5.4 KiB
Odin
package main
|
|
|
|
import "core:fmt"
|
|
import "core:os"
|
|
import "core:strings"
|
|
import "core:strconv"
|
|
|
|
// Simple BigInt implementation using base 10^9
|
|
BigInt :: struct {
|
|
digits: [dynamic]u64,
|
|
}
|
|
|
|
big_int_init :: proc(value: u64) -> BigInt {
|
|
result: BigInt
|
|
if value == 0 {
|
|
append(&result.digits, 0)
|
|
} else {
|
|
append(&result.digits, value)
|
|
}
|
|
return result
|
|
}
|
|
|
|
big_int_add :: proc(a: ^BigInt, b: BigInt) {
|
|
carry: u64 = 0
|
|
max_len := max(len(a.digits), len(b.digits))
|
|
|
|
for i in 0..<max_len {
|
|
x := a.digits[i] if i < len(a.digits) else 0
|
|
y := b.digits[i] if i < len(b.digits) else 0
|
|
sum := x + y + carry
|
|
|
|
if i < len(a.digits) {
|
|
a.digits[i] = sum % 1_000_000_000
|
|
} else {
|
|
append(&a.digits, sum % 1_000_000_000)
|
|
}
|
|
carry = sum / 1_000_000_000
|
|
}
|
|
|
|
if carry > 0 {
|
|
append(&a.digits, carry)
|
|
}
|
|
}
|
|
|
|
big_int_sub :: proc(a: ^BigInt, b: BigInt) {
|
|
borrow: i64 = 0
|
|
|
|
for i in 0..<len(a.digits) {
|
|
x := i64(a.digits[i])
|
|
y := i64(b.digits[i]) if i < len(b.digits) else 0
|
|
diff := x - y - borrow
|
|
|
|
if diff < 0 {
|
|
diff += 1_000_000_000
|
|
borrow = 1
|
|
} else {
|
|
borrow = 0
|
|
}
|
|
|
|
a.digits[i] = u64(diff)
|
|
}
|
|
|
|
// Remove leading zeros
|
|
for len(a.digits) > 1 && a.digits[len(a.digits) - 1] == 0 {
|
|
pop(&a.digits)
|
|
}
|
|
}
|
|
|
|
big_int_mul :: proc(a: BigInt, b: u64) -> BigInt {
|
|
result: BigInt
|
|
resize(&result.digits, len(a.digits))
|
|
|
|
carry: u64 = 0
|
|
for i in 0..<len(a.digits) {
|
|
prod := a.digits[i] * b + carry
|
|
result.digits[i] = prod % 1_000_000_000
|
|
carry = prod / 1_000_000_000
|
|
}
|
|
|
|
if carry > 0 {
|
|
append(&result.digits, carry)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
big_int_div :: proc(a: BigInt, divisor: u64) -> BigInt {
|
|
result: BigInt
|
|
resize(&result.digits, len(a.digits))
|
|
|
|
remainder: u64 = 0
|
|
for i in 0..<len(a.digits) {
|
|
j := len(a.digits) - 1 - i
|
|
cur := remainder * 1_000_000_000 + a.digits[j]
|
|
result.digits[j] = cur / divisor
|
|
remainder = cur % divisor
|
|
}
|
|
|
|
// Remove leading zeros
|
|
for len(result.digits) > 1 && result.digits[len(result.digits) - 1] == 0 {
|
|
pop(&result.digits)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
big_int_is_zero :: proc(a: BigInt) -> bool {
|
|
return len(a.digits) == 1 && a.digits[0] == 0
|
|
}
|
|
|
|
big_int_to_string :: proc(a: BigInt) -> string {
|
|
// Build string using dynamic array of bytes
|
|
result_bytes: [dynamic]u8
|
|
|
|
// Print digits from most significant to least significant
|
|
for i in 0..<len(a.digits) {
|
|
j := len(a.digits) - 1 - i
|
|
if j == len(a.digits) - 1 {
|
|
// Most significant digit - print without leading zeros
|
|
digit_str := fmt.aprintf("{}", a.digits[j])
|
|
append(&result_bytes, digit_str)
|
|
} else {
|
|
// Other digits - print with leading zeros to fill 9 positions
|
|
digit_str := fmt.aprintf("{}", a.digits[j])
|
|
// Pad with leading zeros if needed
|
|
for k in len(digit_str)..<9 {
|
|
append(&result_bytes, '0')
|
|
}
|
|
append(&result_bytes, digit_str)
|
|
}
|
|
}
|
|
|
|
return string(result_bytes[:])
|
|
}
|
|
|
|
pow10 :: proc(exp: int) -> BigInt {
|
|
result := big_int_init(1)
|
|
for i in 0..<exp {
|
|
temp := big_int_mul(result, 10)
|
|
result = temp
|
|
}
|
|
return result
|
|
}
|
|
|
|
arctan :: proc(x: u64, decimals: int) -> BigInt {
|
|
// Use base 10^9 for efficiency
|
|
num_digits := (decimals + 10) / 9 + 10
|
|
|
|
result := big_int_init(0)
|
|
term := big_int_init(1)
|
|
|
|
// Initialize term = 10^(decimals+10) / x
|
|
for i in 0..<(decimals + 10) {
|
|
temp := big_int_mul(term, 10)
|
|
term = temp
|
|
}
|
|
term = big_int_div(term, x)
|
|
|
|
x_squared := x * x
|
|
n: int = 0
|
|
|
|
for !big_int_is_zero(term) && n < decimals * 2 {
|
|
divisor := u64(2 * n + 1)
|
|
contrib := big_int_div(term, divisor)
|
|
|
|
if n % 2 == 0 {
|
|
big_int_add(&result, contrib)
|
|
} else {
|
|
big_int_sub(&result, contrib)
|
|
}
|
|
|
|
term = big_int_div(term, x_squared)
|
|
n += 1
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
calculate_pi :: proc(decimals: int) -> string {
|
|
atan1_5 := arctan(5, decimals)
|
|
atan1_239 := arctan(239, decimals)
|
|
|
|
// pi = 16*arctan(1/5) - 4*arctan(1/239)
|
|
pi16 := big_int_mul(atan1_5, 16)
|
|
pi4 := big_int_mul(atan1_239, 4)
|
|
big_int_sub(&pi16, pi4)
|
|
|
|
pi_str := big_int_to_string(pi16)
|
|
|
|
// Format with decimal point using dynamic array of bytes
|
|
result_bytes: [dynamic]u8
|
|
|
|
// First digit before decimal point
|
|
if len(pi_str) > 0 {
|
|
append(&result_bytes, pi_str[0])
|
|
} else {
|
|
append(&result_bytes, '3')
|
|
}
|
|
append(&result_bytes, '.')
|
|
|
|
// Remaining digits after decimal point
|
|
for i in 1..<(len(pi_str)) {
|
|
if i <= decimals {
|
|
append(&result_bytes, pi_str[i])
|
|
}
|
|
}
|
|
|
|
// Pad with zeros if needed
|
|
for i in len(pi_str)..<(decimals + 1) {
|
|
append(&result_bytes, '0')
|
|
}
|
|
|
|
return string(result_bytes[:])
|
|
}
|
|
|
|
main :: proc() {
|
|
decimals: int = 100
|
|
|
|
if len(os.args) > 1 {
|
|
val, ok := strconv.parse_int(os.args[1])
|
|
if ok {
|
|
decimals = int(val)
|
|
}
|
|
}
|
|
|
|
pi := calculate_pi(decimals)
|
|
fmt.println(pi)
|
|
} |