C语言递归实现组合数乘除顺序不同结果不一致问题咨询
C语言递归计算组合数乘除顺序差异问题解答
为什么乘除顺序不同结果不一致
- C语言中
*和/运算符优先级相同,遵循左结合规则,会从左到右依次计算表达式 - 两个代码的核心差异是整数除法的截断时机:C的整数除法会向零取整,直接舍弃小数部分。
组合数C(15,4)的正确值为1365,两个代码的递归计算过程差异如下:
第一段错误代码(先除后乘)运算过程
return (n-r+1)/r*recursive_combination(n,r-1);
递归步骤:
- 计算C(15,1):(15-1+1)/1 * C(15,0) = 15/1 *1 =15,结果正确
- 计算C(15,2):(15-2+1)/2 * C(15,1) =14/2 15=715=105,结果正确
- 计算C(15,3):(15-3+1)/3 * C(15,2) =13/3 105 → 13整除3得4,4105=420,这里因为提前做整数除法截断了小数部分,结果错误
- 计算C(15,4):(15-4+1)/4 * C(15,3) =12/4 420=3420=1260,最终结果错误
第二段正确代码(先乘后除)运算过程
return recursive_combination(n,r-1)*(n-r+1)/r;
递归步骤:
- C(15,1)=C(15,0)15/1=115/1=15,正确
- C(15,2)=C(15,1)14/2=1514/2=210/2=105,正确
- C(15,3)=C(15,2)13/3=10513/3=1365/3=455,正确,因为组合数为整数,先乘后分子一定能被分母整除,不会出现截断
- C(15,4)=C(15,3)12/4=45512/4=5460/4=1365,结果正确
为什么改成n-r+1.0后结果为1362
- 把
n-r+1改为n-r+1.0后,表达式会隐式转换为浮点数运算,避免了整数除法的截断,但会引入两个问题:- 浮点数本身是近似存储,像13/3=4.333333...这类无限循环小数无法被二进制浮点数精确表示,存储的是略小于真实值的近似值
- 函数返回值为int类型,浮点数转int时会直接截断小数部分
- 运算时,C(15,3)的计算变为13.0/3 105 ≈4.3333333333105≈454.9999999965,转int时截断为454,最终C(15,4)=3*454=1362,结果仍然错误。
内容的提问来源于stack exchange,提问作者ACps
相关产品推荐
相关产品推荐

