Skip to content

break(helpers): use the exact defined conversion factors for feet, inches, yards, acres and square miles - #3159

Open
dylanpulver wants to merge 1 commit into
Turfjs:masterfrom
dylanpulver:fix/exact-imperial-unit-factors
Open

break(helpers): use the exact defined conversion factors for feet, inches, yards, acres and square miles#3159
dylanpulver wants to merge 1 commit into
Turfjs:masterfrom
dylanpulver:fix/exact-imperial-unit-factors

Conversation

@dylanpulver

@dylanpulver dylanpulver commented Sep 1, 2026

Copy link
Copy Markdown

factors and areaFactors in @turf/helpers already use exact defined values for metres, kilometres, miles (earthRadius / 1609.344) and nautical miles (earthRadius / 1852). The imperial entries
are rounded literals instead, and they disagree with each other.

The 1959 international yard and pound agreement fixes 1 yd = 0.9144 m, 1 ft = 0.3048 m and 1 in = 0.0254 m exactly, so 1 mile = 1760 yd = 5280 ft holds by definition. On master it does not:

convertLength(1, "miles", "yards")      1759.9785983999998    should be 1760
convertLength(1, "yards", "feet")       3.0000365764447703    should be 3
convertLength(1, "feet",  "inches")     11.999975616000778    should be 12
convertArea(1,   "miles", "kilometers") 2.5906735751295336    should be 2.589988110336
convertArea(1,   "miles", "acres")      640.1683937823834     should be 640

inches: 39.37 is not a rounding: it is the exact US survey inch (1 US survey ft = 1200/3937 m), which NIST and NGS retired for federal use after 2022-12-31 — and 39.37 / 12 = 3.280833… does not match the neighbouring feet: 3.28084. The largest error is areaFactors.miles = 3.86e-7, 2.65e-4 relative: a 100 km² polygon reports 38.6 sq mi instead of 38.610215854…

The fix writes every by-definition-exact factor as a division by its defining SI value, in the style the table already uses for miles and nautical miles. areaFactors.nauticalmiles was already bit-identical to 1 / 3429904 and is left alone. Precedent: #2177 corrected the degrees factor in this same table. No open issue tracks this; #1857 and #1924 fixed the inverted yards factor for v6.4.0 but kept the rounded literal.

Tests. Eight existing assertions pinned the old constants — convertLength(1, "yards", "meters") asserted 0.91441111923921, where the defining constant is 0.9144 — and are updated. Two new tests assert the definitional identities (1 yd = 3 ft = 36 in, 1 mi = 1760 yd, 1 acre = 4840 sq yd, 1 sq mi = 640 acres) rather than factor values, so they cannot be satisfied by whatever the tables happen to hold. They allow 4 ulp; the area identities land bit-exact.

Verification. With index.ts reverted to master, 9 of the 11 new assertions fail; the 2 that pass are nautical miles and hectares, which were already exact, and are there as a control. Correcting only factors leaves the four imperial area identities failing; correcting only areaFactors leaves the five imperial length identities failing. Whole-repo suite is identical before and after: 112 packages pass, and turf-directional-mean and turf-standard-deviational-ellipse fail on unmodified master here too (Node 24, float drift in the 11th digit of bearingAngle) — please compare against your own baseline.

Breaking: yes. Distances in feet, inches or yards, and areas in square miles or acres, change in the 5th to 8th significant figure.

Please provide the following when creating a PR:

  • Meaningful title, including the name of the package being modified.
  • Summary of the changes.
  • Heads up if this is a breaking change.
  • Any issues this resolves.
  • Inclusion of your details in the contributors field of package.json - you've earned it! 👏
  • Confirmation that you've read the steps for preparing a pull request.

…ches, yards, acres and square miles

factors and areaFactors already use the exact defined values for metres,
kilometres, miles (earthRadius / 1609.344) and nautical miles
(earthRadius / 1852). The imperial entries were rounded literals that
disagree with each other: convertLength(1, "miles", "yards") returned
1759.9785984 rather than 1760, and convertArea(1, "miles", "acres")
returned 640.1683937823834 rather than 640.

The 1959 international yard and pound agreement fixes 1 yd = 0.9144 m,
1 ft = 0.3048 m and 1 in = 0.0254 m exactly. inches: 39.37 was the US
survey inch (1 US survey ft = 1200/3937 m), retired for federal use
after 2022-12-31, and does not relate to feet: 3.28084 by a factor of 12.
The largest error was areaFactors.miles = 3.86e-7, 2.65e-4 relative.

Each factor is now written as a division by its defining SI value.
areaFactors.nauticalmiles was already bit-identical to 1 / 3429904 and
is unchanged.
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