在VBA函数中调用Excel求解器*没有*直接引用单元格?

时间:2019-07-18 03:34:08

标签: excel vba solver

如何在不引用现有单元的情况下在VBA函数中调用求解器?我不想为这些纯粹的中间参数保留单元格。

Public Function calcSomething(param1 As Double, param2 As Double) As Double
' do something
' need to invoke solver to obtain some intermediate params
    Dim intermediate_param As Double
'hopefully should be like intermediate_param = calcWithSolver(param1, param2)
'do something
End Function

Public Function calcWithSolver(param1 As Double, param2 As Double) As Double
' how to call solver here without direct reference to existing cells?
End Function

我在网上发现的使用SolverAdd函数的教程似乎都需要引用已经存在的单元格。有办法避免这种情况吗?

1 个答案:

答案 0 :(得分:1)

作为替代方案,您可以尝试使用这种非常简单的求解器,该求解器使用对分法,并且即使在大多数复杂情况下也能很好地工作。

它没有excel求解器的灵活性,并且不能处理跨越工作簿的深层嵌套引用(您的解决方案参数需要在单个单元格中唯一定义)。但是,只要您可以安排它,它具有自动计算表格的优势,而Excel Solver则无法实现。

还可以通过更改二等分条件(用户练习)来修改代码以找到最大值和最小值

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="popoverOne" class="popover hidden">
 I'm popover 1
</div>
<div id="popoverTwo" class="popover hidden">
 I'm popover 2
</div>
<div id="popoverThree" class="popover hidden">
 I'm popover 3
</div>
<div id="popoverFour" class="popover hidden">
 I'm popover 4
</div>
<div id="popoverFive" class="popover hidden">
 I'm popover 5
</div>
<div id="popoverSix" class="popover hidden">
 I'm popover 6
</div>

<p>
  Look at Popovers 5 and 6, they are broken because you have to scroll the container. Popovers 1-4 work fine because you do not have to scroll.
</p>

<div  id="container" class="container">
  <div class="section" id="sectionOne">
    1 I'm a side menu<br/> 1 <br/> 1 <br/> 1 <br/> 1 <br/>
    <button onClick="togglePopover('popoverOne', 'sectionOne')">Show popover for this section</button>
  </div>
    
  <div class="section" id="sectionTwo">
    2 With options<br/> 2 and a button to show a popover<br/>2 <br/> 2 <br/> 2 <br/>
    <button onClick="togglePopover('popoverTwo', 'sectionTwo')">Show popover for this section</button>
  </div>
  
  <div class="section" id="sectionThree">
    3 <br/> 3<br/> 3 <br/>3<br/> 3 <br/>
    <button onClick="togglePopover('popoverThree', 'sectionThree')">Show popover for this section</button>
  </div>
  
  <div class="section" id="sectionFour">
    4 <br/> 4<br/> 4 <br/> 4 <br/> 4 <br/>
    <button onClick="togglePopover('popoverFour', 'sectionFour')">Show popover for this section</button>
  </div>
   
  <div class="section" id="sectionFive">
    5 <br/> 5 <br/> 5 <br/> 5 <br/> 5 <br/>
    <button onClick="togglePopover('popoverFive', 'sectionFive')">Show popover for this section</button>
  </div>
  
  <div class="section" id="sectionSix">
    6 <br/> 6 <br/> 6<br/> 6 <br/>6<br/>
    <button onClick="togglePopover('popoverSix', 'sectionSix')">Show popover for this section</button>
  </div>
</div>

以excel为例,如果单元格A1中包含方程式

Function Bisect(F_ref As Range, y As Double, xname As String, xmin As Double, xmax As Double, Optional ytol As Double, Optional iter As Double)

'Finds the solution for x of the equation F(x) = y using the bisection method
'Requires a function F(x) and an interval [xmin, xmax] (in which F(x) is continuous) containing one and only one solution.

'F_ref     - reference to single cell containing the function f(x). NOTE : Do not specify the function directly as an input. Cell referenced needs to contain all the dependencies on x directly (no 
'y         - value of F(x) required
'xname     - reference text name for x in F_ref
'xmin,xmax - maximum and minimum values of xname that solution is known to lie within
'ytol      - tolerance to within which solution is needed [optional, default 1e-3]
'iter      - maximum number of iterations [optional, default 20]
'            returns #TOL! if tolerance not met. Increase ytol or increase iter

Dim fun As String, grad As Double, count As Integer

If ytol = 0 Then ytol = 0.001
If iter = 0 Then iter = 20

fun = F_ref.Formula & "-" & y
grad = (Evaluate(Replace(fun, xname, xmax)) - Evaluate(Replace(fun, xname, xmin))) / (xmax - xmin)

For count = 1 To iter
    x = (xmax + xmin) / 2
    y = Evaluate(Replace(fun, xname, x))
    If (y * y) < (ytol * ytol) Then Exit For
    If grad > 0 Then
        If y > 0 Then xmax = x
        If y < 0 Then xmin = x
    Else
        If y < 0 Then xmax = x
        If y > 0 Then xmin = x
    End If
Next count
If count > iter Then x = "#TOL! " & x
Bisect = x
End Function

然后调用函数

=2*LN(B1) + B1

在1和2的值之间求解方程2ln(x)+ x = 2,将x = 1.370的答案返回到默认的小数点后三位。