Skip to content

Speed up geo coordinate transforms: combined sincos + fewer trig calls#11

Merged
alexey-milovidov merged 1 commit into
ClickHouse/v4from
sincos-optimization
Jul 5, 2026
Merged

Speed up geo coordinate transforms: combined sincos + fewer trig calls#11
alexey-milovidov merged 1 commit into
ClickHouse/v4from
sincos-optimization

Conversation

@alexey-milovidov

Copy link
Copy Markdown
Member

Speed up the geo coordinate transforms

The lat/lng <-> H3 cell transforms are dominated by transcendental
function calls. Profiling the hot paths showed two easy, safe wins:

  1. Combined sine/cosine. Several routines need both sin(x) and
    cos(x) of the same angle but computed them with two independent libm
    calls. A small _sincos() helper computes them together — it lowers
    to a single sincos call where libm provides one, and falls back to
    separate sin()/cos() otherwise, so it stays portable.
  2. Removing redundant trig. A couple of routines evaluated the same
    sine/cosine more than once.

Functions touched:

function change
_geoToVec3d one sincos for the latitude, one for the longitude
_geoAzimuthRads sincos pairs; cos(p2->lat) was evaluated twice
_geoAzDistanceRads sincos for p1->lat, distance and azimuth, each previously evaluated twice
_geoToHex2d one sincos for theta

Correctness

The outputs are bit-for-bit identical to before — this only removes
redundant work and fuses paired calls (which return the same values).
All 311 existing unit tests pass unchanged.

Performance

Measured on 10M random cells, clang -O3, no LTO:

function speedup
cellToBoundary +14%
cellToLatLng +9–11%
cellArea* +8%
latLngToCell +3–4%

cellToParent / isValidCell were already limited by their (already
optimal) bit-twiddling and are unchanged.


This backs a ClickHouse-side change: it lets ClickHouse keep the C H3
library while recovering the coordinate-transform speedups that motivated
the experiment in ClickHouse/ClickHouse#100272, without switching the
backend to Rust.

The lat/lng <-> H3 cell transforms are dominated by transcendental
function calls. Several hot routines computed sin(x) and cos(x) of the
same angle with two separate library calls, and a few recomputed the
same value more than once:

  * _geoToVec3d       - sin/cos of the latitude and of the longitude
  * _geoAzimuthRads   - sin/cos pairs; cos(p2->lat) was evaluated twice
  * _geoAzDistanceRads- sin/cos of p1->lat, the distance and the azimuth
                        were each evaluated twice
  * _geoToHex2d       - sin/cos of theta

Compute each sin/cos pair together via a small _sincos() helper (it
lowers to a single libm `sincos` call where available and falls back to
separate sin()/cos() otherwise) and reuse already-computed values. The
outputs are bit-for-bit identical; this only removes redundant work.

Measured on 10M rows (clang -O3, no LTO):

  cellToLatLng     +9..11%
  cellToBoundary   +14%
  cellArea         +8%
  latLngToCell     +3..4%

All 311 existing tests pass unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@alexey-milovidov

Copy link
Copy Markdown
Member Author

Looks ok.

@alexey-milovidov
alexey-milovidov merged commit 2acd332 into ClickHouse/v4 Jul 5, 2026
1 check passed
@alexey-milovidov alexey-milovidov self-assigned this Jul 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant