Rubrik: Variablen/Strings | VB-Versionen: VB2008 | 16.03.09 |
Linq.Enumerable.Average: OverflowException vermeiden! Die Methode Average der Linq.Enumerable-Klasse löst beim Überlauf der Summation eine Ausnahme aus. Bei Verwendung von Sum mit einer Transformationsfunktion kann man das vermeiden. | ||
Autor: Manfred Bohn | Bewertung: | Views: 8.820 |
ohne Homepage | System: Win2k, WinXP, Win7, Win8, Win10, Win11 | kein Beispielprojekt |
Im Namespace 'System.Linq' ist die Klasse 'Enumerable' enthalten, die die 'Average'-Methode zur verfügung stellt. Diese Methode berechnet den Durchschnitt einer Datensequenz, die z.B. in einem Array enthalten sein kann.
'Average' summiert offenbar die Werte der Datenreihe zunächst auf und führt danach die Division durch. Aus diesem Grund kann es zu einer Überschreitung des größtmöglichen Datentyp-Wertes (bzw. zu einer Unterschreitung des kleinstmöglichen Datentyp-Wertes) kommen.
Bei den IEEE-Datentypen 'Single' und 'Double' wird in diesem Fall statt des Mittelwertes der (normalerweise sinnlose) Wert (+/-)'Infinity' zurückgegeben. Eine Ausnahme wird nicht ausgelöst.
Bei den Ganzzahl-Datentypen 'Integer' und 'Long' wird zwar ein Double-Wert zurückgegeben, die berechnete Summe muß aber im Bereich des Datentyps 'Long' liegen, sonst wird eine Ausnahme ausgelöst (OverflowException).
Bei dem Datentyp 'Decimal' muss die Summe innerhalb der Grenzen dieses Typs liegen, sonst wird eine Ausnahme ausgelöst.
Um das Risiko der 'OverflowException' auszuschalten, kann man statt dessen die Methode 'Sum' verwenden und eine 'Transformationsfunktion' angeben, die dafür sorgt, dass die dividierten Elemente der Auflistung summiert werden. Dabei muss ein geringfügiger Verlust an Genauigkeit des berechneten Mittelwertes in Kauf genommen werden.
Option Strict On Option Explicit On Option Infer Off Imports System.Linq.Enumerable Public Module modDemo_Average_Sum Public Sub Ex_Average_Sum() ' 3 Arrays mit großen Zahlen füllen Dim dec_arr(4) As Decimal, lng_arr(4) As Long, dbl_arr(4) As Double For i As Integer = 0 To dec_arr.Length - 1 dec_arr(i) = Decimal.MaxValue / 3 lng_arr(i) = Long.MaxValue \ 3 dbl_arr(i) = Double.MaxValue / 3 Next i ' Beispiel 1: Array-Erweiterungsmethode ' ===================================== ' Überlauf Summe > Decimal.MaxValue Dim dec_av1 As Decimal ' = dec_arr.Average() ' Überlauf Summe > Long.MaxValue Dim lng_av1 As Double ' = lng_arr.Average ' Statt Überlauf: Double.PositiveInfinity Dim dbl_av1 As Double = dbl_arr.Average ' Erweiterungsmethode 'Sum' bei Division der Elemente Dim dec_av2 As Decimal = _ dec_arr.Sum(Function(number) number / dec_arr.Length) Dim lng_av2 As Double = _ lng_arr.Sum(Function(number As Long) number / lng_arr.Length) Dim dbl_av2 As Double = _ dbl_arr.Sum(Function(number) number / dbl_arr.Length) ' Beispiel 2: Linq-Aggregate ' ========================== ' Überlauf Summe > Decimal.MaxValue Dim dec_av3 As Decimal = _ Aggregate x As Decimal In dec_arr Into Average() ' Überlauf Summe > Long.MaxValue Dim lng_av3 As Double = _ Aggregate x As Long In lng_arr Into Average() ' Überlauf Summe > Long.MaxValue Dim dbl_av3 As Double = _ Aggregate x As Double In dbl_arr Into Average() ' Aggregate-Methode 'Sum' bei Division der Elemente Dim dec_av4 As Decimal = _ Aggregate x As Decimal In dec_arr Into Sum(x / dec_arr.Length) Dim lng_av4 As Double = _ Aggregate x As Long In lng_arr Into Sum(CDbl(x / lng_arr.Length)) Dim dbl_av4 As Double = _ Aggregate x As Double In dbl_arr Into Sum(x / dbl_arr.Length) End Sub End Module