A display contract, not formatting. Where a cell has a number format, that format decides
the text and this never runs. Where there is none — a raw Scalar, a computed
aggregate, anything off the value layer — something still has to choose how many digits to
print, and JavaScript's default choice is the wrong one: String(2398.7999999999997) spends
17 digits publishing the binary residue of 0.1 + 0.2-class arithmetic. The float is
correct; the rendering is unusable, because an agent comparing it against an expected
2398.8 sees a mismatch that is not there.
Excel caps display at 15 significant digits for exactly this reason, and the cap is the
whole rule — it is not rounding for readability, it is the point past which the extra digits
describe IEEE-754 rather than the value. Rounding to 15 and re-stringifying lets JavaScript
pick the shortest form that survives the round trip, so 2398.8 prints as 2398.8 and a
genuinely long number keeps every digit it has earned.
Non-finite values pass through: NaN and Infinity are not precision questions, and
toPrecision would only hand back their own string anyway.
The exponent is respelled Excel's way for the same reason the digits are capped Excel's way — see excelExponent.
Encodes a bare number the way a spreadsheet displays one.