一种不会丢失精度的分数表示法

众所周知,C++ 中就算是精度最高的浮点数 long double 也会存在可观的精度丢失的问题,那么我们该如何解决这个问题呢?高精度浮点数又显得过于夸张繁琐。

何不想个折中的法子?

于是,我们想到了一种办法,用 long long 分别表示分母和分子!

而我们在进行分数运算的时候,就可以模拟人工手算分数的办法来操作,比如说

\[\frac{a}{b}+\frac{c}{d}=\frac{ad+bc}{bd} \]

之后再求gcd约分即可

而比较两个分数的方法也很简单

\[\frac{a}{b}<\frac{c}{d}\ \Leftrightarrow\ ad<bc\ (a,b,c,d>0) \]

坑点:

  • 有负数时,比较大小时要分类讨论!
  • 约分时gcd不要传负数进去,概率出玄学错误!
  • 分母的负号一定要传给分子,不然 -114514/1919810 就会输出成 114514/-1919810 !
  • 分母为1或者分子为0时,就不用输出分数线了!(这项看情况,有些题目强制分数形式输出)
struct Fraction{
    LL up/*分子*/,down/*分母*/;
    Fraction(){}
    Fraction(LL a,LL b){
        up=a;down=b;
        reduction();
    }
    inline Fraction reduction(){
        if(down<0){
            up=-up;
            down=-down;
        }
        LL div=__gcd(abs(up),abs(down));
        up/=div;
        down/=div;
        return *this;
    }
    inline void flip(){//取倒数
        swap(up,down);
    }
    inline void print(){
        reduction();
        if(down==1) cout<<up;
        else cout<<up<<'/'<<down;
    }
    friend std::ostream & operator << (std::ostream &os,Fraction x){
        x.reduction();
        if(x.down==1) os<<x.up;
        else os<<x.up<<'/'<<x.down;
        return os;
    }
};
inline Fraction operator + (const Fraction& x,const Fraction& y){
    Fraction res;
    res.up=x.up*y.down+x.down*y.up;
    res.down=x.down*y.down;
    res.reduction();
    return res;
}
inline Fraction operator - (const Fraction& x,const Fraction& y){
    Fraction res;
    res.up=x.up*y.down-x.down*y.up;
    res.down=x.down*y.down;
    res.reduction();
    return res;
}
inline Fraction operator * (const Fraction& x,const Fraction& y){
    Fraction res;
    res.up=x.up*y.up;
    res.down=x.down*y.down;
    res.reduction();
    return res;
}
inline Fraction operator / (const Fraction& x,const Fraction& y){
    Fraction res;
    res.up=x.up*y.down;
    res.down=x.down*y.up;
    res.reduction();
    return res;
}
inline bool operator < (const Fraction& x,const Fraction& y){
    int tmp=(x.down<0)+(y.down<0);//判断负数个数
    return tmp%2==0 ? (x.up*y.down<x.down*y.up) : (x.up*y.down>x.down*y.up);//压行,负数为奇数个变号,反之不变
}
inline bool operator <= (const Fraction& x,const Fraction& y){
    int tmp=(x.down<0)+(y.down<0);
    return tmp%2==0 ? (x.up*y.down<=x.down*y.up) : (x.up*y.down>=x.down*y.up);
}
inline bool operator > (const Fraction& x,const Fraction& y){
    int tmp=(x.down<0)+(y.down<0);
    return tmp%2==0 ? (x.up*y.down>x.down*y.up) : (x.up*y.down<x.down*y.up);
}
inline bool operator >= (const Fraction& x,const Fraction& y){
    int tmp=(x.down<0)+(y.down<0);
    return tmp%2==0 ? (x.up*y.down>=x.down*y.up) : (x.up*y.down<=x.down*y.up);
}
inline bool operator == (const Fraction& x,const Fraction& y){
    return x.up*y.down==x.down*y.up;
}
inline bool operator != (const Fraction& x,const Fraction& y){
    return x.up*y.down!=x.down*y.up;
}
posted @ 2023-02-19 21:21  MessageBoxA  阅读(62)  评论(0)    收藏  举报