- 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
17 KiB
Agent: Lägg till nytt programmeringsspråk
Översikt
För att lägga till ett nytt programmeringsspråk till pi-beräkningsprojektet, följ dessa steg exakt.
VIKTIGT: Undantag för Bash
Bash är ett UNDANTAG och används endast som referenskod. Bash använder bc -l med formeln 4*a(1) för att beräkna pi, vilket är en annan algoritm än Machins formel. Bash inkluderas inte i prestandajämförelser och kraven nedan gäller inte för Bash.
Alla andra språk (Go, Rust, Python, C, C++, Haskell, Erlang, etc.) MÅSTE följa reglerna nedan exakt.
Steg 1: Skapa katalogstruktur
Skapa en ny katalog i projektroten med språkets namn (gemener) med följande struktur:
/Users/einand/Code/test/<språk>/
├── bin/ # Kompilerade binärer eller wrapper-scripts
│ └── print_hej # Den körbara filen
├── src/ # Källkod
│ └── print_hej.<extension> # Källkodsfilen
└── cmd/ # Kommandon och scripts
├── build.sh # Byggscript
└── test.sh # Testscript
Exempel:
-
python/src/print_hej.py -
python/bin/print_hej(wrapper script) -
python/cmd/build.sh -
python/cmd/test.sh -
rust/src/print_hej.rs -
rust/bin/print_hej(kompilerad binär) -
rust/cmd/build.sh -
rust/cmd/test.sh
Steg 2: Skapa programfil
Skapa en fil som heter print_hej.<extension> i src/-katalogen.
Obligatoriska krav för programmet:
-
Ta emot argument: Programmet ska acceptera ett kommandoradsargument med antal decimaler att beräkna.
- Om inget argument ges, använd default 100 decimaler
- Om ogiltigt argument, använd default 100 decimaler
-
Beräkna pi korrekt: Använd Machins formel med Taylor-serien för arctan.
- Machins formel:
pi/4 = 4*arctan(1/5) - arctan(1/239) - Taylor-serien för arctan:
arctan(1/x) = 1/x - 1/(3*x^3) + 1/(5*x^5) - ...
- Machins formel:
Steg 2.5: OBLIGATORISK ALGORITM
VIKTIGT: Alla implementationer MÅSTE använda exakt samma algoritm för att säkerställa rättvis jämförelse mellan språk.
Den obligatoriska algoritmen för arctan(1/x):
function arctan(x, decimals):
scale = 10^(decimals + 10)
x_squared = x * x
term = scale / x
result = 0
sign = 1
n = 0
while term != 0 AND n < decimals * 3:
// Add contribution with sign
contrib = term / (2*n + 1)
if sign > 0:
result = result + contrib
else:
result = result - contrib
// Next term: divide by x²
term = term / x_squared
// Flip sign
sign = -sign
n = n + 1
// Safety limit
if n > decimals * 2:
break
return result
Nyckelpunkter för algoritmen:
- Skala med 10^(decimals+10): Använd heltalsaritmetik med skalfaktor för precision
- Dela med x² varje iteration: Detta är den kritiska optimeringen!
- ❌ FEL: Beräkna
x^(2n+1)från grunden varje iteration (mycket långsamt) - ✅ RÄTT:
term = term / x²varje iteration (snabbt)
- ❌ FEL: Beräkna
- Använd teckenväxling:
sign = -signför att alternera mellan addition och subtraktion - Säkerhetsgräns:
n < decimals * 3för att undvika oändliga loopar
Varför denna algoritm?
Denna algoritm är optimerad för godtycklig precision:
- Effektivitet: Att dela med
x²varje iteration är O(n) operation - Jämförbarhet: Alla språk använder samma algoritm, vilket ger rättvis prestandajämförelse
- Korrekthet: Algoritmen konvergerar snabbt och ger exakta resultat
Exempel på implementationer:
Python:
def arctan(x, precision):
result = Decimal(0)
x = Decimal(x)
x_squared = x * x
term = Decimal(1) / x
sign = 1
for n in range(1000000):
divisor = Decimal(2 * n + 1)
contrib = term / divisor
if sign > 0:
result += contrib
else:
result -= contrib
term = term / x_squared
sign = -sign
if term < Decimal(10) ** (-precision - 10):
break
return result
Rust:
fn arctan_big(x: u32, scale: &BigUint) -> BigUint {
let mut result = BigUint::zero();
let x_big = BigUint::from(x);
let x_squared = &x_big * &x_big;
let mut term = scale / &x_big;
let mut sign: i32 = 1;
let mut n: u64 = 0;
loop {
let divisor = BigUint::from(2u64 * n + 1);
let contrib = &term / &divisor;
if sign > 0 {
result = &result + &contrib;
} else {
result = &result - &contrib;
}
term = &term / &x_squared;
sign = -sign;
if term.is_zero() || n > 5000000 {
break;
}
n += 1;
}
result
}
C:
void arctan(mpz_t result, unsigned long x, unsigned long decimals) {
mpz_t term, x_squared, contrib;
mpz_init(term);
mpz_init(x_squared);
mpz_init(contrib);
mpz_t scale;
mpz_init(scale);
mpz_ui_pow_ui(scale, 10, decimals + 10);
mpz_set_ui(x_squared, x);
mpz_mul_ui(x_squared, x_squared, x);
mpz_fdiv_q_ui(term, scale, x);
mpz_set_ui(result, 0);
unsigned long n = 0;
int sign = 1;
while (mpz_cmp_ui(term, 0) != 0 && n < decimals * 3) {
mpz_fdiv_q_ui(contrib, term, 2 * n + 1);
if (sign > 0) {
mpz_add(result, result, contrib);
} else {
mpz_sub(result, result, contrib);
}
mpz_fdiv_q(term, term, x_squared);
sign = -sign;
n++;
if (n > decimals * 2) break;
}
mpz_clear(term);
mpz_clear(x_squared);
mpz_clear(contrib);
mpz_clear(scale);
}
Steg 4: Utdataformat
Programmet ska skriva ut pi med exakt antal decimaler, följt av newline.
- Format:
3.1415926535...(inga extra tecken, ingen avrundning) - Exakt
<antal_decimaler>decimaler efter punkten
- Inga extra utskrifter: Endast pi-värdet ska skrivas ut, inga debug-meddelanden eller statusinformation.
Exempel på korrekt utdata:
$ bin/print_hej 10
3.1415926535
$ bin/print_hej 5
3.14159
$ bin/print_hej 100
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
Steg 5: Använd godtycklig precision (Arbitrary Precision)
Programmet MÅSTE använda godtycklig precision (arbitrary precision) aritmetik för att beräkna pi korrekt med många decimaler.
Språkspecifika bibliotek:
| Språk | Bibliotek | Användning |
|---|---|---|
| Python | decimal.Decimal |
from decimal import Decimal, getcontext |
| Rust | num-bigint |
use num_bigint::BigUint; |
| Go | math/big |
import "math/big" |
| Bash | bc -l |
echo "scale=$decimals; 4*a(1)" | bc -l |
| C | GMP eller egen implementation |
#include <gmp.h> |
| C++ | boost::multiprecision |
#include <boost/multiprecision/cpp_int.hpp> |
| Java | BigInteger / BigDecimal |
import java.math.BigInteger; |
| JavaScript | big-integer eller decimal.js |
npm install big-integer |
| Ruby | BigDecimal |
require 'bigdecimal' |
Viktigt om precision:
- Sätt precision till minst
decimals + 10för att undvika avrundningsfel - Använd heltalsaritmetik där det är möjligt (skala med 10^n)
- Kontrollera att resultatet matchar facit.txt
Steg 6: Kompilera (om nödvändigt)
Om språket kräver kompilering:
Kompilerade språk:
-
Rust: Skapa
Cargo.tomlmed beroenden[dependencies] num-bigint = "0.4" num-traits = "0.2"Kompilera:
cargo build --releaseBinär:bin/print_hej -
Go: Ingen extra konfiguration behövs Kompilera:
go build -o bin/print_hej src/print_hej.go -
C/C++: Skapa
Makefileeller kompilera manuellt Kompilera:gcc -o bin/print_hej src/print_hej.c -lgmp
Tolkade språk:
Ingen kompilering behövs. Skapa ett wrapper-script i bin/:
#!/bin/bash
# Wrapper script for interpreted languages
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$SCRIPT_DIR"
<interpreter> src/print_hej.<extension> "$@"
Steg 7: Skapa build.sh (OBLIGATORISKT)
VIKTIGT: Varje språk MÅSTE ha en build.sh i cmd/-katalogen som bygger programmet.
Skapa filen <språk>/cmd/build.sh med följande innehåll:
För kompilerade språk:
#!/bin/bash
# <Språk> Build Script
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$SCRIPT_DIR"
echo "=== <Språk> Build ==="
echo ""
# Skapa bin-katalog
mkdir -p bin
# Kompilera programmet
<kompilationskommando> -o bin/print_hej src/print_hej.<extension>
if [ $? -eq 0 ]; then
echo "✓ Kompilering lyckades!"
echo "Binär: bin/print_hej"
echo ""
echo "För att köra:"
echo " bin/print_hej [decimaler]"
else
echo "✗ Kompilering misslyckades!"
exit 1
fi
För interpreterade språk:
#!/bin/bash
# <Språk> Build Script - <Språk> är interpreterat, ingen kompilering behövs
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$SCRIPT_DIR"
echo "=== <Språk> Build ==="
echo "<Språk> är ett interpreterat språk, ingen kompilering behövs."
echo "Script: src/print_hej.<extension>"
echo ""
echo "Skapar wrapper script i bin/"
mkdir -p bin
cat > bin/print_hej << 'EOF'
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$SCRIPT_DIR"
<interpreter> src/print_hej.<extension> "$@"
EOF
chmod +x bin/print_hej
echo "✓ Klart!"
Exempel:
C:
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$SCRIPT_DIR"
echo "=== C Build ==="
mkdir -p bin
gcc -o bin/print_hej src/print_hej.c -lgmp
if [ $? -eq 0 ]; then
echo "✓ Kompilering lyckades!"
else
echo "✗ Kompilering misslyckades!"
exit 1
fi
Python:
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$SCRIPT_DIR"
echo "=== Python Build ==="
mkdir -p bin
cat > bin/print_hej << 'EOF'
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$SCRIPT_DIR"
python3 src/print_hej.py "$@"
EOF
chmod +x bin/print_hej
echo "✓ Klart!"
Steg 8: Skapa test.sh (OBLIGATORISKT)
VIKTIGT: Tester är OBLIGATORISKT, inte valfria. Varje nytt språk MÅSTE ha tester.
Skapa filen <språk>/cmd/test.sh som kör språkets testramverk:
För språk med testramverk:
#!/bin/bash
# <Språk> Unit Tests - använder <testramverk>
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$SCRIPT_DIR"
echo "=== <Språk> Pi-beräkning Unit Tester (<testramverk>) ==="
echo ""
# Kör testramverket
<testkommando>
exit $?
Exempel per språk:
Python (pytest):
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$SCRIPT_DIR"
echo "=== Python Pi-beräkning Unit Tester (pytest) ==="
/Users/einand/Code/test/.venv/bin/python -m pytest src/test_pi.py -v
exit $?
JavaScript (Jest):
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$SCRIPT_DIR"
echo "=== JavaScript Pi-beräkning Unit Tester (Jest) ==="
npm test
exit $?
Go (go test):
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$SCRIPT_DIR"
echo "=== Go Pi-beräkning Unit Tester (go test) ==="
go test -v
exit $?
Rust (cargo test):
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$SCRIPT_DIR"
echo "=== Rust Pi-beräkning Unit Tester (cargo test) ==="
cargo test
exit $?
C (assert):
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$SCRIPT_DIR"
echo "=== C Pi-beräkning Unit Tester (assert) ==="
gcc -o bin/pi_test src/pi_test.c
bin/pi_test
exit $?
Obligatoriska tester:
Varje testfil ska innehålla följande testfall:
- Testa 10 decimaler: Resultatet ska vara
3.1415926535 - Testa 5 decimaler: Resultatet ska vara
3.14159 - Testa 1 decimal: Resultatet ska vara
3.1 - Testa 100 decimaler: Resultatet ska matcha facit.txt
- Testa default (100 decimaler): Resultatet ska matcha facit.txt
- Testa ogiltig input: Ska använda default (100 decimaler)
- Testa 10000 decimaler: Resultatet ska matcha facit.txt
Steg 9: Verifiera
Kör build.sh och test.sh för att verifiera:
# Bygg programmet
cd <språk>
cmd/build.sh
# Kör tester
cmd/test.sh
# Eller kör alla builds och tester från roten
cd /Users/einand/Code/test
./build.sh # Bygger alla språk
./run_all_tests.sh # Kör alla tester
Alla tester ska passera för det nya språket.
Steg 10: Dokumentation
Lägg till en README.md i språkkatalogen med:
- Beskrivning: Kort beskrivning av implementationen
- Krav: Nödvändiga beroenden och versioner
- Kompilering: Instruktioner för att kompilera (om nödvändigt)
- Körning: Instruktioner för att köra programmet
- Prestanda: Notering om prestanda jämfört med andra språk
Exempel på README.md:
# Python Pi-beräkning
## Beskrivning
Beräknar pi med godtycklig precision med hjälp av Machins formel.
## Struktur
python/ ├── bin/ │ └── print_hej # Wrapper script ├── src/ │ └── print_hej.py # Källkod └── cmd/ ├── build.sh # Byggscript └── test.sh # Testscript
## Krav
- Python 3.6+
- Inga externa beroenden (använder `decimal` från standardbiblioteket)
## Körning
```bash
# Bygg (skapar wrapper script)
cmd/build.sh
# Kör
bin/print_hej <antal_decimaler>
Prestanda
- 10 decimaler: ~100 ms
- 100 decimaler: ~40 ms
- 10000 decimaler: ~500 ms
## Vanliga problem och lösningar
### Problem: "Avrundningsfel vid många decimaler"
**Lösning**: Öka precisionen i beräkningen. Sätt precision till minst `decimals + 20` för att undvika avrundningsfel i sista siffrorna.
### Problem: "Programmet är för långsamt"
**Lösning**:
- Använd Machins formel istället för Leibniz formel (konvergerar snabbare)
- Optimera arctan-funktionen med bättre algoritmer
- Använd språkets optimerade bibliotek för stor heltalsaritmetik
### Problem: "Resultatet matchar inte facit.txt"
**Lösning**:
- Kontrollera att du inte avrundar resultatet
- Se till att du klipper till exakt rätt antal decimaler
- Verifiera att algoritmen är korrekt implementerad
### Problem: "Kompileringsfel med beroenden"
**Lösning**:
- Se till att alla beroenden är installerade
- Kontrollera versioner av bibliotek
- Använd container för att isolera miljön
## Facit
Facit finns i `/Users/einand/Code/test/facit.txt` och innehåller pi med 10000+ decimaler.
## Struktur
/Users/einand/Code/test/ ├── bash/ │ ├── bin/ │ │ └── print_hej │ ├── src/ │ │ └── print_hej.sh │ └── cmd/ │ ├── build.sh │ └── test.sh ├── go/ │ ├── bin/ │ │ └── print_hej │ ├── src/ │ │ ├── print_hej.go │ │ └── print_hej_test.go │ └── cmd/ │ ├── build.sh │ └── test.sh ├── rust/ │ ├── bin/ │ │ └── print_hej │ ├── src/ │ │ └── print_hej.rs │ └── cmd/ │ ├── build.sh │ └── test.sh ├── python/ │ ├── bin/ │ │ └── print_hej │ ├── src/ │ │ ├── print_hej.py │ │ └── test_pi.py │ └── cmd/ │ ├── build.sh │ └── test.sh ├── <nytt_språk>/ │ ├── bin/ │ │ └── print_hej │ ├── src/ │ │ └── print_hej. │ └── cmd/ │ ├── build.sh │ └── test.sh └── facit.txt # Facit för verifiering
## Sammanfattning
För att lägga till ett nytt språk:
1. Skapa katalogstruktur `<språk>/{bin,src,cmd}/`
2. Skapa `src/print_hej.<extension>` med korrekt implementation
3. **Använd den obligatoriska algoritmen** (se Steg 2.5)
4. Använd godtycklig precision (arbitrary precision)
5. Skapa `cmd/build.sh` (OBLIGATORISKT) - bygger programmet
6. Skapa `cmd/test.sh` (OBLIGATORISKT) - kör testramverket
7. Skapa testfiler för språkets testramverk (t.ex. `src/test_pi.py`, `src/pi_test.go`)
8. Verifiera med `cmd/build.sh` och `cmd/test.sh`
9. Dokumentera i README.md
**VIKTIGT**:
- Alla implementationer MÅSTE använda exakt samma algoritm (se Steg 2.5) för att säkerställa rättvis prestandajämförelse
- `cmd/build.sh` och `cmd/test.sh` är OBLIGATORISKA, inte valfria
- Tester ska använda språkets standardiserade testramverk (pytest, Jest, go test, etc.)
- Binären/wrappern ska placeras i `bin/`-katalogen
- Källkoden ska placeras i `src/`-katalogen
- Scripts ska placeras i `cmd/`-katalogen
Följ dessa steg exakt för att säkerställa att det nya språket fungerar korrekt med resten av projektet.