6  Number Systems and Data Units

Binary, Decimal, Hexadecimal, Bytes, Ranges, and Overflow

fundamentals
data
rep
number

6.1 In 60 Seconds

Computers store every value as bits, but people read and write numbers in several notations. Binary, decimal, and hexadecimal are three ways to write the same quantity, and a data type is a fixed-width container with a known range. Choosing the right notation to read a value, and the right width to store it, prevents a large class of IoT bugs where a number is technically present but quietly wrong.

6.2 Start With the Story

Start with a tiny payload that says 0x01F4, where one team reads 500 and another reads the wrong value because the width, order, or encoding was never written down. The core idea in Number Systems and Data Units is simple: data representation turns bits into agreed meaning through units, signedness, byte order, text encoding, and payload contracts. This page focuses that idea on IoT data representation binary, decimal, hexadecimal, bit and byte units, fixed-width integer ranges, signedness, overflow. In everyday IoT, a meter reading, firmware flag, topic name, or diagnostic string is only trustworthy when both sender and receiver decode it the same way. Start simple: write the value, its units, its byte width, and the decoding rule before adding clever packing or optimization.

6.3 Same Quantity, Different Notation

A length of two meters is the same length whether you write it in meters or in feet; only the label changes. Number bases work the same way. The quantity eighty can be written as 80 in decimal, 0x50 in hexadecimal, or 01010000 in binary. The amount never changes, but the notation does, and reading one notation as if it were another is a common mistake.

The important idea is that a digital field has a fixed size, and that size is a budget. Eight bits can hold exactly 256 different values. Choosing a data type means choosing how many values a field can ever represent, and what happens when a value tries to exceed that limit.

Three views of the same sensor reading shown as decimal 42 for people, binary 00101010 for machine state, and hexadecimal 0x2A for compact debugging.
Decimal, binary, and hexadecimal are different views of the same value; the right notation depends on whether a person, a machine, or a debugging workflow needs to read it.
Binary byte diagram showing bit 7 through bit 0, their powers of two, the most and least significant bits, and the unsigned byte range from 0 to 255.
A byte is a fixed eight-bit budget; the bit positions set the powers of two that determine range, overflow behavior, and whether a field needs a larger type.

That byte budget is why a counter, status field, or scaled sensor value must be sized before it is trusted. If a value can need bit 8, an 8-bit field cannot represent it; the next storage width is part of the data contract, not an implementation detail.

The core rule is simple: binary is how hardware stores values, hexadecimal is the compact human shorthand for those bits, and decimal is what people usually read. Always confirm which notation you are looking at before trusting a number, and remember that every field has a maximum it cannot exceed.

Hexadecimal is popular because it lines up neatly with bits: one hex digit is exactly four bits, so two hex digits describe one byte. That tidy mapping is why register dumps, MAC addresses, and packet hex views are written in hexadecimal rather than decimal.

Consider a status byte printed by a sensor board as 0xA6. The first step is not to read it as decimal one hundred six; the prefix says it is hexadecimal. Split it into nibbles: A is binary 1010, and 6 is binary 0110, so the byte is 10100110. If the firmware documentation says bit 7 means “fault present,” bit 5 means “battery low,” bits 2-1 encode the operating mode, and bit 0 means “sample ready,” the same byte becomes a field map. The notation did not change the value; it made the byte practical to inspect without writing eight separate bits.

flowchart TD
  A["Hex dump shows 0xA6"] --> B["Split into nibbles: A and 6"]
  B --> C["Map each nibble to bits: 1010 0110"]
  C --> D["Apply the field definition"]
  D --> E["Fault bit, battery bit, mode bits, ready bit"]
  E --> F["Choose storage width and decoding rules"]

The One-Minute View

Binary is the storage

Hardware holds values as bits. Everything else is a more readable way of writing the same bits.

Hex is the shorthand

One hex digit equals four bits, so hexadecimal is the compact, exact view used for bytes and registers.

Width is a budget

A field’s bit width fixes its range. Pick a type that fits the values you expect, with room to spare.

Beginner Examples

  • The hex byte 0x50 is decimal 80, because the digit 5 is in the sixteens place: five times sixteen plus zero.
  • A single byte can hold 256 distinct values, written as 0 to 255 unsigned.
  • The binary number 1111 is decimal 15, which is exactly one hexadecimal digit, 0xF.

Byte Range Knowledge Check

The next design move is to connect that byte budget to an actual field range, signedness, and scale.

6.4 Apply It: Choose a Data Type That Fits

Choosing an integer type is a budgeting decision. Pick the smallest width that comfortably holds every value the field can take, including the extremes, with a margin for growth. Too small risks overflow; needlessly large wastes bytes on constrained links.

Walkthrough: Sizing a Field

  1. State the value range. Find the minimum and maximum the field can ever hold, including error and boundary cases.
  2. Decide signedness. If the value can be negative, you need a signed type, which spends one bit on the sign.
  3. Apply any scaling. If you store a fraction as a scaled integer, scale the range too. Tenths of a degree multiplies the range by ten.
  4. Pick the smallest fitting width. Choose the standard width whose range covers the scaled, signed range with margin.
  5. Record the choice. Document width, signedness, scale, and units so every system decodes the field identically.

Common Widths and Ranges

Width
Unsigned Range
Signed Range
Typical IoT Use
8-bit
0 to 255
-128 to 127
Status codes, small counters, single flags.
16-bit
0 to 65535
-32768 to 32767
Scaled sensor readings, medium counters.
32-bit
0 to 4294967295
-2147483648 to 2147483647
Timestamps, large counters, identifiers.

Worked Example: A Scaled Temperature Field

A sensor reports temperature from -40.0 to 125.0 degrees, stored in tenths of a degree. Scaling by ten gives an integer range of -400 to 1250. Because the low end is negative, the field must be signed. A signed 8-bit type only reaches -128 to 127, far too small. A signed 16-bit type spans -32768 to 32767, which comfortably covers -400 to 1250 with large margin, so signed 16-bit is the smallest safe fit.

range -40.0 .. 125.0 C, stored as tenths
  scaled integer range: -400 .. 1250
  signed 8-bit  (-128 .. 127)    -> too small
  signed 16-bit (-32768 .. 32767) -> fits with margin  [choose this]

Incremental Practice

Beginner

Convert 0x2A to decimal and to binary, and confirm all three notations describe the same quantity.

Intermediate

A counter must hold up to fifty thousand events before reset. Decide whether unsigned 16-bit is safe and justify the margin.

Advanced

A field stores a voltage from 0.00 to 3.30 volts in hundredths. Choose a width and signedness, and explain why a smaller type would fail.

Type Sizing Knowledge Check

A field-size decision is complete only when the range, signedness, scale, and margin are written into the data contract.

6.5 Under the Hood: Ranges, Signedness, and Overflow

The selection rules above come straight from positional notation and modular arithmetic. Understanding them lets you predict exactly what a field can hold and what happens when it cannot.

Positional Value

In any base, a digit’s contribution is the digit times the base raised to its position. The hex byte 0x50 is the digit 5 in the sixteens place plus 0 in the ones place:

0x50 = (5 x 16) + (0 x 1) = 80
0xFF = (15 x 16) + (15 x 1) = 255
binary 1111 = 8 + 4 + 2 + 1 = 15 = 0xF

Range Formulas

For a width of N bits, the representable ranges are fixed:

unsigned:  0 .. 2^N - 1
signed:   -2^(N-1) .. 2^(N-1) - 1   (two's complement)

Signedness costs one bit of magnitude, which is why a signed 8-bit field reaches 127 instead of 255. The negative side reaches one further than the positive side, to -128, because zero occupies one of the non-negative codes.

Overflow Is Modular, Not Saturating

When arithmetic exceeds a field’s range, the result wraps around modulo 2 to the power N rather than clamping at the limit. This is silent: no error is raised, and the next value can be a sudden jump in the opposite direction.

unsigned 8-bit: 255 + 1 -> 0        (wraps to minimum)
signed   8-bit: 127 + 1 -> -128     (wraps to minimum)
unsigned 16-bit: 65535 + 1 -> 0

This behavior explains counters that appear to reset, timers that jump backward, and accumulators that suddenly turn negative. The fix is to choose a width with headroom, or to detect and handle the wrap deliberately.

Hex and Nibble Alignment

Because four bits form one hexadecimal digit, conversion between binary and hex is grouping, not calculation. Split the bits into groups of four from the right and map each group to one hex digit. This is why hex dumps are the natural way to inspect packed fields and bit flags.

Decision
Question
Evidence
Failure If Wrong
Base
Is the value decimal, hex, or binary?
Notation prefix or documented format.
Every value off by a fixed factor.
Width
Does the type cover the full value range?
Minimum and maximum, including extremes.
Silent overflow and wraparound.
Signedness
Can the value be negative?
Sign convention documented per field.
Negative values read as large positives.
Scale
Is a fraction stored as a scaled integer?
Scale factor and units recorded.
Values off by the scale factor.

Common Pitfalls

  1. Reading hex as decimal. Without confirming the base, 0x20 can be mistaken for 20 instead of 32.
  2. Choosing a type at its edge. A field at the edge of its range overflows on the first larger-than-expected value.
  3. Forgetting the sign bit. A signed type holds half the positive range of an unsigned type of the same width.
  4. Ignoring scaling in the range. Storing tenths multiplies the integer range by ten, which can push a value past a small type’s limit.

Overflow Knowledge Check

In production, number systems are about budgets and boundaries. Confirm the base before reading, size each field with margin, document signedness and scale, and treat overflow as a designed-for case rather than a surprise.

6.6 Summary

  • Binary, decimal, and hexadecimal are three notations for the same quantity; always confirm which one you are reading.
  • Hexadecimal aligns with bits because one hex digit equals exactly four bits, which is why bytes and registers are shown in hex.
  • A data type is a fixed-width budget: an N-bit unsigned field holds 0 to 2^N minus 1, and a signed field holds -2^(N-1) to 2^(N-1) minus 1.
  • Signedness costs one bit of magnitude, so a signed 8-bit field reaches 127, not 255.
  • Choose the smallest width that fits the full, scaled, signed range with margin.
  • Overflow wraps around silently rather than clamping, which causes counters and timers to jump unexpectedly.
Key Takeaway

Reading a number starts with knowing its base, and storing a number starts with knowing its range. Pick a width that fits every value with headroom, document signedness and scale, and plan for overflow instead of being surprised by it.

6.7 See Also

Data Representation Fundamentals

See how number systems fit into the wider decode contract for IoT fields.

Bitwise Operations and Endianness

Use masks, shifts, and byte order to pack and unpack the fields you already sized.

Binary Data Formats for IoT

Apply ranges and widths to CBOR, Protobuf, and custom binary payloads.