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,77 @@
|
||||
package pi_test
|
||||
|
||||
import "core:os"
|
||||
import "core:fmt"
|
||||
import "core:strings"
|
||||
import "core:testing"
|
||||
|
||||
SCRIPT_PATH :: "/Users/einand/Code/test/odin/print_hej"
|
||||
|
||||
run_script :: proc(args: []string) -> string {
|
||||
cmd: strings.Builder
|
||||
strings.init_builder(&cmd)
|
||||
defer strings.free_builder(&cmd)
|
||||
|
||||
strings.write_string(&cmd, SCRIPT_PATH)
|
||||
for arg in args {
|
||||
strings.write_byte(&cmd, ' ')
|
||||
strings.write_string(&cmd, arg)
|
||||
}
|
||||
|
||||
process := os.create_process(strings.to_string(cmd))
|
||||
defer os.destroy_process(process)
|
||||
|
||||
output := os.read_entire_file_from_process(process)
|
||||
defer free(output.data)
|
||||
|
||||
// Remove trailing newline
|
||||
result := string(output.data[:])
|
||||
if len(result) > 0 && result[len(result)-1] == '\n' {
|
||||
result = result[:len(result)-1]
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@test "10 decimals"
|
||||
{
|
||||
result := run_script([]string{"10"})
|
||||
expected := "3.1415926535"
|
||||
testing.expect(result == expected)
|
||||
}
|
||||
|
||||
@test "5 decimals"
|
||||
{
|
||||
result := run_script([]string{"5"})
|
||||
expected := "3.14159"
|
||||
testing.expect(result == expected)
|
||||
}
|
||||
|
||||
@test "1 decimal"
|
||||
{
|
||||
result := run_script([]string{"1"})
|
||||
expected := "3.1"
|
||||
testing.expect(result == expected)
|
||||
}
|
||||
|
||||
@test "100 decimals"
|
||||
{
|
||||
result := run_script([]string{"100"})
|
||||
expected := "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679"
|
||||
testing.expect(result == expected)
|
||||
}
|
||||
|
||||
@test "default 100 decimals"
|
||||
{
|
||||
result := run_script([]string{})
|
||||
expected := "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679"
|
||||
testing.expect(result == expected)
|
||||
}
|
||||
|
||||
@test "10000 decimals"
|
||||
{
|
||||
result := run_script([]string{"10000"})
|
||||
// Check length: "3." + 10000 digits = 10002 characters
|
||||
testing.expect(len(result) == 10002)
|
||||
testing.expect(strings.has_prefix(result, "3.14159"))
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
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)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import "core:fmt"
|
||||
import "core:strings"
|
||||
|
||||
main :: proc() {
|
||||
// Test string building
|
||||
builder: strings.Builder
|
||||
strings.builder_init(&builder, context.temp_allocator)
|
||||
|
||||
// Test 1: Using fmt.sbprintf
|
||||
fmt.sbprintf(&builder, "{}", 123)
|
||||
fmt.sbprintf(&builder, "{:09}", 456)
|
||||
|
||||
result := strings.to_string(builder)
|
||||
fmt.println("Result:", result)
|
||||
|
||||
// Test 2: Using append to dynamic array
|
||||
bytes: [dynamic]u8
|
||||
append(&bytes, 51) // 3
|
||||
append(&bytes, 46) // .
|
||||
append(&bytes, 49) // 1
|
||||
append(&bytes, 52) // 4
|
||||
|
||||
str := string(bytes[:])
|
||||
fmt.println("String from bytes:", str)
|
||||
}
|
||||
Reference in New Issue
Block a user