Opened 6 years ago

Closed 3 years ago

#868 closed enhancement (fixed)

Feature request: improve WKTWriter::writeNumber

Reported by: Mike Taves Owned by: strk
Priority: major Milestone: GEOS Fund Me
Component: Core Version: main
Severity: Feature Request Keywords:
Cc:

Description

Numpy recently switched their default floating precision formatter to use a Dragon4 algorithm by Ryan Juckett to print floating point numbers with the shortest decimal representation. This feature request is to use Ryan's library (or similar) for WKTWriter, and implement it for the private WKTWriter::writeNumber, replacing std::fixed and std::setprecision.

There are probably a few ways that such a library could be adapted to better format coordinate data, using WKTWriter's existing setRoundingPrecision and trim options. For instance PrintFloatFormat_Positional can be used to always format numbers in positional notation, which I think is the preferred format for coordinates if setRoundingPrecision>-1 is specified. Also if trim=True and setRoundingPrecision=-1 are set, then the shortest representation which uniquely identifies the floating-point number can be used.

See numpy's format_float_positional see how they implemented their interface.

To see how this matters with shapely and numpy 1.14.2, see this demo (adapted from Shapely issue#586):

import numpy as np
from shapely.wkt import dumps
from shapely.geometry import Point

p = Point(527626.93, 0.00)

# Using GEOS' WKTWriter -- takes up more space than is necessary
print(p.wkt)  # POINT (527626.9300000001 0)
# not sure what's going on here..
print(dumps(p, trim=True, rounding_precision=4))  # POINT (5.276e+005 0)

# Numpy's Dragon4 decimal formatter
pa = np.array(p)
print(np.format_float_positional(pa[0])) # 527626.93

# show that the binary representation is the same:
print(np.float64('527626.9300000001').tostring())
print(np.float64('527626.93').tostring())
# both show '\xc3\xf5(\xdc\x15\x1a A'

# getting fancy  -- this should be the default output with trim=True
print('POINT (' + ' '.join([np.format_float_positional(x, trim='-') for x in pa]) + ')')
# POINT (527626.93 0)

Change History (3)

comment:1 by Mike Taves, 6 years ago

Probably a better double -> string library is Google's double-conversion a.k.a. libdouble-conversion-dev, as it is in widespread use (e.g. V8, Firefox, etc.). Examples are in (e.g.) test/cctest/test-conversions.cc

comment:2 by robe, 6 years ago

Milestone: GEOS FutureGEOS Fund Me

Milestone renamed

comment:3 by Paul Ramsey <pramsey@…>, 3 years ago

Resolution: fixed
Status: newclosed

In 2376cd6/git:

Change setTrim(true) mode to be positional, as users expect, using the ryu library to generate the shortest positionally limited string formats. For setTrim(false) continue to use C++ std::fixed format. Closes #868.

Note: See TracTickets for help on using tickets.