0

Bug im floor Befehl?

Hallo,

wir berechnen Prüfungsnoten nach bestimmten Gewichtungen. Im folgenden Code habe ich direkt Zahlenwerte eingetragen (ansonsten stehen dort Abfragen) und erhalte als Ergebnis 1,14. Es müsste aber 1,15 rauskommen.

Mache ich einen Denkfehler? Bug im floor Befehl? Nutze Version 3.5.14
Könnte das ggf. jemand mit der 3.6.* kurz testen, ob da auch noch 1,14 rauskommt. Wir sind mit der on-premise unterwegs, die bei 3.5.* steht.

Nur

((1 * 7 + 1 * 4 + LPN1 + LPN2 + KFDn + PNote + SRNote) / 30 * 100)

zeigt hier 149,999999999999

Werden die Zahlenwerte 2.5, 2, 2, usw. wie in unserer DB mit Abfragen befüllt, sehe ich die gewünschten 115,0.  Also in etwa: let LPN := sum(select Lehrproben.Noten) * 3. Lehrproben ist dabei bei der Ausgabe auf 1 Dezimale gestellt, weshalb wohl auch 115,0 erscheint.

Freue mich auf Rückmeldung bzw. Bestätigung. Dann würde ich eine Bug-Meldung absetzen.

Maurice

let LPN1 := 2.5 * 3;
let LPN2 := 2 * 3;
let KFDn := 2 * 3;
let SRNote := 1;
let PNote := 1 * 3;
let GNote2 := ((1 * 7 + 1 * 4 + LPN1 + LPN2 + KFDn + PNote + SRNote) / 30 * 100);
let GNote := format(floor((1 * 7 + 1 * 4 + LPN1 + LPN2 + KFDn + PNote + SRNote) / 30 * 100) / 100, "0.00");
styled(text(GNote), "RoyalBlue", "white", "")

7 Antworten

null
    • mirko3
    • vor 1 Jahr
    • Gemeldet - anzeigen

    Hallo Maurice. Wenn die Zahlen so sind, wie oben, kann ich mathematisch keinen Fehler finden. GNote2 ergibt korrekt 114,999... Wird dann floor() angewendet, entsteht korrekt 114. Geteilt durch 100 ist 1,14. Wenn 1,15 "gewünscht" ist, dann wäre round() besser und mathematisch logischer. Aber soweit ich Dein Beispiel sehe, funktioniert floor(). Mirko

      • Maurice
      • vor 1 Jahr
      • Gemeldet - anzeigen

      Mirko Hallo Mirko, GNote2 sollte doch 115 ergeben, da liegt der Fehler, also wohl doch nicht im floor-Befehl. In der Verwaltungsvorschrift zur Berechnung der Note steht, dass nach der zweiten Dezimale abgebrochen wird, also muss ich mit floor arbeiten. Warum ergibt GNote2 114.99999999?. Der Summenterm in GNote2 ergibt 34,5.

      • Ninox-Professional
      • planoxpro
      • vor 1 Jahr
      • Gemeldet - anzeigen

      Maurice In der Tat: Selbst wenn man als Formel "1.15 * 100" eingibt, zeigt Ninox als Ergebnis 114,99999999999999. Ersetze einfach mal "floor" durch "round":

      let GNote := format(round((1 * 7 + 1 * 4 + LPN1 + LPN2 + KFDn + PNote + SRNote) / 30 * 100) / 100, "0.00");
      
    • Ninox-Professional
    • planoxpro
    • vor 1 Jahr
    • Gemeldet - anzeigen

    Ergänzung:

    floor(ZAHL) rundet auf nächste Ganzzahl ab.
    ceil(ZAHL) rundet auf nächste Ganzzahl auf.
    round(ZAHL, X) rundet kaufmännisch auf die angegebene Anzahl Nachkommastellen (X; kann auch 0, also Ganzzahl sein).

    Format-Einstellungen über die Feldoptionen oder die Funktion format() runden lediglich optisch, der ursprüngliche Wert bleibt erhalten.
     

    • Marcel_Bresink
    • vor 1 Jahr
    • Gemeldet - anzeigen

    Sobald Stellen nach dem Dezimalkomma auftreten, schalten die meisten Programmiersprachen auf Gleitkommaarithmetik zur Basis 2 um. Diese hält sich leider nicht an die Mathematik rationaler Zahlen, sondern muss die Industrienorm IEEE 754 erfüllen.

    Bestimmte Zahlen (zu der auch 1,15 gehört), sind gemäß den Vorschriften dieser Norm nicht abspeicherbar, denn die Mantisse ist in Binärdarstellung 1.00100110011... mit unendlicher Periode 0011. Von daher treten automatisch Rundungsfehler auf, wenn etwas mit dem Wert 1,15 verrechnet wird, denn der Computer kann in Wirklichkeit nur den Wert 1,14999997615814208984375 als nächste Näherung speichern.

    Um das Problem zu lösen, müsste man diese Notenvorschriften ganz genau analysieren, in welcher Situation gerundet werden darf und wo nicht. Im schlimmsten Fall lassen sich Gleitkomma-Zahlen gar nicht verwenden, sondern man müsste eine Ersatz-Arithmetik auf Basis von ganzen Zahlen, bzw. Fixkommazahlen mit den Grundrechenarten selbst programmieren.

      • Maurice
      • vor 1 Jahr
      • Gemeldet - anzeigen

      Marcel Bresink Vielen Dank Marcel. Da spricht ein Spezialist. Da wäre ich ja nie drauf gekommen. Das muss man wissen oder zumindest ahnen, damit man recherchieren kann. Ich habe jetzt den Code geändert und ich erhalte die korrekten 1,15. Was ich nicht gefunden habe ist eine Übersicht über problematischen Dezimalzahlen wie die 1,15 Da im konkreten Fall die übergebenen Zahlen alle maximal eine Dezimale haben (halbe Noten) und diese dann gleich mit 100 multipliziert werden, dürfte ich dem Gleitkomma-Problem in diesem Fall entfliehen. Herzlichen Dank.

      Maurice 

      let LPN1 := 2.5 * 300;
      let LPN2 := 2 * 300;
      let KFDn := 2 * 300;
      let SRNote := 1*100;
      let PNote := 1 * 300;
      let GNote := format(floor((1 * 700 + 1 * 400 + LPN1 + LPN2 + KFDn + PNote + SRNote) / 30 ) / 100, "0.00");
      styled(text(GNote), "RoyalBlue", "white", "")
      
      • Marcel_Bresink
      • vor 1 Jahr
      • Gemeldet - anzeigen

      Maurice Man kann die problematischen Zahlen eigentlich nur ausrechnen. Da es in einer üblichen 64-Bit-Programmiersprache über 9 Trillionen verschiedene Gleitkommazahlen gibt, wäre eine Übersicht über die Problemwerte ziemlich unhandlich ...

      In Informatik-Lehrbüchern findet man normalerweise immer das Beispiel, dass sich auch der scheinbar einfachste Wert, nämlich 0,1 nicht speichern lässt. 0,1 + 0,2 sind auf einem Computer nicht etwa 0,3, sondern 0,30000000000000004.

Content aside

  • Status Answered
  • vor 1 JahrZuletzt aktiv
  • 7Antworten
  • 95Ansichten
  • 3 Folge bereits