From 9e07d10c5223a86602079a1c403d14e066b14350 Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Tue, 22 Nov 2022 19:40:22 -0500 Subject: [PATCH] Added internal support for float operations --- calculate.go | 289 +++++++++++++++++++++++++++++++++++++++++++++++++++ error.go | 3 + tree.go | 211 +++++-------------------------------- 3 files changed, 319 insertions(+), 184 deletions(-) create mode 100644 calculate.go diff --git a/calculate.go b/calculate.go new file mode 100644 index 0000000..8015f94 --- /dev/null +++ b/calculate.go @@ -0,0 +1,289 @@ +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: + 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, 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 +} diff --git a/error.go b/error.go index 39e4d0e..33393e4 100644 --- a/error.go +++ b/error.go @@ -7,6 +7,7 @@ const ( ErrorDivideByZero ErrorWrongOperandCount ErrorNegativeShiftAmount + ErrorWrongType ) func (err Error) Error () (description string) { @@ -19,6 +20,8 @@ func (err Error) Error () (description string) { description = "wrong operand amount" case ErrorNegativeShiftAmount: description = "negative shift amount" + case ErrorWrongType: + description = "wrong type" } return } diff --git a/tree.go b/tree.go index ddaaf4b..e643385 100644 --- a/tree.go +++ b/tree.go @@ -1,7 +1,5 @@ package main -import "math" - import "git.tebibyte.media/sashakoshka/stone" var selectedExpression Expression @@ -61,9 +59,10 @@ type Expression interface { } type Operation struct { - parent *Operation - opcode Opcode + parent *Operation + opcode Opcode operands []Expression + floating bool // TODO: add bool to make this into a float // when it is a float: @@ -225,7 +224,12 @@ func (operation *Operation) Last () (last Expression) { } func (operation *Operation) Render (target stone.Buffer, offset int) (moved int) { - target.SetRune(offset, 0, '[') + if operation.floating { + target.SetRune(offset, 0, '(') + } else { + target.SetRune(offset, 0, '[') + } + if selectedExpression == operation { target.SetColor(offset, 0, stone.ColorBlue) } else { @@ -250,7 +254,12 @@ func (operation *Operation) Render (target stone.Buffer, offset int) (moved int) moved += operand.Render(target, offset + moved) } - target.SetRune(offset + moved, 0, ']') + if operation.floating { + target.SetRune(offset + moved, 0, ')') + } else { + target.SetRune(offset + moved, 0, ']') + } + if selectedExpression == operation { target.SetColor(offset + moved, 0, stone.ColorBlue) } else { @@ -261,190 +270,24 @@ func (operation *Operation) Render (target stone.Buffer, offset int) (moved int) } 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 - } - 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 + if operation.floating { + var floatSolution float64 + floatSolution, err = operation.inexactSolution() + solution = int64(floatSolution) + } else { + solution, err = operation.solution() } return } func (operation *Operation) InexactSolution () (solution float64, err error) { - var intSolution int64 - intSolution, err = operation.Solution() - solution = float64(intSolution) - return -} - -func integerPower (x, y int64) (result int64) { - if y == 0 { - result = 1 - return + if operation.floating { + solution, err = operation.inexactSolution() + } else { + var intSolution int64 + intSolution, err = operation.solution() + solution = float64(intSolution) } - - 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 }