Python Part I · Module 2 · Variables and Data Types
Whole Numbers and Decimals
Python has two number types you will use constantly, and the difference between them is not about size. It is about whether the value can have a fractional part. Counts of things — errors found, tests run, seeds — are whole numbers. Measured quantities — a runtime in seconds, a clock period, a voltage — generally are not. This chapter establishes both, shows how Python decides which one you have created, and answers the question every beginner asks within about five minutes of meeting them, which is why dividing ten by four gives 2.5 when both of the numbers involved were whole. It closes with the one genuinely surprising thing about decimal arithmetic, kept short and stated accurately, because meeting it by accident in a report is worse.
Foundation9 min readPythonPart IFundamentalsNumbersintfloat
Part I · Module 2 · Chapter 2.6 · Whole Numbers and Decimals
1. Two Kinds of Number
error_count = 3
runtime_s = 182.4
print(error_count)
print(runtime_s)3
182.43 is a whole number. Python calls this type int, short for integer.
182.4 has a fractional part. Python calls this type float, short for floating-point.
The everyday guide is straightforward:
intfor things you count. Errors found, tests run, seeds, retries. You cannot have 3.5 errors.floatfor things you measure. Runtime, frequency, voltage, slack. A measurement is rarely exactly whole.
2. How Python Decides Which You Get
This is the part that is easy to state wrongly, so it is worth being exact.
It is not the size of the number. It is not whether the value happens to be whole. It is how you write it.
a = 5
b = 5.0
print(a)
print(b)5
5.05 and 5.0 are the same quantity. They are not the same value to Python: a is an int, b is a float. The decimal point in the source is what creates a float, whether or not there is anything after it.
Notice the output confirms it — b printed as 5.0, not 5. Python is telling you which type it has.
3. Why 10 / 4 Is 2.5
Here is the question everyone asks.
print(10 / 4)2.5Both 10 and 4 are whole numbers, so why is the answer not whole?
Because / in Python always produces a float. It is division in the ordinary arithmetic sense, and ordinary arithmetic on whole numbers frequently produces a fraction. Python does not throw the fraction away.
This is true even when the result divides exactly:
print(10 / 5)2.02.0, not 2. The division produced a float, and it printed as one. That trailing .0 is Python telling you the type, and it is not a mistake.
4. Whole Numbers Have No Practical Limit
Worth knowing, because it differs from most languages an engineer will have met.
big = 99999999999999999999999999
print(big)99999999999999999999999999There is no 32-bit or 64-bit ceiling on a Python int. It grows as needed, limited only by available memory.
If you have written C or SystemVerilog, this is a genuine difference: there is no wraparound, no overflow, and no width to declare. A counter cannot silently roll over to zero.
Floats are different — they do have limits and a fixed precision, which is §5.
5. The One Surprise Worth Knowing
Try this:
print(0.1 + 0.2)0.30000000000000004That is not a bug in Python. It is not a bug at all.
Floats store values in binary, and some perfectly ordinary decimal fractions — 0.1 among them — have no exact binary representation, in the same way that one third has no exact decimal representation. The stored value is extremely close but not exact, and occasionally the difference becomes visible.
Every language using the same floating-point representation behaves identically. C does this. SystemVerilog's real does this.
What this means in practice, for now:
- For counting, use
int. There is no imprecision there at all. - For measured quantities,
floatis correct and the imprecision is far below anything you would care about. - Do not be alarmed when a report shows
182.43999999999997instead of182.44. Nothing is broken; the value is simply being printed in full.
6. Which to Use
| The fact | Type | Example |
|---|---|---|
| how many errors were found | int | error_count = 3 |
| which seed was used | int | seed = 4210 |
| how many tests ran | int | total_tests = 600 |
| how long it took, in seconds | float | runtime_s = 182.4 |
| clock frequency in MHz | float | clock_mhz = 500.0 |
| supply voltage | float | voltage = 0.8 |
clock_mhz = 500.0 is worth a note. The value is whole, but frequency is a measured quantity that could reasonably be 499.8, so writing it as a float says something true about the kind of thing it is. Either would work; the float is more honest.
7. Predict, Run, Observe
Predict each line's output exactly — including any trailing .0.
print(7)
print(7.0)
print(10 / 4)
print(10 / 5)
print(100)
print(1 / 3)7
7.0
2.5
2.0
100
0.3333333333333333The last one is §5 again — one third cannot be written exactly, so Python shows as much as it holds. Nothing is wrong.
8. Exercise
Exercise 1 — choose the type. For each, say int or float and write an assignment with a good name: (a) the number of failing tests; (b) the measured slack in nanoseconds; (c) the number of seeds in a sweep; (d) a supply voltage; (e) a retry limit.
Exercise 2 — predict the trailing zero. Before running, say which of these print with a .0 and which do not:
print(6 / 3)
print(6)
print(6.0)
print(9 / 2)Exercise 3 — the same quantity, two types. Write two names, one holding 500 and one holding 500.0, and print both. They represent the same quantity. Describe in one sentence what the output tells you that the values alone do not.
Exercise 4 — explain the surprise. A colleague reports that Python "got the arithmetic wrong" because 0.1 + 0.2 did not give 0.3. Answer them in two sentences, without using the word "bug", and say where the fix belongs.
9. Summary
intis for whole numbers,floatfor numbers with a fractional part.- How you write the value decides the type, not its size and not whether it happens to be whole.
5is anint;5.0is afloat. /always produces a float, even when the division is exact —10 / 5is2.0.- Python integers have no practical size limit. No width to declare, no overflow, no wraparound.
- Floats are slightly imprecise for some decimal fractions, in every language that uses the same representation.
0.1 + 0.2showing0.30000000000000004is correct behaviour. - Count with
int, measure withfloat, and treat the number of displayed decimal places as a formatting question for Module 4.
Two number types down. The next chapter covers the third, which Python provides, almost no engineering script needs, and you should be able to recognise anyway.
Where this fits
Part of the Python curriculum.
