Numeric Data Types
A numeric type is never simply good or bad. It is adequate or inadequate for a specific requirement, and the properties of the type are what you compare against that requirement.
A Count That Could Grow Too Large
Imagine a small program that keeps a running count of the items it processes. At the start the count is zero, and every time an item is handled the count goes up by one. Most of the time this looks like a simple task. The question that matters is not how to add one, but whether the place where the count is stored can hold the largest value the count will ever reach.
Every number a program stores lives in a numeric type, and each numeric type has properties of its own. Those properties decide what values the type can hold and how it behaves. A type that works well in one part of a program may be unsuitable in another, so picking a numeric type without looking at its properties is a guess. Before reading on, try to name what you would need to know about a number type before trusting it with a value that could grow very large.
Every Numeric Type Has Properties
Numeric type properties are the facts about a numeric type that determine which values it can hold and how it behaves when values are computed with it.
The key idea is that these properties can be checked. You do not have to rely on memory or on the assumption that a type is large enough. Once you know what the properties are, checking them turns a guess into a decision. A type is adequate when its properties cover the requirement of the task it has to perform. Adequacy is therefore always relative to a task: the same type can be adequate for one job and inadequate for another.
A numeric type is never simply good or bad. It is adequate or inadequate for a specific requirement, and the properties of the type are what you compare against that requirement.
Reading Properties Through numeric_limits
The properties of numeric types are accessible through numeric_limits. This is the mechanism for reading a type's properties directly. Rather than memorizing the limits of each type or assuming them, you ask numeric_limits for the information about the type you are using. The information it gives you is the raw material for the adequacy decision.
The diagram shows one lookup mechanism branching into several properties. The same mechanism serves every numeric type, so the question you ask does not change when you move from one type to another. What changes is the answer: each type reports its own properties. The values reported by numeric_limits are the ones you compare against your task's requirements, not values you should assume in advance.
What Happens Past the Maximum
Go back to the running count. Suppose the count has reached the largest value its type can hold. If the next increment produces a result above that maximum, the type cannot store that result as a correct value. The count stored in the variable no longer matches the true number of items processed. This is the situation the source warns about when it says a type that is not checked can go wrong quietly.
Read the diagram from left to right. The count sits at the type's maximum, the increment asks for a value one step beyond it, and the stored result is no longer a faithful record of the count. The important detail is that nothing in this sequence necessarily announces the error. The program keeps running with a wrong number, which is why the adequacy check has to happen before the program is trusted with real data.
What do you think happens?
A counter's type can hold values only up to its maximum. The counter already holds that maximum and is incremented once more. What should you expect the stored value to be?
Reveal answer
A value that does not match the true count, because the type cannot hold the result
A numeric type holds only the values its properties allow. An increment past the maximum produces a result the type cannot represent correctly, so the stored value is wrong rather than automatically corrected.
Why Checking Matters for a Task
The reason to check numeric type properties is that a type with a range or precision too small for the task's data produces a chain of consequences. First, the stored value stops matching the real value the program is supposed to represent. Second, every later computation that uses that value inherits the error. Third, the output of the program can look plausible while being wrong, so the failure may only be noticed much later, if at all.
Checking Adequacy Step by Step
The adequacy check follows a clear order. You begin by identifying what the task requires, then query the limits of the candidate type, then compare the two, and finally decide. The flowchart below lays out this sequence. If the type covers the requirement, you use it; if it does not, you choose another type and check again.
- 1Identify the requirement: state the range of values the task will produce and the precision it needs.
- 2Query the limits: use
numeric_limitsto read the properties of the candidate numeric type. - 3Compare: set the reported properties against the requirement and ask whether the type covers it.
- 4Decide: if the type covers the requirement, use it; if not, choose another type and run the check again.
Worked Example: A Running Count
Is the Count's Type Adequate?
A program counts items it processes. The count is expected to reach a value in the range the task needs. Decide whether the candidate numeric type is adequate, using the adequacy check.
- 1Identify the requirement
The count must hold every value it will realistically reach. That range is the requirement the type has to cover.
- 2Query the limits
Ask
numeric_limitsfor the properties of the candidate type rather than assuming them from habit. The reported maximum is the value to compare. - 3Compare
If the reported maximum is at least as large as the largest count the task can produce, the type covers the requirement. If it is smaller, the count will overflow.
- 4Decide
When the type covers the requirement, keep it. When it does not, select a numeric type with a larger range and run the same check on that type.
The type is adequate only if its queried maximum covers the largest count the task will reach. The decision rests on the comparison, not on the type's reputation or on what was used in an earlier program.
Mistakes to Avoid When Choosing a Type
Common mistake Choosing a numeric type from habit
What it looks likeUsing the same type in every program because it worked in the last one.
Why it failsEach numeric type has properties of its own, and a type that suits one task may not suit another. Habit does not check the requirement.
Do this insteadIdentify the requirement of the current task and check the candidate type's properties against it.
Common mistake Assuming the limits instead of checking them
Why it failsThe source emphasizes that you should not need to know the properties from memory or assume them. Assumptions are where the quiet errors come from.
Do this insteadUse numeric_limits to read the properties of the type you actually use.
Common mistake Checking once and never again
Why it failsThe adequacy of a type depends on the requirements of the task. When those requirements change, the earlier decision may no longer hold.
Do this insteadRecheck the numeric type's properties whenever the task's requirements change.
Rechecking When Requirements Change
Treat the adequacy check as part of maintaining a program, not only as part of writing it. If the data a program receives grows, if the precision a calculation needs becomes finer, or if the count is expected to run for longer, the earlier answer to the adequacy question may no longer be correct. Repeat the check against the new requirement, reading the properties again through numeric_limits.
Practice the Adequacy Check
A program stores a running total of sales. Yesterday the largest total was small enough for the type in use. Today the business expects totals many times larger. Walk through the four adequacy steps: state the new requirement, query the limits of the current type, compare, and decide. What do you conclude, and what would you do next?
Hints
- Start by writing the new requirement as a range of values the total must hold.
- Ask whether the current type's queried maximum still covers the new range.
- If it does not, think about what the decision says about the type you use, and check the next candidate the same way.
Key Takeaways
- The properties of numeric types, such as their range and precision, determine what values a type can hold and how it behaves.
numeric_limitsgives access to these properties, so you can check them instead of assuming or memorizing them.- A type is adequate when its properties cover the requirement of the task, and that check must be repeated whenever the requirements change.
- Checking the requirement, querying the limits, comparing, and deciding turns an unexamined guess into a justified choice of numeric type.