当我计算一个大阶乘时,为什么会得到负数?

发布于 2024-07-07 12:27:14 字数 790 浏览 13 评论 0原文

因此,简单的程序,计算阶乘数。 代码如下。

int calcFactorial(int num)
{
    int total = 1;

    if (num == 0)
    {
        return 0;
    }

    for (num; num > 0; num--)
    {
        total *= num;
    }

    return total;
}

现在,对于大多数数字来说,这工作得很好(当然有更快、更优雅的解决方案,但这对我有用)。 然而,当输入更大的数字(例如 250)时,说白了,就会出错。 现在,250 的前几个阶乘“位”是 { 250, 62250, 15126750, 15438000, 3813186000 } 以供参考。

我的代码输出 { 250, 62250, 15126750, 15438000, -481781296 } ,这显然是错误的。 我的第一个怀疑可能是我已经突破了 32 位整数的限制,但考虑到 2^32 是 4294967296 我不这么认为。 我唯一能想到的可能是它违反了有符号 32 位限制,但它不应该能够考虑这种事情吗? 如果有符号是问题,我可以通过使整数无符号来解决这个问题,但这只是一个临时解决方案,因为下一次迭代产生 938043756000,远远高于 4294967296 限制。

那么,我的问题是签名限制吗? 如果是这样,我该怎么做才能计算大数(尽管我不久前制作了一个可能适合的“LargeInteger”类!)而不会再次遇到这个问题?

So, simple procedure, calculate a factorial number. Code is as follows.

int calcFactorial(int num)
{
    int total = 1;

    if (num == 0)
    {
        return 0;
    }

    for (num; num > 0; num--)
    {
        total *= num;
    }

    return total;
}

Now, this works fine and dandy (There are certainly quicker and more elegant solutions, but this works for me) for most numbers. However when inputting larger numbers such as 250 it, to put it bluntly, craps out. Now, the first couple factorial "bits" for 250 are { 250, 62250, 15126750, 15438000, 3813186000 } for reference.

My code spits out { 250, 62250, 15126750, 15438000, -481781296 } which is obviously off. My first suspicion was perhaps that I had breached the limit of a 32 bit integer, but given that 2^32 is 4294967296 I don't think so. The only thing I can think of is perhaps that it breaches a signed 32-bit limit, but shouldn't it be able to think about this sort of thing? If being signed is the problem I can solve this by making the integer unsigned but this would only be a temporary solution, as the next iteration yields 938043756000 which is far above the 4294967296 limit.

So, is my problem the signed limit? If so, what can I do to calculate large numbers (Though I've a "LargeInteger" class I made a while ago that may be suited!) without coming across this problem again?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

自由如风 2024-07-14 12:27:14

2^32 并没有给出有符号整数的限制。

有符号整数限制实际上是 2147483647 (如果您正在使用 MS 工具在 Windows 上进行开发,其他工具套件/平台也有自己的限制,可能类似)。

您需要一个 C++ 大数库像这个

2^32 doesn't give you the limit for signed integers.

The signed integer limit is actually 2147483647 (if you're developing on Windows using the MS tools, other toolsuites/platforms would have their own limits that are probably similar).

You'll need a C++ large number library like this one.

梦幻的心爱 2024-07-14 12:27:14

除了其他评论之外,我还想指出您的代码中的两个严重错误。

  • 你对负数毫无防备。
  • 零的阶乘是一,而不是零。

In addition to the other comments, I'd like to point out two serious bugs in your code.

  • You have no guard against negative numbers.
  • The factorial of zero is one, not zero.
和影子一齐双人舞 2024-07-14 12:27:14

是的,你已经达到极限了。 根据定义,C++ 中的 int 是有符号的。 而且,呃,不,C++ 永远不会思考。 如果你告诉它做一件事,它就会做,即使它明显是错误的。

考虑使用大量的库。 其中有很多是针对 C++ 的。

Yes, you hit the limit. An int in C++ is, by definition, signed. And, uh, no, C++ does not think, ever. If you tell it to do a thing, it will do it, even if it is obviously wrong.

Consider using a large number library. There are many of them around for C++.

仅此而已 2024-07-14 12:27:14

如果不指定签名或未签名,则默认为签名。 您可以使用编译器上的命令行开关来修改它。

请记住,C(或 C++)是一种非常低级的语言,并且完全按照您的要求执行。 如果你告诉它把这个值存储在一个有符号整型中,它就会这么做。 作为程序员必须弄清楚什么时候会出现问题。 这不是语言的工作。

If you don't specify signed or unsigned, the default is signed. You can modify this using a command line switch on your compiler.

Just remember, C (or C++) is a very low-level language and does precisely what you tell it to do. If you tell it to store this value in a signed int, that's what it will do. You as the programmer have to figure out when that's a problem. It's not the language's job.

爱人如己 2024-07-14 12:27:14

我的 Windows 计算器 (Start-Run-Calc) 告诉我,

hex (3813186000) =         E34899D0
hex (-481781296) = FFFFFFFFE34899D0

是的,原因是有符号限制。 由于阶乘根据定义只能是正数,并且只能计算正数,因此参数和返回值无论如何都应该是无符号数。 (我知道每个人都在 for 循环中使用 int i = 0 ,我也是。但抛开这一点,如果值不能为负数,我们应该始终使用无符号变量,在我看来这是一个很好的做法)。

阶乘的普遍问题是,它们可以轻松生成非常大的数字。 您可以使用浮点数,从而牺牲精度但避免整数溢出问题。

哦等等,根据我上面写的,你应该将其设为无符号浮点数;-)

My Windows calculator (Start-Run-Calc) tells me that

hex (3813186000) =         E34899D0
hex (-481781296) = FFFFFFFFE34899D0

So yes, the cause is the signed limit. Since factorials can by definition only be positive, and can only be calculated for positive numbers, both the argument and the return value should be unsigned numbers anyway. (I know that everybody uses int i = 0 in for loops, so do I. But that left aside, we should use always unsigned variables if the value can not be negative, it's good practice IMO).

The general problem with factorials is, that they can easily generate very large numbers. You could use a float, thus sacrificing precision but avoiding the integer overflow problem.

Oh wait, according to what I wrote above, you should make that an unsigned float ;-)

笑忘罢 2024-07-14 12:27:14

如果我没记错的话:

unsigned Short int = max 65535

unsigned int = max 4294967295

unsigned long = max 4294967295

unsigned long long (Int64 )= max 18446744073709551615

编辑来源:

Int/Long 最大值

现代编译器变量

If i remember well:

unsigned short int = max 65535

unsigned int = max 4294967295

unsigned long = max 4294967295

unsigned long long (Int64 )= max 18446744073709551615

Edited source:

Int/Long Max values

Modern Compiler Variable

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文