mathpan/calculate.go

390 lines
8.5 KiB
Go
Raw Normal View History

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
var rawSolution uint64
switch operation.opcode {
case OpcodeAdd:
for _, operand := range operation.operands {
subSolution, err = operand.InexactSolution()
if err != nil { return }
solution += subSolution
}
case OpcodeSubtract:
if len(operation.operands) == 1 {
solution, err = operation.operands[0].InexactSolution()
solution *= -1
if err != nil { return }
break
}
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:
for _, operand := range operation.operands {
subSolution, err = operand.InexactSolution()
if err != nil { return }
rawSolution |= math.Float64bits(subSolution)
}
solution = math.Float64frombits(rawSolution)
case OpcodeNot:
if len(operation.operands) != 1 {
err = ErrorWrongOperandCount
return
}
subSolution, err = operation.operands[0].InexactSolution()
solution = math.Float64frombits(^math.Float64bits(subSolution))
case OpcodeAnd:
for index, operand := range operation.operands {
subSolution, err = operand.InexactSolution()
if err != nil { return }
if index == 0 {
rawSolution = math.Float64bits(subSolution)
} else {
rawSolution &= math.Float64bits(subSolution)
}
}
solution = math.Float64frombits(rawSolution)
case OpcodeXor:
for index, operand := range operation.operands {
subSolution, err = operand.InexactSolution()
if err != nil { return }
if index == 0 {
rawSolution = math.Float64bits(subSolution)
} else {
rawSolution ^= math.Float64bits(subSolution)
}
}
solution = math.Float64frombits(rawSolution)
case OpcodeLeftShift:
if len(operation.operands) != 2 {
err = ErrorWrongOperandCount
return
}
var left, right float64
left, err = operation.operands[0].InexactSolution()
if err != nil { return }
right, err = operation.operands[1].InexactSolution()
if err != nil { return }
if right < 0 {
err = ErrorNegativeShiftAmount
return
}
solution = math.Float64frombits (
math.Float64bits(left) <<
math.Float64bits(right))
case OpcodeRightShift:
if len(operation.operands) != 2 {
err = ErrorWrongOperandCount
return
}
var left, right float64
left, err = operation.operands[0].InexactSolution()
if err != nil { return }
right, err = operation.operands[1].InexactSolution()
if err != nil { return }
if right < 0 {
err = ErrorNegativeShiftAmount
return
}
solution = math.Float64frombits (
math.Float64bits(left) >>
math.Float64bits(right))
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
}