Skip to content

Compute paired sine/cosine together in the coordinate transforms#1188

Open
alexey-milovidov wants to merge 1 commit into
uber:masterfrom
alexey-milovidov:upstream-sincos-optimization
Open

Compute paired sine/cosine together in the coordinate transforms#1188
alexey-milovidov wants to merge 1 commit into
uber:masterfrom
alexey-milovidov:upstream-sincos-optimization

Conversation

@alexey-milovidov

Copy link
Copy Markdown
Contributor

Compute paired sine/cosine together in the coordinate transforms

The lat/lng <-> cell coordinate transforms repeatedly need both sin(x) and cos(x) of the same angle, but currently compute them with two independent libm calls:

  • latLngToVec3 (vec3d.h) — sin/cos of the latitude and of the longitude
  • _vec3ToHex2d (faceijk.c) — sin/cos of theta
  • _hex2dToVec3 (faceijk.c) — sin/cos of theta and of r

This adds a tiny _sincos() helper to mathExtensions.h (it lowers to a single libm sincos call where one exists via __builtin_sincos, and falls back to separate sin()/cos() otherwise, so it stays portable) and uses it in those spots. Computing the pair together shares the argument reduction and polynomial evaluation.

The recent switch to a 3D-Cartesian projection already removed most of the spherical trig (e.g. _vec3AzimuthRads no longer calls sin/cos); this cleans up the paired calls that remain.

Correctness

The results are bit-for-bit identicalsincos returns the same values as separate sin/cos, and the operand order is unchanged. All existing tests pass unchanged (ctest: 317/317).

Performance

On a synthetic 10M-point benchmark (clang -O3), fusing the paired calls measurably speeds up the boundary/center/area transforms (single-digit to low-double-digit percent, depending on the function and platform libm). sincos is ~1.2–1.3× cheaper than sin+cos for real-range arguments on glibc.

No behavior, API, or output changes.

The lat/lng <-> cell coordinate transforms repeatedly need both sin(x)
and cos(x) of the same angle but computed them with two separate libm
calls:

  * latLngToVec3   - sin/cos of the latitude and of the longitude
  * _vec3ToHex2d   - sin/cos of theta
  * _hex2dToVec3   - sin/cos of theta and of r

Add a small _sincos() helper (it lowers to a single libm `sincos` call
where available and otherwise falls back to separate sin()/cos()) and use
it in these spots. Computing the pair together shares the argument
reduction, so it is faster while returning identical values.

The results are bit-for-bit identical; all existing tests pass unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
*/
static inline void _sincos(double x, double *s, double *c) {
#if defined(__GNUC__) || defined(__clang__)
__builtin_sincos(x, s, c);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this is not compiling as expected. Does it maybe require #define _GNU_SOURCE before the include?

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.

3 participants