帕斯卡三角生成方法第14行后失效的技术求助
帕斯卡三角计算错误的根源与修复方案
嘿,我一眼就看出问题所在了——这是**整数溢出(Integer Overflow)**搞的鬼!
你用int类型来计算阶乘和组合数,但C#里int的最大值只有2147483647,而13!(也就是13的阶乘)的结果是6227020800,早就超出了int的容纳范围。当数值溢出时,C#默认不会抛出错误,而是会按照补码规则循环计算,得到错误的负数或者乱码数值,这就是为什么第14行结果完全不对,后续还出现负数的原因。
先确认溢出的关键点
咱们算一下具体数值:
12! = 479001600,这个还在int的范围内,所以前13行结果都没问题13! = 6227020800,远超int上限,此时factorial(13)返回的是一个错误的负数(实际是-1932053504),用这个错误值计算组合数,结果自然全错了
修复方案1:改用更大的整数类型
最直接的办法是把int换成long类型,long的最大值是9223372036854775807,可以容纳到20!,足够支持你计算到n=20左右的帕斯卡三角。
修改后的完整代码如下:
using System; using System.Collections.Generic; namespace PascalsTriangle { class Program { static void Main(string[] args) { Console.WriteLine("Enter size of triangle: "); List<long> number = PascalsTriangle(int.Parse(Console.ReadLine())); number.ForEach(Console.WriteLine); } public static List<long> PascalsTriangle(int n) { List<long> triangle = new List<long>(); long temp = 0; for (int i = 0; i < n; i++) { for (int x = 0; x <= i; x++) { if (x == 0 || x == i) { triangle.Add(1); } else { temp = (factorial(i)) / (factorial(x) * factorial(i - x)); triangle.Add(temp); } } } return triangle; } public static long factorial(long number) { if (number == 0) { return 1; } long factorial = number; while (number > 1) { factorial *= --number; } return factorial; } } }
这里需要注意:你之前写的“正确值”里的186是笔误哦,正确的第14行(对应i=13)第三个数字应该是286(组合数C(13,3)=286),修改后的代码会输出完全正确的结果。
修复方案2:用递推公式(更高效+支持超大n)
用阶乘计算组合数虽然直观,但效率低还容易溢出。帕斯卡三角的核心特性是每个数等于它上方左右两个数之和,用递推的方式计算不仅效率更高,还能通过BigInteger支持任意大的n,彻底解决溢出问题。
示例代码如下:
using System; using System.Collections.Generic; using System.Numerics; namespace PascalsTriangle { class Program { static void Main(string[] args) { Console.WriteLine("Enter size of triangle: "); List<BigInteger> number = PascalsTriangle(int.Parse(Console.ReadLine())); number.ForEach(Console.WriteLine); } public static List<BigInteger> PascalsTriangle(int n) { List<BigInteger> triangle = new List<BigInteger>(); List<BigInteger> currentRow = new List<BigInteger>(); for (int i = 0; i < n; i++) { // 每行开头插入1 currentRow.Insert(0, 1); // 计算中间的数值:当前位置 = 原位置值 + 原位置前一个值 for (int j = 1; j < currentRow.Count - 1; j++) { currentRow[j] = currentRow[j] + currentRow[j + 1]; } // 将当前行所有元素加入总列表 triangle.AddRange(currentRow); } return triangle; } } }
这个版本用BigInteger(需要引用System.Numerics命名空间),可以计算任意大的n,完全不用担心溢出问题,而且计算速度比阶乘方法快得多。
内容的提问来源于stack exchange,提问作者imran
相关产品推荐
相关产品推荐

