Exakten Wert beim Quadrieren von Floats (Python)?
Hallo,
heute bin ich mit einem Bug im Rucksack unterwegs.
Ich versuche folgende Zahl 11.313708498984761 in Python zu quadrieren. Das Ergebnis müsste 128 sein, doch er gibt 128,00000000000003 aus und ich verstehe nicht wie ich das präzisieren könnte.
Es wäre schön, falls mir jemand weiterhelfen könnte.
Mit freundlichen Grüßen
JUCEL
PS: Hier mein derzeitiger Code:
# This Script was made to calculate the distance to celestial bodies in space (nearby milkyway).
import math
import decimal
import datetime
import random, string
sin = math.sin;
degrees = math.radians;
decimal.getcontext().prec = 200;
decimal = decimal.Decimal;
# Log-File, Datum, Star-Name
request = input("Hello, please choose between following options:\nDistance-Calculator [1] \nProtokoll [2]\nExit [q]\nOption: ")
if request == str("1"):
print("Please insert following required data:")
angle1 = input("Angle 1 (°): ")
angle2 = input("Angle 2 (°): ")
distance_In = decimal(input("Distance between the angles (Kilometre): "))
# Angles
summary = decimal(angle1) + decimal(angle2)
angle3 = 180 - float(summary)
# Distances
distance_In_parsec = distance_In * decimal(0.000000000000060019)
# Distance_a
distance_out_a_parsec = decimal(distance_In) * decimal((sin(degrees(decimal(angle1)))/sin(degrees(decimal(angle3))))) * decimal(0.000000000000060019)
distance_out_a_ligh_years = decimal(distance_out_a_parsec) * decimal(3.26156)
distance_out_a_astronomic_unit = decimal(distance_out_a_parsec) * decimal(206265)
print("Distance a: \n ", distance_out_a_parsec, "parsec \n ", distance_out_a_ligh_years, "ly \n", distance_out_a_astronomic_unit, "AU \n")
# Distance_b
distance_out_b_parsec = decimal(distance_In) * decimal((sin(degrees(decimal(angle2)))/sin(degrees(decimal(angle3))))) * decimal(0.000000000000060019)
distance_out_b_ligh_years = decimal(distance_out_b_parsec) * decimal(3.26156)
distance_out_b_astronomic_unit = decimal(distance_out_b_parsec) * decimal(206265)
print("Distance b: \n ", distance_out_b_parsec, "parsec \n ", distance_out_b_ligh_years, "ly \n", distance_out_b_astronomic_unit, "AU \n")
# Distance_center
half = decimal(distance_In)/2
distance_out_center_dump = distance_out_a_parsec * distance_out_a_parsec - half * half
distance_out_center_parsec = decimal(math.sqrt(abs(decimal(distance_out_center_dump)))) * decimal(0.000000000000060019)
distance_out_center_light_years = decimal(distance_out_center_parsec) * decimal(3.26156)
distance_out_center_astronomic_unit = decimal(distance_out_center_parsec) * decimal(206265)
print("Distance from the center of ellipsis: \n ", distance_out_center_parsec, "parsec \n ", distance_out_center_light_years, "ly \n", distance_out_center_astronomic_unit, "AU")
# Protocol
elif request == str("2"):
pass
elif request == str("q"):
exit(0)
4 Antworten
Floats sind - unabhängig von der Programmiersprache - niemals genau, sondern IMMER nur Annäherungen!
Wenn etwas genau sein soll, MUSST du Integer nehmen.
Merke: Floats sind immer nur "ungefähr", mal mehr, mal weniger, aber genau sind sie - von Spezialfällen mal abgesehen - nie.
Eine ohne die Installation von weiteren Bibliotheken durchführbare Alternative wäre diese:
>>> import decimal
>>> decimal.getcontext().prec = 200
>>> decimal.Decimal("128")**decimal.Decimal("0.5")
Decimal('11.313708498984760390413509793677584628557375003015584585413437903925859827696856310803100274621132581880110769847298376199398688446805897701152971976799486651305781327420044742046399604009222256484572')
>>>
Wobei daas Ergebnis natürlich keine 100%ige Genauigkeit hat, da jeder PC nur über eine endliche Menge Speicher verfügt und du wohl kaum Lust darauf hättest, unendlich lange auf das Ergebnis zu warten. ^^
Problem Nummer 1: 128 ist keine Quadratzahl, daher ist die Quadratwurzel irrational.
Problem Nummer 2: Gleitkommazahlen sind nicht exakt.
Problem Nummer 3: Die Größe und damit die Genauigkeit von "Standard-Gleitkommazahlen" ist statisch begrenzt.
--------------------------------------
Aber das Hauptproblem ist Nummer 1: Eine irrationale Zahl hat in Dezimalschreibweise unendlich viele Nachkommastellen. Mit nur einer endlichen Teilmenge wird das Ergebnis also bestenfalls zufälligerweise korrekt.
Das ist kein Bug, da Wurzel 128 keine rationale (= mit einem Bruch darstellbare) Zahl ist und deswegen deine Zahl zum Quadrat auch gar nicht ganz genau 128 ergeben kann. Quelle: https://squareroot.info/number/square-root-of-128.html
Du kannst das Problem beheben, indem du entweder rundest, floor oder ceil benutzt, beziehungsweise die Anwendung veränderst.
Der echte Zahlenwert hat natürlich ∞ viele Stellen. √127=11.31370849898476039041350979367758…
Dein Zahlenwert ist ist also notwendigerweise gerundet, und auch noch ungenau: √127≈11.313708498984761
Es ist also klar, daß beim Quadrieren etwas anderes als 127 herauskommen muß.
Das Problem ist, dass ich mit langen Kommazahlen rechnen muss. Es geht mir darum Parsec berechnen zu können, weshalb Kommazahlen unvermeidlich sind. Gibt es da keine Alternativen?