Lua5.3与Lua5.1阶乘代码差异:为何19!后结果异常?
Great question! This issue comes down to a critical change between Lua 5.1 and 5.3: Lua 5.3 added native 64-bit integer support, while Lua 5.1 only used double-precision floating-point numbers for all values. Let’s break this down:
1. How Lua 5.1 Handles Your Script
In Lua 5.1, every number is a double-precision float. These floats can exactly represent all integers up to 2^53 (about 9e15). Beyond that, they lose precision (since floats store a fixed number of significant digits), but they never "overflow" into nonsensical values—they just use an approximate representation. That’s why your script runs smoothly all the way until the float can’t handle the size anymore (around 1e308, the max for doubles).
2. The Lua 5.3 Problem
Lua 5.3 introduced 64-bit signed integers, and it follows a strict rule: if both operands of a math operation are integers, the operation runs as integer arithmetic.
In your script, N and F start as integers, so every F = F * N is an integer multiplication. The problem? 64-bit signed integers have a maximum value of 9223372036854775807 (roughly 9e18). Let’s check the factorials:
- 20! = 2432902008176640000 (~2.4e18) — still fits in a 64-bit integer, so no problem.
- 21! = 51090942171709440000 (~5.1e19) — way larger than the 64-bit integer limit.
When this happens, Lua 5.3 triggers integer overflow. Since integers use two’s complement representation, the overflow wraps around into a negative number or a garbage positive value. Your loop condition F < 1e200 is still true (negative numbers are definitely less than 1e200), so the script keeps running—but the factorial values are completely wrong from that point on.
Fixing the Script
To make your script work in Lua 5.3, you just need to force the arithmetic to use floating-point numbers instead of integers. Here are a few simple ways:
Option 1: Initialize F as a float
Change the first line to start with a floating-point value:
N, F = 1, 1.0 -- 1.0 is a float, not an integer while F < 1e200 do print(N .. "! is " .. F) N = N + 1 F = F * N end
Now every multiplication will use floating-point arithmetic, matching Lua 5.1’s behavior.
Option 2: Explicitly convert to float during multiplication
If you prefer to keep the initial integer values, you can cast one operand to a float in the multiplication:
N, F = 1, 1 while F < 1e200 do print(N .. "! is " .. F) N = N + 1 F = F * N + 0.0 -- Adding 0.0 forces the result to be a float end
Either fix will prevent integer overflow, and your script will run just like it did in Lua 5.1—you’ll lose precision once you pass 2^53, but you won’t get those weird overflowed values.
内容的提问来源于stack exchange,提问作者costica_p

