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,3 @@
|
||||
module print_hej
|
||||
|
||||
go 1.21
|
||||
@@ -0,0 +1,73 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const scriptPath = "/Users/einand/Code/test/go/print_hej"
|
||||
|
||||
func runScript(decimals ...int) string {
|
||||
args := []string{}
|
||||
if len(decimals) > 0 {
|
||||
args = append(args, string(rune(decimals[0])))
|
||||
}
|
||||
cmd := exec.Command(scriptPath, args...)
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return strings.TrimSpace(string(output))
|
||||
}
|
||||
|
||||
func Test10Decimals(t *testing.T) {
|
||||
result := runScript(10)
|
||||
expected := "3.1415926535"
|
||||
if result != expected {
|
||||
t.Errorf("Expected %s, got %s", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func Test5Decimals(t *testing.T) {
|
||||
result := runScript(5)
|
||||
expected := "3.14159"
|
||||
if result != expected {
|
||||
t.Errorf("Expected %s, got %s", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func Test1Decimal(t *testing.T) {
|
||||
result := runScript(1)
|
||||
expected := "3.1"
|
||||
if result != expected {
|
||||
t.Errorf("Expected %s, got %s", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func Test100Decimals(t *testing.T) {
|
||||
result := runScript(100)
|
||||
expected := "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679"
|
||||
if result != expected {
|
||||
t.Errorf("Expected %s, got %s", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefault100Decimals(t *testing.T) {
|
||||
result := runScript()
|
||||
expected := "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679"
|
||||
if result != expected {
|
||||
t.Errorf("Expected %s, got %s", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func Test10000Decimals(t *testing.T) {
|
||||
result := runScript(10000)
|
||||
// Check length: "3." + 10000 digits = 10002 characters
|
||||
if len(result) != 10002 {
|
||||
t.Errorf("Expected 10002 characters, got %d", len(result))
|
||||
}
|
||||
if !strings.HasPrefix(result, "3.14159") {
|
||||
t.Errorf("Result should start with 3.14159, got %s", result[:10])
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Hämta antal decimaler från argument
|
||||
decimals := 100
|
||||
if len(os.Args) > 1 {
|
||||
if d, err := strconv.Atoi(os.Args[1]); err == nil && d > 0 {
|
||||
decimals = d
|
||||
}
|
||||
}
|
||||
|
||||
// Beräkna pi med Machins formel: pi/4 = 4*arctan(1/5) - arctan(1/239)
|
||||
// Använd exakt aritmetik med big.Int
|
||||
pi := calculatePiExact(decimals)
|
||||
|
||||
// Skriv ut resultatet
|
||||
fmt.Println(formatPiExact(pi, decimals))
|
||||
}
|
||||
|
||||
func calculatePiExact(decimals int) *big.Int {
|
||||
// pi = 4 * (4*arctan(1/5) - arctan(1/239))
|
||||
// Skala med 10^(decimals+10) för exakt aritmetik
|
||||
|
||||
scale := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimals+10)), nil)
|
||||
|
||||
atan1_5 := arctanExact(5, scale)
|
||||
atan1_239 := arctanExact(239, scale)
|
||||
|
||||
// 4 * atan(1/5)
|
||||
result := new(big.Int).Mul(big.NewInt(4), atan1_5)
|
||||
|
||||
// - atan(1/239)
|
||||
result.Sub(result, atan1_239)
|
||||
|
||||
// * 4
|
||||
result.Mul(result, big.NewInt(4))
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func arctanExact(x int64, scale *big.Int) *big.Int {
|
||||
// arctan(1/x) = 1/x - 1/(3*x^3) + 1/(5*x^5) - ...
|
||||
// Med skala: scale/x - scale/(3*x^3) + scale/(5*x^5) - ...
|
||||
|
||||
result := big.NewInt(0)
|
||||
|
||||
xBig := big.NewInt(x)
|
||||
xSquared := new(big.Int).Mul(xBig, xBig)
|
||||
|
||||
// term = scale / x
|
||||
term := new(big.Int).Div(scale, xBig)
|
||||
|
||||
sign := big.NewInt(1)
|
||||
|
||||
for n := 0; n < 100000; n++ {
|
||||
// Lägg till term / (2n+1) med rätt tecken
|
||||
divisor := big.NewInt(int64(2*n + 1))
|
||||
contrib := new(big.Int).Div(term, divisor)
|
||||
|
||||
if sign.Sign() > 0 {
|
||||
result.Add(result, contrib)
|
||||
} else {
|
||||
result.Sub(result, contrib)
|
||||
}
|
||||
|
||||
// Nästa term: term = term / x^2
|
||||
term.Div(term, xSquared)
|
||||
|
||||
// Växla tecken
|
||||
sign.Neg(sign)
|
||||
|
||||
// Avbryt om termen är 0
|
||||
if term.Sign() == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func formatPiExact(pi *big.Int, decimals int) string {
|
||||
// Konvertera till sträng
|
||||
piStr := pi.String()
|
||||
|
||||
// pi är skalad med 10^(decimals+10), så vi behöver justera decimalpunkten
|
||||
// För pi ≈ 3.14159..., pi*10^110 ≈ 314159... (110 siffror)
|
||||
|
||||
// Lägg till ledande noll om nödvändigt
|
||||
for len(piStr) < decimals+10 {
|
||||
piStr = "0" + piStr
|
||||
}
|
||||
|
||||
// Ta första siffran, sedan decimalpunkt, sedan resten
|
||||
if len(piStr) > decimals+10 {
|
||||
piStr = piStr[:decimals+10]
|
||||
}
|
||||
|
||||
// Resultatet bör vara "3" följt av decimaler
|
||||
result := string(piStr[0]) + "." + piStr[1:decimals+1]
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPi10Decimals(t *testing.T) {
|
||||
cmd := exec.Command("./print_hej", "10")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
t.Fatalf("Kunde inte köra program: %v", err)
|
||||
}
|
||||
|
||||
result := strings.TrimSpace(string(output))
|
||||
expected := "3.1415926535"
|
||||
|
||||
if result != expected {
|
||||
t.Errorf("Fel resultat för 10 decimaler.\nFörväntade: %s\nFick: %s", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPi5Decimals(t *testing.T) {
|
||||
cmd := exec.Command("./print_hej", "5")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
t.Fatalf("Kunde inte köra program: %v", err)
|
||||
}
|
||||
|
||||
result := strings.TrimSpace(string(output))
|
||||
expected := "3.14159"
|
||||
|
||||
if result != expected {
|
||||
t.Errorf("Fel resultat för 5 decimaler.\nFörväntade: %s\nFick: %s", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPi1Decimal(t *testing.T) {
|
||||
cmd := exec.Command("./print_hej", "1")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
t.Fatalf("Kunde inte köra program: %v", err)
|
||||
}
|
||||
|
||||
result := strings.TrimSpace(string(output))
|
||||
expected := "3.1"
|
||||
|
||||
if result != expected {
|
||||
t.Errorf("Fel resultat för 1 decimal.\nFörväntade: %s\nFick: %s", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPiDefault(t *testing.T) {
|
||||
cmd := exec.Command("./print_hej")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
t.Fatalf("Kunde inte köra program: %v", err)
|
||||
}
|
||||
|
||||
result := strings.TrimSpace(string(output))
|
||||
|
||||
// Läs facit
|
||||
facit, err := os.ReadFile("../facit.txt")
|
||||
if err != nil {
|
||||
t.Fatalf("Kunde inte läsa facit: %v", err)
|
||||
}
|
||||
|
||||
expected := strings.TrimSpace(string(facit))
|
||||
expected = strings.ReplaceAll(expected, "\n", "")[:103]
|
||||
|
||||
if result != expected {
|
||||
t.Errorf("Fel resultat för default (100 decimaler).\nFörväntade: %s\nFick: %s", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPiInvalidInput(t *testing.T) {
|
||||
cmd := exec.Command("./print_hej", "abc")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
t.Fatalf("Kunde inte köra program: %v", err)
|
||||
}
|
||||
|
||||
result := strings.TrimSpace(string(output))
|
||||
|
||||
// Ska använda default (100 decimaler)
|
||||
if !strings.HasPrefix(result, "3.1415926535") {
|
||||
t.Errorf("Hanterar inte ogiltig input korrekt.\nFick: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCalculatePiExact(t *testing.T) {
|
||||
pi := calculatePiExact(10)
|
||||
result := formatPiExact(pi, 10)
|
||||
|
||||
expected := "3.1415926535"
|
||||
if result != expected {
|
||||
t.Errorf("calculatePiExact gav fel resultat.\nFörväntade: %s\nFick: %s", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestArctanExact(t *testing.T) {
|
||||
scale := new(big.Int).Exp(big.NewInt(10), big.NewInt(20), nil)
|
||||
|
||||
// arctan(1/5) ska vara ungefär 0.1973955598...
|
||||
atan1_5 := arctanExact(5, scale)
|
||||
|
||||
// Kontrollera att resultatet är positivt
|
||||
if atan1_5.Sign() <= 0 {
|
||||
t.Errorf("arctan(1/5) ska vara positivt, fick: %v", atan1_5)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatPiExact(t *testing.T) {
|
||||
// Skapa ett pi-värde: 31415926535... (skalat med 10^10)
|
||||
pi := big.NewInt(31415926535)
|
||||
|
||||
result := formatPiExact(pi, 10)
|
||||
expected := "3.1415926535"
|
||||
|
||||
if result != expected {
|
||||
t.Errorf("formatPiExact gav fel resultat.\nFörväntade: %s\nFick: %s", expected, result)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user