用结构比较分数
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】:如果分子和分母是int
s(或其他整数类型),那么除法是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 < 0) z = -z; if (L.denom < 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);
【讨论】:
以上是关于用结构比较分数的主要内容,如果未能解决你的问题,请参考以下文章