You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
hal/hal_test.go

241 lines
6.0 KiB

package main
import (
"git.jfdev.de/JonasFranzDEV/hal/hal"
"git.jfdev.de/JonasFranzDEV/hal/parser"
"github.com/stretchr/testify/assert"
"math"
"testing"
)
func TestAddition(t *testing.T) {
input := []string{
"1 START",
"2 IN 0",
"3 STORE 10",
"4 IN 0",
"5 ADD 10",
"6 OUT 1",
"7 STOP",
}
program, err := parser.ParseProgram(input)
assert.NoError(t, err)
module, err := hal.NewHALModule(program, 256, 2, false)
assert.NoError(t, err)
module.IO[0] = hal.NewMockIO(10, 10)
outputMock := hal.NewMockIO()
module.IO[1] = outputMock
err = module.Run()
assert.NoError(t, err)
assert.Equal(t, float64(20), outputMock.Outputs[0])
}
func TestMax(t *testing.T) {
input := []string{
"00 IN 0",
"01 STORE 1",
"02 IN 0",
"03 STORE 2",
"04 SUB 1",
"05 JUMPPOS 9",
"06 LOAD 1",
"07 OUT 1",
"08 STOP",
"09 LOAD 2",
"10 OUT 1",
"11 STOP",
}
program, err := parser.ParseProgram(input)
assert.NoError(t, err)
module, err := hal.NewHALModule(program, 256, 2, false)
assert.NoError(t, err)
module.IO[0] = hal.NewMockIO(10, 15)
outputMock := hal.NewMockIO()
module.IO[1] = outputMock
err = module.Run()
assert.NoError(t, err)
assert.Len(t, outputMock.Outputs, 1)
assert.Equal(t, float64(15), outputMock.Outputs[0])
}
func TestNewton1(t *testing.T) {
input := []string{
"01 START",
"02 LOADNUM 1",
"03 STORE 10", // Every x is saved to reg 10
// f(x)
"10 MUL 10", // x²
"11 MUL 10", // x³
"12 STORE 12", // Saving x³ for later
"13 MUL 10", // x⁴
"14 MUL 10", // x⁵
"15 STORE 11", // Save x⁵ in reg 11
"21 LOAD 12", // Load x³
"22 MULNUM 5", // x³ * 5
"30 ADD 11", // (x³ * 5) + x⁵
"31 SUBNUM 5", // ((x³ * 5) + x⁵) - 5
"32 STORE 20", // Store the result of f(x) in 20
// Exit condition
"33 SUB 50", // reg 50 contains the last result which we compare with the last one
"34 JUMPNULL 66", // If both are equal, we go to line 66
"35 LOAD 20", // Otherwise save the last result of f(x) as last result
"36 STORE 50", // and continue
// f'(x)
"40 LOAD 10", // Load x
"41 MUL 10", // x²
"42 STORE 21", // Save x² for later
"43 MUL 10", // x³
"44 MUL 10", // x⁴
"45 MULNUM 5", // x⁴ * 5
"46 STORE 22", // Save 5x⁴ to reg 22
"47 LOAD 21", // load x² from earlier
"48 MULNUM 15", // x² * 15
"49 ADD 22", // 15x² + 5x⁴ from earlier
"50 STORE 30", // Save the result of f'(x) to reg 30
// x - (f(x) / f'(x))
"60 LOAD 20", // f(x) / f'(x)
"61 DIV 30",
"62 STORE 40", // Store the result of it in reg 40
"63 LOAD 10", // Load the x again
"64 SUB 40", // x - (f(x) / f'(x))
"65 JUMP 03", // Start at the beginning
// Load the result and print it
"66 LOAD 10",
"67 OUT 0",
"68 STOP",
}
program, err := parser.ParseProgram(input)
assert.NoError(t, err)
module, err := hal.NewHALModule(program, 256, 1, false)
assert.NoError(t, err)
outputMock := hal.NewMockIO()
module.IO[0] = outputMock
err = module.Run()
assert.NoError(t, err)
calculateNewton := func(start float64) float64 {
f1 := func(x float64) float64 {
return math.Pow(x, 5) + 5*math.Pow(x, 3) - 5
}
f1derived := func(x float64) float64 {
return 5*math.Pow(x, 4) + 15*math.Pow(x, 2)
}
var last float64
x := start
for x != last {
last = x
x = x - f1(x)/f1derived(x)
}
return x
}
assert.Equal(t, calculateNewton(1), outputMock.Outputs[0])
}
func TestNewton2(t *testing.T) {
input := []string{
"01 START",
"02 LOADNUM 1",
"03 STORE 10", // Every x is saved to reg 10
// f(x)
"10 MUL 10", // x²
"11 STORE 11", // Save x² to reg 11 for later use since we need that in the second part of the function
"12 MUL 10", // x³
"13 MUL 10", // x⁴
"14 MUL 10", // x⁵
"15 STORE 20", // This is x⁵ which we save here to save a few instructions
"16 MUL 10", // x⁶
"17 MULNUM 8", // x⁶ * 8
"18 STORE 12", // Reg 12 now contains the result of the first part of f(x)
"19 LOAD 11", // Put x² from earlier back in the accumulator
"20 MULNUM 3", // x² * 3
"21 ADD 12", // Add the first and second part of the function together, basically 8x⁶ + 3x²
"22 SUBNUM 3", // (8x⁶ + 3x²) - 3
"23 STORE 15", // Result in reg 15
// f'(x)
"30 LOAD 20", // x⁵ which we saved earlier while calculating x⁶
"31 MULNUM 48", // x⁵ * 48
"32 STORE 21", // Store the result in 21
"33 LOAD 10", // Load our x
"34 MULNUM 6", // x * 6
"35 ADD 21", // (x * 6) + 48x⁵
"36 STORE 25", // Store the result, which is the total result of f'(x) in reg 25
// x - f(x) / f'(x)
"40 LOAD 15", // load f(x)
"41 DIV 25", // f(x) / f'(x)
"42 MULNUM -1", // Invert the result
"43 ADD 10", // Add x: Because we inverted the result before, we can do this instead of SUB - lets us reuse the content of the accumulator
"44 STORE 35", // Reg 35 now contains the end result of x - f(x) / f'(x)
// This is our exit condition:
// We compare the current result with the last calculated result, if both are equal, we exit
"50 SUB 50", // Reg 50 contains the last result
"51 JUMPNULL 60", // If both are equal, we exit
"52 LOAD 35", // Otherwise load reg 15 again, store it as the current last result and continue
"53 STORE 50",
// Go to the beginning
"54 JUMP 03",
"60 LOAD 10", // Load the result
"61 OUT 0", // Print it
"62 STOP",
}
program, err := parser.ParseProgram(input)
assert.NoError(t, err)
module, err := hal.NewHALModule(program, 256, 1, false)
assert.NoError(t, err)
outputMock := hal.NewMockIO()
module.IO[0] = outputMock
err = module.Run()
assert.NoError(t, err)
calculateNewton := func(start float64) float64 {
f1 := func(x float64) float64 {
return 8*math.Pow(x, 6) + 3*math.Pow(x, 2) - 3
}
f1derived := func(x float64) float64 {
return 48*math.Pow(x, 5) + 6*x
}
var last float64
x := start
for x != last {
last = x
x = x - f1(x)/f1derived(x)
}
return x
}
assert.Equal(t, calculateNewton(1), outputMock.Outputs[0])
}