# 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// ├── bin/ # Kompilerade binärer eller wrapper-scripts │ └── print_hej # Den körbara filen ├── src/ # Källkod │ └── print_hej. # 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.` i `src/`-katalogen. ### Obligatoriska krav för programmet: 1. **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 2. **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) - ...` ## 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: 1. **Skala med 10^(decimals+10)**: Använd heltalsaritmetik med skalfaktor för precision 2. **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) 3. **Använd teckenväxling**: `sign = -sign` för att alternera mellan addition och subtraktion 4. **Säkerhetsgräns**: `n < decimals * 3` fö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:** ```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:** ```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:** ```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 `` decimaler efter punkten 5. **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 ` | | C++ | `boost::multiprecision` | `#include ` | | 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 + 10` fö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: 1. **Rust**: Skapa `Cargo.toml` med beroenden ```toml [dependencies] num-bigint = "0.4" num-traits = "0.2" ``` Kompilera: `cargo build --release` Binär: `bin/print_hej` 2. **Go**: Ingen extra konfiguration behövs Kompilera: `go build -o bin/print_hej src/print_hej.go` 3. **C/C++**: Skapa `Makefile` eller 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/`: ```bash #!/bin/bash # Wrapper script for interpreted languages SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)" cd "$SCRIPT_DIR" src/print_hej. "$@" ``` ## Steg 7: Skapa build.sh (OBLIGATORISKT) **VIKTIGT**: Varje språk MÅSTE ha en `build.sh` i `cmd/`-katalogen som bygger programmet. Skapa filen `/cmd/build.sh` med följande innehåll: ### För kompilerade språk: ```bash #!/bin/bash # Build Script SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)" cd "$SCRIPT_DIR" echo "=== Build ===" echo "" # Skapa bin-katalog mkdir -p bin # Kompilera programmet -o bin/print_hej src/print_hej. 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: ```bash #!/bin/bash # Build Script - är interpreterat, ingen kompilering behövs SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)" cd "$SCRIPT_DIR" echo "=== Build ===" echo " är ett interpreterat språk, ingen kompilering behövs." echo "Script: src/print_hej." 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" src/print_hej. "$@" EOF chmod +x bin/print_hej echo "✓ Klart!" ``` ### Exempel: **C:** ```bash #!/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:** ```bash #!/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 `/cmd/test.sh` som kör språkets testramverk: ### För språk med testramverk: ```bash #!/bin/bash # Unit Tests - använder SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)" cd "$SCRIPT_DIR" echo "=== Pi-beräkning Unit Tester () ===" echo "" # Kör testramverket exit $? ``` ### Exempel per språk: **Python (pytest):** ```bash #!/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):** ```bash #!/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):** ```bash #!/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):** ```bash #!/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):** ```bash #!/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: 1. **Testa 10 decimaler**: Resultatet ska vara `3.1415926535` 2. **Testa 5 decimaler**: Resultatet ska vara `3.14159` 3. **Testa 1 decimal**: Resultatet ska vara `3.1` 4. **Testa 100 decimaler**: Resultatet ska matcha facit.txt 5. **Testa default (100 decimaler)**: Resultatet ska matcha facit.txt 6. **Testa ogiltig input**: Ska använda default (100 decimaler) 7. **Testa 10000 decimaler**: Resultatet ska matcha facit.txt ## Steg 9: Verifiera Kör `build.sh` och `test.sh` för att verifiera: ```bash # Bygg programmet cd 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: 1. **Beskrivning**: Kort beskrivning av implementationen 2. **Krav**: Nödvändiga beroenden och versioner 3. **Kompilering**: Instruktioner för att kompilera (om nödvändigt) 4. **Körning**: Instruktioner för att köra programmet 5. **Prestanda**: Notering om prestanda jämfört med andra språk ### Exempel på README.md: ```markdown # 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 ``` ## 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 ├── / │ ├── 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 `/{bin,src,cmd}/` 2. Skapa `src/print_hej.` 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.