Checked against Excel-cached TEXT() results in number- and text-format test workbooks: 226 of 352 TEXT cells mismatched before, 0 after.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
insert.checkbox existed but had no ribbon button, replaced existing values
with FALSE and was written to XLSX as an invalid number format. Now:
Insert > Checkbox (Cell Controls); empty cells start FALSE, other values
stay and display as General; toggling an emptied box checks it and only
checkbox cells toggle; Delete unchecks first, then removes the boxes; XLSX
reads and writes the checkbox as Excel's feature-property-bag cell control
([MS-XLSX] 2.1.22, 2.3.9, 2.4.99).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Excel shows 15 significant digits. When a number is an exact tie at the 16th
(its exact decimal expansion is 15 digits, a 5, then only zeros), Excel
rounds it toward zero: TEXT(1234567890123455,"0") is 1234567890123450.
GridCraft took Rust's `{:.14e}`, which rounds that tie to even, so any tie
with an odd 15th digit came out one unit too high (…460).
decimal_digits now formats 16 digits (correct unless the 16th is a 5),
and only on a 5 checks the exact expansion (a 30-digit screen, then the
full one) and truncates a true tie. Non-ties, including values just above
or below a tie, round as before. One format serves almost every number.
Tests: ties of every 15th-digit parity, negatives, fractional ties, the
neighbours just above and below a tie, the carry after fifteen 9s
(999999999999999.5 shows 999999999999999), and unchanged ordinary cases.
Evidence: Windows Excel 16.0.20430 TEXT() over a 174-row probe and a 24-row
carry probe agree on every row except those under a percent format and
General over negatives (the two bugs named below). The suite's number-format
golden goes from 183,843 to 184,900 of 187,810 passing with no row that
passed before failing now.
modified: crates/numfmt/src/decimal.rs
modified: crates/numfmt/src/tests.rs
Local clippy 1.96 flags pre-existing patterns the code has always had:
manual range-contains comparisons, a dead `|| true` filter and a
simplifiable boolean. None change behaviour; they only clear the lints
so `cargo xtask ci` passes on a current toolchain.