Big Numbers

comments Kommentare deaktiviert für Big Numbers
By , 30. Juli 2015

Hallo,
heute möchte ich mal über richtig große Zahlen berichten, denn VBA hat genau mit denen Probleme diese zu verarbeiten.
Gerade in der Finanzwelt z.B. bei der Berechnung von Prüfziffern werden diese benötigt. Es sind dann schon spezielle Fälle, aber man sollte wissen wie man damit umgehen kann.

Schauen wir uns mal die Datentypen an, die uns in VBA zur Verfügung stehen:
– der Long-Datentyp ist bereits mit etwas über 2,1 Milliarden überfordert.
– Double schaft es immerhin auf 15 Stellen, bevor in die gerundete Exponential-Schreibweise gewechselt wird.
– eine weitere Möglichkeit ist der wenig bekannte Dezimal-Datentyp. Dieser lässt sich mit der Funktion CDec() herstellen, und damit haben wir schon 29 Stellen mit denen wir genau rechnen können.

Aber darüber hinaus? Nichts, Nada, Niente.

Angenommen Sie möchten von einer 36-Stelligen Zahl den Modulo nehmen, denn so groß kann maximal der BBAN (Basic Bank Account Number) nämlich werden: 30 Stellen Kontoidentifikation + 4 Stellen konvertiertes Länderkürzel + „00“

Mit dividieren so wie in den vorherigen Beitrag zum Modulo kommt man da nicht weit.

Aber es gibt für solche Fälle spezielle Rechenvorschriften, und eine möchte ich euch vorstellen, die Neun-Stellen-Regel.
Diese Regel besagt folgendes:

1. Von einer großen Zahl werden von links weg 9 Ziffern genommen werden, davon der Modulo genommen.
2. Es wird eine neue Zahl gebildet die mit dem berechneten Modulo beginnt, 
   und mit Ziffern der großen Zahl bis auf 9 Stellen aufgefüllt wird.
3. Von dieser neuen Zahl wird wieder der Modulo genommen
4. Die Vorgänge 2. und 3. werden so lange wiederholt, bis alle Ziffern der ursprünglichen 
   großen Zahl verarbeitet wurden.
5. Der Modulo, der bei der letzten Berechnung herauskommt, ist das Endergebnis.

Machen wir mal ein Beispiel.
Unsere große Zahl sei diese: 661400580’9000014’5786179’5321700’131400
Der Übersichtlichkeit ist diese in die verwendeten Blöcke eingeteilt.
Davon wollen wir den Modulo 97 bestimmen:

661400580 Mod 97 = 66
669000014 Mod 97 = 35
355786179 Mod 97 = 73
735321700 Mod 97 =  8
8131400   Mod 97 = 84

Der Modulo 97 userer großen Zahl ist also 84.

Um nun nicht ständig von Hand zu rechnen, erstellen wir aus diesen Informationen eine Prozedur.
Da wir von unserer großen Zahl (Dividend) nur Ziffern abschneiden, und nicht mit ihr rechnen, können wir diese als String-Parameter übergeben.

Public Function Modulo(ByVal Dividend As String, ByVal Devisor As Long)
    Dim NeueZahl As Long
    Dim ZwischenModulo As Variant

    Do While Len(Dividend) > 0
        NeueZahl = CLng(ZwischenModulo & Left(Dividend, 9 - Len(CStr(ZwischenModulo))))
        Dividend = Mid(Dividend, 10 - Len(CStr(ZwischenModulo)))
        ZwischenModulo = NeueZahl Mod Devisor
    Loop
    Modulo = ZwischenModulo
End Function

Was euch sicherlich Kopfzerbrechen macht ist diese Zeile:
NeueZahl = CLng(ZwischenModulo & Left(Dividend, 9 – Len(CStr(ZwischenModulo))))

Im ersten Durchlauf der Schleife ist ZwischenModulo (Typ Variant) Leer bzw. Empty. Daher ist Len(CStr(Zwischenmodulo)) = 0. Es werden also genau 9 Stellen von der großen Zahl genommen.
Im zweiten und weiteren Durchläufen ist ZwischenModulo mit dem zuvor berechneten Modulo besetzt. Die NeueZahl bildet sich also aus ZwischenModulo & 9-Len(CStr(ZwischenModulo)) Stellen der großen Zahl, um wieder maximal 9 Stellen zu erhalten.

Die Zeile: Dividend = Mid(Dividend, 10 – Len(CStr(ZwischenModulo))) schneidet einfach nur die verwendeten Ziffern von der großen Zahl ab.
Da die Mid()-Funktion 1-Basiert ist, muss man Mid(Dividend,10) schreiben um 9 Stellen vom Dividend abzuschneiden, also alles richtig.

Vieleicht noch der Hinweis warum ZwischenModulo als Variant deklariert ist und nicht als Long: Wäre er als Long deklariert dann wäre im ersten Schleifendurchgang der Wert nicht Leer sondern 0, und die Länge von CStr(0) ist nunmal 1 und nicht 0.

OK, ich denke ich konnte euch die Problematiken von richtig großen Zahlen – den Big Numbers – ein wenig näher bringen. Und die neue Modulo-Funktion könnt ihr auch sofort in euren Projekten einsetzen und ihr läuft nicht Gefahr dass irgendwann der Wertebereich nicht ausreicht oder dass falsche Ergebnisse durch die gerundete Exponential-Darstellung von Double auftreten, denn diese können in der Finanzwelt schnell sehr teuer werden.

Bis dahin
© 2015 Andreas Vogt

Excel-Dokumente aus Access heraus formatieren

comments Kommentare deaktiviert für Excel-Dokumente aus Access heraus formatieren
By , 27. Juli 2015

Hallo,
angenommen ihr exportiert Daten von Access nach Excel und möchtet nach Bearbeitung das Excel-Sheet ausdrucken.
Das Anpassen der Seitenränder für den Druck kann man nämlich auch gleich aus Access heraus erledigen.
Dazu benötigen wir zuerst den Verweis auf die aktuelle Microsoft Excel Library.

Danach benötigen wir die 3 Excel-Objekte für die Anwendung, das Workbook und das Worksheet:

    Dim xlApp As Excel.Application
    Dim xlBook As Workbook
    Dim xlSheet As Worksheet

    Set xlApp = CreateObject("Excel.Application")
    Set xlBook = xlApp.Workbooks.Open("c:\output.xlsx")
    Set xlSheet = xlBook.Worksheets(1)

Das Anwendungsobjekt ist definiert, das Workbook geöffnet und der Verweiss auf das erste Arbeitsblatt gesetzt. Jetzt gehts los:

    With xlSheet.PageSetup
        .LeftHeader = "&""Arial,Standard""&8&F"
        .CenterHeader = "&""Arial,Standard""&8&A"
        .RightHeader = "&""Arial,Standard""&8&D"
        .LeftFooter = ""
        .CenterFooter = ""
        .RightFooter = "&""Arial,Standard""&8Seite &P"
        .LeftMargin = xlApp.InchesToPoints(0.5)
        .RightMargin = xlApp.InchesToPoints(0.25)
        .TopMargin = xlApp.InchesToPoints(0.75)
        .BottomMargin = xlApp.InchesToPoints(0.75)
        .HeaderMargin = xlApp.InchesToPoints(0.5)
        .FooterMargin = xlApp.InchesToPoints(0.5)
        ....
    End With

Man kann also alles einstellen was auch in Excel einzustellen geht. Zu beachten ist, dass die Angaben in Points zu machen sind. Dazu kann man die Excel-Funktion InchesToPoints() verwenden.
Seht euch die Schreibweise für die Schriftart und -Größe an. Beachtet die doppelte Anführungszeichen.
Man kann auch bequem Einstellungen wie Druckqualität, Papiergröße oder Seitenzahlen einfügen wie oben im rechten Footer.

Bis dahin
© 2015 Andreas Vogt

Datentypen und Berechnungen

comments Kommentare deaktiviert für Datentypen und Berechnungen
By , 25. Juli 2015

Hallo,
heute möchte ich euch ein paar Fallstricke zeigen in die man bei Berechnungen innerhalb VBA tappen kann.
Doch Zuvor unsere kleine Testprozedur:

Sub berechnen()
    Dim i As Long, k As Long
    i = 1 * 64000
    k = 2 * 32000
End Sub

Wir setzen auf die Prozedur einen Haltepunkt und starten sie.
Ihr werdet sehen dass i korrekt berechnet wird, aber bei k ein Überlauf-Fehler kommt.
Der Grund liegt in der Größe der Zahlen.

Macht einfach mal folgendes:
Haltepunkt setzen und Prozedur starten.
Markiert 1 * 64000, rechte Maustaste klicken und auf „Überwachung hinzufügen“ klicken.
Im Fenster für Überwachungsausdrücke seht ihr jetzt als Datentyp „Long“ stehen.
Dann macht das gleiche für 2 * 32000. Jetzt sehr ihr als Datentyp „Integer“.

Das bedeutet, dass obwohl ihr die Variablen als Long deklariert habt, die Berechnung selbst unter einem anderen Datentyp laufen kann. Access nimmt sich hier einfach die größte Zahl aus der Berechnung und ermittelt anhand deren den Datentyp. Und 32000 passt nunmal ziemlich gut in den signed Integer Wertebereich hinein.

Hier ein paar gebräuchliche Datentypen mit ihren Wertebereichen:

Byte:     -128 bis 127 bzw. unsigned von 0 bis 255
Integer:  -32768 bis 32767 bzw. unsigned von 0 bis 65535
Long:     −2.147.483.648 bis 2.147.483.647 bzw. unsignet von 0 bis 4.294.967.295

Um jetzt das ganze noch verwirrender zu machen folgende Multiplikationen:
i = 2.1 * 32000
k = 2 = 32000

Wie Wunder gibt es bei i keinen Überlauf-Fehler, bei k aber schon. Wieder als Überwachungsausdruck eingefügt zeigt der Debugger nun für 2.1 * 32000 jetzt als Datentyp Double an.
Das liegt an der Nachkommastelle, die VBA dazu bewegt hat den Double-Datentyp zu verwenden.

Um nun aber 2 * 32000 berechnen zu können gibts einfach einen Trick.
entweder man schreibt hinter die 2 das Formarzeichen „#“ oder man schreibt einfach 2.0, welches automatisch auch in ein 2# umgewandelt wird.
Werden nun aber Variablen multipliziert, so ist der deklarierte Datentyp der Variablen maßgebend.

Ihr seht, eine kleine Berechnung kann ganz schön Kopfzerbrechen verursachen, aber nun wisst ihr wie ihr das umschiffen könnt.

Bis dahin
© 2015 Andreas Vogt

IBAN für deutsche Kontos berechnen

comments Kommentare deaktiviert für IBAN für deutsche Kontos berechnen
By , 24. Juli 2015

Hallo,
im letzten Beitrag gings um Modulo-Berechnung großer Zahlen. Und genau hier bei der Berechnung des IBAN benötigen wir diese Funktion.
Der übersicht wegen hab ich diese etwas gekürzt:

Private Function Modulo(ByVal Dividend As Double, ByVal Devisor As Double) As Long
    If Devisor = 0 Then Exit Function
    Modulo = Dividend - Fix(Dividend / Devisor) * Devisor
End Function

Bekannter Weise wird der IBAN wird gebildet aus:
– 2 Ziffern für die Länderkennung
– 2 Ziffern für die Prüfziffer
– Je nach Land bis zu 30 Ziffern für die Kontoidentifikation,
meist bestehend aus Bankleitzahl und Kontonummer und ggf. weiteren Kontrolziffern.

In Deutschland besteht die Kontoidentifikation aus 8-Stelliger Bankleitzahl und auf 10 Stellen aufgefüllt mit Nullen die Kontonummer.
Wie sich diese Kontoidentifikation zusammensetzt ist bei Wikipedia nachzulesen: https://de.wikipedia.org/wiki/IBAN

Kommen wir nun zum Berechnen der Prüfziffer, weil das das einzig schwierige am IBAN ist.
Diese wird Berechnet aus Bankleitzahl und Kontonummer durch Multiplikation von 62 mit den Modulo von BLZ durch 97 addiert mit 1 und dem Modulo von Kontonummer multipliziert mit 27 durch 97
Aus diesem ganzen Ausdruck wird wiederum der Modulo-Wert durch 97 ermittelt und von 98 abgezogen.

Also ziemlich verwirrend das ganze.
Deshalb teilen wir das auf in 2 Schritte, und speichern das Zwischenergebnis in einer Hilfsvariable:
Hilfsvar1 = 62 * (1 + Modulo(Blz, 97) + Modulo(27 * Kto, 97))

Die Prüfziffer berechnet sich dann wie folgt:
98 – Modulo(Hilfsvar1, 97)

Der Rest ist dann ziemlich einfach:

Public Function IBAN(ByVal Kto As Variant, ByVal Blz As Variant) As String
    Dim Hilfsvar1 As Variant
    
    Hilfsvar1 = 62 * (1 + Modulo(Blz, 97) + Modulo(27 * Kto, 97))
    IBAN = "DE" & 98 - Modulo(Hilfsvar1, 97)
    IBAN = IBAN & Blz & Left("0000000000", 10 - Len(Kto)) & Kto
End Function

Das wars auch schon wieder für heute.

Bis dahin
© 2015 Andreas Vogt

Modulo großer Zahlen berechnen

comments Kommentare deaktiviert für Modulo großer Zahlen berechnen
By , 23. Juli 2015

Hallo,
bei einer Berechnung von Modulo-Werten, also dem ganzzahligen Rest einer Division, bin ich auf ein Problem gestoßen, dessen Lösung ich euch nicht vorenthalten möchte.
Angenommen ihr möchtet den Modulo-Wert einer sehr großen Zahl berechnen. Dann stößt Access schnell an die Grenze des Longinteger-Wertebereichs, der bekanntlich bis 2147483647 reicht.
Beispiel:
2147483647 Mod 97 Ergebnis 65
2147483648 Mod 97 Ergebnis Überlauf.

Erinnert man sich wie der Modulo-Wert (ganzzahliger Rest einer Division) berechnet wird:
2147483648 geteilt durch 97 ergibt 22139006,86
Multipliziert man 22139006 mit 97, und zieht das Ergebnis von 2147483648 ab, so erhält man als Modulo-Wert 66

Und genau so bauen wir eine kleine Hilfsfunktion auf, die uns den Modulo-Wert berechnet:

Public Function Modulo(ByVal Dividend As Double, ByVal Devisor As Double) As Long
    Dim GanzzahlErgebnis As Long
    If Devisor = 0 Then Exit Function
    
    GanzzahlErgebnis = Fix(Dividend / Devisor)
    Modulo = Dividend - GanzzahlErgebnis * Devisor
End Function

Der Wert von GanzzahlErgebnis muss wirklich die abgeschnittene ganze Zahl der Division sein, deswegen muss hier die Funktion fix() verwendet werden.
Da wir immer den ganzzahligen Rest als Ergebnis möchten, genügt es die Prozedur als Long zu deklarieren.

Kopiert die Funktion in ein Modul und ruft sie z.B. wie folgt auf:

MsgBox Modulo(2200000000, 97)

Als Antwort wird die Zahl 36 ausgegeben.

Bis dahin
© 2015 Andreas Vogt

OfficeFolders theme by Themocracy