Abrunder funktion

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

Hallo zusammen,

ich brauche eine Funktion, welche zuverlässig abrundet und dabei auch mit float problemen (1.1+2.2 == 3.000000xxx) umgehen kann.
Ich hab natürlich schon nach abrunder funktionen gegoogelt und auch was gefunden, was aber leider nicht mit der float problematik umgehen kann. Deshalb habe ich es bis jetzt wie folgt modifiziert:

Code: Alles auswählen

def abrunder(zahl, schritt_weite):
    zahl = float(zahl)
    if zahl==0:
        ergebnis = zahl
    else:
        original_schritt_weite = int(schritt_weite)
        schritt_weite = round((1/10)**schritt_weite,original_schritt_weite) # dadurch kann man 1 fuer eine nachkommastelle und 2 fuer zwei stellen usw angeben
        ergebnis = math.floor(round(zahl/schritt_weite,12))*schritt_weite  # 0.58/0.1 sind leider 0.5799999... sobald bei round 15 anstatt 14 verwendet wird, rundet er falsch ... auch bei 14 kommt falsches runden vor -.-
        ergebnis = repr(ergebnis)
        zaehler = 0
        for zeichen in ergebnis: # jedes zeichen dieser zahl durchgehen und . bzw , finden. und Position feststellen
            if zeichen == "," or zeichen == ".":
                break   # sobald gebreaked wird, gibt zaehler die position des punktes an
            zaehler += 1
            if zaehler >= 1000:
                raise AssertionError("Zeichenkette im Abrunder zu lang oder enthaelt kein , oder . ")
        cut = int(zaehler+1+original_schritt_weite)
        ergebnis = ergebnis[:cut] # bei 2 gewuenschten nachkommstellen ab der dritten zahl nach dem komma abtrennen, damit keine .0000001 kram bei rauskommt
        ergebnis = float(ergebnis)
    return (ergebnis)
In meinem anderen Thread zum exakten rechnen, haben wir ja schon möglichkeiten überlegt, wie man diese float problematik umgehen kann.
1) Da wäre zum einen Decimal(), was aber tatsächlich um den Faktor 20 länger dauert, als wenn man mit float rechnet. Da ich sehr häufig abrunden muss, wäre das also eher keine option.
2) Anstatt mit 0.01 zu rechnen, mit 1 rechnen und so nachkommastellen vermeiden.
-> dies im ganzen skript anzuwenden würde einige Zeit dauern (das skript zu ändern) und wäre auch nicht optimal. Innerhalb der abrunder funktion wird ja bereits so gerechnet, indem diese schrittweite berechnet wird.. oder nicht?

Das Problem bei der aktuellen funktion ist einmal die Zeile:
ergebnis = math.floor(round(zahl/schritt_weite,12))*schritt_weite
das round() habe ich eingeführt, weil es vorkommt, dass übergebene zahlen, zb 1.14 dort zu 1.139999 werden, wodurch zahl/schritt_weite == 113.99999999999999 ist, was natürlich zu fehlern führt.
Gerade eben noch hatte diese ergebnis Zeile ein round() auf 14 stellen, anstatt 12. Aber ich musste leider feststellen, dass auch mit 14 manche zahlen, so auch die 1.14 falsch gerundet werden. Deswegen habe ich es jetzt auf 12 geändert... die Frage ist nur, ob das auch die endgültige Lösung ist, oder ob es noch andere Zahlen gibt, wo dies noch niedriger sein muss?

Und zusätzlich dann natürlich noch das Ergebnis selbst, welches potentiell ebenfalls x.0000000x sein kann.
Dort werden aktuell einfach nur alle stellen nach der gewünschten Nachkommastelle abgeschnitten, was bisher auch keine Probleme gemacht hat, also so funktioniert.

edit:
im falle von 1.14 will ich auf 2 nachkommastellen genau runden, dh. wenn ich 1.14 übergebe, soll er auch 1.14 zurückgeben.
würde es da also schon helfen, die zahl der nachkommastellen der übergebenen zahl zu anfang zu überprüfen, und wenn sie bereits 2 stellen hat, sie einfach wieder auszugeben, ohne veränderung ? Oder wuerde das nicht alle probleme lösen?
Benutzeravatar
sparrow
User
Beiträge: 4599
Registriert: Freitag 17. April 2009, 10:28

Kannst du mal ein Beispiel mit Werten zeigen, das nicht funktioniert?
Also sprich mit Werten, dann das was du erwartest und das was im Augenblick passiert.
BlackJack

@Serpens66: Wie prüfst Du denn die Anzahl der Nachkommastellen? Wie viele Nachkommastellen hat denn Deiner Meinung nach der `float`-Wert 1.0/10 beziehungsweise 0.1? Und wie prüfst Du das? Ich glaube Dir ist das was Du die „float problematik“ nennst immer noch nicht klar. Es gibt ganz einfach sehr viele, ganz ”gewöhnliche” Dezimalbrüche die mit der internen Darstellung schlicht gar nicht exakt repräsentiert werden können, also so wirklich *gar nicht*, egal wie viel Du da rumrundest. Und das trifft schon auf so wenig exotische Zahlen wir 0,1 zu.
Sirius3
User
Beiträge: 18335
Registriert: Sonntag 21. Oktober 2012, 17:20

@Serpens66: das habe ich Dir doch schon im anderen Thread gezeigt, aber hier nochmal zum Nachlesen:

Code: Alles auswählen

print("{0:.2f}".format(math.floor(wert + epsilon)))
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

sparrow hat geschrieben:Kannst du mal ein Beispiel mit Werten zeigen, das nicht funktioniert?
Also sprich mit Werten, dann das was du erwartest und das was im Augenblick passiert.
so wie die fkt jetzt da steht, funktioniert sie mit allen werten, die ich aktiv probiert habe :D
Aber wenn in der ergebniszeile anstelle der 12 eine 14 steht, dann wird 1.14 zu 1.13 gerundet, weil "zahl/schritt_weite == 113.99999999999999" und round(113.99999999999999,14) = 113.99999999999999 ist... was auch irgendwie logisch ist... ... warum hab ich das so gemacht... ? :D

Ursprünglich sah die Zeile auch so aus:
ergebnis = math.floor(round(zahl/schritt_weite,original_schritt_weite))*schritt_weite
Allerdings hat das auch probleme gemacht... ich weiß nur leider echt nicht mehr wobei genau... In meinen Tests funktioniert es gerade fuer alle Zahlen zwischen 0 und 100 in 0.01er schritten...
hmm... ... deshalb schreib ich mir immer überall als kommentar daneben, warum ich was ändere :D nur in diesem speziellen Fall hab ich das wohl vergessen -.-
Naja, dann ändere ich die Zeile also, sodass anstatt der 12 dann "original_schritt_weite" da steht... mal schauen ob das Problem weshalb ich es genändert hatte wieder kommt...

@BlackJack:
wie ich die zahl der Nachkommastellen prüfe steht ja im skript, ich suche nach dem , bzw. . seperator ;)
Meiner Meinung nach muss 1.1+2.2 == 3.3 sein (also eine nachkommastelle), was es mathematisch ja auch so ist. In float ist es das natürlich nicht und das verstehe ich auch. Aber ich möchte trotzdem, dass 3.3 und nicht 3.3000000x ausgegeben wird.

@Sirius3:
und wie/wo füge ich das ein? wie sieht die fertige abrunder fkt dann aus?
BlackJack

@Serpens66: Wenn Du 3.3 ausgegeben haben möchtest, dann formatiere die Gleitkommazahl ganz einfach entsprechend:

Code: Alles auswählen

In [11]: format(1.1 + 2.2, '.2f')
Out[11]: '3.30'
Gegebenfalls noch ein `rstrip()` wegen der 0.
Sirius3
User
Beiträge: 18335
Registriert: Sonntag 21. Oktober 2012, 17:20

@Serpens66: Dein Verständnisproblem ist, dass Du glaubst, Du könntest eine float-Zahl mit 2 Nachkommastellen erzeugen. Das geht nicht. Du kannst nur etwas mit einer gewissen Anzahl an Nachkommastellen ausgeben.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

Sirius3 hat geschrieben:@Serpens66: Dein Verständnisproblem ist, dass Du glaubst, Du könntest eine float-Zahl mit 2 Nachkommastellen erzeugen. Das geht nicht. Du kannst nur etwas mit einer gewissen Anzahl an Nachkommastellen ausgeben.
aber wenn ich print(0.1) schreibe, dann wird mir doch 0.1 ausgegeben. Also hat diese float zahl doch offensichtlich nur eine nachkommastelle (bzw. wird als solche ausgegeben) - auch wenn sie intern vllt was weiß ich für viele nachkommastellen hat, sie wird mir als eine stelle ausgegeben. Und das ist alles was ich erreichen will. Ich will, dass mir eine Zahl ohne diese ganzen nachkommastellen ausgegeben wird.

Ich hab das Problem übrigens wieder gefunden. Wenn ich in der Ergebniszeile die original_schrittweite nehme, dann ist:
print(abrunder(0.019999000121,2)) -> 0.02 , was natürlich verkehrt ist.

@BlackJack:
dh. du stimmst mir mit meiner abrunder funktion soweit zu, aber den umständlichen "cut" Teil, kann ich einfach durch deinen Code ersetzen, richtig? Ja das sollte passen, danke :)

Bleibt halt nur noch diese ergebnis Zeile zu klären. Ich glaube nicht, dass es mit 12 eine allgemeingültige Lösung ist. Da muss es doch was besseres geben, wie ich dafuer sorgen kann ,dass immer die richtige zahl ausgegeben wird.

edit:
okay, ich versuch nochmal diese float problematik zu verstehen. Ihr sagt also, dass z.b 0.1 als float eigentlich garnicht 0.1 ist, sondern halt noch x nachkommastellen dabei sind.
Dann stellt sich fuer mich jetzt die Frage, wann wird diese 0.1 so umgewandetl, dass sie nur eine nachkommastelle hat? Ich mein bei print(0.1) wird sie dann ja offensichtlich in eine zahl mit einer kommastelle umgewandelt. Ist dies auch der Fall wenn ich repr(0.1) oder str(0.1) mache?
Ein gutes Beispiel ist möglicherweise noch die 0.28. Ich übergebe nämlich z.b 0.28 an die API, aber anzukommen scheint immer 0.280000001, obwhol ich zusätzlich noch round(0.28,2) anwende. Und wenn ich die Zahl, die ich an die API übergeben habe durch print ausgebe, dann kommt 0.28 , weshalb ich mir diese 0.2800001 bisher nie erklären konnte.
Deshalb nun die Frage, wann die Zahl wie ausgegeben wird. Evlt sollte ich die 0.28 als string an die API uebergeben, um sicherzustellen, dass der kommakram nicht uebergeben wird?
Benutzeravatar
sparrow
User
Beiträge: 4599
Registriert: Freitag 17. April 2009, 10:28

Wenn du anfängst Fließkommazahlen in eine Zeichenkette zu wandeln, um darin die Position des Dezimalkennzeichens zu finden, dann klingt das doch schon komisch.
Vielleicht solltest du doch auf Decimal zurück greifen. Das ist zwar langsamer, tut aber das was du erwartest.
BlackJack

@Serpens66: Nein, ich stimme Deiner ”abrunder”-Funktion nicht zu. Es geht hier nicht ums runden von `float`-Werten sondern um eine Umwandlung von solchen in eine Zeichenkettendarstellung. `format()` ”rundet” dabei auch nicht nur ab, sondern natürlich auch auf. Ich denke Du hast `float` immer noch nicht wirklich verstanden wenn Du sagst 0.1 (als `float`) hätte nur eine Nachkommastelle. Schauen wir mal ein bisschen weiter:
In [2]: format(0.1, '.50f')
Out[2]: '0.10000000000000000555111512312578270211815834045410'
Das ist also grösser als 0,1.

So, nun nehmen wir davon mal 10 Einzelwerte und addieren die. Was meinst Du, kommt da etwas heraus was grösser als 1 ist, oder etwas das kleiner als 1 ist? Hier die Auflösung:

Code: Alles auswählen

In [3]: [0.1] * 10
Out[3]: [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]

In [4]: sum([0.1] * 10)
Out[4]: 0.9999999999999999

In [5]: format(sum([0.1] * 10), '.50f')
Out[5]: '0.99999999999999988897769753748434595763683319091797'
Wenn man die Anzeige auf zwei Nachkommastellen begrenzt, kommt dann aber wieder etwas das als Anzeige passt, weil dann natürlich aufgerundet wird für die Anzeige:

Code: Alles auswählen

In [6]: format(sum([0.1] * 10), '.2f')
Out[6]: '1.00'
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

BlackJack hat geschrieben:@Serpens66: Nein, ich stimme Deiner ”abrunder”-Funktion nicht zu. Es geht hier nicht ums runden von `float`-Werten sondern um eine Umwandlung von solchen in eine Zeichenkettendarstellung. `format()` ”rundet” dabei auch nicht nur ab, sondern natürlich auch auf. Ich denke Du hast `float` immer noch nicht wirklich verstanden wenn Du sagst 0.1 (als `float`) hätte nur eine Nachkommastelle. Schauen wir mal ein bisschen weiter:
In [2]: format(0.1, '.50f')
Out[2]: '0.10000000000000000555111512312578270211815834045410'
Das ist also grösser als 0,1.

So, nun nehmen wir davon mal 10 Einzelwerte und addieren die. Was meinst Du, kommt da etwas heraus was grösser als 1 ist, oder etwas das kleiner als 1 ist? Hier die Auflösung:

Code: Alles auswählen

In [3]: [0.1] * 10
Out[3]: [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]

In [4]: sum([0.1] * 10)
Out[4]: 0.9999999999999999

In [5]: format(sum([0.1] * 10), '.50f')
Out[5]: '0.99999999999999988897769753748434595763683319091797'
Wenn man die Anzeige auf zwei Nachkommastellen begrenzt, kommt dann aber wieder etwas das als Anzeige passt, weil dann natürlich aufgerundet wird für die Anzeige:

Code: Alles auswählen

In [6]: format(sum([0.1] * 10), '.2f')
Out[6]: '1.00'
ich danke dir dafür. Genau das habe ich mit meinem edit des letzten Beitrag erfragt und weiß jetzt also, wie ich die tatsächlichen nachkommastellen anzeigen lassen kann :)
Das 10*0.1 ergebnis ist kleiner 1, weil du ja nur mit einer begrenzten Zahl an nachkommastellen rechnest, richtig? Daraus folgere ich, wenn man mit allen Stellen rechnen können würde, würde 1 bei raus kommen? Kann ja eigentlich nicht sein, denn 10 mal eine zahl leicht größer 0.1, kann ja nicht genau 1 ergeben.

Gut.... nur wie hilft mir das nun bei der abrunder funktion? bzw. jetzt wo ich sehe, das quasi jede kommazahl intern als float unendlich viele nachkommastellen hat, verweifel ich so ein bisschen, und frage mich, warum überhaupt irgendeine meiner Rechnungen funktioniert :D
Gut, bei den meisten Rechnungen sind die kommaunterschiede so klein, dass normale Ausgaben der Zahlen dann erscheinen, als gäbe es die Problematik nicht. Das ist der Grund, warum ich nicht überall das Problem habe. Das größte Problem damit habe ich ja eigentlich nur beim runden. Denn innerhalb der abrunder Funktion macht es schon einen großen unterschied, ob etwas 2 oder 1.9999 ist... (wird ja potenziert)

Also könnt ihr mir nun eine Abrunder funktion zeigen, welche 0.01999999239 auf 0.1 abrundet und 0.58 als 0.58 ausspuckt (also beides auf 2 nachkommastellen runden und die Zahlen verstehen sich als "ausgegebene" zahl, soll heißen auch wenn 0.58 dann ausgegeben wird ist es in wahrheit natürlich 0.57999999999999996003 ).
Das Problem ist ja immernoch diese ergebnis zeile mit mathfloor. Da ist es wichtig wie das ergebnis von zahl/schritt_menge ausfällt.

So.. angeommen ich habe dann diese abrunder funktion. Für "auszugebene" Zahlen funktioniert diese dann natürlich. Aber ich kann mit ihr nicht dafür sorgen, dass 0.1 wirklich exakt 0.1 ist.
Wann wird nun also was angegeben? Wenn ich zahl = 0.1 definiere, und diese float zahl, so wie sie ist an die API übergebe, hängt es dann davon ab, wie die Website mit der float Zahl umgeht? Vermutlich schon... Um sicherzugehen, sollte ich, sofern von der API akzeptiert, also lieber format(zahl, '.2f') übergeben, denn das ist ja dann ein string und fehlerfrei (wobei falls die website das dann in float wandeln sollte, kann es wieder probleme geben, aber wir gehen mal davon aus, dass sie das nicht macht)
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Du brauchst keine Hilfe bei der abrunder Funktion. Eine abrunder Funktion kann es nicht geben. Die Art und Weise wie floats intern dargestellt werden verbietet es. Lass dich dabei nicht von der Ausgabe täuschen die Python macht wenn man floats mit print ausgibt. Python nutzt einen sehr aufwendigen Algorithmus der rät wieviele Nachkommastellen interessant sein könnten und passt die Ausgabe entsprechend an. Wieviele dir angezeigt werden hat also nichts damit zu tun wieviele Nachkommastellen die Zahl tatsächlich hat.

Die Webseite und jedes andere Program mit dem du interagierst oder jemals interagiert hat verhält sich genauso ungenau. Es sei den es wird irgendwo explizit erwähnt dass es nicht mit floats hantiert.
BlackJack

@Serpens66: Bei 0,1 kann man mit `float` nicht mit allen Stellen rechnen, denn das sind *unendlich viele*. Versuch mal mit allen Nachkommastellen von 1/3 im Dezimalsystem zu rechnen. Bei Binärbrüchen geht halt 1/10 nicht auf. An der Stelle vielleicht mal der Hinweis das auch `Decimal` nicht alles exakt darstellen kann, die Sachen sind für Menschen die im Dezimalsystem rechnen einfach weniger überraschend, weil ”normaler”. Wenn man 1/3 und 1/10 exakt haben möchte, müsste man sich das `fractions`-Modul ansehen (weiss nicht ob wir das hier schon mal erwähnt hatten…).

Die meisten Rechnungen funktionieren weil die Ungenauigkeiten in der Regel so klein sind und bleiben das sie nicht ins Gewicht fallen. Das wurde ja auch schon mehrfach gesagt: Mach Dir einfach mal in realen Einheiten klar um was es hier geht. Der Wert für 0,1 liegt aufgerundet nur um 0,000000000000000006 daneben, und das Ergebnis von 10-mal aufaddieren auch nur um etwas mehr als 0,0000000000000001. Das ist wenn man den Werten mal irgendwelche physikalischen Einheiten verpasst ziemlich sicher kleiner als die üblichen Messungenauigkeiten bei den allermeisten realen Anwendungen dieser Zahlen und Rechnungen und damit schlicht vernachlässigbar.

Da wo es dem Entwickler wirklich wichtig erscheint würde er, und das wurde ja auch schon gesagt, sich seine Berechnungen anschauen die er anstellt, und eine Fehlerrechnung aufstellen, um zu ermitteln wie gross der Rechenfehler maximal werden kann und ob der noch unterhalb dessen ist was relevant ist. Und erst wenn das nicht mehr der Fall ist, würde man zuerst versuchen die Rechnungen so umzugestalten das der Fehler kleiner wird, und erst wenn das nicht funktioniert solche Zeitfresser wie `Decimal` in Betracht ziehen. Also zumindest dann wenn die Rechenzeit eine wesentliche Rolle spielt, und Deine anderen Themen hier im Forum legen genau das nahe.
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

@Serpens66: Wenn Du Float Zahlen mit Hilfe von Runden auf Gleichwertigkeit überprüfen willst, dann ist das ziemlich inflexibel. In vielen numerischen Verfahren werden zwei Float Zahlen als gleichwertig betrachtet, wenn ihre Differenz kleiner als ein Epsilon ist. Das Epsilon hängt dabei von der Problematik ab (der Domäne). Bei Gewichten von Schiffen könnte das Epsilon z.B. 1 Gramm sein und bei Teebeuteln vielleicht 1 Mikrogramm.

Code: Alles auswählen

a = 1.87
b = 1.131
c = 3.001
print a + b, a + b == c

domain_size = 20
epsilon = domain_size * 1.e-12

print abs(a+b - c), abs(a+b - c)<epsilon
a fool with a tool is still a fool, www.magben.de, YouTube
Benutzeravatar
sparrow
User
Beiträge: 4599
Registriert: Freitag 17. April 2009, 10:28

MagBen hat geschrieben:@Serpens66: Wenn Du Float Zahlen mit Hilfe von Runden auf Gleichwertigkeit überprüfen willst, dann ist das ziemlich inflexibel.
Zudem ist runden teuer.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@Serpens66:
In den anderen Thread hattest Du doch geschrieben, dass Deine Zahlen trotz Nachkommastellen keine Floats sind, da diese nur bis 8 Nachkommastellen eingegeben werden können. Dann ist es einfacher, mit Integerarithmetik mit der 8. Nachkommastelle als kleinsten Schritt zu rechnen (kbr hat das im alten Thread auch schon geschrieben). Dafür musst Du die Stringrepräsentationen nur ensprechend umwandeln - aus "0.12345678" wird 12345678 und aus 1001 wird "0.00001001". Und durch Einführung weiterer Stellen kannst Du auch Deine Zusatzrechnung nahezu rundungsfrei abbilden (gerundet wird immer erst am Ende, sprich bei Ausgabe, auf diese 8 Nachkommastellen). Das Decimal-Modul geht übrigens ähnlich vor (Hintergrund des Ganzen ist fixedpoint vs floatpoint).
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Hier mal eine kleine Spielerei mit Integern:

Code: Alles auswählen

import re

POINT_REX = re.compile('^[-+]?(?P<pre>\d*)?\.?(?P<post>\d*)$')

def string_to_num(s, precision=8):
    match = POINT_REX.match(s)
    if not match:
        raise Exception('cannot parse "%s" as number' % s)
    num = int(match.group(1) or '0') * 10**precision
    num += int(match.group(2).ljust(precision, '0')[:precision])
    return num

def num_to_string(num, digits=8):
    base = 10 ** digits
    pre = num / base
    post = num % base + base # add base to get leading zeros

    # strip nonsense zeros from right
    # cut first character from post
    return "%s.%s" % (pre, str(post).rstrip('0')[1:])


if __name__ == '__main__':
    print num_to_string(string_to_num("123.123456789"))

    # influence of precision
    a = string_to_num("1000.12345678", precision=100)
    b = string_to_num("0.12345678", precision=10)
    
    # after division we have a different "precision" of 100-10
    result = a / b
    print num_to_string(result, digits=90)
Runden ist nicht implementiert - wenn man das weiter treibt, landet man quasi bei der Decimal-Klasse.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

@ jerch:
wenn das letzlich auf decimal rausläuft, ist es dann genauso oder noch langsamer als wenn ich direkt Decimal() fuer alle meine Rechnungen verwende? (also alle Zahlen beim empfangen aus der API von string direkt in Decimal umwandele und dann damit rechne) ?
Frage mich halt, ob es sinnvoller ist Decimal() zu nehmen, oder eben alles bis auf 8 Stellen als integer zu formulieren, wie es dein skript macht.

@alle anderen:
wieso sollte es keine abrunder funktion bei floats geben? Klar wäre sie evlt keine echte abrunder funktion, aber eine pseudo abrunder funktion sollte doch moeglich sein.
Der Sinn hinter der Abrunder funktion ist es doch schon lange nicht mehr, aus .10000000000001 exakt 0.1 zu machen (so wie ich es ehrlicherweise mal vorhatte, als ich float noch nicht verstanden hatte). Der Sinn der Abrunder Funktion (auf 2 stellen) ist es, aus der float zahl 0.1 weiterhin 0.1 zu machen, während aus der float zahl 0.1234 dann die float zahl 0.12 wird.
Ich verwende hier absichtlich immer wieder den Begriff "float zahl". Damit will ich darauf hinweisen, dass 0.1 natürlich in wirklichkeit 0.10000000001 ist und auch 0.1234 bzw 0.12 noch mehr nachkommastellen hat. Dennoch sind 0.1234 und 0.12 offensichtlich völlig andere Zahlen, egal wieviele nachkommastellen man berücksichtigt. -> es existiert eine (pseudo) abrunder funktion.
Das problem ist jetzt, diese funktion zu schreiben, sodass sie das zurückgibt was sie soll.
Sirius3
User
Beiträge: 18335
Registriert: Sonntag 21. Oktober 2012, 17:20

@Serpens66: auf die Gefahr hin, dass ich mich wiederhole:

Code: Alles auswählen

EPSILON = 1e-9
def abrunden(wert, stellen):
    return math.floor(wert * 10 ** stellen + EPSILON) * 10 ** (-stellen)
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

Sirius3 hat geschrieben:@Serpens66: auf die Gefahr hin, dass ich mich wiederhole:

Code: Alles auswählen

EPSILON = 1e-9
def abrunden(wert, stellen):
    return math.floor(wert * 10 ** stellen + EPSILON) * 10 ** (-stellen)
ne, wiederholen tust du dich damit nicht ;)
danke, werde es dann nachher mal testen :)
Antworten