[Talk-de] Genauigkeit der Koordinaten in der OSM-DB (Nachkommastellen)
Christian Müller
cmue81 at gmx.de
Mi Jan 15 02:46:11 UTC 2025
> Gesendet: Montag, 13. Januar 2025 um 11:45
> Von: "Frederik Ramm" <frederik at remote.org>
> An: "Christian Müller via Talk-de" <talk-de at openstreetmap.org>
> Betreff: Re: [Talk-de] Genauigkeit der Koordinaten in der OSM-DB (Nachkommastellen)
>
> In OSM werden die Daten intern nicht als float-Werte gespeichert,
> sondern als Ganzzahlen, und vorher mit 1E7 multipliziert:
>
> https://github.com/openstreetmap/openstreetmap-website/blob/5d76ec051e2c429b6647401674e13688c1251956/app/models/concerns/geo_record.rb#L17-L20
[..] welche die Funktion "round" nach der
Skalierung verwenden.
Noch fortführend dazu:
======================================
Zwei Beispiele bei denen das Runden vor
Skalierung von Vorteil ist (single float
wegen der überschaubareren Demonstrierbar-
keit):
>>> import numpy as np
>>> np.single(round(1.677721705, 7))
1.6777217
>>> np.single(round(1.677721705, 7))*1e7
16777217.388153076
>>> np.single(round(1.677721705, 7))*np.single(1e7)
16777218.0
>>> np.single(round(1.677721705*1e7))
16777216.0
>>> np.single(round(1.677721749, 7))
1.6777217
>>> np.single(round(1.677721749, 7))*np.single(1e7)
16777218.0
>>> np.single(round(1.677721749*1e7))
16777216.0
Gegenbeispiel:
>>> np.single(round(1.677721655, 7))
1.6777217
>>> np.single(round(1.677721655, 7))*np.single(1e7)
16777218.0
>>> np.single(round(1.677721655*1e7))
16777216.0
Rein mathematisch, also falls jeder reelle Wert re-
präsentierbar wäre, stellt sich die Frage nach dem
Rundungszeitpunkt nicht: Man würde vermeiden, Rund-
ungsfehler zu skalieren.
Alternative mittels Zeichenkettenoperationen:
---------------------------------------------
Womöglich ohne obige Probleme, aber weit weniger performant,
kann der Umweg über Zeichenkettentypen sein, wobei es die
Randbedingung gibt, dass die Eingabe-Fließkommazahl in der
jew. Programmierumgebung möglichst ohne Rundung in eine
Zeichenkette wandelbar ist:
>>> def to_int(l):
... s = str(l)
... s = s + ('.' if s.find('.')<0 else '') + '0'*15
... d = s.find('.')
... e = d+1+7
... r = int(s[e:e+1])
... n = int(s[0:d] + s[d+1:e])
... return n + (0 if r<5 else (-1 if n<0 else 1))
...
(hier mit "away from zero" Rundungsstrategie;
Aufruf ggf. mittels struct.pack('i', to_int(l))
um das Ergebnis in den Maschinentyp zu packen
– https://docs.python.org/3.7/library/struct.html)
Zur Problematik, floats in Zeichenketten zu wandeln,
um sie ohne builtin-Rundung abzuschneiden gibt es
noch fortführend diesen post von vor 15+ Jahren:
https://stackoverflow.com/questions/783897/how-to-truncate-float-values
Das entfernt sich aber vom Thema der Mailingliste.
Gruß
Mehr Informationen über die Mailingliste Talk-de