mathpan/calculate.go
2022-11-25 17:51:24 -05:00

304 lines
6.5 KiB
Go

package main
import "math"
func (operation *Operation) solution () (solution int64, err error) {
var subSolution int64
switch operation.opcode {
case OpcodeAdd:
for _, operand := range operation.operands {
subSolution, err = operand.Solution()
if err != nil { return }
solution += subSolution
}
case OpcodeSubtract:
if len(operation.operands) == 1 {
solution, err = operation.operands[0].Solution()
solution *= -1
if err != nil { return }
break
}
for index, operand := range operation.operands {
subSolution, err = operand.Solution()
if err != nil { return }
if index == 0 {
solution = subSolution
} else {
solution -= subSolution
}
}
case OpcodeMultiply:
solution = 1
for _, operand := range operation.operands {
subSolution, err = operand.Solution()
if err != nil { return }
solution *= subSolution
}
case OpcodeDivide:
for index, operand := range operation.operands {
subSolution, err = operand.Solution()
if err != nil { return }
if index == 0 {
solution = subSolution
} else if subSolution == 0 {
err = ErrorDivideByZero
} else {
solution /= subSolution
}
}
case OpcodePower:
for index, operand := range operation.operands {
subSolution, err = operand.Solution()
if err != nil { return }
if index == 0 {
solution = subSolution
} else {
solution = integerPower(solution, subSolution)
}
}
case OpcodeRoot:
for index, operand := range operation.operands {
subSolution, err = operand.Solution()
if err != nil { return }
if index == 0 {
solution = subSolution
} else {
solution = integerRoot (
solution, subSolution)
}
}
case OpcodeModulo:
for index, operand := range operation.operands {
subSolution, err = operand.Solution()
if err != nil { return }
if index == 0 {
solution = subSolution
} else {
if subSolution == 0 {
err = ErrorDivideByZero
} else {
solution %= subSolution
}
}
}
case OpcodeOr:
for _, operand := range operation.operands {
subSolution, err = operand.Solution()
if err != nil { return }
solution |= subSolution
}
case OpcodeNot:
if len(operation.operands) != 1 {
err = ErrorWrongOperandCount
return
}
subSolution, err = operation.operands[0].Solution()
solution = ^subSolution
case OpcodeAnd:
for index, operand := range operation.operands {
subSolution, err = operand.Solution()
if err != nil { return }
if index == 0 {
solution = subSolution
} else {
solution &= subSolution
}
}
case OpcodeXor:
for index, operand := range operation.operands {
subSolution, err = operand.Solution()
if err != nil { return }
if index == 0 {
solution = subSolution
} else {
solution ^= subSolution
}
}
case OpcodeLeftShift:
if len(operation.operands) != 2 {
err = ErrorWrongOperandCount
return
}
var left, right int64
left, err = operation.operands[0].Solution()
if err != nil { return }
right, err = operation.operands[1].Solution()
if err != nil { return }
if right < 0 {
err = ErrorNegativeShiftAmount
return
}
solution = left << right
case OpcodeRightShift:
if len(operation.operands) != 2 {
err = ErrorWrongOperandCount
return
}
var left, right int64
left, err = operation.operands[0].Solution()
if err != nil { return }
right, err = operation.operands[1].Solution()
if err != nil { return }
if right < 0 {
err = ErrorNegativeShiftAmount
return
}
solution = left >> right
case OpcodeMean:
if len(operation.operands) == 0 { break }
for _, operand := range operation.operands {
subSolution, err = operand.Solution()
if err != nil { break }
solution += subSolution
}
solution /= int64(len(operation.operands))
default:
err = ErrorUnknownOpcode
}
return
}
func (operation *Operation) inexactSolution () (solution float64, err error) {
var subSolution float64
switch operation.opcode {
case OpcodeAdd:
for _, operand := range operation.operands {
subSolution, err = operand.InexactSolution()
if err != nil { return }
solution += subSolution
}
case OpcodeSubtract:
for index, operand := range operation.operands {
subSolution, err = operand.InexactSolution()
if err != nil { return }
if index == 0 {
solution = subSolution
} else {
solution -= subSolution
}
}
case OpcodeMultiply:
solution = 1
for _, operand := range operation.operands {
subSolution, err = operand.InexactSolution()
if err != nil { return }
solution *= subSolution
}
case OpcodeDivide:
for index, operand := range operation.operands {
subSolution, err = operand.InexactSolution()
if err != nil { return }
if index == 0 {
solution = subSolution
} else if subSolution == 0 {
err = ErrorDivideByZero
} else {
solution /= subSolution
}
}
case OpcodePower:
for index, operand := range operation.operands {
subSolution, err = operand.InexactSolution()
if err != nil { return }
if index == 0 {
solution = subSolution
} else {
solution = math.Pow(solution, subSolution)
}
}
case OpcodeRoot:
for index, operand := range operation.operands {
subSolution, err = operand.InexactSolution()
if err != nil { return }
if index == 0 {
solution = subSolution
} else {
solution = math.Pow(solution, 1 / subSolution)
}
}
case OpcodeModulo:
for index, operand := range operation.operands {
subSolution, err = operand.InexactSolution()
if err != nil { return }
if index == 0 {
solution = subSolution
} else {
if subSolution == 0 {
err = ErrorDivideByZero
} else {
solution = math.Mod (
solution,
subSolution)
}
}
}
case
OpcodeOr, OpcodeNot, OpcodeAnd, OpcodeXor, OpcodeLeftShift,
OpcodeRightShift:
err = ErrorWrongType
case OpcodeMean:
if len(operation.operands) == 0 { break }
for _, operand := range operation.operands {
subSolution, err = operand.InexactSolution()
if err != nil { break }
solution += subSolution
}
solution /= float64(len(operation.operands))
default:
err = ErrorUnknownOpcode
}
return
}
func integerPower (x, y int64) (result int64) {
if y == 0 {
result = 1
return
}
result = x
for index := int64(2); index <= y; index ++ {
result *= x
}
return
}
func integerRoot (x, y int64) (result int64) {
// FIXME: find some algorithm for the nth root of an integer
result = int64(math.Pow(float64(x), 1 / float64(y)))
return
}