[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