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

运算符重载实现分数运算时乘减组合计算异常排查

问题描述

我用C++实现了一个Fraction类,包含成员变量zaehler(分子)和nenner(分母),通过运算符重载实现分数的加、减、乘、除运算。基础运算及多数组合运算结果正确且能完成约分化简,但在执行乘减组合运算(如d * e - b)时出现结果错误。调试过程中发现减法运算的临时对象dif的zaehler和nenner存在值异常,请问该异常产生的原因是什么?

相关代码

类定义与运算符重载

Fraction::Fraction()
{
    zaehler = 1;
    nenner = 1;
}

unsigned int Fraction::ggT(unsigned int a, unsigned int b)
{
    if (b != 0)     //b = 0, wenn a % b = 0, bedeutet Division ohne Rest
    {
        return ggT(b, a % b);
    }
    else
    {
        return a;
    }
}

unsigned int Fraction::kgV(unsigned int a, unsigned int b)
{
    int facA[30], facB[30];

    for (int i = 0; i < 30; i++)    
    {
        facA[i] = a * (i + 1);
        facB[i] = b * (i + 1);
    }
    for (int i = 0; i < 30; i++)    
    {
        for (int k = 0; k < 30; k++)
        {
            if (facB[k] == facA[i])     
            {
                return facA[i];
            }
        }
    }
}

Fraction Fraction::operator-(const Fraction& b)
{
    Fraction dif;
    int temp_zaehler;

    int zaehler_a = ((float)this->zaehler / this->nenner) * kgV(this->nenner, b.nenner);        
    int zaehler_b = ((float)b.zaehler / b.nenner) * kgV(this->nenner, b.nenner);
    dif.zaehler = (zaehler_a - zaehler_b);
    dif.nenner = kgV(this->nenner, b.nenner);

    if (dif.zaehler < 0)
    {
        temp_zaehler = dif.zaehler;
        dif.zaehler /= ggT(dif.zaehler*-1, dif.nenner);
        dif.nenner /= ggT(temp_zaehler*-1, dif.nenner);
    }
    else
    {
        temp_zaehler = dif.zaehler;
        dif.zaehler /= ggT(dif.zaehler, dif.nenner);
        dif.nenner /= ggT(temp_zaehler, dif.nenner);
    }

    return dif;
}


Fraction Fraction::operator*(const Fraction& b)
{
    Fraction prod;
    int temp_zaehler;
    prod.zaehler = (this->zaehler) * b.zaehler;     
    prod.nenner = (this->nenner) * b.nenner;        

    if (prod.zaehler < 0)
    {
        temp_zaehler = prod.zaehler;
        prod.zaehler /= ggT(prod.zaehler * -1, prod.nenner);
        prod.nenner /= ggT(temp_zaehler * -1, prod.nenner);
    }
    else
    {
        temp_zaehler = prod.zaehler;
        prod.zaehler /= ggT(prod.zaehler, prod.nenner);
        prod.nenner /= ggT(temp_zaehler, prod.nenner);
    }
    return prod;
}

主函数相关代码

std::cout << "d * e - b = " << d.getString() << " * " << e.getString() << " - " << b.getString() << " = " << (d * e - b).getString() << "\n";
异常原因分析
  • kgV函数存在未定义行为:kgV函数仅在找到两个分母前30倍范围内的公倍数时返回值,若两个分母的最小公倍数超过各自的30倍(例如分母为31和37,最小公倍数为1147,超过31*30=930),循环结束后无返回语句,会返回随机垃圾值,直接导致减法运算中分子、分母计算完全错误。
  • 减法运算中浮点数转换导致精度丢失:减法里用((float)this->zaehler / this->nenner) * kgV(...)计算转换后的分子,float类型仅约6-7位有效数字,当分子分母数值较大时,浮点数计算会出现精度误差,结果非整数,赋值给int时被截断,最终得到错误的分子值。正确做法是用整数运算:先计算最小公倍数kgV_val = kgV(this->nenner, b.nenner),再通过zaehler_a = this->zaehler * (kgV_val / this->nenner)计算,因kgV是分母的公倍数,kgV_val / this->nenner必然为整数,无精度问题。
  • ggT函数存在参数溢出风险:当dif.zaehler为INT_MIN时,dif.zaehler*-1会触发整数溢出(INT_MIN的绝对值比INT_MAX大1),转换为unsigned int后变成极大的错误值,导致ggT计算错误,进而使约分后的分子分母异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 10:49:58