2016-02-27 2 views
0

Этот метод основан на следующих 3 шагов алгоритма:Функция Возвращает #value Ошибка иногда

1 - генерировать две равномерные числа на [-1,1] интервал, который вы называете U1 и U2

2 - вычислить S = U1^2 + U2^2

3 - Если S < 1 нормальное число задается U1 * квадратный корень (-2 Ln (S)/S) в противном случае вернуться к шагу 1 до S < 1.

Запрограммируйте эту функцию в VB и дайте ей имя BoxMuller.

Это функция, которую я написал на основе вышеуказанных шагов я не уверен, является ли это правильно или нет, потому что иногда она возвращает #value ошибку

я прохожу следующие значения функции =BoxMuller(Rand(),Rand())

Function BoxMuller(U1 As Double, U2 As Double) As Double 
Dim S As Double 

Do 
    U1 = WorksheetFunction.NormInv(U1, 0, 1) 
    U2 = WorksheetFunction.NormInv(U2, 0, 1) 
    S = U1 * U1 + U2 * U2 

    If S < 1 Then 
     BoxMuller = U1 * Sqr(-2 * Log(S)/S) 
     Exit Function 
    End If 

Loop Until S < 1 
End Function 

является условие Loop Until S < 1 правильно, потому что я думаю, что, возможно, настоящая причина ошибки.

Также попробовал следующее:

Function BoxMuller() As Double 
Dim S As Double 
Dim U1 As Double 
Dim U2 As Double 
Do 

U1 = WorksheetFunction.RandBetween(-1, 1) 
U2 = WorksheetFunction.RandBetween(-1, 1) 

    S = U1 * U1 + U2 * U2 

    If S < 1 Then 
     BoxMuller = U1 * Sqr(-2 * Log(S)/S) 
     Exit Function 
    End If 

Loop 
End Function 

И Called =BoxMuller() Still #value Ошибка

+0

ли вы когда-нибудь передать отрицательное значение Log (S)? –

+0

Я не думаю, что S будет отрицательным, потому что S - сумма квадратов U1 и U2, поэтому квадрат всегда будет возвращать положительные числа. – newguy

+0

Справа. Попробуйте в то время как вместо этого переходите вместо петли, как вы предполагаете, тогда –

ответ

1

я сделал некоторые приспосабливаются к конечной продукции, выход не стандартное распределение, но распределение выборки, так размножаются сигма, а затем плюс му. В противном случае функция не потребует ввода.

Rnd - это родной VBA для генерации случайного числа, он всегда попадает внутрь (0, 1).

Вместо того, чтобы делать do...loop, вы можете использовать GoTo, так что вам не нужно звонить exit function, чтобы закончить цикл.

application.volatile гарантирует, что функция пересчитывается каждый раз, когда вы нажимаете F9. Удалите это, если вы этого не сделаете.

Function BoxMuller(mu As Double, sigma As Double) As Double 
    Application.Volatile 
    Dim U1 As Double, U2 As Double, S As Double 

ReCalc: 

    Randomize 
    'U1 = Rnd 'this is not correct for the function, leaving it here for reference. 
    'U2 = Rnd 
    'U1 = WorksheetFunction.RandBetween(-1, 1) 'this is wrong too, RandBetween only returns interger 
    'U2 = WorksheetFunction.RandBetween(-1, 1) 
    U1 = Rnd * 2 - 1 
    U2 = Rnd 'the BoxMuller formula don't require U2 to be negative. 
    S = U1 * U1 + U2 * U2 

    If S < 1 Then 
     BoxMuller = U1 * Sqr(-2 * (Log(S)/S) * sigma + mu 
    Else 
     GoTo ReCalc 
    End If 

End Function 
+0

ах, я вижу ур вторую попытку, возможно, 'U1 = WorksheetFunction.RandBetween (-1, 1)' более подходит – Rosetta

+0

Спасибо за помощь, но все же возвращает #Value Error. – newguy

+0

исправлено .... я думаю, что это должно сработать – Rosetta

2

KS Sheon рабочий процесс является правильным

но

  • WorksheetFunction.RandBetween (-1, 1) возвращает целое число в диапазоне от -1 и 1

    в то время как VBA Rnd() функция возвращает случайное двойное от 0 до 1

  • Функция VBA Log() фактически возвращает natur аль логарифм

Я отправляю два решения (BoxMuller1 и BoxMuller2), что, наряду с тем, что выше, отличается только стиль кодирования и как использовать рекурсивные вызовы

Function BoxMuller1(mu As Double, sigma As Double) As Double 
    Application.Volatile 
    Dim U1 As Double, U2 As Double, S As Double 

    Do While GetS(Rnd, Rnd, U1, U2, S) >=1 
     Randomize 
    Loop 
    BoxMuller1 = U1 * Sqr(-2 * Log(S)/S) * sigma + mu 

End Function 

Function GetS(Rnd1 As Double, Rnd2 As Double, U1 As Double, U2 As Double, S As Double) As Double 
    U1 = 2*Rnd1 - 1 
    U2 = 2*Rnd2 - 1 
    S = U1 * U1 + U2 * U2 
    GetS = S 
End Function 




Function BoxMuller2(mu As Double, sigma As Double) As Double 
    Application.Volatile 
    Dim U1 As Double, U2 As Double, S As Double 

    Randomize 
    U1 = 2*Rnd -1 
    U2 = 2*Rnd -1 
    S = U1 * U1 + U2 * U2 

    If S >= 1 Then 
     BoxMuller2 = BoxMuller2(mu, sigma) 
    Else 
     BoxMuller2 = U1 * Sqr(-2 * Log(S)/S) * sigma + mu 
    End If 

End Function 
+0

Ха-ха да и правильно, я не думал. Btw U1 shud может быть отрицательным числом i. е. (-1,1). Rnd находится только в пределах (0,1). – Rosetta

+0

Да рекурсивная функция более элегантна. Но просто не хочу путать его. – Rosetta

+0

исправлены настройки U1 и U2: добавлено «-1» для возврата удвоений между -1 и 1 – user3598756

Смежные вопросы