Simple Windows PowerShell Calculator v1.0

Programlama ve Script dilleri konusunda bilgi paylaşım alanıdır.
Cevapla
Kullanıcı avatarı
TRWE_2012
Zettabyte1
Zettabyte1
Mesajlar: 15578
Kayıt: 25 Eyl 2013, 13:38
cinsiyet: Erkek
Teşekkür etti: 2704 kez
Teşekkür edildi: 5608 kez

Simple Windows PowerShell Calculator v1.0

Mesaj gönderen TRWE_2012 »

Merhabalar

Bu betik hakkında öyle uzun uzun açıklama yapmayı gerek görmüyorum.Sıradan basit ama çok güçlü karmaşık işlemler yapabilen bir konsol hesap makinesidir.

KOD İÇERİĞİ : ( Simple Calculator v1.0.ps1)

Kod: Tümünü seç

# ============================================================
# Simple Windows PowerShell Calculator
# System : Windows 11
#
# Supports: + - * / % ^ (power) and parentheses, plus these functions:
#   sin, cos, tan, asin, acos, atan  (trigonometric - ANGLES IN RADIANS)
#   sqrt, abs, exp, log (base 10), ln (natural log), pow(x, y)
#
# SAFETY: Uses a custom recursive-descent parser, not Invoke-Expression
# or any generic evaluator. Only numbers, the operators above, and the
# whitelisted function names below are ever recognized - anything else
# (letters that aren't a known function, variables, PowerShell syntax,
# semicolons, etc.) is rejected before evaluation ever begins. This is
# the same safety guarantee as bash's 'bc': math only, no code execution.
# ============================================================

$AllowedFunctions = @('sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'sqrt', 'abs', 'exp', 'log', 'ln', 'pow')

function Invoke-MathFunction {
    param([string]$Name, [double[]]$Arguments)
    switch ($Name.ToLower()) {
        'sin'  { return [math]::Sin($Arguments[0]) }
        'cos'  { return [math]::Cos($Arguments[0]) }
        'tan'  { return [math]::Tan($Arguments[0]) }
        'asin' { return [math]::Asin($Arguments[0]) }
        'acos' { return [math]::Acos($Arguments[0]) }
        'atan' { return [math]::Atan($Arguments[0]) }
        'sqrt' { return [math]::Sqrt($Arguments[0]) }
        'abs'  { return [math]::Abs($Arguments[0]) }
        'exp'  { return [math]::Exp($Arguments[0]) }
        'log'  { return [math]::Log10($Arguments[0]) }
        'ln'   { return [math]::Log($Arguments[0]) }
        'pow'  {
            if ($Arguments.Count -lt 2) { throw "pow() requires two arguments: pow(base, exponent)" }
            return [math]::Pow($Arguments[0], $Arguments[1])
        }
        default { throw "Unknown function: $Name" }
    }
}

# --- TOKENIZER ---
function Get-Tokens {
    param([string]$Expr)
    $pattern = '\d+\.?\d*|[A-Za-z]+|[\+\-\*/\^%\(\),]'
    $matches = [regex]::Matches($Expr, $pattern)

    $cleanInput = $Expr -replace '\s', ''
    $matchedLength = ($matches | ForEach-Object { $_.Value } | Measure-Object -Property Length -Sum).Sum
    if ($matchedLength -ne $cleanInput.Length) {
        throw "Input contains characters that are not numbers, allowed operators, or known function names."
    }

    return @($matches | ForEach-Object { $_.Value })
}

# --- RECURSIVE DESCENT PARSER / EVALUATOR ---
$script:tokens = @()
$script:pos = 0

function Peek-Token { if ($script:pos -lt $script:tokens.Count) { return $script:tokens[$script:pos] } else { return $null } }
function Read-Token  { $t = Peek-Token; $script:pos++; return $t }

function Parse-Expression {
    $value = Parse-Term
    while ((Peek-Token) -in @('+', '-')) {
        $op = Read-Token
        $rhs = Parse-Term
        if ($op -eq '+') { $value += $rhs } else { $value -= $rhs }
    }
    return $value
}

function Parse-Term {
    $value = Parse-Power
    while ((Peek-Token) -in @('*', '/', '%')) {
        $op = Read-Token
        $rhs = Parse-Power
        switch ($op) {
            '*' { $value = $value * $rhs }
            '/' {
                if ($rhs -eq 0) { throw "Division by zero." }
                $value = $value / $rhs
            }
            '%' { $value = $value % $rhs }
        }
    }
    return $value
}

function Parse-Power {
    $value = Parse-Unary
    if ((Peek-Token) -eq '^') {
        Read-Token | Out-Null
        $rhs = Parse-Power
        $value = [math]::Pow($value, $rhs)
    }
    return $value
}

function Parse-Unary {
    if ((Peek-Token) -eq '-') {
        Read-Token | Out-Null
        return -1 * (Parse-Unary)
    }
    return Parse-Primary
}

function Parse-Primary {
    $t = Peek-Token
    if ($null -eq $t) { throw "Unexpected end of expression." }

    if ($t -match '^\d') {
        Read-Token | Out-Null
        return [double]::Parse($t, [System.Globalization.CultureInfo]::InvariantCulture)
    }

    if ($t -eq '(') {
        Read-Token | Out-Null
        $value = Parse-Expression
        if ((Peek-Token) -ne ')') { throw "Missing closing parenthesis." }
        Read-Token | Out-Null
        return $value
    }

    if ($t -match '^[A-Za-z]+$') {
        if ($t.ToLower() -notin $AllowedFunctions) {
            throw "Unknown or unsupported function: '$t'"
        }
        $funcName = Read-Token
        if ((Peek-Token) -ne '(') { throw "Expected '(' after function name '$funcName'." }
        Read-Token | Out-Null

        $argsList = @(Parse-Expression)
        while ((Peek-Token) -eq ',') {
            Read-Token | Out-Null
            $argsList += Parse-Expression
        }
        if ((Peek-Token) -ne ')') { throw "Missing closing parenthesis for function '$funcName'." }
        Read-Token | Out-Null

        return Invoke-MathFunction -Name $funcName -Arguments $argsList
    }

    throw "Unexpected token: '$t'"
}

function Show-Header {
    Clear-Host
    Write-Host "============================================" -ForegroundColor Blue
    Write-Host "  Simple Windows PowerShell Calculator      " -ForegroundColor Blue
    Write-Host "============================================" -ForegroundColor Blue
    Write-Host ""
}

# --- MAIN LOOP ---
while ($true) {
    Show-Header
    Write-Host "Enter an arithmetic expression:"
    Write-Host "(Supported: + - * / % ^ ( ) and sin cos tan asin acos atan sqrt abs exp log ln pow - angles in RADIANS)" -ForegroundColor DarkGray
    $userInput = Read-Host

    try {
        $script:tokens = Get-Tokens -Expr $userInput
        $script:pos = 0

        if ($script:tokens.Count -eq 0) { throw "Empty expression." }

        $numericResult = Parse-Expression

        if ($script:pos -lt $script:tokens.Count) {
            throw "Unexpected token after end of expression: '$(Peek-Token)'"
        }

        $invariant = [System.Globalization.CultureInfo]::InvariantCulture

        Write-Host ""
        Write-Host "Two decimal places of precision:"
        Write-Host $numericResult.ToString("F2", $invariant)

        Write-Host "Ten decimal places of precision:"
        Write-Host $numericResult.ToString("F10", $invariant)

        Write-Host "Rounded integer value:"
        Write-Host ([math]::Round($numericResult, 0, [MidpointRounding]::AwayFromZero))
    } catch {
        Write-Host ""
        Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Red
    }

    Write-Host ""
    Write-Host "Press ENTER to exit, or press 'R' to run another calculation..." -ForegroundColor Yellow
    $key = [Console]::ReadKey($true)

    if ($key.KeyChar -eq 'r' -or $key.KeyChar -eq 'R') {
        continue
    } else {
        break
    }
}
EKRAN GÖRÜNTÜSÜ :
Resim
Güle güle kullanın...
Kullanıcı avatarı
TRWE_2012
Zettabyte1
Zettabyte1
Mesajlar: 15578
Kayıt: 25 Eyl 2013, 13:38
cinsiyet: Erkek
Teşekkür etti: 2704 kez
Teşekkür edildi: 5608 kez

Simple Windows PowerShell Calculator v2.0

Mesaj gönderen TRWE_2012 »

Artık bu konsol hesap makinesi 2.dereceden bir bilinmeyenli denklemlerin köklerini bulabiliyor..

KOD İÇERİĞİ :

Kod: Tümünü seç

# ============================================================
# Simple Windows PowerShell Calculator
# System : Windows 11
#
# Supports: + - * / % ^ (power) and parentheses, plus these functions:
#   sin, cos, tan, asin, acos, atan  (trigonometric - ANGLES IN RADIANS)
#   sqrt, abs, exp, log (base 10), ln (natural log), pow(x, y)
#
# SAFETY: Uses a custom recursive-descent parser, not Invoke-Expression
# or any generic evaluator. Only numbers, the operators above, and the
# whitelisted function names below are ever recognized - anything else
# (letters that aren't a known function, variables, PowerShell syntax,
# semicolons, etc.) is rejected before evaluation ever begins. This is
# the same safety guarantee as bash's 'bc': math only, no code execution.
# ============================================================

$AllowedFunctions = @('sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'sqrt', 'abs', 'exp', 'log', 'ln', 'pow')

function Invoke-MathFunction {
    param([string]$Name, [double[]]$Arguments)
    switch ($Name.ToLower()) {
        'sin'  { return [math]::Sin($Arguments[0]) }
        'cos'  { return [math]::Cos($Arguments[0]) }
        'tan'  { return [math]::Tan($Arguments[0]) }
        'asin' { return [math]::Asin($Arguments[0]) }
        'acos' { return [math]::Acos($Arguments[0]) }
        'atan' { return [math]::Atan($Arguments[0]) }
        'sqrt' { return [math]::Sqrt($Arguments[0]) }
        'abs'  { return [math]::Abs($Arguments[0]) }
        'exp'  { return [math]::Exp($Arguments[0]) }
        'log'  { return [math]::Log10($Arguments[0]) }
        'ln'   { return [math]::Log($Arguments[0]) }
        'pow'  {
            if ($Arguments.Count -lt 2) { throw "pow() requires two arguments: pow(base, exponent)" }
            return [math]::Pow($Arguments[0], $Arguments[1])
        }
        default { throw "Unknown function: $Name" }
    }
}

# --- TOKENIZER ---
function Get-Tokens {
    param([string]$Expr)
    $pattern = '\d+\.?\d*|[A-Za-z]+|[\+\-\*/\^%\(\),]'
    $matches = [regex]::Matches($Expr, $pattern)

    $cleanInput = $Expr -replace '\s', ''
    $matchedLength = ($matches | ForEach-Object { $_.Value } | Measure-Object -Property Length -Sum).Sum
    if ($matchedLength -ne $cleanInput.Length) {
        throw "Input contains characters that are not numbers, allowed operators, or known function names."
    }

    return @($matches | ForEach-Object { $_.Value })
}

# --- RECURSIVE DESCENT PARSER / EVALUATOR ---
$script:tokens = @()
$script:pos = 0

function Peek-Token { if ($script:pos -lt $script:tokens.Count) { return $script:tokens[$script:pos] } else { return $null } }
function Read-Token  { $t = Peek-Token; $script:pos++; return $t }

function Parse-Expression {
    $value = Parse-Term
    while ((Peek-Token) -in @('+', '-')) {
        $op = Read-Token
        $rhs = Parse-Term
        if ($op -eq '+') { $value += $rhs } else { $value -= $rhs }
    }
    return $value
}

function Parse-Term {
    $value = Parse-Power
    while ((Peek-Token) -in @('*', '/', '%')) {
        $op = Read-Token
        $rhs = Parse-Power
        switch ($op) {
            '*' { $value = $value * $rhs }
            '/' {
                if ($rhs -eq 0) { throw "Division by zero." }
                $value = $value / $rhs
            }
            '%' { $value = $value % $rhs }
        }
    }
    return $value
}

function Parse-Power {
    $value = Parse-Unary
    if ((Peek-Token) -eq '^') {
        Read-Token | Out-Null
        $rhs = Parse-Power
        $value = [math]::Pow($value, $rhs)
    }
    return $value
}

function Parse-Unary {
    if ((Peek-Token) -eq '-') {
        Read-Token | Out-Null
        return -1 * (Parse-Unary)
    }
    return Parse-Primary
}

function Parse-Primary {
    $t = Peek-Token
    if ($null -eq $t) { throw "Unexpected end of expression." }

    if ($t -match '^\d') {
        Read-Token | Out-Null
        return [double]::Parse($t, [System.Globalization.CultureInfo]::InvariantCulture)
    }

    if ($t -eq '(') {
        Read-Token | Out-Null
        $value = Parse-Expression
        if ((Peek-Token) -ne ')') { throw "Missing closing parenthesis." }
        Read-Token | Out-Null
        return $value
    }

    if ($t -match '^[A-Za-z]+$') {
        if ($t.ToLower() -notin $AllowedFunctions) {
            throw "Unknown or unsupported function: '$t'"
        }
        $funcName = Read-Token
        if ((Peek-Token) -ne '(') { throw "Expected '(' after function name '$funcName'." }
        Read-Token | Out-Null

        $argsList = @(Parse-Expression)
        while ((Peek-Token) -eq ',') {
            Read-Token | Out-Null
            $argsList += Parse-Expression
        }
        if ((Peek-Token) -ne ')') { throw "Missing closing parenthesis for function '$funcName'." }
        Read-Token | Out-Null

        return Invoke-MathFunction -Name $funcName -Arguments $argsList
    }

    throw "Unexpected token: '$t'"
}

function Show-Header {
    Clear-Host
    Write-Host "============================================" -ForegroundColor Blue
    Write-Host "  Simple Windows PowerShell Calculator      " -ForegroundColor Blue
    Write-Host "============================================" -ForegroundColor Blue
    Write-Host ""
}

# --- QUADRATIC EQUATION SOLVER (ax^2 + bx + c = 0) ---
function Parse-QuadraticCoefficients {
    param([string]$EquationText)

    if ($EquationText -notmatch '=') {
        throw "Equation must contain '=' (e.g. 2x^2+3x+1=0)."
    }
    $sides = $EquationText -split '=', 2
    $left = ($sides[0]).Trim()
    $right = ($sides[1]).Trim()

    if ($right -ne '0') {
        throw "Only equations in the form ax^2+bx+c=0 are supported (right side must be 0)."
    }

    $normalized = $left -replace '\s', ''
    if ($normalized.Length -eq 0) { throw "Empty equation." }
    if ($normalized[0] -ne '+' -and $normalized[0] -ne '-') {
        $normalized = '+' + $normalized
    }

    $termMatches = [regex]::Matches($normalized, '[+-][^+-]+')
    if ($termMatches.Count -eq 0) { throw "Could not parse any terms from the equation." }

    $reconstructed = ($termMatches | ForEach-Object { $_.Value }) -join ''
    if ($reconstructed -ne $normalized) {
        throw "Could not fully parse the equation - check for unsupported syntax."
    }

    $a = 0.0; $b = 0.0; $c = 0.0
    $invariant = [System.Globalization.CultureInfo]::InvariantCulture

    foreach ($m in $termMatches) {
        $term = $m.Value
        $sign = if ($term[0] -eq '-') { -1.0 } else { 1.0 }
        $body = $term.Substring(1) -replace '\*', ''

        if ($body -match '^([\d\.]*)x\^2$') {
            $coefText = $Matches[1]
            $coef = if ($coefText -eq '') { 1.0 } else { [double]::Parse($coefText, $invariant) }
            $a += $sign * $coef
        }
        elseif ($body -match '^([\d\.]*)x$') {
            $coefText = $Matches[1]
            $coef = if ($coefText -eq '') { 1.0 } else { [double]::Parse($coefText, $invariant) }
            $b += $sign * $coef
        }
        elseif ($body -match '^[\d\.]+$') {
            $c += $sign * [double]::Parse($body, $invariant)
        }
        else {
            throw "Unrecognized term: '$term' (only x^2, x, and constant terms are supported)."
        }
    }

    return [PSCustomObject]@{ A = $a; B = $b; C = $c }
}

function Invoke-QuadraticSolver {
    Show-Header
    Write-Host "--- Quadratic Equation Solver ---" -ForegroundColor Blue
    Write-Host "Format: ax^2+bx+c=0  (right side must be 0)" -ForegroundColor DarkGray
    Write-Host "Example: 2x^2+3x+1=0  or  2*x^2+3*x+1=0  or  x^2-4=0" -ForegroundColor DarkGray
    Write-Host ""
    $eqInput = Read-Host "Enter the equation"

    try {
        $coef = Parse-QuadraticCoefficients -EquationText $eqInput

        if ($coef.A -eq 0) {
            throw "Coefficient 'a' (the x^2 term) cannot be zero - this would not be a quadratic equation."
        }

        Write-Host ""
        Write-Host "Detected coefficients: a=$($coef.A)  b=$($coef.B)  c=$($coef.C)" -ForegroundColor DarkGray

        $discriminant = ($coef.B * $coef.B) - (4 * $coef.A * $coef.C)
        $invariant = [System.Globalization.CultureInfo]::InvariantCulture

        Write-Host ""
        Write-Host "Discriminant (b^2 - 4ac): $($discriminant.ToString('F4', $invariant))"
        Write-Host ""

        if ($discriminant -gt 0) {
            $x1 = (-$coef.B + [math]::Sqrt($discriminant)) / (2 * $coef.A)
            $x2 = (-$coef.B - [math]::Sqrt($discriminant)) / (2 * $coef.A)
            Write-Host "Two distinct real roots:" -ForegroundColor Green
            Write-Host "  x1 = $($x1.ToString('F6', $invariant))"
            Write-Host "  x2 = $($x2.ToString('F6', $invariant))"
        }
        elseif ($discriminant -eq 0) {
            $x = -$coef.B / (2 * $coef.A)
            Write-Host "One real root (repeated):" -ForegroundColor Green
            Write-Host "  x = $($x.ToString('F6', $invariant))"
        }
        else {
            $realPart = -$coef.B / (2 * $coef.A)
            $imagPart = [math]::Sqrt(-$discriminant) / (2 * $coef.A)
            Write-Host "No real roots - two complex conjugate roots:" -ForegroundColor Yellow
            Write-Host "  x1 = $($realPart.ToString('F6', $invariant)) + $($imagPart.ToString('F6', $invariant))i"
            Write-Host "  x2 = $($realPart.ToString('F6', $invariant)) - $($imagPart.ToString('F6', $invariant))i"
        }
    } catch {
        Write-Host ""
        Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Red
    }

    Write-Host ""
    Read-Host "Press Enter to return to main menu"
}

function Invoke-Calculator {
    Show-Header
    Write-Host "Enter an arithmetic expression:"
    Write-Host "(Supported: + - * / % ^ ( ) and sin cos tan asin acos atan sqrt abs exp log ln pow - angles in RADIANS)" -ForegroundColor DarkGray
    $userInput = Read-Host

    try {
        $script:tokens = Get-Tokens -Expr $userInput
        $script:pos = 0

        if ($script:tokens.Count -eq 0) { throw "Empty expression." }

        $numericResult = Parse-Expression

        if ($script:pos -lt $script:tokens.Count) {
            throw "Unexpected token after end of expression: '$(Peek-Token)'"
        }

        $invariant = [System.Globalization.CultureInfo]::InvariantCulture

        Write-Host ""
        Write-Host "Two decimal places of precision:"
        Write-Host $numericResult.ToString("F2", $invariant)

        Write-Host "Ten decimal places of precision:"
        Write-Host $numericResult.ToString("F10", $invariant)

        Write-Host "Rounded integer value:"
        Write-Host ([math]::Round($numericResult, 0, [MidpointRounding]::AwayFromZero))
    } catch {
        Write-Host ""
        Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Red
    }

    Write-Host ""
    Read-Host "Press Enter to return to main menu"
}

# --- MAIN MENU ---
while ($true) {
    Show-Header
    Write-Host "--- Main Menu ---" -ForegroundColor Blue
    Write-Host "  1 - Evaluate an Arithmetic Expression"
    Write-Host "  2 - Solve a Quadratic Equation (ax^2+bx+c=0)"
    Write-Host "  3 - Exit"
    Write-Host ""
    $choice = Read-Host "Your choice [1-3]"

    switch ($choice) {
        "1" { Invoke-Calculator }
        "2" { Invoke-QuadraticSolver }
        "3" {
            Read-Host "`nPress ENTER to exit."
            exit 0
        }
        default {
            Write-Host "Invalid choice." -ForegroundColor Red
            Start-Sleep -Seconds 1
        }
    }
}
Cevapla

“Programlama ve Script dilleri” sayfasına dön