Numbers and maths
Lesson 3.2
Lua 5.4 has two kinds of numbers, integers and floats, and a full set of maths operators and functions.
Integers and floats
An integer is a whole number: 64, 0, -12. A float has a fractional part: 0.5, 3.0, 1e3 (which means 1000.0). Both have the type number. math.type tells them apart:
print(math.type(64)) --> integer
print(math.type(64.0)) --> float
print(64 == 64.0) --> true
Most of the time you don’t have to care. Integers and floats compare equal when they have the same value, and Lua converts between them when needed. The difference shows when you print them: a float always shows a decimal point.
print(10) --> 10
print(10.0) --> 10.0
print(1e3) --> 1000.0
You can also write integers in hexadecimal with 0x: 0xFF is 255.
Arithmetic
| Operator | Meaning | Example | Result |
|---|---|---|---|
+ |
add | 5 + 3 |
8 |
- |
subtract | 5 - 3 |
2 |
* |
multiply | 5 * 3 |
15 |
/ |
divide | 6 / 3 |
2.0 |
// |
floor division | 7 // 2 |
3 |
% |
remainder (modulo) | 7 % 2 |
1 |
^ |
power | 2 ^ 10 |
1024.0 |
- |
negate | -5 |
-5 |
Two of these surprise people:
/always gives a float, even when the division is exact:6 / 3is2.0.^also always gives a float.
Use // when you want a whole-number result. It rounds down, towards minus infinity:
print(7 // 2) --> 3
print(-7 // 2) --> -4
print(7.0 // 2) --> 3.0
Remainder
% gives what is left over after floor division. It is great for “every Nth time” checks and for wrapping around:
-- 20 ticks make a second: tick 47 is 7 ticks into the current second
local tick = 47
print(tick % 20) --> 7
-- a 9-slot hotbar has slots 0 to 8: moving right from slot 8 wraps to 0
local slot = 8
print((slot + 1) % 9) --> 0
With a negative number, the result takes the sign of the right side: -7 % 3 is 2.
A common use: a number is even when n % 2 == 0.
Order of operations
Lua follows the usual maths rules. ^ comes first, then *, /, //, %, then + and -. Use brackets when in doubt:
print(2 + 3 * 4) --> 14
print((2 + 3) * 4) --> 20
print(-2 ^ 2) --> -4.0
The last one is -(2 ^ 2), because ^ binds tighter than the minus sign.
Updating a variable
Lua has no += or ++. Write the full form:
local xp = 10
xp = xp + 5
xp = xp * 2
print(xp) --> 30
The math library
The math table holds useful functions and constants:
print(math.floor(3.7)) --> 3
print(math.ceil(3.2)) --> 4
print(math.abs(-8)) --> 8
print(math.max(4, 19, 7)) --> 19
print(math.min(4, 19, 7)) --> 4
print(math.sqrt(16)) --> 4.0
print(math.pi) --> 3.1415926535898
print(math.huge) --> inf
math.floor and math.ceil return integers. To round to the nearest whole number, add a half and floor it:
local function round(x)
return math.floor(x + 0.5)
end
print(round(2.5), round(2.4)) --> 3 2
Other handy ones: math.fmod(a, b) (remainder that keeps the sign of a), math.tointeger(3.0) (gives 3, or nil if the float has a fraction), math.maxinteger and math.mininteger (the largest and smallest integers), and the trigonometry functions math.sin, math.cos, math.atan (angles in radians; math.rad and math.deg convert).
Random numbers
print(math.random()) -- a float from 0 up to (not including) 1
print(math.random(6)) -- an integer from 1 to 6
print(math.random(5, 10)) -- an integer from 5 to 10
Lua 5.4 seeds the generator for you, so each run gives different numbers. Call math.randomseed(42) if you want the same sequence every time, for example to test something.
Floats are not exact
Floats store most fractions only approximately. Printing hides this, but comparisons don’t:
print(0.1 + 0.2) --> 0.3
print(0.1 + 0.2 == 0.3) --> false
Never compare floats with == after doing maths on them. Check that they are close instead:
local a = 0.1 + 0.2
print(math.abs(a - 0.3) < 1e-9) --> true
Integers don’t have this problem, so counts and slot numbers are always exact.
Division by zero
Dividing a float by zero gives infinity: 1 / 0 is inf and -1 / 0 is -inf. Floor division or remainder of two integers by zero is an error (attempt to divide by zero or attempt to perform 'n%0'). Check the divisor first when it could be zero.
Numbers and strings
tonumber turns a string into a number, and gives nil if it can’t:
print(tonumber("42")) --> 42
print(tonumber("3.5")) --> 3.5
print(tonumber("ff", 16)) --> 255
print(tonumber("abc")) --> nil
tostring goes the other way: tostring(42) is "42".
Lua also converts a string to a number automatically in arithmetic: "10" + 5 is 15. Don’t rely on that. Convert explicitly with tonumber, so a bad value shows up as nil where you can check it.
Bitwise operators
For integers, Lua has bit operators: & (and), | (or), ~ (xor), ~x (not), << and >> (shift). They are useful for flags and packed data:
print(5 & 3) --> 1
print(5 | 3) --> 7
print(1 << 4) --> 16
You won’t need them often.
Try it
A player has 1234 experience points. Each level costs 100 points. Print the player’s level (full levels only), the points towards the next level, and the progress as a percentage with no decimals.
Show a solution
local xp = 1234
local level = xp // 100
local leftover = xp % 100
local percent = math.floor(leftover / 100 * 100)
print(level) --> 12
print(leftover) --> 34
print(percent) --> 34
Recap: integers and floats are both numbers, / always gives a float, // and % give whole-number division and remainder, and the math library has the rest.