fix: scientific notation with plain numbers
This commit is contained in:
@@ -64,35 +64,66 @@ local function formatSci(value)
|
||||
return out
|
||||
end
|
||||
|
||||
local function finalizePlainString(s)
|
||||
local sign, intPart, rest = s:match("^(%-?)(%d+)(.*)$")
|
||||
if intPart then
|
||||
s = sign .. groupDigits(intPart) .. rest
|
||||
end
|
||||
return displayMinus(s)
|
||||
end
|
||||
|
||||
-- render a value in plain decimal notation, 3 significant figures.
|
||||
-- IMPORTANT: C's %g spec has its own internal rule for switching to
|
||||
-- exponential form ("use %e if exponent < -4 or exponent >= precision").
|
||||
-- With precision 3, that means %.3g silently flips to "1e+03"-style
|
||||
-- output for anything >= 1000 -- BEFORE any magnitude threshold of ours
|
||||
-- gets a say. Rather than duplicating that rule with a second threshold
|
||||
-- gets a say. Rather than duplicating that rule with a second threshold,
|
||||
-- we let %g decide, then intercept its exponential output and re-render it through
|
||||
-- formatSci() instead of ever emitting the raw "1e+03" string.
|
||||
-- NOTE: this function is used for the "auto" mode ONLY. It is allowed to
|
||||
-- fall back to scientific notation. For an explicit, non-negotiable
|
||||
-- notation="plain" override, see formatForcedPlain below instead.
|
||||
local function formatPlain(value)
|
||||
local s = string.format("%.3g", value)
|
||||
if s:find("[eE]") then
|
||||
return formatSci(value)
|
||||
end
|
||||
-- split into optional sign, integer part, and remainder (decimal point
|
||||
-- + fractional digits, if any) so grouping applies only to the
|
||||
-- integer part -- fractional digits are never grouped
|
||||
local sign, intPart, rest = s:match("^(%-?)(%d+)(.*)$")
|
||||
if intPart then
|
||||
s = sign .. groupDigits(intPart) .. rest
|
||||
return { pandoc.Str(finalizePlainString(s)) }
|
||||
end
|
||||
|
||||
-- render a value in plain decimal notation that NEVER falls back to
|
||||
-- scientific form, regardless of magnitude, this is what
|
||||
-- notation="plain" actually promises the caller. %g's own exponent-switch
|
||||
-- rule (the reason formatPlain above sometimes defers to formatSci) is
|
||||
-- sidestepped entirely by computing the required number of decimal places
|
||||
-- directly from the value's exponent (read robustly off a %e string,
|
||||
-- since %e always reports the exponent Lua/C computed rather than
|
||||
-- re-deriving it ourselves and risking a boundary rounding mismatch) and
|
||||
-- formatting with %f at that precision.
|
||||
local function formatForcedPlain(value, sig)
|
||||
sig = sig or 3
|
||||
if value == 0 then return { pandoc.Str("0") } end
|
||||
local sciStr = string.format("%." .. (sig - 1) .. "e", value)
|
||||
local exp = tonumber(sciStr:match("e([+-]?%d+)$"))
|
||||
local decimals = sig - 1 - exp
|
||||
if decimals < 0 then decimals = 0 end
|
||||
local s = string.format("%." .. decimals .. "f", value)
|
||||
if s:find("%.") then
|
||||
s = s:gsub("0+$", ""):gsub("%.$", "")
|
||||
end
|
||||
return { pandoc.Str(displayMinus(s)) }
|
||||
return { pandoc.Str(finalizePlainString(s)) }
|
||||
end
|
||||
|
||||
-- decide plain vs. scientific, unless overridden.
|
||||
-- mode: nil/"auto" (let %g decide, see formatPlain), "sci", or "plain"
|
||||
-- "plain" is a hard override -- it must never silently become scientific,
|
||||
-- which is exactly the bug that motivated splitting formatForcedPlain out
|
||||
-- from formatPlain rather than reusing it for both cases.
|
||||
local function formatNumber(value, mode)
|
||||
if value == 0 then return { pandoc.Str("0") } end
|
||||
if mode == "sci" then return formatSci(value) end
|
||||
return formatPlain(value) -- handles both "auto" and explicit "plain"
|
||||
if mode == "plain" then return formatForcedPlain(value) end
|
||||
return formatPlain(value) -- "auto"
|
||||
end
|
||||
|
||||
local function appendAll(dst, list)
|
||||
|
||||
Reference in New Issue
Block a user