不同Rep类型的std::chrono::duration转换出现异常bug如何解决?
问题根因
你遇到的std::ceil异常进位问题本质是单精度浮点数float的精度不足导致的,和std::chrono的规范用法无关:
- 32位
float仅支持6~7位十进制有效数字,当你把系统时钟返回的高分辨率整数duration(通常是微秒/纳秒级)转换为fsec(以float为存储类型的秒级duration)时,转换计算会产生微小的精度误差,你的输出里30.0000019073就是这类误差的体现。 - 误差导致除法结果为
3.0000002384,略大于3,std::ceil自然会向上取整为4。而double支持15~17位有效数字,存储常规时间跨度不会出现这类精度损失,因此换成dsec后运行结果正常。
你测试的几个调用结果不同的原因:
- 前两次直接将
system_clock的30秒纳秒级duration转为fsec,转换计算过程中出现精度误差,实际存储值略大于30; - 第三次先将时间差转为
uint32_t为存储类型的整数秒duration,30属于float可精确表示的整数范围(≤16777216),转换后无误差; - 用
double存储的dsec精度足够,所有转换场景都不会出现这类误差。
正确实现方案
你的需求是获取支持小数秒的duration格式,优先推荐使用double作为底层存储的dsec类型,绝大多数业务场景下精度完全够用,也能避免你遇到的这类浮点精度问题。
如果必须使用float存储,可以采用两种方案规避误差:
- 先做整数秒转换:将时间差先转为整数类型的秒级duration,再转换为
fsec,只要时间跨度不超过194天(16777216秒),转换结果都是精确的; - 取整时添加误差抵消偏移:计算时减去一个极小的epsilon抵消浮点误差,示例:
std::ceil(time_jump.count() / interval.count() - 1e-6)。
内容的提问来源于stack exchange,提问作者lord.didger
相关产品推荐
相关产品推荐

