SheepDev

数值、单位与位

较大的 ID 需要多少位?也用十六进制查看

使用工具

订单 ID 粘贴进表格后,末位变成 0;另一个页面又把两个相邻 ID 显示成同一个数字。能显示大整数与能完整保留每一位是两回事,小数值正常的处理也可能在越界时出错。

下面使用容易观察边界的示例整数,不使用真实 ID。先检查类型能否容纳,再转换进制并转回。借此考虑数据库、API、浏览器、表格软件整个传递过程的表示方式。

255 的下一个数,还能放进 8 位吗?

在整数范围工具选择范围模式、8 位、无符号,得到 0 到 255,共 256 种值,但最大值不是 256。值的数量与最大值相差一,这个关系在更大位宽下仍成立。

跨越边界的三个值
254 = 11111110₂
255 = 11111111₂
256 = 100000000₂

切换到所需位数模式,以无符号分别检查 255 和 256,结果为 8 位与 9 位。只增加 1,也可能需要多一位。按预计用量选择类型时,还应考虑未来增长与保留值,而不只是当前数值。

同为 64 位,范围也不同

把位宽改成 64,比较有符号与无符号。有符号还要表示负数,正数上限较小:9,223,372,036,854,775,807;无符号上限是 18,446,744,073,709,551,615。仅凭“64 位列”无法判断能否兼容传递。

8 位有符号的最大值也只有 127。正数 128 需要 8 位无符号或 9 位有符号。即便 ID 不用负数,接收方若声明为有符号类型,仍须遵守其范围;ID 不会自动变成无符号。

把 20 位十进制整数转成十六进制再转回

十进制输入:不加分组逗号
18446744073709551615

选择十进制转十六进制,得到 ffffffffffffffff,共 16 个 f。再以十六进制转十进制输入此结果,应还原原来的 20 位。核对全部数字,确认表示变化未改变整数。中途保持文本,不要先经过其他计算器的数值输入。

一个十六进制位可表示 4bit,因此此值对应 64 个二进制 1。但由字符数推算最小位宽时,要考虑前导零和首位。0f 虽有两个字符,值 15 仍只需 4 位无符号。固定存储宽度与最小表示宽度不同。

能放进整数类型,不代表 Number 能精确保留

JavaScript 的 Number 不是 64 位整数类型,其安全整数上限为 9,007,199,254,740,991。更大的某些整数仍可表示,但无法保证所有相邻整数都可区分。某个大值显示正常,不代表同位数的所有 ID 都安全。

精度检查示例
9007199254740993

直接输入进制转换,十进制转十六进制得到 20000000000001,再检查逆转换。如果经过其他步骤后已经变成 9007199254740992,原来的位数已经丢失,之后转 BigInt 也无法推断还原原整数。

ID 应该是数字还是字符串?

编号 00123 的数值是 123,但文本表示不同。进制转换处理数值,不适合保留前导零数量。先确定是参与运算的数量,还是精确匹配的标识,不要仅因邮编或会员号只含数字就转成数值。

API 用字符串传 ID,需要与接收类型共同约定,不能擅自加引号就当解决。如果约定本来是字符串,途中却转 Number,那一步就可能丢精度。排查时应覆盖显示、搜索、CSV 导出,而不只看存储。

把完整位数一致作为传递测试

测试应覆盖边界前、边界上、边界后,而不只选安全小值。8 位无符号可用 254、255、256,Number 则用安全边界附近连续整数。区分明确拒绝与自动舍入,不能靠缩小数值让验证通过。

报告时应写明位置和表示,例如“可放入 64 位无符号存储,浏览器中保留为字符串”,而不是笼统说“64 位没问题”。所需位数只是类型选择依据,不保证实际数据库列或协议支持,仍需检查规范并做原路径往返测试。

同一位模式,有无符号会改变含义

八位 11111111 无符号时是 255,按有符号补码读则是 -1。把十进制 255 转成二进制不等于自动解释为 -1。进制是表示方法,符号和位宽是固定长度字段的解释规则;日志里看到 ff,应先查字段是否有符号。

前导零也一样:数值 0010 与 10 相等,但商品编码可能不同。进制工具不负责保留标识符宽度,CSV 使用方也可能把文字编码当数字。应先判断这是用于运算的数量还是用于匹配的名称;不仅大整数,小值转换也会丢掉重要信息。

复现时测试边界及相邻值:八位无符号用 254、255、256,JavaScript 安全整数边界用 9007199254740991 附近。检查 JSON 解析和 API 传递前后何处从文字变数字。上游已经丢失的尾数,高精度工具无法恢复;保留原始文字并找到首次变化的位置。

参考资料

使用工具

指南 →