summaryrefslogtreecommitdiff
path: root/internal/rpn/arithmetic.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/rpn/arithmetic.go')
-rw-r--r--internal/rpn/arithmetic.go186
1 files changed, 186 insertions, 0 deletions
diff --git a/internal/rpn/arithmetic.go b/internal/rpn/arithmetic.go
new file mode 100644
index 0000000..049cf25
--- /dev/null
+++ b/internal/rpn/arithmetic.go
@@ -0,0 +1,186 @@
+// SPDX-License-Identifier: MIT
+// Copyright (c) 2026 Paul Buetow
+
+package rpn
+
+import (
+ "fmt"
+ "math"
+)
+
+// ArithmeticOperations provides arithmetic operator implementations.
+type ArithmeticOperations struct {
+ mode CalculationMode
+}
+
+// NewArithmeticOperations creates a new ArithmeticOperations instance.
+func NewArithmeticOperations(mode CalculationMode) *ArithmeticOperations {
+ return &ArithmeticOperations{mode: mode}
+}
+
+// Add pops two values from stack, adds them, and pushes result.
+func (o *ArithmeticOperations) Add(stack *Stack) error {
+ bVal, err := stack.Pop()
+ if err != nil {
+ return fmt.Errorf("insufficient operands for +: %w", err)
+ }
+
+ aVal, err := stack.Pop()
+ if err != nil {
+ return fmt.Errorf("insufficient operands for +: %w", err)
+ }
+
+ // Use the Number interface for arithmetic
+ stack.Push(aVal.Add(bVal))
+ return nil
+}
+
+// Subtract pops two values from stack, subtracts (a - b), and pushes result.
+func (o *ArithmeticOperations) Subtract(stack *Stack) error {
+ b, err := stack.Pop()
+ if err != nil {
+ return fmt.Errorf("insufficient operands for -: %w", err)
+ }
+
+ a, err := stack.Pop()
+ if err != nil {
+ return fmt.Errorf("insufficient operands for -: %w", err)
+ }
+
+ stack.Push(a.Sub(b))
+ return nil
+}
+
+// Multiply pops two values from stack, multiplies them, and pushes result.
+func (o *ArithmeticOperations) Multiply(stack *Stack) error {
+ b, err := stack.Pop()
+ if err != nil {
+ return fmt.Errorf("insufficient operands for *: %w", err)
+ }
+
+ a, err := stack.Pop()
+ if err != nil {
+ return fmt.Errorf("insufficient operands for *: %w", err)
+ }
+
+ stack.Push(a.Mul(b))
+ return nil
+}
+
+// Divide pops two values from stack, divides (a / b), and pushes result.
+func (o *ArithmeticOperations) Divide(stack *Stack) error {
+ b, err := stack.Pop()
+ if err != nil {
+ return fmt.Errorf("insufficient operands for /: %w", err)
+ }
+
+ if b.IsZero() {
+ return fmt.Errorf("division by zero")
+ }
+
+ a, err2 := stack.Pop()
+ if err2 != nil {
+ return fmt.Errorf("insufficient operands for /: %w", err2)
+ }
+
+ result, err2 := a.Div(b)
+ if err2 != nil {
+ return fmt.Errorf("division error: %w", err2)
+ }
+ stack.Push(result)
+ return nil
+}
+
+// Power pops two values from stack, raises first to power of second (a ^ b), and pushes result.
+func (o *ArithmeticOperations) Power(stack *Stack) error {
+ b, err := stack.Pop()
+ if err != nil {
+ return fmt.Errorf("insufficient operands for ^: %w", err)
+ }
+
+ a, err := stack.Pop()
+ if err != nil {
+ return fmt.Errorf("insufficient operands for ^: %w", err)
+ }
+
+ stack.Push(a.Pow(b))
+ return nil
+}
+
+// Modulo pops two values from stack, computes modulo (a % b), and pushes result.
+func (o *ArithmeticOperations) Modulo(stack *Stack) error {
+ b, err := stack.Pop()
+ if err != nil {
+ return fmt.Errorf("insufficient operands for %%: %w", err)
+ }
+
+ a, err := stack.Pop()
+ if err != nil {
+ return fmt.Errorf("insufficient operands for %%: %w", err)
+ }
+
+ if b.IsZero() {
+ return fmt.Errorf("modulo by zero")
+ }
+
+ result, err := a.Mod(b)
+ if err != nil {
+ return fmt.Errorf("modulo error: %w", err)
+ }
+ stack.Push(result)
+ return nil
+}
+
+// Log2 pops one value from stack, computes log base 2 (log₂(a)), and pushes result.
+func (o *ArithmeticOperations) Log2(stack *Stack) error {
+ a, err := stack.Pop()
+ if err != nil {
+ return fmt.Errorf("insufficient operands for lg: %w", err)
+ }
+
+ // Check if value is zero or negative
+ val := a.Float64()
+ if val <= 0 {
+ return fmt.Errorf("log2 undefined for non-positive numbers")
+ }
+
+ // Compute log2 using the number interface
+ stack.Push(NewNumber(math.Log2(val), o.mode))
+ return nil
+}
+
+// Log10 pops one value from stack, computes log base 10 (log₁₀(a)), and pushes result.
+func (o *ArithmeticOperations) Log10(stack *Stack) error {
+ a, err := stack.Pop()
+ if err != nil {
+ return fmt.Errorf("insufficient operands for log: %w", err)
+ }
+
+ // Check if value is zero or negative
+ val := a.Float64()
+ if val <= 0 {
+ return fmt.Errorf("log10 undefined for non-positive numbers")
+ }
+
+ // Compute log10 using the number interface
+ stack.Push(NewNumber(math.Log10(val), o.mode))
+ return nil
+}
+
+// Ln pops one value from stack, computes natural log (ln(a)), and pushes result.
+func (o *ArithmeticOperations) Ln(stack *Stack) error {
+ a, err := stack.Pop()
+ if err != nil {
+ return fmt.Errorf("insufficient operands for ln: %w", err)
+ }
+
+ // Check if value is zero or negative
+ val := a.Float64()
+ if val <= 0 {
+ return fmt.Errorf("ln undefined for non-positive numbers")
+ }
+
+ // Compute ln using the number interface
+ stack.Push(NewNumber(math.Log(val), o.mode))
+ return nil
+}