定点数通过整数模拟小数运算,适用于无浮点硬件的场景。文章提出C++模板类FixedPoint,采用16.16格式(32位整数,16位小数),支持构造、转换、四则运算与比较操作,关键优化包括使用int64_t防止溢出、右移时加偏移实现四舍五入、constexpr提升性能,并通过私有构造避免重载歧义,示例验证了3.5×2.0=7.0的正确性,具备高效、简洁、可移植特点。

在嵌入式系统、游戏开发或没有浮点硬件支持的平台上,使用浮点数运算可能效率低下甚至不可行。这时,定点数(Fixed-Point Arithmetic)是一种高效替代方案。C++ 中可以通过封装类来实现一个灵活、易用的定点数算术库。
什么是定点数?
定点数是用整数来模拟小数的一种方式。它通过固定小数点的位置来表示数值。例如,使用 16.16 格式(32位整数,高16位整数部分,低16位小数部分),数值 3.5 可以表示为:
3.5 × 65536 = 229376。
所有运算都在整数层面进行,最后再按比例转换回真实值。
设计一个定点数类
我们可以定义一个模板类 FixedPoint,支持不同精度配置:
templateclass FixedPoint { private: int32_t value; // 存储定点数的原始整数值 static constexpr int32_t FRACTION_SHIFT = FractionBits; static constexpr int32_t ONE = 1 << FractionBits; public: // 构造函数 constexpr FixedPoint() : value(0) {} constexpr FixedPoint(int32_t v) : value(v << FractionBits) {} constexpr FixedPoint(double v) : value(static_cast
(v * ONE)) {} // 转换回浮点数 double toDouble() const { return static_cast(value) / ONE; } // 基本运算符重载 FixedPoint operator+(const FixedPoint& rhs) const { return FixedPoint{ 0, value + rhs.value }; // 使用私有构造 } FixedPoint operator-(const FixedPoint& rhs) const { return FixedPoint{ 0, value - rhs.value }; } FixedPoint operator*(const FixedPoint& rhs) const { int64_t temp = static_cast (value) * rhs.value; return FixedPoint{ 0, static_cast ((temp + (ONE >> 1)) >> FractionBits) }; // 四舍五入 } FixedPoint operator/(const FixedPoint& rhs) const { int64_t temp = (static_cast (value) << FractionBits); return FixedPoint{ 0, static_cast ((temp + rhs.value/2) / rhs.value) }; } FixedPoint& operator+=(const FixedPoint& rhs) { value += rhs.value; return *this; } FixedPoint& operator-=(const FixedPoint& rhs) { value -= rhs.value; return *this; } FixedPoint& operator*=(const FixedPoint& rhs) { *this = *this * rhs; return *this; } FixedPoint& operator/=(const FixedPoint& rhs) { *this = *this / rhs; return *this; } // 比较操作符 bool operator==(const FixedPoint& rhs) const { return value == rhs.value; } bool operator!=(const FixedPoint& rhs) const { return value != rhs.value; } bool operatorzuojiankuohaophpcn(const FixedPoint& rhs) const { return value zuojiankuohaophpcn rhs.value; } bool operatoryoujiankuohaophpcn(const FixedPoint& rhs) const { return value youjiankuohaophpcn rhs.value; } bool operatorzuojiankuohaophpcn=(const FixedPoint& rhs) const { return value zuojiankuohaophpcn= rhs.value; } bool operatoryoujiankuohaophpcn=(const FixedPoint& rhs) const { return value youjiankuohaophpcn= rhs.value; } // 支持从原始整数构造(避免歧义) private: struct RawTag {}; public: constexpr FixedPoint(RawTag, int32_t raw) : value(raw) {} };
关键细节与优化
实现时需注意以下几点:
立即学习“C++免费学习笔记(深入)”;
-
溢出控制:乘法和除法容易溢出,建议使用
int64_t中间计算。 -
四舍五入:在右移时加上偏移量(如
ONE >> 1)可实现四舍五入,提升精度。 -
构造函数重载冲突:直接用
double和int构造可能产生歧义,上面通过私有构造函数规避。 -
常量表达式支持:使用
constexpr提升编译期计算能力。 - 精度选择:16位小数位适合大多数场景;若范围更大可用 8.24 或 32位整数扩展为 64位存储。
使用示例
下面是一个简单测试:
#includeint main() { FixedPoint<16> a(3.5); // 3.5 FixedPoint<16> b(2.0); // 2.0 FixedPoint<16> c = a * b; // 应得 7.0
std::cout zuojiankuohaophpcnzuojiankuohaophpcn "a = " zuojiankuohaophpcnzuojiankuohaophpcn a.toDouble() zuojiankuohaophpcnzuojiankuohaophpcn "\n"; std::cout zuojiankuohaophpcnzuojiankuohaophpcn "b = " zuojiankuohaophpcnzuojiankuohaophpcn b.toDouble() zuojiankuohaophpcnzuojiankuohaophpcn "\n"; std::cout zuojiankuohaophpcnzuojiankuohaophpcn "c = " zuojiankuohaophpcnzuojiankuohaophpcn c.toDouble() zuojiankuohaophpcnzuojiankuohaophpcn "\n"; if (c youjiankuohaophpcn a) { std::cout zuojiankuohaophpcnzuojiankuohaophpcn "c youjiankuohaophpcn a\n"; } return 0;}
输出:
a = 3.5b = 2
c = 7
c > a
基本上就这些。这个定点数类足够轻量,可在无 FPU 的设备上高效运行,同时保持接口简洁。根据具体需求,还可加入 sin/cos 等数学函数查表实现。










