2016-04-30 31 views
3

我試圖在工作表上使用求解器,比如表A中。我也在表A中有一些帶「= rand()」的單元格,或者在表格中使用寫入Application.Volatile的自定義函數說出任何公式。我希望這些揮發性細胞在我解算器時停止重新計算,所以我在我的求解器程序中使用了Application.Calculation = xlCalculationManual,但在運行求解器後我發現那些易失性細胞已經發生了變化。我在哪裏做錯了?在VBA中使用Solver時,如何關閉重新計算?

回答

3

有2種方法來避免這種情況:

  1. 不要求解使用!如果您編寫自己的子文件來執行這些操作,您可以使用Range.Calculate,而計算是手動計算這些單元格(所有其他單元格將被忽略)。

  2. 更改公式並進行迭代選項 - >公式 - >啓用迭代計算。現在使用的輔助細胞持有真/假(或1/0或其他)和變化的公式,你不想計算如下(輔助細胞A1/A2公式):


=IF(A1,A2,[your old formula]) 

這樣,只要A1是true它會輸出計算前的值。

據我所知,沒有其他辦法,因爲求解器每次測試一個新的循環時都會執行Calculate


編輯
具有揮發性UDF它不需要揮發的全部時間,你可以使用一個簡單的技巧(又一個輔助細胞)需要:

A1: [volatile function like =NOW() or =RAND()] 
A2: =MY_UDF(A1) 

在模塊中:

Public Function MY_UDF(a As Variant) As Double 
    a = a 
    MY_UDF = Now 
End Function 

只要A1持有一些易變的東西,你的UDF就會每次重新計算。但是如果你清空了A1(或者使其處於非易失性狀態),那麼對於提交給UDF的值就不會有任何變化,這樣excel/vba就會假定不會發生變化,只需跳過它就可以進行重新計算。這樣,只要輔助單元是非易失性的,您也可以建立自己的RAND -UDF(當然有不同的名稱)來停止工作簿中的所有易失性函數。

作爲說明:在使A1(本例中)非易失性之後,之後的第一次計算仍然會運行1次,就像它是易失性的。同時將A1從一個值更改爲另一個值(如0到1)將運行一次。

+0

你當然是對的。解算器顯然不可能在不重新計算的情況下實現其魔力,因爲要求優化的函數和約束由*電子表格公式組成。 –

+0

但是爲什麼Solver會重新計算整個工作表/整張工作表?爲什麼不使用範圍。計算?我遇到了這個問題,因爲我正在做一個非線性OLS(可能沒有機會跳過Solver?),但我想這樣做N次,每次優化函數(SolverOk中的第一個參數)是簡單的,因爲我用它們可以得到N個不同的優化函數!),雖然它們不直接參與優化,但是它們不能改變,因爲它們會改變優化函數。所以這是故事:( – Nicholas

+0

順便說一句,那麼將它們複製到一個新的區域作爲價值? – Nicholas

3

這是一種解決方法,可以幫助您在電子表格中隨機選擇可以隨意重新計算並且可以開啓和關閉波動率的值。

首先,創建一個名爲範圍1節,說「觸發」

然後,把下面的代碼在一個標準的代碼模塊:

Function SemiVolatileRand(x As Variant) As Double 
    SemiVolatileRand = x - x + Rnd() 
End Function 

Sub ReSample() 
    Randomize 
    Range("trigger").Value = Range("trigger").Value + 0.01 
End Sub 

附上ReSample子到一個按鈕。用 =SemiVolatileRand(trigger)替換所有的出現的=RAND()。只要按下按鈕,他們就會重新調節。此外,如果您想要恢復全部波動率,只需將公式=RAND()放入觸發單元格中即可。 (在這最後一種情況下獲得全面波動似乎需要我的代碼確實與虛擬變量x,因此有些無點x - x)。

Randomize從系統時鐘重新生成隨機數發生器。它應該在每個會話中至少調用一次。如果您不這樣做,那麼每次打開使用VBA rnd的Excel工作簿時,都會得到相同的隨機值序列。您可以通過一個空白工作簿,並在ThisWorkbook代碼模塊放驗證這一點:

Private Sub Workbook_Open() 
MsgBox Rnd() 
End Sub 

消息塊將在每次打開工作簿時顯示的值相同。另一方面,如果您將Randomize一行放在MsgBox之前,那麼每次打開它時都會得到不同的值。

請注意,如果您打算使用rnd,則工作簿打開事件是放置語句Randomize的自然地點。

我沒有把Randomize放在函數本身中的原因既是爲了節省CPU週期,也是因爲一個令人擔憂的問題,即在一定比例的時間內你將用完全相同的系統時間重新發送隨機數發生器。運行最新版本的Excel的現代體系結構可能是不可能的,但例如,如果您有Randomize Timer(您在閱讀其他代碼時有時會遇到),有時會發生,因爲定時器功能具有1毫秒的分辨率,與系統時鐘無關。

我有的代碼確實有缺點,如果你繞過按鈕,只是改變觸發單元,那麼你可能會錯過重新播種。如果這是一個問題,1個可能會是這樣的:

公共初始化爲布爾

功能SemiVolatileRand(X爲Variant)爲雙 如果未初始化然後 隨機化 初始化=真 結束如果 SemiVolatileRand = x - x + Rnd() End Function

如果rnd未正確接種,這將阻止函數運行。

Excel本身會自動處理工作表函數Rand(),因此它嚴格是VBA併發症。

+0

爲什麼你要在你的ReSample()子程序中使用Randomize? – Nicholas

+0

@NicholasLiu這是種子的僞隨機數發生器。查看編輯。 –

相關問題