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]) }