用结构比较分数

Posted

技术标签:

【中文标题】用结构比较分数【英文标题】:Comparing fractions with struct 【发布时间】:2014-04-20 01:43:52 【问题描述】:

该函数应该比较存储在两个结构中的两个分数。

如果分数 L = 分数 R 返回 0 如果 L > R 返回 1 如果 R > L 返回 -1

这是我现在的代码:

int compare_fractions(Fraction L, Fraction R)

    double z = (L.numer/L.denom) - (R.numer/R.denom);
    // THIS CODE IS INCORRECT - FIX IT!  
    if(z == 0)
        return 0;
    else if(z < 0)
        return -1;
    else if(z
        return 1;

但是,当我运行以下测试时,我收到 0 并进行以下比较:

(1,3) ? (2,3)
(5,6) ? (3,4)
(2,4) ? (1,4)

其中 (1,3) 是分数 L,(2,3) 是分数 R

【问题讨论】:

并且 z 等于零的测试很糟糕。见***.com/questions/19837576/… 【参考方案1】:

如果分子和分母是ints(或其他整数类型),那么除法是integer division,你永远不会得到正确的小数部分

将其转换为 double 可以纠正大部分问题,但您将面临除法缓慢,有时还会因浮点舍入而出现错误。

您应该改用乘法。它会快得多,并且您不需要在某些架构上非常慢的浮点除法。这样你也不必担心浮点比较

int compare_fractions(Fraction L, Fraction R)

    int z = L.numer*R.denom - L.denom*R.numer;
    if (z == 0)
        return 0;
    else if (z > 0)
        return 1;
    else
        return -1;

当然你需要确保所有的分母都是正数,否则你需要标准化它(你可以使用下面chux的建议)。如果您的值可以通过以更广泛的类型进行数学运算(例如

)来计算,您还需要考虑溢出
long long z = (long long)L.numer*R.denom - L.denom*R.numer

如果您可以稍微放宽要求以返回小于、等于或大于大小写的负值、0 或正值,就像 strcmp() 一样,那么您可以完全删除对 z 值的检查,而直接删除 return L.numer*R.denom - L.denom*R.numer

如果您仍然需要返回 -1、0 和 1,那么有几种方法可以缩短/优化它,例如

return (z > 0) - (z < 0);
return (z == 0) ? 0 : (z < 0 ? -1 : 1);
return (z >> 31) | (!!z);
Is there a standard sign function (signum, sgn) in C/C++? Fast sign of integer in C Branchless code that maps zero, negative, and positive to 0, 1, 2

【讨论】:

规范化建议:int z = ...; if (R.denom &lt; 0) z = -z; if (L.denom &lt; 0) z = -z; 注意:仅使用int 的缺点是整数溢出。扩大int 的大小会有所帮助,但也不是一个很好的解决方案。但你的答案是正确的方法。 @chux 大多数架构都有加宽乘法,所以使用更宽的 int 类型并不是什么大问题,它仍然比将数字从 int 转换为 double 然后除法要快 同意大多数架构都有更宽的整数。使用intmax_t 通常是一个安全的候选者。如果没有,double 可以与您采用的相同的无除法方法一起使用。【参考方案2】:

当您将int 除以另一个int 时,它会首先将它们除以(因为结果也必须是int)将结果四舍五入到零。首先在这一点上将其转换为double

int a = 7;
int b = 3;
double c = a / b; // = 2, because 2.333... rounded down is 2, which is
                  //      then cast to a double

解决方案是在除法之前将分子或分母转换为double

int a = 7;
int b = 3;
double c = (double)a / b; // = 2.333... because it's cast to a double before
                          //            dividing
//double c = a / (double)b; // this will also work

更具体地说,如果您将代码中的一行更改为此,它应该可以工作:

double z = ((double)L.numer/L.denom) - ((double)R.numer/R.denom);

【讨论】:

以上是关于用结构比较分数的主要内容,如果未能解决你的问题,请参考以下文章

差分法详解

用Java编写比较两个数大小的题目

LeetCode括号的分数(栈树形结构贡献率三种解法)

LeetCode括号的分数(栈树形结构贡献率三种解法)

最高的分数

最高的分数