Added internal support for float operations
This commit is contained in:
parent
7417b58bad
commit
9e07d10c52
|
@ -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
|
||||||
|
}
|
3
error.go
3
error.go
|
@ -7,6 +7,7 @@ const (
|
||||||
ErrorDivideByZero
|
ErrorDivideByZero
|
||||||
ErrorWrongOperandCount
|
ErrorWrongOperandCount
|
||||||
ErrorNegativeShiftAmount
|
ErrorNegativeShiftAmount
|
||||||
|
ErrorWrongType
|
||||||
)
|
)
|
||||||
|
|
||||||
func (err Error) Error () (description string) {
|
func (err Error) Error () (description string) {
|
||||||
|
@ -19,6 +20,8 @@ func (err Error) Error () (description string) {
|
||||||
description = "wrong operand amount"
|
description = "wrong operand amount"
|
||||||
case ErrorNegativeShiftAmount:
|
case ErrorNegativeShiftAmount:
|
||||||
description = "negative shift amount"
|
description = "negative shift amount"
|
||||||
|
case ErrorWrongType:
|
||||||
|
description = "wrong type"
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
211
tree.go
211
tree.go
|
@ -1,7 +1,5 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "math"
|
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/stone"
|
import "git.tebibyte.media/sashakoshka/stone"
|
||||||
|
|
||||||
var selectedExpression Expression
|
var selectedExpression Expression
|
||||||
|
@ -61,9 +59,10 @@ type Expression interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Operation struct {
|
type Operation struct {
|
||||||
parent *Operation
|
parent *Operation
|
||||||
opcode Opcode
|
opcode Opcode
|
||||||
operands []Expression
|
operands []Expression
|
||||||
|
floating bool
|
||||||
|
|
||||||
// TODO: add bool to make this into a float
|
// TODO: add bool to make this into a float
|
||||||
// when it is 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) {
|
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 {
|
if selectedExpression == operation {
|
||||||
target.SetColor(offset, 0, stone.ColorBlue)
|
target.SetColor(offset, 0, stone.ColorBlue)
|
||||||
} else {
|
} else {
|
||||||
|
@ -250,7 +254,12 @@ func (operation *Operation) Render (target stone.Buffer, offset int) (moved int)
|
||||||
moved += operand.Render(target, offset + moved)
|
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 {
|
if selectedExpression == operation {
|
||||||
target.SetColor(offset + moved, 0, stone.ColorBlue)
|
target.SetColor(offset + moved, 0, stone.ColorBlue)
|
||||||
} else {
|
} else {
|
||||||
|
@ -261,190 +270,24 @@ func (operation *Operation) Render (target stone.Buffer, offset int) (moved int)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (operation *Operation) Solution () (solution int64, err error) {
|
func (operation *Operation) Solution () (solution int64, err error) {
|
||||||
var subSolution int64
|
if operation.floating {
|
||||||
|
var floatSolution float64
|
||||||
switch operation.opcode {
|
floatSolution, err = operation.inexactSolution()
|
||||||
case OpcodeAdd:
|
solution = int64(floatSolution)
|
||||||
for _, operand := range operation.operands {
|
} else {
|
||||||
subSolution, err = operand.Solution()
|
solution, err = operation.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
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (operation *Operation) InexactSolution () (solution float64, err error) {
|
func (operation *Operation) InexactSolution () (solution float64, err error) {
|
||||||
var intSolution int64
|
if operation.floating {
|
||||||
intSolution, err = operation.Solution()
|
solution, err = operation.inexactSolution()
|
||||||
solution = float64(intSolution)
|
} else {
|
||||||
return
|
var intSolution int64
|
||||||
}
|
intSolution, err = operation.solution()
|
||||||
|
solution = float64(intSolution)
|
||||||
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue