Scala中Int类型溢出结果为何无规律?时而正时而负最终趋零
Great question! Let's break down exactly what's going on with your factorial code and Scala's Int type.
First: What's a Scala Int?
Scala's Int is a 32-bit signed integer (just like Java's, since Scala runs on the JVM). That means it can only hold values between -2147483648 and 2147483647. When you multiply two Ints and the result exceeds this range, the JVM doesn't throw an error—it uses wrap-around overflow (think of it as the number "looping back" around the min/max values).
Why the Positive/Negative Flip-Flop?
Wrap-around overflow works by discarding any bits that don't fit into the 32-bit space. For signed integers, the leftmost bit is the sign bit: 0 means positive, 1 means negative.
Factorials grow extremely quickly. Each multiplication step can flip that sign bit depending on the binary result of the product:
- If the product's binary representation has the sign bit set to 1, the
Intbecomes negative. - If it's set to 0, it stays positive.
Since each factorial step multiplies by a larger number, the sign bit toggles unpredictably as the overflow wraps around the 32-bit range.
Why Does It Eventually Converge to Zero?
Once you hit a point where multiplying the current accumulator by the next integer results in a value that's a multiple of 2³², the 32-bit Int will be all zeros (because all extra bits are discarded, leaving nothing but 0s). After that, multiplying zero by any number will still be zero—so the result stays at zero forever after that.
In your code, this happens once the factorial grows large enough that repeated overflow clears all 32 bits of the accumulator.
How to Get Accurate Factorial Results?
If you want correct factorial values for numbers up to 100, use a type that can handle larger or arbitrary-sized integers:
- BigInt: Scala's
BigIntsupports arbitrarily large integers with no overflow issues. - Long: A 64-bit signed integer, which can hold factorials up to 20! before overflowing.
Here's a modified version of your code using BigInt to get accurate results:
import scala.annotation.tailrec object FactorialExample { def main(args: Array[String]): Unit = { (1 to 100).foreach(i => println(s"Factorial of ${i} is " + factorial(i))) } def factorial(i: Int): BigInt = { @tailrec def fact(i: Int, acc: BigInt): BigInt = { if (i <= 0) acc else fact(i - 1, acc * i) } fact(i, 1) } }
内容的提问来源于stack exchange,提问作者Shashi Shankar

