Das deutsche QBasic- und FreeBASIC-Forum Foren-Übersicht Das deutsche QBasic- und FreeBASIC-Forum
Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
 
FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   BenutzergruppenBenutzergruppen  RegistrierenRegistrieren
ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin
Zur Begleitseite des Forums / Chat / Impressum
Aktueller Forenpartner:

Zahlen richtig runden

 
Neues Thema eröffnen   Neue Antwort erstellen    Das deutsche QBasic- und FreeBASIC-Forum Foren-Übersicht -> Allgemeine Fragen zu FreeBASIC.
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
stevie1401



Anmeldungsdatum: 04.07.2006
Beiträge: 133

BeitragVerfasst am: 27.11.2006, 22:27    Titel: Zahlen richtig runden Antworten mit Zitat

Kann es sein, dass FB nicht richtig runden kann?

Ich habe mal folgendes probiert:

dim as double summe,mwst,netto

summe=10
netto=summe/1.16
netto=int(netto*100+0.5)/100
mwst=summe-netto
print "Summe "+str(summe)
print "Netto "+str(netto)
print "Mwst "+str(mwst)

Bei Summe=100 ist es genauso
Auch CINT hilft nichts.

Hat jemand eine Lösung?
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
terminate



Anmeldungsdatum: 12.09.2006
Beiträge: 56

BeitragVerfasst am: 28.11.2006, 02:16    Titel: Re: Zahlen richtig runden Antworten mit Zitat

stevie1401 hat Folgendes geschrieben:
Kann es sein, dass FB nicht richtig runden kann?


Nein.
Jedenfalls nicht schlechter oder besser als andere Compiler.

Zitat:
Ich habe mal folgendes probiert:
...
Hat jemand eine Lösung?


Das beobachtete Verhalten ist in der Natur von DOUBLE und SINGLE Variablen begründet:
http://de.wikipedia.org/wiki/Gleitkommazahl

Zum runden von Gleitkommazahlen wird eine separate Rundungsfunktion benötigt z.B. folgende, (das wär wohl eher was für YTWINKY):
(Quelle: http://www.freebasic.net/forum/viewtopic.php?p=14022#14022)

Code:

declare Function RoundOff (x as single, k as integer)  as single
dim as double summe,mwst,netto

summe=10
netto=summe/1.16

mwst=summe-netto
print "Summe "+str(summe)
print "Netto "+str(netto)
print "Mwst "+str(mwst)

print RoundOff(CSng(summe),3)
print RoundOff(CSng(netto),3)
print RoundOff(CSng(mwst),3)

sleep

Function RoundOff (x as single, k as integer)  as single
dim as integer np
dim as double pn
dim as long l

 If k > 6 Then k = 6
 If Abs(x) > 1E-39 Then
 np = k - 1 - Int(Log(Abs(x)) / Log(10))
 pn = 10 ^ Cdbl(np)
 l = pn * x
 RoundOff = l / pn
 Else
 RoundOff = 0
 End If
End Function


Ebenfalls interessant:

Die ceil(), floor(), round() etc. Funktionen aus der math.bi.
(Einbinden mit: #include "crt/math.bi")
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
stevie1401



Anmeldungsdatum: 04.07.2006
Beiträge: 133

BeitragVerfasst am: 28.11.2006, 11:46    Titel: Antworten mit Zitat

Nein, dass funktioniert auch nur bedingt.
Auch die Mathe.bi scheint nicht richtig zu laufen.

Jetzt habe ich mir mal selbst etwas gebastelt.
Ist zwar mächtig von-hinten-durchs-Knie-ins-Auge, aber es scheint zu funktionieren lächeln


Code:




Declare Function Stevie1401Round(Byval zahl As Double,Byval KommaStelle As Integer) As single
Screen 20,32,1,1
Dim As single OriginalZahl

'OriginalZahl MUSS Single sein!

OriginalZahl=32.6598

Print "OriginalZahl:"+Str(OriginalZahl)
'Umwandeln
Print
OriginalZahl=Stevie1401Round(OriginalZahl,2)
Print
Print "Zahl nach Stevie1401Round:     "+Str(OriginalZahl)






Function Stevie1401Round(Byval zahl As Double,Byval KommaStelle As Integer) As Single

 Dim komma,lz,vlz,gekuerzteZahl As Double,HinzuZaehlerZahl As Double,minusflg 
    Dim As String dummy, HinzuZaehlerStr
    if zahl<0 then
        zahl=zahl*-1
        minusflg=1
    end if
   
    'Zahl als Sting umwandeln
    dummy=Str(zahl)
    'Nach Komma suchen (naja, eigentl. Punkt :-) )
    komma=Instr(dummy,".")
    If Len(dummy)>komma+KommaStelle And komma>0 Then
        'Nachkommastellen ansagen
        Print "Nachkommastellen:"+Str(KommaStelle)
        'String auf Nachkommastellen+1 kürzen
        '+1 deshalb, weil nach dieser beurteilt wird, ob aufgerundet werden soll
        dummy=Left(dummy,komma+KommaStelle+1)
        dummy=Trim(dummy)
        Print "Abgeschnittener String:"+dummy
        'Letzte Zahl ermitteln
        lz=Val(Right(dummy,1))
        Print "Letzte Zahl="+Str(lz)
        'vorletzte Zahl ermitteln
        vlz=Val(Mid(dummy,komma+KommaStelle,1))
        Print "Vorletzte Zahl="+Str(vlz)
        If lz>4 Then    'Wenn die letzte Zahl über 4, dann aufrunden
            gekuerzteZahl=Val(Left(dummy,komma+KommaStelle))
            Print "Gekuertze Zahl:"+Str(gekuerzteZahl)
            HinzuZaehlerStr="0."+String$(Kommastelle-1,"0")+"1"
            Print "HinzuZaehlerString="+HinzuZaehlerStr
            HinzuZaehlerZahl=Val(HinzuZaehlerStr)
            Print "HinzuZaehlerZahl:"+Str(HinzuZaehlerZahl)
            ' Print "Vorletzte Zahl aufgerundet="+str(vlz)
            Print "Letzte Zahl ist >4, deshalb vorletzte Zahl aufrunden:"
            Print "ZahlenString VOR Bearbeitung:  "+Space(KommaStelle+2-Len(dummy))+dummy
            zahl=zahl+HinzuZaehlerZahl
            'String auf die richtige Länge kürzen
            dummy=Str(zahl)
            dummy=Left(dummy,komma+KommaStelle)
            Print "ZahlenString NACH Bearbeitung: "+Space(KommaStelle+2-Len(dummy))+dummy
        Else   'Wenn die letzte Zahl NICHT über 4, dann NICHT aufrunden
            Print "Es wird NICHT aufgerundet."
            'String auf die richtige Länge kürzen
            dummy=Left(dummy,komma+Kommastelle)
        End If
    End If
    if minusflg=1 then
        zahl=val(dummy)
        zahl=zahl*-1
        dummy=str(zahl)
    end if
   
    Stevie1401Round=Val(dummy)
End Function


Das klappt natürlich nur mit POSITIVEN Zahlen.
Deshalb wandelt die Function bei Bedarf die Originalzahl erst einmal um, merkt es sich aber, um am Ende wieder Minus zu machen.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
terminate



Anmeldungsdatum: 12.09.2006
Beiträge: 56

BeitragVerfasst am: 28.11.2006, 15:40    Titel: Antworten mit Zitat

stevie1401 hat Folgendes geschrieben:
Nein, dass funktioniert auch nur bedingt.

Gut möglich, ich hab die Rundungsfunktion weder geschrieben noch getestet, nur Copy&Paste gemacht und die Qbasic Suffixes entfernt, (möglicherweise fehlerbehaftet), damit sich das ganze auch unter FB 0.17 CVS kompilieren lässt.
Zitat:

Auch die Mathe.bi scheint nicht richtig zu laufen.

Das glaube ich nicht, die math.bi ist nur eine Headerdatei, die auf die entsprechen, (Standard) C Funktionen zugreift, d.h. mit allem was hier an Ungereimtheiten oder möglichen Problemen auftritt muß sich auch jeder 'normale' C Programmierer auseinandersetzen.

Ich würde einfach mal behaupten Floatingpointvariablen sind ein bewährter und brauchbarer Kompromiss zwischen minimalem Speicherplatzverbrauch, maximal darstellbarer Zahlengröße und hinreichender Genauigkeit, für die meisten Anwendungen geeignet wo es nicht darum geht Zahlen in 'menschenlesbarer', genehmer, Form darzustellen. Jetzt mal im Ernst: 13.9999999999999 sieht natürlich Scheiße aus, wenn da eigentlich 14.0000000000 stehen müßte, aber der Fehler ist für die meisten Anwendungen vernachlässigbar klein, vor allem, wenn man bedenkt, dass man mit einer 'nur' 8 Byte großen Variable einen Zahlenraum von +/-4.490 656 458 412 465 E-324 bis +/-1.797 693 134 862 310 E+308 darstellen kann, wenn man dafür Integervariablen verwenden würde wäre man schnell bei etlichen hundert Bytes pro Variable, (oder noch mehr?). Wenn es z.B. um Grafikberechnungen in einem Spiel geht wird am Schluß sowieso zwangsläufig wieder auf maximal 'ein Pixel genau' gerundet, fällt also gar nicht auf.

Wenn ich aber tatsächlich in einem sehr kleinen Zahlenbereich, (z.B. max 10 Vorkammastellen und 10 Nachkommastellen), 'absolute' Genauigkeit benötigen würde, dann würde ich stattdessen einfach den Variablentyp ULONGINT verwenden und alles 'vor dem Komma' berechnen, d.h. ich wandle jede "Kommazahl" vor der Berechnung in eine ULONGINT Zahl um, indem ich das Komma definiert 'nach rechts verschiebe', (und nach der Berechnung, bzw. vor der Ausgabe, wieder zurück). Das ist nicht unüblich, eine ganze Menge Leute haben sich schon Fließkomma/Integer Libraries geschrieben um eine höhere Genauigkeit zu erzielen.

Zitat:

Jetzt habe ich mir mal selbst etwas gebastelt.
Ist zwar mächtig von-hinten-durchs-Knie-ins-Auge, aber es scheint zu funktionieren lächeln


Sieht aufwändig aus, aber ich bin hier auch nicht der Mathematikspezialist, wenns funktioniert und ausreichend schnell ist, gut. Da würde ich jetzt gerne mal einen Lösungsansatz von YTWINKY sehen, (falls du Zeit hast zwinkern.)
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
ytwinky



Anmeldungsdatum: 28.05.2005
Beiträge: 2624
Wohnort: Machteburch

BeitragVerfasst am: 28.11.2006, 17:59    Titel: Antworten mit Zitat

Nu schrei doch nicht so laut, ich bin zwar kurzsichtig, aber nicht schwerhörig grinsen
Für genaue Berechnungen ist Double echt super, wenn an die Zeit dafür hat..
Für die Ausgabe von doppelt genauen Zahlen siehe:
http://forum.qbasic.at/viewtopic.php?p=20694&highlight=format#20694
und Befehlsreferenz etc pp usw.
Ich hatte gestern abend schon ein Beispiel fertig, war dann aber zu müde..
..so müde, daß ich es auch nicht mehr auf meinen Stick kopiert hab..
mußte warten, bis ich wieder zu Hause bin ~20:00
Bis später
Gruß
ytwinky
_________________
v1ctor hat Folgendes geschrieben:
Yeah, i like INPUT$(n) as much as PRINT USING..
..also ungefähr so, wie ich GOTO..
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
stevie1401



Anmeldungsdatum: 04.07.2006
Beiträge: 133

BeitragVerfasst am: 28.11.2006, 19:15    Titel: Antworten mit Zitat

Tja, was in aller Welt nützt mir das schönste runden!

Guckt euch DAS einmal an:

dim as single a,b

a=68.50
b=59.05
print a-b

Ergebnis: 9.450001

QBASIC spuckt als Ergebnis feine 9.45 aus.
Ebenso das GFA-Basic

Und DAS soll KEIN BUG sein??
Wie soll man denn so rechnen?
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
Mao



Anmeldungsdatum: 25.09.2005
Beiträge: 4409
Wohnort: /dev/hda1

BeitragVerfasst am: 28.11.2006, 20:43    Titel: Antworten mit Zitat

Das ist eigentlich der absolute Wert. neutral
Hm, verwendest du irgendwo zwischen drin die ABS-Funktion?
Ich kann dir nur erklären, warum was anderes rauskommt mit Double als Datentyp, anstatt mit Single - 'ne Gleitpunktoperation ist nie genau.
Aber warum da das Vorzeichen weggelassen wird, kA. neutral
_________________
Eine handvoll Glück reicht nie für zwei.
--
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Michael712
aka anfänger, programmierer


Anmeldungsdatum: 26.03.2005
Beiträge: 1593

BeitragVerfasst am: 28.11.2006, 20:47    Titel: Antworten mit Zitat

Äh, Mao?

Wieso soll da ein Vorzeichen sein? Zunge rausstrecken

a>b, daraus folgt, das a-b größer als 0 sein muss grinsen
Und das heißt, kein Vorzeichen. Oder erwartest du ein "+ 9.450001"? Zunge rausstrecken

Edit:

Code:
#include <stdio.h>

 
int main () {
   float a;
   float b;
   float c;

   a=68.50;
   b=59.05;
   c=a-b;

   printf ("Ergebnis: %f ",c);
};


In C ist es genau so.

Also ist so die beste möglichkeit(gefunden auf freebasic.net, nach 0.17 "portiert"):

Code:
Declare Function RoundOff(x As Single, k AS Integer) As Single

Dim As Single a,b,c
a=68.5
b=59.05
c=a-b

print c

Print RoundOff(c, 0)
Print RoundOff(c, 1)
Print RoundOff(c, 2)
Print RoundOff(c, 3)
Print RoundOff(c, 4)
Print RoundOff(c, 5)
Print RoundOff(c, 6)

Function RoundOff(x As Single, k As Integer) As Single
    Dim pn As Double
    Dim np AS Integer
    Dim l As LongInt
   
    If k > 6 Then k = 6
     
    If Abs(x) > 1E-39 Then
        np = k - 1 - Int(Log(Abs(x)) / Log(10#))
        pn = 10 ^ Cdbl(np)
        l = pn * x
        Return l / pn
    Else
        Return 0
    End If
End Function

_________________
Code:
#include "signatur.bi"
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
ytwinky



Anmeldungsdatum: 28.05.2005
Beiträge: 2624
Wohnort: Machteburch

BeitragVerfasst am: 28.11.2006, 21:00    Titel: Antworten mit Zitat

So, hier nun das versprochene Beispiel:
Code:
#include "vbcompat.bi"
dim as double summe, mwst, netto, Test, d
Dim As String Fmt="#####.00", dt
summe=10
netto=summe/1.16
'netto=int(netto*100+0.5)/100
mwst=summe-netto
print "Summe "+str(summe)
print "Netto "+str(netto)
print "Mwst "+str(mwst)

'Bei Summe=100 ist es genauso
'Auch CINT hilft nichts.
?"Summe " &Format(summe, Fmt) &" Euro"
?"Netto " &Format(netto, Fmt) &" Euro"
?"Mwst  " &Format(mwst, Fmt) &" Euro"
Test=mwst+netto
?"Test  " &Format(Test, Fmt) &" Euro"
?Summe-Test
?"Soll=0=" &Format(Summe-Test, Fmt)
?
?"Problem"
?"Netto " &Format(netto, Fmt)
dt=Format(netto, Fmt)
dt=Left(dt, Instr(dt, ",")-1) &"." &Mid(dt, Instr(dt, ",")+1)
d=Val(dt)
?dt
?d
?"Format=" &Format(d, Fmt)
?"wg. ',' im String"
?"btw.: +Str(Irgendwas) ist dasselbe wie &Irgendwas"
Sleep
..das mit dem Runden ist so eine Sache, wie das letzte Beispiel zeigt traurig
Wenn es einfacher wäre, gäbe es sicherlich schon eine allgemeine Runden-Funktion..
Gruß
ytwinky
_________________
v1ctor hat Folgendes geschrieben:
Yeah, i like INPUT$(n) as much as PRINT USING..
..also ungefähr so, wie ich GOTO..

Zuletzt bearbeitet von ytwinky am 28.11.2006, 21:03, insgesamt 2-mal bearbeitet
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
Mao



Anmeldungsdatum: 25.09.2005
Beiträge: 4409
Wohnort: /dev/hda1

BeitragVerfasst am: 28.11.2006, 21:00    Titel: Antworten mit Zitat

Scheiße, ich glaub, jetzt fängts an... durchgeknallt mit dem Kopf durch die Mauer wollen
Sry, hab irgendwas mit b-a gemacht. lachen
_________________
Eine handvoll Glück reicht nie für zwei.
--
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
dreael
Administrator


Anmeldungsdatum: 10.09.2004
Beiträge: 2529
Wohnort: Hofen SH (Schweiz)

BeitragVerfasst am: 28.11.2006, 21:25    Titel: Antworten mit Zitat

stevie1401 hat Folgendes geschrieben:
a=68.50
b=59.05
print a-b

Ergebnis: 9.450001

Passender Artikel zum gesamten Thema:

http://www.dreael.ch/Deutsch/BASIC-Knowhow-Ecke/Gleitkommazahlen.html

FreeBasic rechnet intern ebenfalls binär und somit gilt das dort Gezeigte 1:1 genauso!
_________________
Teste die PC-Sicherheit mit www.sec-check.net
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
Dominik



Anmeldungsdatum: 22.12.2004
Beiträge: 172

BeitragVerfasst am: 28.11.2006, 23:36    Titel: Antworten mit Zitat

Wenn ich das richtig sehe, dann arbeitest du mit einfacher Genauigkeit. Wenn dir diese Genauigkeit reicht, dann rechne doch mit doppelter Genauigkeit und konvertiere, wenn du fertig bist, das Ergebnis nach Single:

Code:

Dim A As Double = 68.50
Dim B As Double = 59.05

Print CSng(A - B)
Sleep


Ausgabe: 9.45
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    Das deutsche QBasic- und FreeBASIC-Forum Foren-Übersicht -> Allgemeine Fragen zu FreeBASIC. Alle Zeiten sind GMT + 1 Stunde
Seite 1 von 1

 
Gehe zu:  
Du kannst keine Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum nicht antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.

 Impressum :: Datenschutz