none
Ist 43,18€ nicht gleich 43,18€ ?

    Frage

  • Ich vergleiche in einem Bericht twei Beträge. Sofern ein Unterschied besteht, soll die Differenz ausgegeben werden, ansonsten nichts.

    In diesem Feld vergleiche ich die Werte mit Wenn(;;).

    Lustigerweise kommt gelegentlich ein Differenz-Wert von 0,00€ oder auch 0,01€, obwohl auf den (ersten) Blick die beiden Beträge identisch sind.

    Eine Abänderung mit Konvertierung auf Zcurrency(Betrag) bringt übrigens auch nichts.

    zur Info:

    Einer der Beträge stammt als Currency aus einer Access-DB, der andere aus einer SQL-DB

    Donnerstag, 31. Mai 2012 11:19

Antworten

  • Hallo!

    > Einer der Beträge stammt als Currency aus einer Access-DB, der andere aus einer SQL-DB

    Wenn beide Currency (Money)-Datentypen sind, sollte ein Vergleich ohne Runden möglich sein, da es sich nicht um Gleitkommazahlen handelt.
    Beachte aber, dass Currency 4 Dezimalstellen hat. Falls du nur die ersten 2 Dezimalstellen vergleichen willst, musst du, wie bereits erwähnt, runden bzw. mit einer Toleranz vergleichen.

    GleichOderUngleichDasIstDieFrage: Wenn(Abs(Zahl1 - Zahl2) < 0.01; "Gleich oder fast gleich"; "Ungleich")

    Tipp: Damit du alle Dezimalzahlen der Originaldaten siehst, könntest du das Anzeige-Format anpassen.

    mfg
    Josef


    Code-Bibliothek für Access-Entwickler
    AccUnit - Testen von Access-Anwendungen
    Virtueller Access-Stammtisch

    • Bearbeitet Josef Pötzl Donnerstag, 31. Mai 2012 18:39
    • Als Antwort markiert NicoNi Freitag, 1. Juni 2012 12:10
    Donnerstag, 31. Mai 2012 18:39

Alle Antworten

  • Hallo NicoNI,

    hast Du es 'mal mit

    Round(Betrag [,AnzahlAnDezimalpunktn])

    versucht...?

    Gruß Giorgio

    Donnerstag, 31. Mai 2012 11:23
  • Nein. Kann ich aber mal tun. Tortzdem strange, oder ?
    Donnerstag, 31. Mai 2012 11:48
  • Hallo,

    eigentlich nicht. Dies liegt an den verschiedenen Speichervarianten bei Zahlen.

    0,00 und 00000000 sind genau genommen eben nicht gleich, nur der Wert ist der Gleiche.

    Desgleichen trifft auf Null und "" zu. Eigentlich stellt sich beides als leer dar, es gibt aber bei Vergleichen verschiedene Ergebnisse.

    Gruß

    Bjoern

    Donnerstag, 31. Mai 2012 12:01
  • Hallo,

    Stefan-G. Albers wrote:

    hast Du es 'mal mit

    Round(Betrag [*,*/AnzahlAnDezimalpunktn/]*)*

    versucht...?

    Nee, lass das mal lieber. Begruendung siehe http://www.donkarl.com?FAQ2.1

    @NicoNi, in dem FAQ-Beitrag steht uebrigens auch der Grund fuer die
    Ungenauigkeit, und eine Rundungsfunktion, die genau arbeitet.

    Gruss - Peter


    Mitglied im http://www.dbdev.org
    FAQ: http://www.donkarl.com

    Donnerstag, 31. Mai 2012 15:25
    Moderator
  • Hallo NicoNi

    was ist den wenn du beide beträge in neues feld legst und diese vergleichst

    GerundeterBetragEins= Int((BetragEins / 100) * 100 + 0.5) / 100

    GerundeterBetragZwei= Int((BetragZwei / 100) * 100 + 0.5) / 100

    GerundeterBetragEins und GerundeterBetragZwei dann vergleichen

    Michael

    Donnerstag, 31. Mai 2012 18:25
  • Hallo!

    > Einer der Beträge stammt als Currency aus einer Access-DB, der andere aus einer SQL-DB

    Wenn beide Currency (Money)-Datentypen sind, sollte ein Vergleich ohne Runden möglich sein, da es sich nicht um Gleitkommazahlen handelt.
    Beachte aber, dass Currency 4 Dezimalstellen hat. Falls du nur die ersten 2 Dezimalstellen vergleichen willst, musst du, wie bereits erwähnt, runden bzw. mit einer Toleranz vergleichen.

    GleichOderUngleichDasIstDieFrage: Wenn(Abs(Zahl1 - Zahl2) < 0.01; "Gleich oder fast gleich"; "Ungleich")

    Tipp: Damit du alle Dezimalzahlen der Originaldaten siehst, könntest du das Anzeige-Format anpassen.

    mfg
    Josef


    Code-Bibliothek für Access-Entwickler
    AccUnit - Testen von Access-Anwendungen
    Virtueller Access-Stammtisch

    • Bearbeitet Josef Pötzl Donnerstag, 31. Mai 2012 18:39
    • Als Antwort markiert NicoNi Freitag, 1. Juni 2012 12:10
    Donnerstag, 31. Mai 2012 18:39
  • Vielleicht ist letzte Variante die am einfachsten umsetzbare.

    Ich werde es probieren.

    Schönes WoE

    Freitag, 1. Juni 2012 12:10
  • Hallo NicoNi

    NicoNi wrote:

    Ich vergleiche in einem Bericht twei Beträge. Sofern ein Unterschied
    besteht, soll die Differenz ausgegeben werden, ansonsten nichts.

    In diesem Feld vergleiche ich die Werte mit Wenn(;;).

    Lustigerweise kommt gelegentlich ein Differenz-Wert von 0,00€ oder auch
    0,01€, obwohl auf den (ersten) Blick die beiden Beträge identisch sind.

    Der Bericht rundet implizit mit der Format Funktion auf 2 Stellen. Die Zahlen dürften allerdings nicht ganz genau sein, was der Bericht da gerundet anzeigt.
    Beispiel:
    Folgende beiden Zahlen werden im Bericht als 43.18 angezeigt:
    43.184
    43.175
    Bildest Du nun die Differenz zwischen diesen Zahlen, die vermeintlich 43.18 drin haben, erhälst Du eine Differenz von 0.009, welches dann, auf zwei Stellen gerundet eben 0.01 ergibt.

    Um diese Zahlen gemäss Anzeige zu vergleichen, musst Du diese bereits in der Datenquelle gerundet auslesen. Noch besser ist es, wenn Du eine atomare Rundung in der DB benutzt, also die Zahlen, bereits in der Datenbank richtig gerundet ablegst, sonst bekommst Du immer wieder solche Ungenauigkeiten und Rundungsfehler, die ausgeglichen werden müssen.

    Nochwas: Ich verzichte inzwischen bewusst auf die Verwendung von SINGLE, CURRENCY oder MONEY. Für Dezimalzahlen benutze ich in Access immer DOUBLE, auf dem SQL Server FLOAT. Diese beiden Datentypen stimmen im Wertebereich genau überein und damit hast Du viel weniger Schwierigkeiten (eigentlich habe ich seither gar keine diesbezüglich mehr).

    Gruss
    Henry

    Freitag, 8. Juni 2012 03:49
  • Vielen Dank.

    Ich habe inzwischen den Vorschlag aufgegriffen, mit der Abs()-Funktion zu arbeiten und ggf. bei Differenzen unter 0,01 irgendwelche Aktionen zu unterdrücken.

    Nicht schön, funktioniert aber.

    Freitag, 8. Juni 2012 07:44
  • Ich habe es jetzt nochmal nachvollzogen: ALle beteiligtne Felder sind vom Typ Währung (Access).

    Ich hatte eigentlich geglaubt, Rundungen würden mit Währung automatisch korrekt gehandhabt, sodaß Währungen eben problemlos vergleichbar sind.

    Freitag, 8. Juni 2012 07:48
  • Hallo NicoNi

    Schau' nochmals den Currency Datentypen von Access genauer an. Dieser ist so definiert, dass er 4 (nicht 2) Dezimalstellen hat. Wenn Du in Deinem Report auf 4 Nachkoma stellen umstellst, wirst Du schnell sehen, dass es eben an 3. und 4. Stelle nicht einfach nur 0 drin hat.

    Natürlich werden die Currency Variablen richtig gerundet, aber eben auf 4 Stellen. Dein Report rundet auf 2 Stellen. Daher kommen die Unterschiede, die Du nicht siehst.

    Gruss

    Henry

    Freitag, 8. Juni 2012 10:01
  • Hallo NicoNi,

    für das kaufmännische Runden verwende ich mittlerweile folgenden Funktion.

    Dabei korrigiere ich Abweichungen von Gleitkommazahlen mit CCur (Festkommazahlen).

    Vor dem Vergleichen von Geldbeträgen runde ich beide mit dieser Funktion.

    Gruß Josef

    Public Function finance_round_arithmetic(ByVal dbl_wert As Double, _
                                                                          ByVal int_stellen As Integer) As Double

      '-------------------------------------------------------------------
      '--- modul for Microsoft Access 2002XP/2003/2007/2010/2013/2016: version 15.04.2017
      '-------------------------------------------------------------------

      On Error GoTo finance_round_arithmetic_error

      '--- kaufmännisches Runden auf eine bestimmte Anzahl

      '--- Vorsicht beim Runden von Gleitkommazahlen:

      '--- VBA Direktfenster: 1 * 10.3 * (1 - 0.15) ergibt 8,755

      '--- VBA Direktfenster: CSng(1)*CCur(10.3)*(1-CSng(0.15)) ergibt 8,75499993860722

      '--- und somit nach finance_round_ arithmetic entweder richtig 8,76 oder falsch 8,75

      '--- Lösung:  mit CCur() zunächst Währungsarithmetik erzwingen

      '--- und somit in Festkommazahl 8,7550 umwandeln

      '--- anschließendes finance_round_arithmetic ergibt richtig 8,76

      Dim lng_vorzeichen As Long
      Dim var_zwischenergebnis As Variant
      Dim cur_wert As Currency

      '--- Sonderfall Wert = 0
      If dbl_wert = 0 Then
        finance_round_arithmetic = 0
        GoTo finance_round_arithmetic_exit
      End If

      '--- Vorzeichen merken und entfernen
      '--- ?finance_round_arithmetic(8.125,2) ergibt 8,13
      '--- ?finance_round_arithmetic(-8.125,2) ergibt -8,13
      lng_vorzeichen = VBA.Math.Sgn(dbl_wert)
      dbl_wert = VBA.Math.Abs(dbl_wert)

      '--- häufige Sonderfälle 0 bis 4 extra behandeln für mehr Performance
      '--- Division durch 0 verhindern (var_zwischenergebnis immer <> 0)
      Select Case int_stellen
    '    Case Is < 0
    '      var_zwischenergebnis = 10 ^ int_stellen
    '      finance_round_arithmetic = VBA.Conversion.Int(dbl_wert * var_zwischenergebnis + 0.5) / var_zwischenergebnis
        Case 0
          cur_wert = VBA.Conversion.CCur(dbl_wert)
          finance_round_arithmetic = VBA.Conversion.Int(cur_wert + 0.5)
        Case 1
          var_zwischenergebnis = 10
          cur_wert = VBA.Conversion.CCur(dbl_wert * var_zwischenergebnis)
          finance_round_arithmetic = VBA.Conversion.Int(cur_wert + 0.5) / var_zwischenergebnis
        Case 2
          var_zwischenergebnis = 100
          cur_wert = VBA.Conversion.CCur(dbl_wert * var_zwischenergebnis)
          finance_round_arithmetic = VBA.Conversion.Int(cur_wert + 0.5) / var_zwischenergebnis
        Case 3
          var_zwischenergebnis = 1000
          cur_wert = VBA.Conversion.CCur(dbl_wert * var_zwischenergebnis)
          finance_round_arithmetic = VBA.Conversion.Int(cur_wert + 0.5) / var_zwischenergebnis
        Case 4
          var_zwischenergebnis = 10000
          cur_wert = VBA.Conversion.CCur(dbl_wert * var_zwischenergebnis)
          finance_round_arithmetic = VBA.Conversion.Int(cur_wert + 0.5) / var_zwischenergebnis
        Case Else
          var_zwischenergebnis = 10 ^ int_stellen
          cur_wert = VBA.Conversion.CCur(dbl_wert * var_zwischenergebnis)
          finance_round_arithmetic = VBA.Conversion.Int(cur_wert + 0.5) / var_zwischenergebnis
      End Select

      '--- negatives Vorzeichen hinzufügen
      If lng_vorzeichen < 0 Then
        finance_round_arithmetic = -finance_round_arithmetic
      End If

    finance_round_arithmetic_exit:
      On Error GoTo 0
      Exit Function

    finance_round_arithmetic_error:
      Call log_error_handler("Modul", "bas_finance", "finance_round_arithmetic", Err.Description, Err.Number)
      Resume finance_round_arithmetic_exit

    End Function

                     
    Sonntag, 16. April 2017 04:07