43 段「本段用時」相加是 12616 秒,總時長那一格寫 12600
距離填 42.195,總用時填 3:30:00,段長停在 1 公里、遞進 0,頁面給出一張 43 行的分段表。把「本段用時」那一列的 43 個顯示值挨個加起來是 12616 秒,比同一幀總時長的 12600 秒多出 16 秒。可「累計用時」那一列的末行照樣寫著 3:30:00,它拿的是沒逐段取整過的累計秒。兩列並排站在同一張表裡,一列閉合,一列差 16 秒。
段數沒錯,43 行的起止與長度都對得上 42.195。不一致的是尺:每一行的用時先各自四捨五入成整數秒再上屏,43 個整數加起來就不再等於那個整數秒的總時長。
同一處口徑在半馬示例那張表上更扎眼:第 3 行「本段用時」的前三格相加是 26:15 加 25:25 加 24:35,得 1:16:15,而同一行的「累計用時」列寫著 1:16:14,那 1 秒的差就擺在挨著的兩列裡。
段長一換,漂移連方向一起變
距離與總用時不動,只擰段長那一格,差值在正負之間來回跳,也能正好落回 0。
| 場景 | 段長 | 段數 | 逐段相加 | 與總時長比 |
|---|---|---|---|---|
| 42.195 / 3:30:00 | 1 | 43 | 12616 秒 | 多 16 秒 |
| 同上 | 2 | 22 | 12595 秒 | 少 5 秒 |
| 同上 | 5 | 9 | 12599 秒 | 少 1 秒 |
| 同上 | 0.3 | 141 | 12658 秒 | 多 58 秒 |
| 21.0975 / 1:45:00 | 1 | 22 | 6308 秒 | 多 8 秒 |
| 26.2188 英里 | 1 | 未取回 | 未取回 | 多 11 秒 |
| 10 公里 / 1 小時 | 1 | 未取回 | 每段 360 整秒 | 差 0 秒 |
同一幀的讀數各用一把尺
配速那一格走整數秒取整,總時長串、長格式串、帶符號差又各走一次同樣的取整;時速、英里/時、每秒米三格是乘 100 再除 100 的兩位小數;距離回寫框是乘 10000 再除 10000 的四位小數;段表的起止區間留一位小數、累計距離留三位;段數那一行是 Math.floor 之外再補一個 1e-9。這幾把尺互不閉合,最直白的證據是拿顯示值反推推不回顯示值。
真值配速 298.61357980803410328 秒上屏成 4:59。用 4:59 那 299 秒反推時速是 12.04,頁面時速格寫著 12.06 km/h;反推每秒米得 3.34,頁面寫著 3.35 m/s;400 米圈顯示 1:59,乘 2.5 是 297.5 秒每公里,與配速格那 299 秒差 1.5 秒每公里。每一格在自己那層都沒錯,跨一格就散。跑步配速計算器上這六格寫的是同一個秒數。
圖 1 豎著讀就是那把尺的清單:同一秒數被切成整數、兩位、四位、一位、三位五種寫法。
把那個 1e-9 單獨刪掉,108 組一段都沒少
段數那一行末尾的 epsilon 看著像段賬漂移的嫌疑人。其餘 416 行一字不動、另開一個上下文把它摘掉,掃 108 組距離與段長:段數差全部為 0,末段長度的最大差 4.86e-15,末段累計終點的差 7.1e-15,段說明串逐字相同。真正把那一段補回來的是緊接下一行的餘數分支,剩下的長度小於段長乘 1e-6 就當沒有餘數。所以這個 epsilon 改的是第 14 位有效數字,一位可見顯示都沒動,那 16 秒跟它無關。
英里檔回寫四位小數,換回來就不是原來那個數
單位常數 RP_MILE 是 1.609344。42.195 公里切到英里檔,距離框被回寫成 26.2188,真值 26.218757456454305554,四位這一層把它抬高而不是截短。再把框裡的 26.2188 當英里換算回公里,出來 42.195068467200002260,一趟往返漂了 0.0000685 公里。每英里配速也有兩條路:直接用英里距離去除得 480.57197298258091678 秒,拿公里配速乘常數得 480.57197298258085993 秒,差 5.68e-14,兩檔上屏倒是都寫著 8:01。
螢幕上那個 4:59 再填回去,完賽時間成 3:30:16
先在時間框打 3、30、0,總用時 12600 秒,配速格顯示 4:59。再按這個顯示值把 4 分 59 秒提交進配速框,頁面拿 299 乘 42.195 得 12616.305 秒,總用時格上屏 3:30:16。一個來回多出 16 秒,跟段表那 43 段相加多出來的 16 秒是同一件事:整數秒的配速乘回帶四位小數的距離,落不回原來那個整數秒。目標檔那一行「3:30:00 對應 4:59」把右列乘回去也差 16.305 秒,同一張表左右兩列互不相認。兩串差多少,可以在時間加減計算裡按秒相減。
圖 2 那四行是同一件事的四種寫法:加過一次的 16 秒,減回去也還是 16 秒。
同一個終點,三張表三種算法
42.195 公里這一幀裡被算了三遍:逐段推進那套和「距離乘均速配速」都落在 12599.999999999998 秒,目標檔的 3:30:00 是 12600 秒,顯示層三個一律寫 3:30:00,前兩個帶著 2e-12 的浮點尾巴。行數也各按各的口徑:里程碑公里檔 12 行、英里檔 11 行、半馬距離只給 7 行,預測表剔掉與當前距離同檔那點剩 7 行,目標檔全馬 8 檔、非標準距離按六個係數給 6 行。至於段與段之間該讀成什麼,是站內那篇分段配速表的範圍,這一篇只停在取整與段賬上。
Q:這些數字是瀏覽器裡量出來的嗎?
不是。模板 609 行 / 27084 字節,腳本塊那 417 行逐行比對未命中 0 行,塊內 42 個頂層函數用 toString 讀回在原文裡逐字命中 42/42,全程沒重寫沒修 bug,讀數全部來自純 Node 的 vm。排版、滾動條與耗時一律未實測。
Q:段表相加對不上,是頁面算錯了嗎?
每一格在自己那一層都對,只是層與層之間不閉合:逐段取整的那一列與未取整的累計列並排站著,16 秒就落在兩列中間。
Q:距離框填 1e400 會怎樣?
它被解析成 1400 靜默寫進距離,提示為空,大距離這一側沒有任何攔截;那一場景的段表行數在探針裡因輸出截斷沒取回,未實測。