雜記 › 技術筆記 › 3.7 讀成 3、1e3 讀成 1:分數計算器這一頁先在輸入端截成整數,再在 14 個字元處換顯示口徑

3.7 讀成 3、1e3 讀成 1:分數計算器這一頁先在輸入端截成整數,再在 14 個字元處換顯示口徑

分子框填3.7被讀成3,填1e3讀成1、填0x10讀成16;等值小數那格只看字串是否超14個字元,1/4096恰好14原樣通過,1/8192變成0.0001220703...,1e-7只有4個字元照樣上屏。

我在分子框裡填 3.7,這一頁拿去算的是 3

起因很普通:分子填 3.7、分母填 2,另一個分數保持 1/3,運算符停在加號。頁面給出 11/6,小數格寫 1.8333333333...,沒一處提示我它把 3.7 換了。

把模板(11127 位元組 / 231 行)的腳本區塊整段摘出來,回讀的 7 個函式原始碼與模板原文逐字命中,再餵進純 Node 的 vm 跑 calc()。只看這一頁的程式碼,沒開瀏覽器,重繪那一類賬一律沒測。

輸入端:四個 number 框被不帶 radix 的 parseInt 又讀了一遍

四個框的類型都寫著 number,程式碼卻把它們的值再 parseInt 一遍,不帶第二個參數。於是 3.7 在句點前停住得 3,3.99 同樣得 3——是截斷不是四捨五入,兩格都出 11/6;填 -3.5 得 -3,結果 -7/6,小數格 -1.1666666667...。

剩下幾格更容易看漏。填 1e3 讀成 1,它在字母 e 那裡就停了,出來的 5/6 與直接填 1 完全同形。填 0x10 讀成 16,十六進位前綴被不帶 radix 的寫法認了下來,界面給 25/3;帶 radix 10 的那條路只會給 NaN。填 -0 讀成 0,結果格剩 1/3。這幾格都在分數計算器上,只改分子那一格、其餘三格停在預設值就能復現。

再往空的一側走就更安靜:任一格填空字串、abc、純空格、Infinity,四個值在 isNaN 判定上直接 return,兩張卡一起被隱藏,既不報錯也不清空——實測前後步驟容器的 innerHTML 長度都是 338,舊運算式與步驟文字一個位元組沒掉,下一次合法輸入踩著舊串覆寫。錯誤出口那兩條也不擦:分母填 0 寫「分母不能為 0,請檢查輸入」,連前面的警告符合計 21 位元組;除法時分數 B 的分子填 0 寫另一句,恢復合法輸入後舊串仍在,只是父容器被隱藏。

分子框填parseInt 讀到分數格等值小數那格
3.7311/61.8333333333...
3.99311/6同上
-3.5-3-7/6-1.1666666667...
1e315/60.8333333333...
0x101625/38.3333333333...
-001/30.3333333333...
分子框 → 無 radix parseInt → 讀到幾 你填 讀到 停在哪 上屏 3.7 3 句點前 11/6 1e3 1 字母 e 前 5/6 0x10 16 前綴被認下 25/3 -3.5 -3 負號照收 -7/6 空字串 NaN 直接 return 舊串 338

圖 1 只畫讀取那一步:在哪個字元前停住,就送哪個整數進算式。

顯示端:這把尺是 14 個字元,不是小數位數

等值小數那一格判的是 String(val) 的字元數是否超 14:超線走 toFixed(10) 再拼三個 ASCII 句點,不超線原樣印出。於是 1/2048 那 13 個字元原樣上屏,1/4096 正好 14 個字元也原樣上屏,1/8192 是 15 個字元就被砍成 0.0001220703...,一個本來整除、末尾還帶 3 位有效數字的有限小數只因總長度超線換了口徑。整數結果也歸這把尺管。

不超線那一支的原樣是字面意義的:1/10000000 那一格實測就是 1e-7,只有 4 個字元;1/1000000 是 0.000001。這條線只量十進位寫法,4 個字元的指數串根本走不到判定之前。

超線那一支的第 11 位參與四捨五入:1/7 真值 0.142857142857... 的第 11 位是 5,本頁顯示 0.1428571429,末位比真值大 1;1/11 的第 11 位是 0,所以顯示 0.0909090909。程式碼註解那句「有限小數最多顯示12位」既不按 12 位、也不判是否循環。

等值小數格:字元數與 14 這條線 分數 字元數 分支 螢幕上 1/2048 13 原樣 0.00048828125 1/4096 正好 14 原樣 0.000244140625 1/8192 15 超線 0.0001220703... 1/10000000 4 指數形態 1e-7 整數那格 16 超線 4503599627370496.0000000000...

圖 2 那幾行最直白:14 字元壓線通過,15 字元被砍,4 字元的指數串沒碰上這條線。

負分母那一步,同一行裡有兩把口徑

公分母按絕對值算,通分因子卻拿有符號的分母去除。於是 1/-2 加 1/3 的步驟行打成「公分母 = LCM(-2, 3) = 6」,緊接一行「分子 ×-3」,求和行「-3/6 + 2/6 = -1/6」:結果格符號是對的,同一個 -2 卻一邊被當參數顯示、一邊被絕對值吃掉。換成 1/-2 加 1/-3,兩個因子都是負的,求和 -5/6。減法分支的通分行還不帶「分子 ×k」那半句,與加法分支不同形。

符號的搬運只在 reduceFrac 那一步做,負號一翻面,約分行會憑空出現:-1/2 乘 -1/-3 的第一步打 1/-6,第二步打「GCD(1, -6) = 1」再打 -1/6,那個公約數等於 1,行卻照樣在。約分行的第一個參數也是有符號值,-1/2 加 -1/2 那行寫「第三步:約分 GCD(-2, 2) = 2」,負號只出現在標籤裡。同一族另一頁也有符號歸屬問題,那本賬在單獨做約分的那一頁。

約分那一行是條件行,步數在 6 與 8 之間跳

1/2 加 1/3 的步驟卡只有 6 行,沒有約分行;1/6 加 1/3 變 8 行,多出那行寫「GCD(3, 6) = 3」;0/3 加 0/5 打「GCD(0, 15) = 15」,結果格是 0。判據一句話說完:公分母恆正,那一行出現當且僅當分子和與它的公約數大於 1,等於 1 時整塊不拼進去,步數從 8 掉回 6。乘法分支是 2 行或 4 行,除法分支是 3 行或 5 行,3 除以 1/3 得 9 就不出約分行。分母為 1 時分數格只印分子,所以 0/3 乘 0/5 出的是單個 0,不是 0/1。

這把尺之外我只測到一處精度:99999999 乘 99999999 在這一頁得 9999999800000000,BigInt 真值 9999999800000001,差 1。預設首屏就是 1/2 加 1/3 出 5/6,連調兩次四個欄位逐位元組相同(運算式 11 位元組、分數 3 位元組、小數 15 位元組、步驟原文 157 位元組)。通分與約分該怎麼教不在這篇,那是站內那篇算理文的範圍。

Q:填 3.7 為什麼一點提示都沒有?

截斷發生在讀取階段而不是校驗階段:parseInt 在第一個讀不下去的字元前停住,剩下的 3 是個合法分子,頁面沒有理由報錯。

Q:填 1e3 是想讓它等於一千,為什麼不是?

讀取那一步在字母 e 處停住,讀到 1,輸出 5/6,與直接填 1 一模一樣。

Q:約分那一行為時有時無,是漏渲染嗎?

不是,它本來就是條件行;步數在 6 與 8 之間跳,說明判定走完了,只是那一塊沒被拼進去。

📎 相關文章

後綴只切最後一個點:archive.tar.gz 分走 gz,photo. 和 .gitignore 擠進同一格,表格首列還會掉一個點 2026-11-14 正則測試頁永遠帶 g:填 gg 直接報錯、填大寫靜默失效,21 處帶組匹配只列 20 行 2026-11-14 星號段長寫死:脫敏頁五套掩碼固定切出 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