有理逼近
SheetJS frac
库计算具有有界分母的浮点数的有理近似值。它是数字格式的核心组件,为 "最多 1 位数字的分数" 和相关数字格式提供支持。
¥The SheetJS frac
library computes rational approximations to floating point
numbers with bounded denominator. It is a core component in number formatting,
powering "Fraction with up to 1 digit" and related number formats.
该库还可在 SheetJS CDN[^1] 上独立使用。
¥The library is also available for standalone use on the SheetJS CDN[^1].
源代码和项目文档托管在位于 https://git.sheetjs.com/sheetjs/frac 的 SheetJS git 服务器上
¥Source code and project documentation are hosted on the SheetJS git server at https://git.sheetjs.com/sheetjs/frac
在线演示
¥Live Demo
格式化文本是根据指定的数字格式和值计算的。如果不支持特定格式,请 报告问题。
¥The formatted text is calculated from the specified number format and value. Please report an issue if a particular format is not supported.
function SheetJSFrac() { const [val, setVal] = React.useState(0.6994); const [text, setText] = React.useState(""); if(typeof frac == "undefined") return ( <b>ERROR: Reload this page</b> ); const fmt = arr => `${(""+arr[1]).padStart(3)} / ${(""+arr[2]).padEnd(3)}`; React.useEffect(() => { if(typeof frac == "undefined") return setText("ERROR: Reload this page!"); let v = +val; if(!isFinite(v)) return setText(`ERROR: ${val} is not a valid number!`); try { fmt(frac(val, 9)); setText(""); } catch(e) { setText("ERROR: " + (e && e.message || e)); } }, [val]); const g = { backgroundColor:"#C6EFCE", color:"#006100", whiteSpace:"pre-wrap" }; const b = { backgroundColor:"#FFC7CE", color:"#9C0006" }; return ( <table> <tr><td><b>Number Value</b></td><td colspan="2"> <input type="text" value={val} onChange={e => setVal(e.target.value)}/> </td></tr> <tr><td></td><th>Mediant</th><th>Cont</th></tr> <tr><td><b>Up to 1 Digit</b></td> <td><code style={text?b:g}>{text||fmt(frac(val,9))}</code></td> <td><code style={text?b:g}>{text||fmt(frac.cont(val,9))}</code></td> </tr> <tr><td><b>Up to 2 Digits</b></td> <td><code style={text?b:g}>{text||fmt(frac(val,99))}</code></td> <td><code style={text?b:g}>{text||fmt(frac.cont(val,99))}</code></td> </tr> <tr><td><b>Up to 3 Digits</b></td> <td><code style={text?b:g}>{text||fmt(frac(val,999))}</code></td> <td><code style={text?b:g}>{text||fmt(frac.cont(val,999))}</code></td> </tr> </table> ); }
API
在浏览器中,该库导出 frac
全局。在 NodeJS 中,库默认导出是一个函数。
¥In the browser, the library exports the frac
global. In NodeJS, the library
default export is a function.
算法
¥Algorithms
"中音" 算法(浏览器中的 frac
;NodeJS 中的默认导出)计算精确解。
¥The "Mediant" algorithm (frac
in the browser; the default export in NodeJS)
calculates the exact solution.
"连分数" 算法(浏览器中的 frac.cont
;NodeJS 导出中的 cont
字段)计算近似解。Excel 使用这种方法是因为中值算法在最坏情况下具有指数性能。
¥The "Continued Fractions" algorithm (frac.cont
in the browser; the cont
field in the NodeJS export) calculates an approximate solution. Excel uses this
approach since the mediant algorithm has exponential worst-case performance.
LibreOffice[^2] 中存在已知的舍入错误,会导致分数计算不准确。
¥There are known rounding bugs in LibreOffice[^2] which result in inaccurate fraction calculations.
LibreOffice 开发者认为这些数字错误是可取的:
¥The LibreOffice developers believe these numerical errors are desirable:
"为了改善用户体验,我们忽略了许多东西的最后两位。"
¥"We ignore the last two bits for many stuff to improve the user experience."
强烈建议使用不同的电子表格工具来准确处理涉及分数和数值数据的数据。
¥It is strongly recommended to use a different spreadsheet tool for accurate data processing involving fractions and numeric data.
函数
¥Functions
这两个函数都接受三个参数:
¥Both functions accept three arguments:
var frac_mediant = frac(value, denominator, mixed);
var frac_cont = frac.cont(value, denominator, mixed);
-
value
:原值¥
value
: original value -
D
:最大分母(例如 99 = "最多 2 位数字")¥
D
: maximum denominator (e.g. 99 = "Up to 2 digits") -
mixed
:如果true
,则返回带分数。¥
mixed
: iftrue
, return a mixed fraction.
返回值是一个包含三个整数的数组:
¥The return value is an array with three integers:
var [ int, num, den ] = result;
-
int
(第一个元素)表示估计值的整数部分。¥
int
(first element) represents the integer part of the estimate. -
num
(第二个元素)是分数的分子¥
num
(second element) is the numerator of the fraction -
den
(第二个元素)是分数的正分母¥
den
(second element) is the positive denominator of the fraction
可以从数组中恢复估计值:
¥The estimate can be recovered from the array:
var estimate = int + num / den;
如果 mixed
是 false
,则 int = 0
和 0
< den
≤ D
¥If mixed
is false
, then int = 0
and 0
< den
≤ D
如果 mixed
是 true
,则 0
≤ num
< den
≤ D
¥If mixed
is true
, then 0
≤ num
< den
≤ D
当 mixed
为真时,int
将是结果的下限。例如,在
¥When mixed
is true, int
will be the floor of the result. For example, in
var result = frac( -0.125 , 9, true);
结果将是 [ -1, 7, 8 ]
。这被解释为
¥the result will be [ -1, 7, 8 ]
. This is interpreted as
-0.125 ~ (-1) + (7/8)
[^1]: 详细信息请参见 https://cdn.sheetjs.com/frac/。
¥See https://cdn.sheetjs.com/frac/ for more details.
[^2]: 请参阅 LibreOffice 错误跟踪器中的 问题#83511。
¥See issue #83511 in the LibreOffice bug tracker.