diff --git a/hal_test.go b/hal_test.go index f80dd99..edcf6f5 100644 --- a/hal_test.go +++ b/hal_test.go @@ -120,26 +120,107 @@ func TestNewton1(t *testing.T) { err = module.Run() assert.NoError(t, err) - assert.Len(t, outputMock.Outputs, 1) - assert.Equal(t, float64(15), outputMock.Outputs[0]) + 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), module.IO[1]) } -func f1(x float64) float64 { - return math.Pow(x, 5) + 5*math.Pow(x, 3) - 5 -} +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 1", // Print it + "62 STOP", + } -func f1derived(x float64) float64 { - return 5*math.Pow(x, 4) + 15*math.Pow(x, 2) -} + program, err := parser.ParseProgram(input) + assert.NoError(t, err) -func calculateNewton(start float64) float64 { - var last float64 - x := start - for x != last { - last = x - x = x - f1(x)/f1derived(x) + module, err := hal.NewHALModule(program, 256, 2, false) + assert.NoError(t, err) + + 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 } - return x + + assert.Equal(t, calculateNewton(1), module.IO[1]) } diff --git a/newton2.hal b/newton2.hal index 72cf628..3e51a0b 100644 --- a/newton2.hal +++ b/newton2.hal @@ -17,11 +17,6 @@ 22 SUBNUM 3 23 STORE 15 -24 SUB 50 -25 JUMPNULL 45 -26 LOAD 15 -27 STORE 50 - 30 LOAD 20 31 MULNUM 48 32 STORE 21 @@ -34,6 +29,16 @@ 41 DIV 25 42 MULNUM -1 43 ADD 10 -44 JUMP 03 -45 OUT 10 -46 STOP \ No newline at end of file + +44 STORE 35 + +50 SUB 50 +51 JUMPNULL 60 +52 LOAD 35 +53 STORE 50 + +54 JUMP 03 + +60 LOAD 10 +61 OUT 1 +62 STOP