You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C++自定义分数类中避免SIGFPE及算术运算溢出?

从零实现安全的C++ Fraction类:避免溢出与浮点异常

最近我在自学C++的类设计,打算写一个尽可能完整的Fraction类,核心诉求是给这个类加上足够的防护——既要避免浮点异常(SIGFPE),也要防止整数溢出,而且绝对不能依赖更大的整数类型(毕竟不是所有编译环境都提供比long更大的原生类型,强行用会带来兼容性问题)。

我的核心目标

  • 优先以最小的时间/内存开销,在常见算术运算(+、-、*、/、pow、root)中避免溢出和异常
  • 当溢出/异常完全无法避免时,至少要能精准检测到情况,而不是让程序直接崩溃

已梳理的溢出判断逻辑(基于long类型)

我先从基础的整数运算溢出判断入手,毕竟分数的运算最终还是要落到分子分母的整数操作上:

加法(a + b,a、b为long)

一开始我只想到了正数的情况:LONG_MAX - b > a就会溢出,但这显然不完整,得区分正负场景:

  • 当a、b均为正数:如果LONG_MAX - a < b,说明相加结果超出long的最大值,溢出
  • 当a、b均为负数:如果LONG_MIN - a > b,说明相加结果小于long的最小值,溢出
  • 一正一负相加时,绝对值是抵消的,不会出现溢出

减法(a - b,a、b为long)

减法可以拆解成a + (-b),直接复用加法的判断逻辑:

  • 等价于判断a + (-b)是否溢出,对应场景:
    • 若a为正、b为负(即-b为正):检查LONG_MAX - a < (-b)
    • 若a为负、b为正(即-b为负):检查LONG_MIN - a > (-b)
    • 其他场景(比如正减正、负减负)不会出现溢出

乘法(a * b,a、b为long)

乘法的溢出判断要更细致:

  • 若a或b为0:直接返回0,无溢出
  • 同号相乘时:
    • 正数相乘:如果a > LONG_MAX / b,说明a*b超过最大值,溢出
    • 负数相乘:如果a < LONG_MIN / b,说明a*b小于最小值,溢出(两个负数相乘得正数,若结果超过LONG_MAX也会溢出)
  • 异号相乘时:
    • 若a为正、b为负:如果b < LONG_MIN / a,说明a*b小于LONG_MIN,溢出
    • 若a为负、b为正:如果a < LONG_MIN / b,说明a*b小于LONG_MIN,溢出

除法(a / b,a、b为long)

除法主要有两个风险点:

  • 除以0:直接触发SIGFPE,必须提前检测b是否为0,禁止执行运算
  • 特殊溢出场景:LONG_MIN / (-1)会溢出,因为LONG_MIN的绝对值比LONG_MAX大1,除以-1后结果超出long的范围,必须单独判断这个情况

pow与root运算

这两个运算的溢出风险更隐蔽:

  • pow:分数a/b的n次方是aⁿ/bⁿ,这里aⁿ和bⁿ都可能溢出,需要分别对分子分母的幂运算做溢出检测
  • root:比如对分数开n次方,首先要确保运算有意义(比如开偶次方时分母分子不能为负),其次要检测开方后的结果是否超出long范围,还要处理非整数结果的情况(比如是否要转为近似分数还是抛出异常)

实现小技巧

  • 运算前先约分:对分数的分子分母先求最大公约数(GCD)约分,能大幅降低后续运算的溢出概率
  • 自定义异常类:比如实现FractionOverflowError、DivisionByZeroError,检测到异常时抛出,让调用方可以捕获并处理,而不是直接崩溃
  • 优先提前检测:不要依赖运行时的系统信号,提前在代码层做判断,能让程序的行为更可控

内容的提问来源于stack exchange,提问作者Pernoctador

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:22:20