因为double存在二进制精度误差,而定点数用整数存储放大后的值,可确保小数位数固定、运算无浮点漂移,适用于金融、嵌入式等需确定性舍入的场景。

为什么不用 double 而要自己写定点数类
因为 double 有二进制精度误差,比如 0.1 + 0.2 != 0.3;金融、嵌入式或协议解析等场景需要确定的小数位数和可预测的舍入行为。定点数本质是用整数存“放大后的值”,比如用 int64_t 存毫秒(×1000)、存分(×100)、存厘(×1000)——小数位数固定,运算无浮点漂移。
核心设计:用 int64_t + 缩放因子实现 FixedPoint
缩放因子(scale)决定小数位数,例如 scale=100 表示两位小数,值 1234 对应真实数值 12.34。所有运算在整数层面进行,最后按需调整缩放。
- 构造时直接传入整数或浮点字面量,但浮点初始化要小心:
FixedPoint(0.1)会先经过double表示再转整数,可能引入误差;推荐用字符串或整数+小数位构造,如FixedPoint::from_raw(1234, 2)表示 12.34 - 加减法只需对齐缩放因子(左移/右移),然后整数加减;乘法结果缩放变为
scale²,需右移回原 scale;除法同理,需先放大被除数避免精度丢失 - 默认缩放设为 1000(三位小数),但建议把 scale 定为模板参数:
FixedPoint,编译期确定,避免运行时分支
关键陷阱:除法截断、溢出与舍入策略
整数除法默认向零截断(C++ 的 /),但金融常需四舍五入或向上取整。必须显式处理:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 除法前放大被除数:
(a.raw() * scale + b.raw() / 2) / b.raw()实现四舍五入(注意:+scale/2 更安全,避免负数问题) -
int64_t最大值约 ±9e18,若 scale=1e6,原始值不能超过 ±9e12,否则乘法溢出;建议用__builtin_mul_overflow或手动检查 - 比较操作符必须先对齐缩放因子,不能直接比
raw()值;a > b应转成a.raw() * b.scale() > b.raw() * a.scale()
一个可用的最小实现骨架
不依赖第三方库,仅需 C++17:
template<int64_t scale>
class FixedPoint {
int64_t value_;
public:
constexpr FixedPoint(int64_t raw) : value_(raw) {}
static constexpr FixedPoint from_double(double d) {
return FixedPoint(static_cast<int64_t>(round(d * Scale)));
}
FixedPoint operator+(const FixedPoint& rhs) const {
return FixedPoint(value_ + rhs.value_);
}
FixedPoint operator*(const FixedPoint& rhs) const {
return FixedPoint((value_ * rhs.value_ + Scale/2) / Scale); // 四舍五入
}
// 其他运算类似,注意溢出检查和缩放对齐
};</int64_t></int64_t>
真正上线前,务必补全:溢出检测、IO 流支持( 输出带小数点)、<code>constexpr 构造、以及针对负数的舍入一致性——这点最容易被忽略,测试用例至少覆盖 -0.5、-1.5 这类边界。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










