Did you know that Python evaluates -5 // 2 as -3, not -2? The double slash is floor division: it rounds the quotient down towards negative infinity rather than merely deleting the decimal part. A single unfamiliar rule can change the result of an otherwise correct-looking program. Learning numerical operations means understanding the precise rule, not recognising a symbol.
Ministry of Education V3.0 Reference 368 is a practical 2027 Singapore–Cambridge SEC G3 Computing K349 guide to numeric operations in Python. It covers integer and float values, arithmetic, true and floor division, modulo, powers, round(), math.ceil(), math.floor(), math.trunc(), math.sqrt(), range(), random.randint(), random.random() and numerical conversion to and from strings. The examples are original fictional learning cases, including negative-number boundaries and unpredictable outputs.
This is an independent eduKateSG educational guide, not an official MOE, SEAB or Cambridge publication. Refer to the published 2027 K349 syllabus and its quick-reference guide for the precise examination requirements. Code examples are for educational use in approved environments; random outputs are described by their possible ranges, not invented as if one unpredictable draw were certain.
1. The exact syllabus boundary
The official K349 Module 2.3.7 covers arithmetic, modulo, exponentiation, rounding normally or up/down/towards zero, square roots, generating ranges, generating random integers or floats, and conversion between numeric values and strings. The Python quick reference limits the functions and modules that candidates need to know.
This article follows that boundary rather than introducing a broad numerical computing library. Use built-in arithmetic, math functions listed in the reference, and the stated random functions. If a question specifies a particular convention or precision, preserve it throughout the calculation.
2. Numeric type is part of the meaning
An integer such as 7 represents a whole number. A float such as 7.0 is a floating-point number. They may compare as numerically equal in many contexts but their types and possible behaviours are not identical. The text ‘7’ is a string and does not automatically behave as the integer seven.
For example, ‘7’ + ‘2’ is ’72’, while 7 + 2 is 9. A learner should annotate each intermediate value with its type when a program mixes input(), int(), float() and str(). A wrong type can produce an entirely different result without a syntax error.
3. Ordinary addition, subtraction and multiplication
Python uses +, – and * for basic arithmetic on numbers. If a=7 and b=3, then a+b is 10, a-b is 4 and a*b is 21. Operator precedence applies, so 2+3*4 is 14 rather than 20; parentheses can express the intended grouping.
Students should not assume that all operators have one meaning for every value type. The + symbol joins strings or lists as well as adding numeric values. Identify both the operand types and the arithmetic precedence before evaluating a long expression.
4. True division gives a quotient
Using / performs true division and produces a floating-point result for ordinary numeric inputs. For 7/2 the result is 3.5. The notation is not the same as //, which performs floor division. A student who sees both symbols in one question should explain their difference explicitly.
Division by zero raises an error. A good trace checks the divisor rather than assuming every input is valid. In a general program, the appropriate response to zero depends on the requirements; a school problem may specify a nonzero denominator.
5. Floor division is not simple truncation
The expression 7//2 gives 3, while -7//2 gives -4. Floor division selects the greatest integer no greater than the mathematical quotient. For a negative quotient such as -3.5, that floor is -4 rather than -3.
This is one of the most useful numerical traps to practise. The rules for math.trunc() differ because truncation moves towards zero. On negative nonintegers, floor and truncation are not interchangeable. Check the direction on a number line before reporting the answer.
6. Modulo gives a remainder under Python’s convention
The % operator returns the modulo remainder. For 17%5, the result is 2 because 17 = 3*5 + 2. With a positive divisor, Python’s remainder is nonnegative even for a negative dividend: -5%2 is 1 because -5 = (-3)*2 + 1.
Modulo is useful in even/odd checks, periodic patterns and cyclic indexing. But it is not a substitute for the quotient, and behaviour with negative values must follow Python’s rule rather than an assumed school-division shortcut. A quick identity check is a = (a//b)*b + (a%b) for a nonzero divisor.
7. Powers and square roots
The ** operator raises a number to a power: 2**3 is 8. The built-in pow(2,3) also gives 8 under the relevant usage. math.sqrt(81) gives 9.0. A learner should distinguish square roots from ordinary division by two; sqrt(81) is not 40.5.
The math module must be imported before calling math.sqrt. For the real-number math.sqrt function, a negative input is outside its valid real domain and causes an error. Check the specified mathematical domain before trying to calculate an output.
8. Normal rounding has boundary subtleties
Python’s built-in round() rounds to the requested number of decimal places or to an integer when no ndigits is provided. In tie cases, Python generally uses a round-to-even rule for exact ties, so round(2.5) is 2 and round(3.5) is 4.
Binary floating-point representations can make decimal-looking halfway values difficult to interpret. Avoid claiming that every displayed decimal is stored exactly. Use unambiguous values to practise basic rounding, and explain when a task’s requested rounding convention differs from a casual ‘always round .5 up’ slogan.
9. Ceiling, floor and truncation differ
math.ceil(x) gives the smallest integer greater than or equal to x. math.floor(x) gives the greatest integer less than or equal to x. math.trunc(x) discards the fractional portion towards zero. At x=2.7, these are 3, 2 and 2.
At x=-2.7, the results are -2, -3 and -2. The negative case is essential. A student who memorises only positive examples may believe floor and truncation always agree; they do not. Draw the position of -2.7 on a number line and ask which integer lies immediately below it.
10. Import the module the function belongs to
The quick-reference guide identifies math.ceil, math.floor, math.trunc and math.sqrt as mathematical module functions, and random.randint and random.random as functions from the random module. A student can use import math and import random before calling those module-qualified names.
If code calls math.sqrt without importing math in the relevant environment, the name may not exist. A notebook with an earlier hidden import can mask this dependency. Running a clean, top-to-bottom notebook helps confirm that all required imports and variables are present.
11. range generates a sequence of integers
range(5) describes integers 0,1,2,3,4 when iterated. range(2,7) yields 2 through 6. range(2,10,3) yields 2,5,8. Its stop boundary is excluded, and its step tells the sequence how to advance.
The function is commonly used with for loops. It does not automatically print all the values just because it was created. The program must iterate through the range or otherwise use it. A zero step is invalid, and a positive step may yield nothing if the start is already beyond the stop.
12. Randomness is a possible-value rule, not a predicted result
random.randint(1,6) returns an integer from 1 through 6 inclusive when appropriately called. It may yield any value in that range; the function’s meaning does not tell us which value a particular run will return. Repeating the expression may produce the same or a different result.
random.random() returns a floating-point value at least 0.0 and less than 1.0 under the usual interface. A random example should state its range and type. Avoid hard-coding a fictional result as though the program must produce it. Real security-sensitive randomness has different requirements beyond this syllabus example.
13. Numeric input arrives as text
The built-in input() returns a string, even if a user types digits. If a program needs the integer 12, it may call int() on a suitable numeric string. float() converts suitable strings into floating-point values, while str() produces a string representation from a value.
A useful check distinguishes int(’12’) = 12 from str(12) = ’12’. Joining two strings gives textual concatenation, not arithmetic addition. If the input is invalid, conversion can raise an error rather than inventing a number. The assignment should define the required response to malformed input.
14. Floating point has representation limits
Many decimal fractions do not have exact finite binary floating-point representations. Consequently a result involving apparently simple decimals may display a tiny rounding discrepancy. This is a property of the number representation rather than proof that multiplication or division rules have changed.
For secondary-level exercises, use the given conventions and appropriate rounding, but do not promise exactness that the data type cannot provide. In a real measurement task, it is also important to distinguish the precision of the input measurement from the number of decimal places shown in the output.
15. Order of operations is part of a correct trace
Exponents, multiplication and division, and addition and subtraction follow defined precedence. For 2 + 3*4, multiplication happens first, giving 14. For (2+3)*4, the parentheses produce 20. In a longer expression, the student should mark the chosen grouping before evaluating individual numbers.
Be especially careful when negative signs, exponentiation and floor division appear together. A short hand-written trace can identify the intended intermediate results and prevent guessing. Parentheses make the code’s meaning easier to explain to another reader.
16. Connect numerical correctness with testing
A numerical programme may be correct for positive inputs yet fail on negative numbers, zero divisors or values on rounding boundaries. A good test set includes ordinary, boundary and error cases, derived from the requirements rather than merely whichever examples produce pleasant results.
When testing random output, do not require one exact draw; instead verify the permitted range and type under suitable repeated or controlled tests. When testing rounding, include negative inputs that expose the difference between ceil, floor and trunc. These are conceptually targeted tests, not decorations added at the end.
import math
import random
print(7 / 2) # 3.5
print(-7 // 2) # -4
print(-5 % 2) # 1
print(math.ceil(-2.7)) # -2
print(math.floor(-2.7))# -3
print(math.trunc(-2.7))# -2
print(list(range(2,10,3))) # [2, 5, 8]
print(1 <= random.randint(1,6) <= 6) # True
A twelve-stage numeric reasoning protocol
This independent eduKateSG teaching routine is not an official mark scheme. It guides learners through any unfamiliar expression by identifying types, choosing the correct arithmetic or rounding rule, and checking the result against a boundary case.
Stage 1 — Write the exact expression
Preserve negative signs, parentheses, decimal points and the distinction between / and //. A copied error can invalidate the entire trace.
Stage 2 — Name every input type
Decide whether an operand is an integer, floating-point number or string. A character sequence containing digits is not automatically numeric.
Stage 3 — Read the operator
Identify addition, subtraction, multiplication, division, floor division, modulo or exponentiation. Operators can behave differently across types.
Stage 4 — Resolve the grouping
Use parentheses and precedence before calculating individual values. If necessary, write the intermediate subexpressions explicitly.
Stage 5 — Check the denominator
A divisor of zero produces an error. Do not proceed as though a numerical result must always exist.
Stage 6 — Compute the quotient accurately
Use / for true division, but // for flooring the quotient. Pay special attention when the quotient is negative.
Stage 7 — Check modulo through an identity
For nonzero b, verify that a equals (a//b)*b+(a%b). This catches many mistakes with negative dividends.
Stage 8 — Identify the rounding direction
Distinguish round-to-nearest, ceiling, floor and truncation. Their results can differ for negative nonintegers.
Stage 9 — Check the function import
math and random functions require the corresponding names to be imported or otherwise made available in the executed environment.
Stage 10 — Interpret ranges and random outputs
Remember that range stops before its end, randint includes both limits, and random.random gives a value in a half-open interval.
Stage 11 — Convert types deliberately
Use int, float or str for the intended purpose and do not silently turn an identifier into an arithmetic quantity.
Stage 12 — Test a contrasting case
Use zero, a negative value, a halfway value or an alternative step to check whether the rule genuinely transfers.
Twelve original numerical worked cases
Worked case 1 — Two forms of division
7/2 returns 3.5 while 7//2 returns 3. The first gives the true quotient; the second floors it. The operator, not the appearance of the two integer operands, controls the result.
Worked case 2 — Negative floor division
-7//2 is -4 because -3.5 floors to -4. Simply deleting the fractional part would have produced -3, which is truncation towards zero rather than floor division.
Worked case 3 — A basic remainder
17%5 is 2 because 17 = 3*5 + 2. Check both the quotient and remainder rather than interpreting the symbol as a percentage operation.
Worked case 4 — Negative modulo
-5%2 is 1. Python uses floor division with quotient -3, so -5 = (-3)*2 + 1. The nonnegative remainder is consistent with a positive divisor.
Worked case 5 — Arithmetic precedence
2+3*4 is 14; (2+3)*4 is 20. Parentheses change which operation occurs first. The correct answer is not based on simply reading numbers from left to right.
Worked case 6 — An exponent
2**3 is 8 because it multiplies two by itself three times. It is not the same as 2*3, which gives six.
Worked case 7 — Square root
After importing math, math.sqrt(81) returns 9.0. The input is a perfect square, but the function returns a floating-point value for the standard real-valued computation.
Worked case 8 — Exact halfway rounding
round(2.5) is 2 and round(3.5) is 4 under Python’s ties-to-even rule for these exact halfway cases. The two examples disprove a blanket rule of always rounding halves upward.
Worked case 9 — Ceiling on a negative
math.ceil(-2.7) gives -2 because -2 is the smallest integer at least as large as -2.7. It is closer to zero than the original value.
Worked case 10 — Floor on a negative
math.floor(-2.7) gives -3 because -3 is the greatest integer not exceeding -2.7. It is different from both ceiling and truncation for this case.
Worked case 11 — Truncation on a negative
math.trunc(-2.7) gives -2 because it removes the fractional part towards zero. That differs from math.floor(-2.7), which gives -3.
Worked case 12 — Convert string to integer
int(‘007’) yields integer 7 while str(7) yields string ‘7’. An identifier whose leading zeros matter should not automatically undergo integer conversion.
Twelve additional calculations: ranges, randomness and boundaries
Worked case 13 — Simple range
range(5) produces the sequence of integer values 0 through 4 when iterated. It does not include five. A for loop over that range performs five iterations if the body executes normally.
Worked case 14 — Range with a start
range(2,7) yields 2,3,4,5,6. The start is included and the stop excluded, so the resulting count is five rather than six.
Worked case 15 — Range with a step
range(2,10,3) yields 2,5,8. The next value 11 would be beyond the excluded stop, so it is not generated.
Worked case 16 — An empty range
range(5,2) with its normal positive step contains no elements because it begins above the stop. Do not invent a descending sequence without a negative step.
Worked case 17 — Possible randint outputs
random.randint(1,6) can return any integer from 1 through 6 inclusive. A precise prediction of the next draw is not justified by the function’s specification.
Worked case 18 — Possible random outputs
random.random() produces a float at least zero and less than one. A result equal to one is outside the stated range, even though some results can lie very close to it.
Worked case 19 — A string from input
If a user types ’12’, input() returns the string ’12’. Without conversion, adding another string ‘3’ produces ‘123’, not fifteen.
Worked case 20 — Conversion of a decimal
int(3.9) gives 3, truncating towards zero; int(-3.9) gives -3. This is not the same as rounding to the nearest integer.
Worked case 21 — Float conversion
float(‘2.5’) gives the floating-point number 2.5 if the string has a suitable format. An invalid source such as ‘two’ causes a conversion error rather than being guessed.
Worked case 22 — A zero denominator
5/0 raises ZeroDivisionError. A complete algorithm must either rely on an explicit nonzero-input guarantee or define what to do when the divisor is zero.
Worked case 23 — A real square-root boundary
math.sqrt(0) returns 0.0, while math.sqrt(-1) raises ValueError for the real-domain function. A mathematical name does not override its defined input range.
Worked case 24 — Rounding towards zero
For -3.8, math.trunc returns -3. This differs from math.floor, which returns -4. The negative input reveals the directional difference clearly.
Connecting numerical ideas to reliable software
Fictional ticket groups and remainders
Suppose a fictional school event needs to arrange 17 paper tokens into groups of five. There are three complete groups and two tokens left, reflected by 17//5 = 3 and 17%5 = 2. The quotient and remainder answer different parts of the same practical question. The check 3*5+2 = 17 verifies the pair.
A second example with negative numbers should not be described as physical leftover tokens. For -5%2 the mathematical convention leads to remainder one, but a real scenario would need a careful definition of what a negative quantity means. Translating arithmetic into stories requires a sensible domain, not only a correct operator.
The importance of negative-number rounding
For x=-2.7, ceiling is -2, floor is -3 and truncation is -2. All three methods are understandable on a number line. Ceiling moves to the next integer upward, floor moves to the next integer downward and truncation removes the fractional part towards zero.
A student may know all three names yet use them interchangeably because positive examples conceal the distinction. Practise one positive and one negative number side by side. Explain how the result follows the definition rather than memorising a small table of outputs.
A random value is an uncertain observation
A teacher’s fictional simulation could draw an integer between one and six with randint. Each call returns a value allowed by the inclusive endpoints, but no individual call is guaranteed to produce a different value from the previous one. Randomness is not the same as cycling deterministically through all six numbers.
The right way to test such a function is to check its promised type and range, not insist that a single draw equal a number printed in a textbook. Repeated trials can be informative, but they still do not provide absolute proof of every implementation property. This subject’s emphasis is on understanding the API contract.
Rounding and reporting an observation
Suppose a fictional measurement is 2.746 units and the output requires two decimal places. The task needs a defined rounding method; ordinary nearest rounding would be expected to display about 2.75. However, printed decimal digits can differ from exact binary representation for some values.
A sound computational explanation also retains the unit and meaning of the measurement. Reporting more decimal places than the source accuracy supports can imply a false level of certainty. Software formatting and arithmetic correctness should be connected to honest communication about what was actually measured.
Input conversion and preserving identifiers
A synthetic class code ‘007’ looks numeric, but converting it with int produces 7, removing the two leading zeros. That is appropriate if the intended quantity is seven but unsuitable if the code’s three-character format matters. Data type choices carry semantic consequences.
A learner should ask what the input represents before converting it. A phone number, shelf label or school code is usually not something to add arithmetically. Numeric arithmetic is meaningful for quantities, whereas character strings preserve formatting. Correct programmes reflect the task’s domain, not just the appearance of digits.
Trace a two-stage numerical function
Imagine a programme reads a numeric value, computes a quotient and rounds it. The first step depends on successful conversion and a valid divisor. The second step depends on the chosen rounding method. An error in either stage changes the final output. A clear trace records types, mathematical intermediate results and the final representation.
For a novice, separating these stages is more reliable than writing a single long expression and guessing the printed result. It also allows independent tests of the conversion, divisor and rounding behaviour. When the output is surprising, locate the earliest step that diverges from the requirement.
Why a programme should test boundaries
An algorithm that works with x=2.7 can still fail with x=-2.7, and a division that works with divisor two may fail with zero. A range starting below its stop can produce items while an otherwise similar range starting above its stop may be empty. Boundaries expose the rules underlying the syntax.
Designing normal, boundary and error tests is part of the wider Computing curriculum. For this topic, use negative values, exact integers, zero divisors, omitted range endpoints and random-output ranges. A good answer identifies which condition it is testing and the expected behaviour.
What tutors should listen for
When a student answers ‘because Python does it that way’, ask for the definition of the operation. Why does -7//2 floor to -4? Why is -5%2 positive? Why can randint return either endpoint? Explaining the rule develops a more durable understanding than matching a memorised code screenshot.
Parents can support simple number-line practice and remainder checks without programming expertise. Students can then run the same expressions in a permitted Python environment, compare results and correct their own predictions. The goal is a transferable method, not certainty about one unpredictable random value.
Frequently asked questions
Why are / and // different?
The slash performs true division; double slash floors the quotient. For negative quotients, flooring and truncating towards zero are not identical.
Is % a percentage operator?
No. In Python arithmetic it gives a modulo remainder, tied to the floor-division relationship for integers.
Is 2**3 the same as 2*3?
No. Exponentiation gives eight, whereas simple multiplication gives six.
Does round always send .5 upwards?
No. Python’s exact halfway ties generally follow ties-to-even, and floating-point representation adds further considerations.
Does ceiling always make a number bigger in magnitude?
No. Ceiling moves toward the next higher integer. For -2.7 it returns -2, which has a smaller magnitude.
Does truncation mean floor?
Not always. For negative non-integers, truncation moves toward zero while floor moves downward.
Does range include the stop?
No. The ordinary range stop is exclusive, even when a step other than one is used.
Can randint return either endpoint?
Yes. The stated integer range includes both the lower and upper bounds.
Can random.random return exactly one?
No, its usual interval includes zero and excludes one.
Why use import math?
It makes the named module’s functions available to the executing program when the import has been performed.
Is input(‘Number: ‘) already numeric?
No. input returns a string, and conversion is needed if numerical arithmetic is required.
What should I check first in a long expression?
Identify types, grouping, operator meanings and boundary conditions before computing or formatting the final result.
A final transfer exercise
Take the invented expression (17//5, 17%5, -7//2, math.ceil(-2.7), math.trunc(-2.7)). Its values are (3, 2, -4, -2, -2) when the math module has been imported. The first pair describes complete groups and a remainder; the third uses a negative floor; the last two happen to agree because both choose -2 under their distinct rules. The agreement for one input does not establish that the operations are identical.
Next change -2.7 to +2.7. Ceiling becomes 3 while truncation becomes 2. The change exposes how the direction rules differ. Finally state the legal results of random.randint(2,4) without inventing a particular next value: 2, 3 and 4 are all possible. This exercise connects deterministic arithmetic, rounding definitions and uncertainty within one short revision session.
For an examination-ready explanation, accompany every value with its rule and any required assumption. A nonzero divisor, a correctly imported module, a valid conversion string and a specified rounding convention are parts of correctness. The most valuable outcome is a learner who can diagnose an unexpected result and check it independently rather than copying whichever number happens to appear on a screen.
Official 2027 syllabus and connected learning
Read the 2027 SEC G3 Computing K349 syllabus and Python quick reference, especially outcome 2.3.7. Related reading: Reference 367 — Python Lists, Reference 361 — Software Engineering, the MOE V3.0 Library and the immutable Clementi teaching standard.
Editorial review: 29 October 2026, Singapore. All cases are invented learning exercises. The transferable skill is to identify operator, input type, rounding direction and output range before trusting the result.
