' Dim sak As Double ' sak = a * a + b * b + c * c + d * d ' sums = a + b + c + d ' i = i - 1 ' stdev = (sak - (sums * sums / i)) / i ' stdevf = Sqr(stdev)
jeg har det her som melder fejl ved den sidste linie!
Public Function stdvar(felt1 As Single, Optional felt2 As Single, Optional felt3 As Single, Optional felt4 As Single) As Double Dim var As Double Dim parametre As Integer antalparametre = 1 sum = felt1 sum2 = felt1 ^ 2
If Not IsMissing(felt2) Then antalparametre = antalparametre + 1 sum = sum + felt2 sum2 = sum2 + felt2 ^ 2 End If If Not IsMissing(felt3) Then antalparametre = antalparametre + 1 sum = sum + felt3 sum2 = sum2 + felt3 ^ 2 End If If Not IsMissing(felt4) Then antalparametre = antalparametre + 1 sum = sum + felt4 sum2 = sum2 + felt4 ^ 2 End If var = sum2 / antalparametre - (sum / antalparametre) ^ 2 stdvar = Sqr(var) End Function
Jeg havde sløset lidt med dimensioneringen af variablerne (ændrer ikke noget i funktionaliteten), så her er en mere "finpudset" version:
Public Function stdvar(felt1 As Single, Optional felt2 As Single, Optional felt3 As Single, Optional felt4 As Single) As Double Dim var As Double Dim antalparametre As Integer Dim sum As Double Dim sum2 As Double antalparametre = 1 sum = felt1 sum2 = felt1 ^ 2
If Not IsMissing(felt2) Then antalparametre = antalparametre + 1 sum = sum + felt2 sum2 = sum2 + felt2 ^ 2 End If If Not IsMissing(felt3) Then antalparametre = antalparametre + 1 sum = sum + felt3 sum2 = sum2 + felt3 ^ 2 End If If Not IsMissing(felt4) Then antalparametre = antalparametre + 1 sum = sum + felt4 sum2 = sum2 + felt4 ^ 2 End If var = sum2 / antalparametre - (sum / antalparametre) ^ 2 stdvar = Sqr(var) End Function
Oops, den gav forkerte tal. For at den kan afgøre, om en parameter er blevet medsendt, skal variablen være af type variant:
Public Function stdvar(felt1 As Single, Optional felt2 As Variant, Optional felt3 As Variant, Optional felt4 As Variant) As Double Dim var As Double Dim antalparametre As Integer Dim sum As Double Dim sum2 As Double antalparametre = 1 sum = felt1 sum2 = felt1 ^ 2
If Not IsMissing(felt2) Then antalparametre = antalparametre + 1 sum = sum + felt2 sum2 = sum2 + felt2 ^ 2 End If If Not IsMissing(felt3) Then antalparametre = antalparametre + 1 sum = sum + felt3 sum2 = sum2 + felt3 ^ 2 End If If Not IsMissing(felt4) Then antalparametre = antalparametre + 1 sum = sum + felt4 sum2 = sum2 + felt4 ^ 2 End If var = sum2 / antalparametre - (sum / antalparametre) ^ 2 stdvar = Sqr(var) End Function
og den bruges nogle gange fordi man kan noejes med at gennemloebe data en gang
andre gange fravaelges den fordi den kan give numeriske problemer
hvis man foretraekker "text book" formlerne saa
Function Mean(A As Double, B As Double, C As Double, D As Double) As Double Mean = (A + B + C + D) / 4 End Function
Function Var(A As Double, B As Double, C As Double, D As Double) As Double Dim m As Double m = Mean(A, B, C, D) Var = ((A - m) ^ 2 + (B - m) ^ 2 + (C - m) ^ 2 + (D - m) ^ 2) / 4 End Function
Function StdDev(A As Double, B As Double, C As Double, D As Double) As Double StdDev = Sqr(Var(A, B, C, D)) End Function
Hvor stor er forskellen i præcision mellem de to formler (den som bl.a. DB2 bruger i sin databasemotor) og så din studiebogsudgave (som jeg går ud fra er mere korrekt?).
Det er forhåbentlig ikke særligt meget resultaterne fra de to beregningsformer afviger fra hinanden? Jeg vil da gerne kunne stole på den udregning DB2 bruger.
Function Mean(A As Double, B As Double, C As Double, D As Double) As Double Mean = (A + B + C + D) / 4 End Function
Function Var(A As Double, B As Double, C As Double, D As Double) As Double Dim m As Double m = Mean(A, B, C, D) Var = ((A - m) ^ 2 + (B - m) ^ 2 + (C - m) ^ 2 + (D - m) ^ 2) / 4 End Function
Function StdDev(A As Double, B As Double, C As Double, D As Double) As Double StdDev = Sqr(Var(A, B, C, D)) End Function
Function FastVar(A As Double, B As Double, C As Double, D As Double) As Double FastVar = (A ^ 2 + B ^ 2 + C ^ 2 + D ^ 2) / 4 - ((A + B + C + D) / 4) ^ 2 End Function
Function FastStdDev(A As Double, B As Double, C As Double, D As Double) As Double FastStdDev = Sqr(FastVar(A, B, C, D)) End Function
Function Test() MsgBox CStr(StdDev(0, 1, 2, 3)) MsgBox CStr(FastStdDev(0, 1, 2, 3)) MsgBox CStr(StdDev(10000000000000#, 10000000000001#, 10000000000002#, 10000000000003#)) MsgBox CStr(FastStdDev(10000000000000#, 10000000000001#, 10000000000002#, 10000000000003#)) End Function
Normalt sender man et array over til den slags funktioner - jeg fortsatte bare med argumenter fordi det havde I - jeg undlod dog at lave argumenterne optionelle
Fejlmeldingen betyder, at de variabler (A, B, C, ...) du kalder rutinen med ikke er defineret som double. Som standard overfører VB(A) ikke værdier, men derimod en pointer til den variabel du bruger.
Derfor, hvis du ønsker en rutine, som skal kunne kaldes fra mange forskellige steder i et program og med flere variabeltyper (integer, single, double osv.), så er det en god ide at gøre et af to ting:
1. definere parametrene med variabeltypen Variant, som er en speciel type som kan indeholde alle de andre typer. Så skal du bare teste for typen i rutinen. 2. definere parametrene med en Byval, sådan at det er værdierne der bliver overført, og ikke pointeren til de oprindelige variable.
Hvis du ønsker at gøre en parameter optional (dansk: valgfri), skal du bruge variabeltypen Variant. Se evt. mit bidrag fra 09/03-2006 16:14:29
Som arne_v fortalte, så er den bedste metode til at overdrage parametrene, hvis du bruger en array. VBA understøtter dette gennem ParamArray.
Den rutine jeg viste i mit indlæg fra 09/03-2006 16:14:29 ville med denne metode se sådan ud:
Public Function Stddev(ByVal Param1 As Double, ParamArray f()) As Double ' Den hurtige udgave med kun et gennemløb... Dim p As Long, x As Long, al As Long, au As Long Dim s As Double, s2 As Double, Avg As Double, Var As Double If Not IsMissing(f()) Then al = LBound(f()): au = UBound(f()): p = au - al + 2 s = Param1 s2 = Param1 ^ 2 For x = al To au If IsNumeric(f(x)) Then s = s + f(x) s2 = s2 + f(x) ^ 2 Else MsgBox "Kun numeriske værdier er acceptable.", _ vbExclamation + vbApplicationModal + vbOKOnly, _ "Fejl i funktionsparametre" Exit Function End If Next Avg = s / p Var = s2 / p - (s / p) ^ 2 Stddev = Sqr(Var) Else Avg = Param1 Var = 0 Stddev = 0 End If End Function
Men som arne_v korrekt påpegede, så giver denne udregning forkerte resultater ved store værdier p.g.a afrundingsfejl (selv Double variabler er ikke præcise nok), så med hans korrektioner, er en mere præcis rutine:
Public Function Stddev(ByVal Param1 As Double, ParamArray f()) As Double ' Den mere korrekte version... Dim p As Long, x As Long, al As Long, au As Long Dim s As Double, s2 As Double, Avg As Double, Var As Double If Not IsMissing(f()) Then al = LBound(f()): au = UBound(f()): p = au - al + 2 s = Param1 For x = al To au If IsNumeric(f(x)) Then s = s + f(x) Else MsgBox "Kun numeriske værdier er acceptable.", _ vbExclamation + vbApplicationModal + vbOKOnly, _ "Fejl i funktionsparametre" Exit Function End If Next Avg = s / p s2 = (Param1 - Avg) ^ 2 For x = al To au s2 = s2 + (f(x) - Avg) ^ 2 Next Var = s2 / p Stddev = Sqr(Var) Else Avg = Param1 Var = 0 Stddev = 0 End If End Function
Begge funktioner er fleksible, så man kan angive så mange eller så få parametre man har brug for.
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.