在编程需求中,把单位与舍入分开说明

使用 AI 辅助编写与复核。

本文目录

为长度字段写需求时,应分别说明输入单位、统一保存的量值、计算精度和显示舍入。显示三位小数,不应悄悄替换掉原本精度更高的保存量值。

“支持米和毫米,合理保留小数”仍留下许多未定事项。实现者需要知道 1 m 是否等于 1000 mm、负数是否有效,以及把舍入后的显示值重新打开编辑时会怎样。

本文为一个小型虚构长度录入应用明确这些选择。数据和规则都是教学示例,不是测量规范,也不是金融或医疗软件的需求。

先建立单位与输入字典

本例接受一个十进制字符串,以及一个独立、必选的单位选项:

单位值 含义 换算为统一的毫米量值 输入最多允许的小数位数
m 米 精确乘以 1000 6
mm 毫米 保持原值 3

NIST 的 SI 前缀表将 milli 定义为千分之一,支持 1000 mm = 1 m 这一关系。下面的输入限制和舍入选择属于本应用的规则,并非来自前缀定义。

选择以下有明确边界的输入语法:

  • 接受非负的 ASCII 十进制字符串,以 . 为小数点。
  • 小数点前必须有数字。允许 0,但不允许 01 这样的多余前导零。
  • 最多接受 11 个字符,并遵守前表中各单位的小数位数限制。
  • 拒绝正负号、指数、逗号、空白、空字符串,以及 NaN 等特殊值。
  • 换算后的统一长度范围为 0 到 1000000 mm,包含两端。零有效,负数无效。
  • 必须选择 m 或 mm;绝不能根据数值大小猜测单位。

两个小数位数限制是有意设定的。每个可接受的量值,都能用最多三位毫米小数或六位米小数精确表示。因此,在编辑字段中切换这两个单位时,无需凭空增加输入精度,也不用丢弃部分量值。

这些是练习采用的有限规则。如果应用接受本地化数字格式,应另行定义解析规则,不能悄悄对同一个逗号作多种解释。

分开处理保存、计算和呈现

事项 选定规则 为什么要单独规定
原始输入 本例保留原始字符串及单位 它们说明用户输入了什么
统一量值 保存精确的十进制毫米量值;序列化为十进制字符串 传输中的数字不应悄悄引入二进制浮点转换
计算 本例有限的换算/加法模型使用十进制数,上下文精度为 28 位有效数字 精度是运算设置,不是显示的小数位数
以米显示 三位小数,ROUND_HALF_UP 显示可以舍去细节,而不改变量值
以毫米显示 一位小数,ROUND_HALF_UP 两种显示采用不同的小数位数
编辑缓冲区 按所选单位显示未舍入的十进制值 编辑应从量值开始,而不是从已舍入的显示文本开始

例如,编写的保存记录可以是:

{
  "sourceText": "0.0004",
  "sourceUnit": "m",
  "millimetres": "0.4"
}

原始字符串,与先成为二进制浮点数再转换为字符串的值,并不是一回事。Python 的 3.12 decimal 文档说明了构造函数、运算上下文,以及固定指数的 quantize 操作。转换浮点数时,保留的是该浮点数的值,不能找回先前的十进制文本输入。十进制运算也仍受所选精度和舍入设置约束。

这里的教学计算使用 Python 3.12.14,其版本经过单独核实,不是根据文档页面推定。所选运算规则只适用于这个小型换算/加法模型。

设计字段之前,先推演精确字符串

以下人工设定的预期,将量值与各自的显示结果区分开:

输入字符串 单位 统一量值 mm 以米显示,3 位小数 以毫米显示,1 位小数
1 m 1000 1.000 1000.0
1000 mm 1000 1.000 1000.0
0.0005 m 0.5 0.001 0.5
0.0004 m 0.4 0.000 0.4
12.345 mm 12.345 0.012 12.3
12.35 mm 12.35 0.012 12.4
1.234567 m 1234.567 1.235 1234.6
0.001 mm 0.001 0.000 0.0
999.999999 m 999999.999 1000.000 1000000.0

前两行是同一量值的不同单位表示。第三行明确了恰好处于中点时的处理:所选的中点进位规则显示为 0.001 m。换一种舍入模式,显示结果可能不同,因此“正常舍入”不足以成为明确需求。

第四行和第八行说明,正数在选定的显示精度下可能呈现为零。最后一行说明,显示值可能向上舍入到最大值,而保存的量值仍略低于它。这些显示结果都不应覆盖统一保存的量值。

对于表中的中点进位边界情况,对应的 Python 操作是:

from decimal import Decimal, ROUND_HALF_UP

shown = Decimal("0.0005").quantize(
    Decimal("0.001"), rounding=ROUND_HALF_UP
)

进入该操作的是示例中的未舍入输入,而不是先前格式化过的显示文本。

先计算,再对最终显示结果舍入

考虑把两个 0.0004 m 的长度相加。它们的统一量值分别是 0.4 mm,总和为 0.8 mm,即 0.0008 m。按选定的米显示规则,总和显示为 0.001 m。

如果应用改为把两个舍入后的显示值相加,计算的就是 0.000 + 0.000,得到 0.000。显示文本就意外成了计算输入。

在这个有限模型中,应把通过校验的输入字符串换算为统一量值,执行规定的计算,仅对要显示的输出做量化舍入。这不保证今后所有运算都能得到精确结果:除法、大得多的数值或不同的精度上下文,都需要另行规定处理方式。

重新打开舍入后的值,量值不应变化

把表中第四行展开为一段编辑过程:

步骤 界面或操作 操作后的统一量值
输入 0.0004 m 保存通过校验的精确输入 0.4 mm
查看以米显示的文本 显示 0.000 m 仍是 0.4 mm
以米为单位打开编辑器 编辑缓冲区是 0.0004,不是 0.000 仍是 0.4 mm
不作编辑直接保存 保留量值 仍是 0.4 mm
明确把编辑缓冲区改成 0 并保存 提交新的量值 0 mm

改变显示单位偏好也应保持量值不变。保存的值,以及希望怎样查看它的偏好,属于不同的状态。

明确无效输入的结果

输入与单位 选定结果
1,无单位 拒绝:请选择单位
1,2 m 拒绝:逗号不属于此语法
-1 mm 拒绝:不接受负长度
NaN m 或 1e3 mm 拒绝:不接受特殊值和指数语法
0.0001 mm 拒绝:毫米小数超过三位
1000.000001 m 拒绝:超过统一量值的最大值
空输入、 1 m 或 01 mm 拒绝空输入、空白或多余前导零形式

拒绝输入时,最后一次保存的统一量值应保持不变。实现者仍需实现并检查实际字段的报错和编辑行为;仅有运算辅助函数并不能提供这些行为。

复制这份长度字段需求

按本文虚构的米/毫米规则,规划一个长度字段。

输入:
精确的十进制字符串与必选单位 m 或 mm 分开传入。
不能先解析为浮点数。使用非负 ASCII 数字,可带小数点和小数部分,
小于一时保留小数点前的零,不允许多余前导零、正负号、指数、逗号或空白。
最多 11 个字符;m 最多 6 位小数,mm 最多 3 位小数。
统一范围:0 到 1000000 mm,包含两端。拒绝无效输入时,
不改变最后一次保存的量值。

保存/计算/显示:
m 换算为 mm 时精确乘以 1000。原始字符串/单位与统一十进制 mm 分开保留;
统一量值序列化为十进制字符串。
本例有限模型采用 28 位有效数字的十进制上下文。
m 显示 3 位小数,mm 显示 1 位小数,采用 ROUND_HALF_UP。
不能把舍入后的显示文本用作保存值或计算输入。

九个示例的预期统一量值 mm:
1 m -> 1000;1000 mm -> 1000;0.0005 m -> 0.5;
0.0004 m -> 0.4;12.345 mm -> 12.345;12.35 mm -> 12.35;
1.234567 m -> 1234.567;0.001 mm -> 0.001;
999.999999 m -> 999999.999。
两种显示结果均以本文完整表格为准。

编辑:
0.4 mm 显示为 0.000 m,但在米编辑器中打开时应为精确的 0.0004。
不作修改直接保存,或切换显示单位,都应保留 0.4 mm。
只有明确编辑为零,才提交零值。
两个 0.0004 m 相加得到 0.8 mm,显示为 0.001 m。

检查当前的解析/保存/计算/编辑路径。返回范围明确的计划,
以及覆盖表格和无效形式的本地案例检查。
指出路径上已有的每一处浮点转换或舍入字符串转换。
不要把这个例子延伸为测量公差或其他领域的规则。
本调查步骤不得连接数据库、调用真实 API、安装软件包、
修改生产环境或部署。

编写的表格、无效输入形式、精确编辑缓冲区和加法示例,已用一个小型离线 Python 3.12.14 模型检查过。这一结果涵盖这些计算和选定的解析规则;它不能证明应用的界面、传输或持久化存储会如何运作。