编辑 | blame | 历史 | 原始文档

功能测试报告_全精度存储与两位小数显示_2026-09-20

一、功能说明

需求(用户 2026-09-20 指令):所有的数据都全部全精度保留,计算得到的结果显示两位小数。

改前问题:

  1. 后端在**写单元格之前**就做了四舍五入,底层存储值被提前截断:
  • round(v, 4):货运规上/规下/同比、累计与当月、中口径排名/分析、÷10000 单位换算、投资进度、物流占比、投资计划万吨;
  • round(v, 2):通用数据格 setDataCell、平均运距兜底、客运转运写入;
  • round(v, 1):排名页占比(setFreightShare、货运量排名/周转量排名块)。
    误差虽小,但属于「计算口径被写死」,与人工用全精度重算的结果天然对不上(正是 09-19 中口径差异问题的同源风险)。
  1. 母版个别格自带 3~4 位小数**显示格式**(0.0000_);[Red]\(0.0000\)、0.000_),展示位数不统一。

改后实现:

  1. 全精度:取消所有写入/运算前的预舍入,数值以 double 原值参与运算并写入;/10000、占比、同比、平均运距兜底等一律不截断。
  2. 两位小数展示:由单元格数字格式承担。重写 applyTwoDecimalFormat():
  • 数值格格式统一为 0.00(cloneStyleFrom 保留边框/字体/对齐,只换数字格式,;[Red]\(...\) 等前后缀原样保留);
  • 3 位及以上小数的格式(0.000_、0.0000_);[Red]\(0.0000\))用正则 \.0{3,} 收敛为 .00;
  • 百分比(%)、科学计数(E)、文本(@)、日期格式**不动**;
  • 整数值格沿用既有约定不显示 .00(如年份、排名)。
  1. 控制台/接口返回的**预览摘要**里的 round(addSum(...))保留,它不进报表数据。

改动文件:

文件 改动
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java 去除 40 处预舍入;重写 applyTwoDecimalFormat()(新增 DEC_MORE_THAN_TWO 正则常量)
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/calc/WycSplitCalc.java 平均运距兜底改全精度;删除已无引用的私有 round(double,int)

二、测试环境

项 内容
后端 Spring Boot localhost:8090,mvn -q -o compile 通过后由 start-dev.ps1 重启(PID 15568)
前端 Vue localhost:8080(PID 28608),与后端一并重启
数据库 MySQL localhost:3308/traffic_audit
报表期 2026-08(1-8 月累计块 + 8 月单月块)
对照件 改前生成件 _after_busfix_2026-08.xlsx(09-19 口径修复后、本次改造前)
改后生成件 _after_precision_2026-08.xlsx、_after_precision_midrank/midana/middetail.xlsx,以及 _out_precision\ 下 22 个接口产物
取证脚本 _qa_prec_*.py、_regen_precision.ps1、_regen_all.ps1

三、用例与结果

编号 类型 输入 预期 实际 结论
T1 正向 mvn -q -o compile 编译通过 exit=0,无告警 通过
T2 正向 22 个导出接口(period=2026-08) 全部 200 且非空 21 个 OK;wycSplit 500(缺输入文件,见「四-5」) 通过
T3 正向 改前/改后《道路运输量汇总表》逐格数值对比(66205 个共有数值格) 仅目标格出现差异 实际变化 249 格,全部落在「货运量排名」107 +「中口径排名」142 通过
T4 正向 最大变化量 只应是去掉舍入带来的尾数差 0.00022 万人公里(=2 人公里),位置「中口径排名」全省行 O3 通过
T5 正向 武汉累计周转量 全精度保留,4 位小数位仍为 8912 中口径明细 S104 = 152330.89119999998;排名页 O4 / 道路运输周转量 Q5 = 152330.8912 通过
T6 正向 孝感累计周转量 不再截断到 64429.9445 64429.944543113306(排名页与明细页逐位一致) 通过
T7 正向 「中口径排名」改前/改后按两位小数对比 完全一致(不应改变可见结果) 不一致格 0 通过
T8 正向 全省行 =SUM(O4:O20) 闭合 缓存值 = 17 市州全精度求和 1227147.4890200002,**差 0.0**(09-19 的 0.0002 残留已消除) 通过
T9 正向 汇总大表「有值数值/公式格」的 3 位以上小数格式 0 格 改前 108 格 → 改后 0 格 通过
T10 正向 中口径明细(独立件)0.000_ 格式格 收敛为两位 改前 134 格 → 改后 0 格;C19 值 13.599765541547498 不变,格式变 0.00_ 通过
T11 正向 22 个产物的 3 位以上小数格式汇总 全为 0 15 个可解析产物合计 0 格 通过
T12 回归 表内错误值(#DIV/0!/#VALUE!/#REF!)数量 不新增 改前 589 = 改后 589(分布逐项相同) 通过
T13 回归 百分比格 / 两位小数格数量 不受影响 25665 / 39552,与改前一致 通过
T14 回归 独立件 passengerMidRank、passengerMidAnalysis 无 3 位以上小数格式 0 格(改前本就 0) 通过
T15 边界 空值格、文本格(如月份文本「2023年4月」) 不动 仍带 4 位小数格式 274 格(260 空值 + 14 文本),无显示值,不处理 通过
T16 边界 整数值格(年份/排名) 不显示 .00 沿用既有「整数不显示 .00」保护,未被本次改动破坏 通过
T17 边界 与 round(改后,4) 不一致的 30 格 属二阶重算而非错误 同比列由全精度分子分母重算,量级 1e-9~1e-8(如 0.0712378390 → 0.0712378363) 通过
T18 负向 母版排名页 Q 列公式 =ROUND(B/L*10,1) 本次不改母版 仍保留(36×2 格),Excel 打开会按公式重算到 1 位后再按 0.00 展示 见「四-4」待拍板

四、发现的问题与处置

  1. 母版带 4 位小数格式的有值格 108 个(货运!EO90/EO93/EO108/EO111 等 SUM 公式格、公路总客运!DE2 等)→ 已由格式归一处理为 0.00;剩余带该格式的 274 格均为空值/文本格,无显示值。
  2. 「整数不显示 .00」保护先把公式格跳过了:首轮改造后 货运!EO90/EO93/EO108/EO111 仍是 0.0000(缓存值为 0,被判定为整数而跳过)。已把「3 位以上小数格式归一」的判断**提到整数保护之前**——这类格本来就走数值格式展示,与「General 的整数值不显示 .00」不冲突。
  3. 3 位小数格式未被识别(0.000_):原判断用 f.contains("0.00") 认为已是两位,而 0.000_ 恰好包含子串 0.00 而被跳过,导致中口径明细 134 格漏改。已改为正则 \.0{3,} 统一收敛。
  4. 母版排名页 Q 列仍是 =ROUND(B/L*10,1)(货运量排名 Q4:Q42、货运周转量排名 Q5:Q44,共 72 格):
    程序对公式格一律不覆写(保留母版公式设计),Excel/WPS 打开时会按公式重算回 1 位小数再以 0.00 格式展示。
    若要连这 72 格也全精度,需要把三个母版的公式改成 =B/L*10(并同步 R 列 =10-Q)——**待用户确认后再动母版**。
  5. wycSplit 接口 500:loadWycMonthlyInput() 抛「未找到网络约车(全省)汇总.xlsx,请放到 docs/网络客运 目录」,而 docs\网络客运 目录当前不存在——属**缺输入数据的既有现象**,与本次改造无关。

五、结论

  • 报表数值已全部改为**全精度写入/运算**,展示位数统一由单元格格式承担(两位小数;百分比、日期、文本格式不变)。
  • 逐格对比证实:改后与改前的可见结果(两位小数口径)**完全一致**,差异仅出现在被去掉舍入的尾数位,最大 0.00022 万人公里。
  • 顺带消除了 09-19 遗留的「全省行 0.0002 万人公里」:各市州改为全精度后,母版公式 =SUM(O4:O20) 与明细全精度求和**逐位闭合**。
  • 22 个导出接口回归通过(wycSplit 为既有缺数据问题);错误值数量、百分比格数量均无变化。
  • 遗留一项待拍板:母版排名页 Q/R 占比公式的 ROUND(...,1)。

测试人:Codex(AI) 测试日期:2026-09-20