在knitr/bookdown生成PDF时保留数字末尾零以统一有效位数
在knitr/bookdown生成PDF时保留科学计数法末尾零的方法
当用knitr或bookdown生成PDF输出时,需要让科学计数法的数字保留末尾零(比如显示$1.0 \times 10^{-9}$而非$1 \times 10^{-9}$),确保所有输出数字的有效位数统一。
最小示例
--- title: "Test" author: "Author" output: pdf_document --- `r options(scipen=3, digits=2)` # Introduction 希望$`r signif(1.0e-9, 2)`$能保留末尾零格式,与$`r signif(1.1e-9, 2)`$的长度匹配。使用$`r sprintf(signif(1.0e-9, 2), fmt='%#.2g')`$也无法实现。
问题核心
knitr内置的format_sci_one()函数会把1.0这类值简化为1,导致末尾零丢失。默认逻辑里,基数b经过round_digits()处理后会自动省略末尾的零,还会把1/-1转为空字符串,进一步破坏格式统一。
无额外依赖的解决方案
直接在Rmd文档开头重写knitr::format_sci_one()函数,修改基数格式化的逻辑,强制按指定有效位数保留末尾零:
# 重写knitr的科学计数法格式化函数,保留末尾零 knitr::format_sci_one = function( x, format = 'latex', times = getOption('knitr.inline.times', '\\times ') ) { if (!(class(x)[1] == 'numeric') || is.na(x) || x == 0) return(as.character(x)) if (is.infinite(x)) { return( switch(format, latex = { sprintf("%s\\infty{}", ifelse(x < 0, "-", "")) }, html = { sprintf("%s∞", ifelse(x < 0, "-", "")) }, as.character(x))) } scipen_val = getOption('scipen') if (abs(lx <- floor(log10(abs(x)))) < scipen_val + 4L) return(round_digits(x)) # 不需要科学计数法 # 关键修改:用sprintf按digits选项指定的有效位数格式化基数 digits_val = getOption('digits') b = sprintf(paste0("%.", digits_val, "g"), x / 10^lx) # 注释掉默认的空字符串转换,避免丢失1.0的格式 # b[b %in% c(1, -1)] = '' switch(format, latex = { knitr::sci_notation('%s%s10^{%s}', b, times, lx) }, html = knitr::sci_notation('%s%s10<sup>%s</sup>', b, ' × ', lx), md = knitr::sci_notation('%s%s10^%s^', b, '× ', lx), rst = { if (inherits(x, 'AsIs')) { s = knitr::sci_notation('%s%s10^{%s}', b, times, lx) sprintf(':math:`%s`', s) } else { knitr::sci_notation('%s%s10 :sup:`%s`', b, ' |times| ', lx) } }, as.character(x))) }
使用效果
把这段代码放在Rmd文档的yaml配置下方,设置options(scipen=3, digits=2)后:
$r signif(1.0e-9, 2)$会输出$1.0 \times 10^{-9}$$r signif(1.1e-9, 2)$会输出$1.1 \times 10^{-9}$
两者格式完全统一,有效位数保持一致。
内容的提问来源于stack exchange,提问作者NicolasBourbaki
相关产品推荐
相关产品推荐

