Added internal support for float operations

This commit is contained in:
Sasha Koshka 2022-11-22 19:40:22 -05:00
parent 7417b58bad
commit 9e07d10c52
3 changed files with 319 additions and 184 deletions

289
calculate.go Normal file
View File

@ -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
}

View File

@ -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
}

211
tree.go
View File

@ -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
}