diff --git a/d/main.go b/d/main.go new file mode 100644 index 0000000..bc32558 --- /dev/null +++ b/d/main.go @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" +) + +func derivative(f func(float64) float64, x, e float64) float64 { + return (f(x+e) - f(x-e)) / (e) +} + +func gradient(f func(x float64) float64, a, x, e float64) float64 { + for derivative(f, x, e) > 1e-6 { + x -= a * derivative(f, x, e) + } + return x +} + +func main() { + e := 1e-6 + f := func(x float64) float64 { return x*x*x*x - 4*x*x*x + 2*x*x + 10*x + 12 } + min := gradient(f, 0.01, 1, e) + fmt.Println(min) +} diff --git a/d/main_test.go b/d/main_test.go new file mode 100644 index 0000000..adc1157 --- /dev/null +++ b/d/main_test.go @@ -0,0 +1,26 @@ +package main + +import ( + "math" + "testing" +) + +func TestSolveSecant(t *testing.T) { + for _, tc := range []struct { + f func(float64) float64 + a, x, eps float64 + want float64 + }{ + {f: func(x float64) float64 { return math.Pow(x, 3) - 2*x - 5 }, a: 0.01, x: 2, eps: 1e-3, want: 0.816}, + {f: func(x float64) float64 { return 3*x*x*x*x - 4*x*x*x - 12*x*x - 5 }, a: 0.01, x: 1, eps: 1, want: 2}, + {f: func(x float64) float64 { return x - 5*math.Sin(x) - 3.5 }, a: 0.09, x: 10, eps: 1e-5, want: 7.65262}, + {f: func(x float64) float64 { return (1+x)*math.Pow(10, 3*x) - 5 }, a: 0.01, x: 0.01, eps: 1e-3, want: -1.145}, + {f: func(x float64) float64 { return -(1+x)*math.Pow(10, (-2)*x) + 8 }, a: 0.001, x: 2, eps: 1e-3, want: -0.783}, + } { + got := gradient(tc.f, tc.a, tc.x, tc.eps) + if math.Abs(got-tc.want) > tc.eps { + t.Errorf("got = %v, want = %v", got, tc.want) + } + + } +} diff --git a/main.go b/main.go index e39985b..1b85ad7 100644 --- a/main.go +++ b/main.go @@ -3,13 +3,30 @@ package main import ( "image" "log" + "math" "time" "github.com/hajimehoshi/ebiten/v2" ) -func f(x float64) float64 { return x*x + 5*x - 3 } -func df(x float64) float64 { return 2*x + 5 } +func f(x float64) float64 { return -(1+x)*math.Pow(10, (-2)*x) + 8 } + +func derivative(f func(float64) float64, x, e float64) float64 { + return (f(x+e) - f(x-e)) / (2 * e) +} + +func sign(x float64) float64 { + if x > 0 { + return 1 + } else if x < 0 { + return -1 + } + return 0 +} + +func gradientlength(a float64) float64 { + return a / math.Sqrt(a*a) +} func main() { ebiten.SetWindowSize(640, 480) @@ -17,12 +34,17 @@ func main() { img := make(chan *image.RGBA, 1) go func() { + e := 1e-6 p := Plot(-5, 0, 0.1, f) x := 0.0 img <- p(x) - for i := 0; i < 50; i++ { + lr := 1e-3 + for derivative(f, x, e) > 1e-6 { time.Sleep(30 * time.Millisecond) - x -= df(x) * 0.1 + // x -= lr * sign(derivative(f, x, e)) + gradient := derivative(f, x, e) + normalized := (1 / gradientlength(gradient)) * gradient + x -= lr * sign(normalized) img <- p(x) } }()