/src/h3/src/h3lib/include/adder.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2025 Uber Technologies, Inc. |
3 | | * |
4 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | | * you may not use this file except in compliance with the License. |
6 | | * You may obtain a copy of the License at |
7 | | * |
8 | | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | | * |
10 | | * Unless required by applicable law or agreed to in writing, software |
11 | | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | * See the License for the specific language governing permissions and |
14 | | * limitations under the License. |
15 | | */ |
16 | | |
17 | | #ifndef ADDER_H |
18 | | #define ADDER_H |
19 | | |
20 | | /* |
21 | | Header-only implementation of a "compensated summation" algorithm (Kahan |
22 | | summation), which allows us to add up sequences of floating-point numbers |
23 | | with better precision than naive summation, especially when the terms in |
24 | | the sum vary significantly in magnitude. |
25 | | See: https://en.wikipedia.org/wiki/Kahan_summation_algorithm |
26 | | |
27 | | This is useful when computing the area of (multi)polygons, which |
28 | | often involves adding many small terms to a large aggregate. For example, |
29 | | D3 uses an improved accuracy summation when computing polygonal areas via its |
30 | | `Adder` class: |
31 | | https://github.com/d3/d3-geo/blob/main/src/area.js |
32 | | |
33 | | There are a few potential algorithms we might consider for summation: |
34 | | |
35 | | 1. Naive sum |
36 | | 2. Kahan summation |
37 | | 3. Neumaier summation |
38 | | 4. Other approaches like pairwise summation, or Python's `fsum` |
39 | | |
40 | | We considered the first three for simplicity, and settled on Kahan summation: |
41 | | it achieves noticeably better accuracy than naive summation and almost as |
42 | | good accuracy as Neumaier, while being only slightly slower than naive and |
43 | | slightly faster and simpler than Neumaier. |
44 | | |
45 | | See also: https://github.com/python/cpython/issues/100425 for discussion of |
46 | | tradeoffs between Kahan, Neumaier, and `fsum`. |
47 | | |
48 | | ## Usage |
49 | | |
50 | | Adder adder = {}; // initialize |
51 | | kadd(&adder, x); // add x to summation |
52 | | out = adder.sum; // extract final sum |
53 | | */ |
54 | | |
55 | | typedef struct { |
56 | | double sum; // running total. public |
57 | | double _c; // compensation term. private |
58 | | } Adder; |
59 | | |
60 | 0 | static inline void kadd(Adder *adder, double x) { |
61 | 0 | double y = x - adder->_c; |
62 | 0 | double t = adder->sum + y; |
63 | 0 | adder->_c = (t - adder->sum) - y; |
64 | 0 | adder->sum = t; |
65 | 0 | } |
66 | | |
67 | | #endif |