在Visual Basic上使用对分法的问题

时间:2019-03-29 12:51:54

标签: vb.net loops diamond-problem bisection

这是我的二等分方法代码。如果我输入45,则程序将无限循环。运行有问题。

Sub TheBisectionMethod1()
        Dim a, b As Double 'Taking two variables, A and B
        Console.Write(vbLf & "Input A: ")
        a = Double.Parse(Console.ReadLine()) 'This is where user inputs and value stored for A
        Console.Write(vbLf & "Input B: ")
        b = Double.Parse(Console.ReadLine()) 'This is where user inputs and value stored for B
line1:
        Dim c As Double
        c = (a + b) / 2 'declearing variable c for the sum of half of the user entered values
        If ((Math.Abs(func(c))) < 0.0001) Then 'in flow chart the value of C remians unchange so the program will not run, so it will run if i is >0.0001
            Console.Write(vbLf & "C : {0}", c)
        ElseIf (Math.Sign(func(c)) = Math.Sign(func(a))) Then
            Console.WriteLine("Hello")
            a = c
            GoTo line1
        ElseIf (Math.Sign(func(c)) <> Math.Sign(func(a))) Then
            b = c
            GoTo line1
        End If
    End Sub

Function func(x As Double) As Double
        Dim y As Double
        y = x ^ 2 - 2
        Return y
    End Function

1 个答案:

答案 0 :(得分:2)

不要使用GoTo不需要。另外,从执行实际工作的方法中删除用户交互。一次读取数据,将其传递给执行工作并返回结果的方法(通常为Function而不是Sub),然后在函数结束后向用户显示结果。

这使这个问题变得棘手,因为我们在原始代码中看到的唯一结果是将"Hello"写入控制台,并且显然这只是一条调试语句。您要这段代码做什么? (我假设您是说this

Function Bisect(a as Double, b As Double) As Double
    Dim c As Double = (a + b) / 2 
    Dim d As Double = func(c)

    While Math.Abs(d) >= 0.0001
        If Math.Sign(d) = Math.Sign(func(a)) Then 
           a = c
        Else
           b = c
        End If    

        c = (a + b) / 2
        d = func(c)
    End While
    Return c
End Function

Function func(x As Double) As Double
    Return x ^ 2 - 2
End Function

实际上,它应该看起来像这样:

Function Bisect(a as Double, b As Double, f As Function(Of Double, Double)) As Double
    Dim c As Double = (a + b) / 2 
    Dim d As Double = f(c)

    While Math.Abs(d) >= 0.0001
        If Math.Sign(d) = Math.Sign(f(a)) Then 
           a = c
        Else
           b = c
        End If    

        c = (a + b) / 2
        d = f(c)
    End While
    Return c
End Function

并这样称呼:

Bisect(a, b, Function(x) x ^ 2 - 2)

此外,根据维基百科的文章,此处的算法略有偏离。这更精确:

Function Bisect(a as Double, b As Double, f As Function(Of Double, Double)) As Double
    Dim TOL As Double = 0.0001
    Dim MaxSteps As Integer = 1000
    Dim c As Double = (a + b) / 2 

    While Math.Abs(f(c)) >= TOL AndAlso (b-a)/2 >= TOL AndAlso MaxSteps > 0
        If Math.Sign(f(c)) = Math.Sign(f(a)) Then
           a = c
        Else
           b = c
        End If    

        MaxSteps -= 1
        c = (a + b) / 2
    End While

    If MaxSteps = 0 Then
        Throw New ArgumentException("The bisection fails to converge within the allowed time for the supplied arguments.")
    End If

    Return c
End Function

我提出来,因为原始问题中的投诉是这样:

  

程序无限循环[sic]

并且算法的租户之一不能保证收敛,因此是步数计数器。

最后,在我看来,这似乎很适合作为递归函数。递归可以改善这里的情况,因为我们可以依赖调用堆栈的溢出,而不需要实现步骤计数器:

Function Bisect(a as Double, b As Double, f As Function(Of Double, Double)) As Double
    Dim c As Double = (a + b) / 2
    If Math.Abs(f(c)) < TOL OrElse (b-a)/2 < TOL Then Return c

    If Math.Sign(f(c)) = Math.Sign(f(a)) Then
        Return Bisect(c, b, f)
    Else
        Return Bisect(a, c, f)
    End If
End Function

当然,捕获StackOverflowException本身就是一个技巧,因此您可能仍需要该计数器。但是我需要离开某事让你自己做。

这也有助于说明为什么我建议从Bisect()方法中删除所有用户I / O的部分原因。如果此方法还负责与最终用户对话,则甚至无法考虑递归选项,因为该代码显然比其他任何代码都短且简单。