// Round a modelled estimate to a rough magnitude for display. // // A model output should never imply single-account precision: "~942.001" reads as a census // when it is a language-weighted guess. But whole millions ("~3M") throw away a digit the // model does resolve, and are inconsistent with the "~940K" national figures. So estimates // are shown to a consistent TWO significant figures with an M/K suffix: a single-digit // magnitude keeps one decimal ("2.8M", "6.1K", "3.0M"), ten or more shows none ("12M", // "62K", "940K"). Two is the honest ceiling for a number we label "least certain"; three // ("2.98M") would overclaim precision we have not measured. A period decimal (not a comma) // because the abbreviated M/K form reads internationally, where "2,8M" invites a "28M" misread. // // Small communities (< 1000) keep their real number — at that scale the digits are not false // precision and the count deserves to be seen. // // Returns the bare figure without a leading "~"; callers add the tilde where they want it, // so a styled tilde element or an "around"/"roughly" lead-in stays in the caller's hands. export function roughEstimate(n: number, locale = 'nl-NL'): string { if (!Number.isFinite(n) || n <= 0) return ''; if (n < 1000) return n.toLocaleString(locale); const digits = Math.floor(Math.log10(n)); const factor = Math.pow(10, Math.max(0, digits - 1)); // round to two significant figures const r = Math.round(n / factor) * factor; const unit = r >= 1_000_000 ? 1_000_000 : 1000; const suffix = r >= 1_000_000 ? 'M' : 'K'; const v = r / unit; const s = v < 10 ? v.toFixed(1) : String(Math.round(v)); return `${s}${suffix}`; }