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 }