2016-04-30 3 views
3

シートAにソルバーを使用しようとしました。シートAに「= rand()」というセルがいくつかあります。あるいは、Application.Volatileというカスタム関数を使ってシート上の式を書いています。私はソルバを実行しているときにこれらの揮発性セルの再計算を止めたいので、ソルバープログラムでApplication.Calculation = xlCalculationManualを使用しましたが、ソルバーを実行した後に判明しました。私はどこで間違っているのですか?VBAでソルバーを使用するときに、再計算をオフに切り替えるにはどうすればよいですか?

答えて

3

これを回避するために、2通りの方法があります。

  1. ソルバを使用しないでください!あなたが自分のサブを書く場合は、Range.Calculateを使うことができますが、計算はこのセルを計算するだけです(他のすべてのセルは無視されます)。

  2. 数式を変更して、繰り返しを実行します。オプション - >数式 - >繰り返し計算を有効にします。


:今、あなたは(ヘルパー細胞A1/A2式)を以下のように計算する必要はありません式真/偽保持している(または1/0または何でも)ヘルパー細胞および変更を使用
=IF(A1,A2,[your old formula]) 

このように、A1がtrueの場合、計算前の値を出力します。

私が知る限り、ソルバーは新しいサイクルがテストされるたびにCalculateを実行するので、他の方法はありません。


EDIT:全体の時間は、あなたが簡単なトリック(再びヘルパー細胞)を使用することができ、揮発性である必要はありません
揮発性の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がvolatileを保持している限り、UDFは毎回再計算されます。しかし、A1を空にする(または、それを非揮発性であるとする)場合、UDFに提出された値に変更はなくなります。この方法でExcel/VBAは変更が行われないと仮定し、再計算のためにスキップします。このようにして、ヘルパーセルが不揮発性である限り、ワークブック内のすべての揮発性機能を停止するだけで、独自のRAND -UDF(もちろん別の名前)を構築することもできます。

注意:A1(この例では)を不揮発性にした後、最初の計算はそれがvolatileであるように1回も実行されます。 A1をある値から別の値(0〜1など)に変更すると、1回実行されます。

+0

あなたは確かに正しいです。ソルバーが再計算せずにその魔法を行うことは明らかに不可能です。なぜなら、最適化するよう求められている関数や制約は*スプレッドシートの式で構成されているからです。 –

+0

しかし、ソルバーが操作するシート全体/シート全体を再計算する理由を教えてください。なぜそれは範囲を使用しません。計算する?私は非線形OLSを行っていたときにこの問題に遭遇しましたが(ソルバーをスキップする機会はありませんでしたが)、最適化関数(SolverOkの第1引数)が揮発性のもの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サブを取り付けます。 =RAND()の出現箇所をすべて =SemiVolatileRand(trigger)に置き換えます。ボタンを押すたびに再計算されます。また、完全なボラティリティを元に戻したい場合は、数式=RAND()をトリガーセルに入れてください。 (この最後のケースで完全なボラティリティを得ることは、私のコードがのダミー変数であることを要求するように思えたので、ややポテンシャルのないx - x)。

Randomizeは、システムクロックから乱数ジェネレータを再配置します。セッションごとに少なくとも1回は呼び出す必要があります。そうしないと、VBA rndを使用するExcelワークブックを開くたびに、ランダムな値の同じシーケンスが取得されます。あなたは空白のブックを作ることによって及びThisWorkbookコードモジュールプットでこれを確認することができます。

Private Sub Workbook_Open() 
MsgBox Rnd() 
End Sub 

メッセージブロックが同じ値にブックを開くたびに表示されます。一方、MsgBoxの前に行Randomizeを置くと、開くたびに異なる値が得られます。

rndを使用する予定がある場合は、ワークブック公開イベントは文Randomizeを置くための自然な場所です。

私がRandomizeを関数自体に入れなかったのは、CPUサイクルを節約したことと、正確に同じシステム時間で乱数ジェネレータを再シードする一定割合の時間。最近のバージョンのExcelを使用している現代のアーキテクチャでは不可能かもしれませんが、タイマーの機能がシステムクロックに関係なく1ミリ秒の分解能を持つため、Randomize Timer(他のコードを読むときに遭遇することがあります)があった場合には時々発生します。

私が持っているコードには、ボタンをバイパスしてトリガーセルを変更するだけで、再シードができないという欠点があります。これが懸念される場合は、1つの可能性は次のようになります:

公共初期化

ブールとして機能SemiVolatileRand(バリアントとしてx)のダブル として初期化されていない場合は、 ランダム化 初期化= Trueの エンド SemiVolatileRandの場合= x - x + Rnd() 最終機能

rndが正しくシードされていないと、この機能が実行されなくなります。

Excel自体がワークシート機能Rand()で自動的にシード処理を行うため、厳密にはVBAの複雑さです。

+0

なぜあなたはReSample()サブルーチンにRandomizeを入れますか? – Nicholas

+0

@NicholasLiu擬似乱数ジェネレータをシードすることでした。編集を参照してください。 –

関連する問題