跳转至

32 位与 64 位固件使用场景

作者:魏健强 | 最后修改:2026-03-09

概述

本文档基于 LuatOS 在 Air780EPM 设备上的测试结果,详细分析 32 位和 64 位固件在整数处理、浮点数精度和性能方面的差异。

核心差异总结

整数处理能力

整数范围

特性 32位固件 64位固件
整数位宽 32位 64位
最大整数 2,147,483,647 9,223,372,036,854,775,807
最小整数 -2,147,483,648 -9,223,372,036,854,775,808
十六进制表示 0x7FFFFFFF / 0x80000000 0x7FFFFFFFFFFFFFFF / 0x8000000000000000

溢出行为

  • 32 位固件​:整数溢出时发生环绕(wrap-around)
2147483647 + 1 = -2147483648
  • 64 位固件​:同样存在环绕行为,但范围更大
9223372036854775807 + 1 = -9223372036854775808

浮点数精度表现

基础精度测试

测试项 32位固件 64位固件
圆周率显示 3.141593 3.1415926540000
圆周率显示 约7位有效数字 约15位有效数字

误差累积测试(连续除法)

关键发现​:

  • 32 位固件​:在 10^40 次方后精度显著下降
除以10^40后: 3.099994502e-40  -- 误差开始明显
除以10^45后: 2.802596912e-45  -- 严重失真
  • 64 位固件​:在整个测试范围内保持较好精度
除以10^45后: 3.099999982e-45  -- 仍保持较高精度

经典一致性测试

  • 32 位固件​:0.1 + 0.2 == 0.3 返回 true

  • 实际存储值相同:0.30000001200000000000

  • 因精度限制,误差被掩盖
  • 64 位固件​:0.1 + 0.2 == 0.3 返回 false

  • 显示值相同但实际存储存在微小差异

  • 更高精度暴露了浮点运算的本质问题

性能对比

运算速度

测试项 时间单位毫秒 32位固件 64位固件
for循环1000000次整数运算耗时 1969 2057
for循环5000000次整数运算耗时 9747 10188

Flash/内存占用差异

编译时 Flash

64 位固件会比 32 位固件多使用 10KB 的 Flash 代码空间

运行时内存

组件 32位固件 64位固件 差异
Lua虚拟机 1,048,568字节 1,048,568字节 相同
系统库 2,374,608字节 2,392,520字节 0.0075
PSRAM使用 59,388字节 59,388字节 相同

功耗对比测试

分别连续做 10 秒钟整数运算、小数运算、位运算

32 位固件

64 位固件

实际应用影响

适合 32 位固件的场景

  1. 内存敏感型应用​:内存占用略低
  2. 整数范围需求小​:处理数值在 ±21 亿以内
  3. 精度要求不高​:对浮点数精度要求较低的场合

适合 64 位固件的场景

  1. 大数据处理​:需要处理超大整数
  2. 高精度计算​:科学计算、财务应用等
  3. 长期运行系统​:更好的数值稳定性

技术建议

开发注意事项

  1. 整数溢出处理​:两种架构都需要注意整数溢出问题
  2. 浮点数比较​:避免直接比较浮点数相等,应使用误差范围

迁移建议

从 32 位迁移到 64 位时:

  • 检查所有整数运算的边界条件
  • 验证浮点数精度是否满足要求
  • 测试性能提升效果

测试代码:

function test()
log.info("sys", "Lua整数处理能力对比测试开始")
-- log.info("sys", "运行环境: " .. (string.packsize("T") == 8 and "64位" or "32位") .. " Lua 5.3")

-- 获取环境信息
log.info("\n===== 测试1: 环境信息与整数范围 =====")
log.info("整数类型:", math.type(42))
log.info("整数默认大小:", string.packsize("j"))  -- Lua 5.3 中 'j' 表示 Lua_Integer
log.info("Lua整数位宽:", string.packsize("j") * 8, "位")

-- 测试整数范围
log.info("\nLua整数范围测试:")
if math.maxinteger then
    log.info("math.maxinteger =", math.maxinteger)
    log.info("math.mininteger =", math.mininteger)
    log.info("十六进制表示:")
    log.info("  maxinteger (十六进制):", string.format("0x%X", math.maxinteger))
    log.info("  mininteger (十六进制):", string.format("0x%X", math.mininteger))
else
    log.info("注意: 您的Lua版本不支持 math.maxinteger/mininteger")
    -- 手动测试整数范围
    local max_int = 2^31 - 1  -- 假设32位
    local min_int = -2^31
    log.info("假设整数范围: ", min_int, "到", max_int)
end

-- 测试2: 整数溢出行为
log.info("\n===== 测试2: 整数溢出行为测试 =====")
log.info("--- 32位边界测试 ---")
local int32_max = math.maxinteger
local int32_min = math.mininteger

log.info("int32_max =", int32_max)
log.info("int32_max + 1 =", int32_max + 1)
log.info("int32_max + 2 =", int32_max + 2)
log.info("int32_min =", int32_min)
log.info("int32_min - 1 =", int32_min - 1)
log.info("int32_min - 2 =", int32_min - 2)


log.info("sys", "Lua浮点数精度对比测试开始")
-- log.info("sys", "预计运行环境: " .. (string.packsize("T") == 8 and "64位" or "32位"))

-- 测试1: 基础精度与有效数字测试
-- 目的:直接展示两种精度能保留多少位有效数字
log.info("\n===== 测试1: 基础精度 (有效数字位数) =====")
local pi_high_precision = 3.14159265358979323846 -- 多位圆周率
log.info("高精度圆周率值: ", pi_high_precision)
log.info("默认输出: ", ("%.15f"):format(pi_high_precision))
log.info("科学计数法: ", ("%.15e"):format(pi_high_precision))

-- 测试2: 经典浮点误差放大测试 (基于您的原始代码优化)
-- 目的:展示连续运算下的误差累积与放大过程
log.info("\n===== 测试2: 误差累积测试 (连续除法) =====")
local num = 3.1
log.info("初始值: ", num, " (注意:3.1无法用二进制精确表示)")
for i = 1, 45 do
    num = num / 10
    log.info(("除以10^%2d 后: %-25s  (十六进制: %s)"):format(
        i, 
        ("%.20e"):format(num),  -- 显示20位科学计数,看清细节
        ("%a"):format(num)       -- %a格式:以十六进制显示浮点数的精确位表示
    ))
end

-- 测试4: 一致性测试 (经典问题)
-- 目的:展示因精度限制导致的违反直觉的结果
log.info("\n===== 测试4: 经典一致性测试 =====")
log.info("0.1 + 0.2 == 0.3 ?", 0.1 + 0.2 == 0.3)
log.info("0.1 + 0.2 的实际值: ", ("%.20f"):format(0.1 + 0.2))
log.info("0.3 的实际存储值: ", ("%.20f"):format(0.3))


log.info("sys", "浮点数精度测试结束")

end

sys.taskInit(test)

function sum_time_test()
    local tick1 = mcu.ticks()
    local num = 0
    for i = 1, 5000000 do
        num = num + 111
    end
    local tick2 = mcu.ticks()
    local diff_ticks = tick2 - tick1
    log.info("sys", "5000000次整数运算耗时:", diff_ticks .. "毫秒")
end
sys.taskInit(sum_time_test)