雜記 › 技術筆記 › 兩個 tab 各算一遍同一個 C(n,r):n=20 寫滿 40 個因子、n=21 一格不剩,300 位大數與 r=0 的兩種讀法

兩個 tab 各算一遍同一個 C(n,r):n=20 寫滿 40 個因子、n=21 一格不剩,300 位大數與 r=0 的兩種讀法

組合計算器把同一句階乘除法寫了兩遍:12組裡10組大數字格逐字相等、2組是分支差;展開列只在n≤20出現而結果照算,項數只跟r走;r=0兩tab讀法相反,大數全程BigInt整除無餘數。

同一道除法,頁上寫了兩遍

起因是我想核對一個數:先在該頁的計算 tab 填 n=15、r=7,大數字格給出「6,435」;切到全組合生成 tab,用 E1 到 E15 湊出 15 個元素,格子又寫「6,435」。把這頁模板(9838 位元組 / 236 行)原樣摘進 Node 跑了一圈才看清:計算側 L120 與生成側 L207 是字面同構的一句 factorialBig(n) / (factorialBig(r) * factorialBig(n - r)),同一個數被算了兩遍;再算上 combos 遞迴條數與統計行文文案,同一組 (n,r) 有三個來源對帳。

交叉測了 12 組同 (n,r),10 組的大數字格字串逐字相等,連「6,435」這種帶逗號形狀也一致;另 2 組不等,且都不是算錯,是分支差:(20,10) 撞在 15 元素閘門上、格子停在 markup 預設的「—」;(7,0) 計算側出「1」,生成側把 r<1 靜默改成 1,算的其實是 C(7,1),出「7」。這就是組合計算器兩 tab 的口徑差。

(n, r)計算 tab生成 tab
(8, 3)5656
(15, 7)6,4356,435
(20, 10)184,756—
(7, 0)17

展開式有開關,結果沒有

L130 那句 if (n <= 20) 只圈住「展開」這一行。0≤r≤n≤20 的 231 格實測 231 格都帶展開行;n=21..60 的 1660 格實測一格展開都沒有,可同一格 (21,10) 的結果「352,716」照樣給得出來。整段展開的項數只跟 r 走、不跟 n 走:固定 r=3,n=3、5、10、15、20 五格全是分子 3 項加分母 3 項,湊成 6 個因子,只有整串從 25 字元慢慢長到 28 字元;n 一到 21,這 6 個因子一起消失。

項數最多的是 (20,20):分子 20 項加分母 20 項,展開行寫滿 40 個因子、183 字元,算出來卻是「1」;次一格的 (20,19) 是 38 個因子、174 字元,結果「20」。

固定 r=3:展開的 6 個因子不隨 n 變 n = 3 6 因子 25 字元 結果 1 n = 15 6 因子 n = 5 6 因子 25 字元 結果 10 n = 20 6 因子 n = 10 6 因子 26 字元 結果 120 n = 21 展開消失 項數最大 (20,20):40 個因子、183 字元,結果「1」 次大 (20,19):38 個因子、174 字元,結果「20」

圖 1:固定 r=3 時五檔 n 的展開項數與整串字元,以及項數封頂的兩格。

對稱性那句是真文案,算的卻是三個整階乘

L150「利用對稱性簡化計算」出現的那一屏,L120 仍照算 factorialBig(20)、factorialBig(19)、factorialBig(1) 三個完整階乘,實測 factorialBig(20) = 2432902008176640000,19 位;展開行照舊寫滿 38 個因子,頁內沒有任何 min(r, n-r) 的約簡。階乘本身的帳另有一頁:階乘計算器。

大數這側:整除從不留餘數,逗號按公式插

掃 0≤r≤n≤60 共 1891 格逐格取餘,餘數非 0 的 0 格——L120 是無取整保護的 BigInt 整除,在這段裡從不截斷。位數最長的一行 C(1000,500) 出 300 位,fmtBig(L99)給它插 99 枚千分位逗號,逗號數 = floor((位數-1)/3) 在整張表逐格相等。參照數 Number.MAX_SAFE_INTEGER = 9007199254740991(16 位)。另有一條不在頁面路徑上的 double 對照,第一處偏離落在 n=55、r=27,精確值 3824345300380220 對 double 的 3824345300380219.5。逐位帳不在這篇重算,舊文裡已列過表:BigInt 階乘舊文。

位數與 fmtBig 插進去的逗號數 C(20,10) 6 位 1 逗號 184,756 C(50,25) 15 位 4 逗號 126,410,606,437,752 C(100,50) 30 位 9 逗號 C(1000,500) 300 位 99 逗號 逗號數 = floor((位數-1)/3)

圖 2:四檔結果的位數與逗號數,逗號按那條公式整張表逐格對齊。

r=0 的兩種讀法,和「看不見不等於清空」

計算 tab 裡 5/0、0/0、20/0 三行都全過守衛出「1」,展開行退化成一字面「() / ()」(7 字元、0 個數字)——0≤0 這種邊界不落到提前返回,因為 r > n 在這裡是假。生成 tab 則完全兩樣:L184 把 r<1 靜默改掉,r 輸入「0」「-1」「abc」、空串、「1.9」五行都無 toast、統計行統一「每個組合取:1 個」、格子都是「4」。

兩條隱藏面板的提前返回(L110 與 L114)差別只在有沒有那句 toast,實測兩種都不清格子:上一輪的「56」和 4 行 formula 全部殘留,看不見並不等於被清空。輸入框也都不設 max——comb-n、comb-r 是 min="0",comb-gen-r 是 min="1",JS 側沒有上限閘門(isFinite 與 Infinity 在本模板出現 0 次),所以 n=1000、r=500 直接出 300 位。

切一次 tab 會多算一遍

switchMode 的 L86 會順手再算一次。實測:6 個元素配 r=3 連調 200 次生成函數,去重只剩 1 個狀態「20:20:0」——combos 是函數內常量、每次重開,不會越點越多;同輸入連跑兩次 calcComb,formula 407 字元逐位元組相同。切到生成 tab 會讓格子從「—」變「6」。

代碼本體這幾筆帳

腳本體 6607 位元組 / 159 行,markup 裡 id 共 13 個、math-* 類 27 處;7 個函數從上下文讀回的原始碼在模板原文裡逐字命中,最長的 generateCombinations 2532 字元。清單那一欄另有一條 5000 的顯示條數舊帳。

Q:兩 tab 出的數一定相同嗎?

不一定。同一句除法寫了兩遍,12 組裡 10 組大數字格逐字相等;但 (20,10) 生成側停在「—」、(7,0) 一側「1」一側「7」——差別全在分支,不在算式。相等只指大數字格字串逐字相等,不涉及渲染或效能。

Q:為什麼 n=21 就沒有展開過程了?

L130 的 n <= 20 只管展開行的顯隱,結果照常算。(21,10) 的「352,716」照樣出來,只是那一屏少了分子與分母兩排可見片段。

Q:r 填 0 到底算什麼?

分 tab:計算側認它合法,出 1;生成側被 L184 改成 1,於是給出的是 C(n,1)。同是 r=0,兩套讀法。

📎 相關文章

星號段長寫死:脫敏頁五套掩碼固定切出 4、3、11、12 枚星號,18 碼元串被手機檔搶走、空框回落 * 2026-11-13 鎖是單向的、百分比是兩把尺:pct 50 得 619×430,PNG 四檔 quality 全 6971 B 2026-11-13 相對時間的「一個月」寫死 30 天:時間戳頁六檔除數、13 位毫秒輸入與 UTC+8/UTC-5 兩檔截斷實測 2026-11-13 8 個元素算得出 40320 條卻只列 5000 行:排列計算器的兩道互不相干的上限、重複元素按 3! 計數與 n≤20 的過程斷點 2026-11-12 投放連結的裝配順序與大小寫摺疊:UTM 產生器六態標註、兩道硬上限與五欄各用一把尺實測 2026-11-12