base-n

User guide

How it works

Read this part and the rest of the app explains itself.

The app holds exactly one thing: a pattern of bits, as wide as you say. Every panel on the page is a different way of looking at that same pattern — as a binary string, as a decimal number, as a float, as bytes in memory.

Change it anywhere and everything else follows. Type a hex digit, click a bit, run a calculation: the value moves in one place and every panel redraws from it. Because nothing is converted twice, no two panels can ever disagree with each other.

Two settings decide how that pattern is read: data width, which says how many bits there are, and representation, which says what they mean. Everything else on the page follows from those two.

The console

The strip of settings under the title.

Data width

Anything from 4 to 256 bits. Use a preset button, or type an exact number in the box — 12, 24 and 48 are all legal. In the two float modes the width is fixed by the format, so the box is disabled.

Changing the width keeps the value where it can:

  • Widening preserves the value. In Signed mode the sign bit is extended, so -1 in 8 bits (1111 1111) becomes -1 in 16 bits (1111 1111 1111 1111), not 255.
  • Narrowing drops the high bits. If the value no longer fits you get an overflow indicator telling you what was kept.

Representation

Four ways to read the same bits. Note what the decimal field means in each — in the float modes it is the value, while binary, octal and hex are the stored bit pattern.

ModeDecimal fieldBinary / octal / hexRangeWidth
Unsignedthe valuethe same value0 … 2n−14–256
Signedthe value, two's complementthe stored bit pattern−2n−1 … 2n−1−14–256
Float32the real valuethe stored bit pattern±3.4×103832, fixed
Float64the real valuethe stored bit pattern±1.8×1030864, fixed

Switching between modes does one of two things, and the difference matters:

  • Between Unsigned, Signed and a float mode, the bit pattern is kept — a reinterpret cast. The unsigned 32-bit value 42 becomes 5.9e-44 in Float32, because that is genuinely what those bits mean as a float. This is the useful direction for reading a raw register dump.
  • Between Float32 and Float64, the value is kept and re-encoded. A single-precision 0.1 becomes the double nearest to it.

Display options

OptionOffOn
Zero padding10101100101011 — padded to the full width
Group digits001010110010 1011 — nibbles in binary and hex, threes in octal and decimal
Uppercase hexdeadbeefDEADBEEF

These change how values are written, never what is stored. Grouping separators are ignored when you type, so you can paste a grouped value straight back in.

Entering values

Type in any of the four fields; the other three follow on every keystroke.

You can typeExampleNotes
Plain digits2ACase doesn't matter
A base prefix0x2A 0b1010 0o755Must match the field you're in
A trailing marker2Ah 1010bAssembler style
Separators1010 1011 1_000_000 3,000Spaces, underscores, commas and apostrophes are ignored
A leading sign-42 +42Negatives belong in Signed mode
Exponent notation6.022e23Decimal field, float modes only
Named valuesinf -inf nan pi eDecimal field, float modes only

A red outline with a message under the field means the text isn't valid for that base — a 2 in the binary field, say. Nothing is stored until it parses.

Press Enter to normalise a field: it is rewritten with your current padding, grouping and case settings. Copy puts exactly what you see on the clipboard, separators and all.

The readout

The strip of facts under the four fields.

FactShown inMeans
Unsignedinteger modesThe pattern read as a plain magnitude. Highlighted when it is the active reading.
Signedinteger modesThe same pattern read as two's complement. Both are always shown, so you can see at a glance that 0xFF is either 255 or −1.
Bits setall modesPopulation count — how many 1 bits, out of the width.
Highest set bitinteger modesIndex of the topmost 1, or for zero. One less than the number of bits the value actually needs.
Rangeinteger modesThe smallest and largest value this width and mode can hold.
Valuefloat modesThe shortest decimal that round-trips back to these exact bits.
Classfloat modesNormal, Subnormal, Zero, Infinity or NaN.
Bit patternfloat modesThe stored bits as hex, for pasting into a debugger.

The overflow indicator

An Overflow badge appears in the Conversion header whenever the value you entered cannot be held.

A red bar under the fields says what was kept instead, and the field you typed in is outlined. It clears as soon as you enter a value that fits. Four things set it off:

What you didWhat the app says
Typed a value wider than the register — 300 at 8 bits300 needs more than 8 bits — only the low 8 are kept, leaving 44.
Narrowed the width below the value it was holding1 000 does not fit in 8 bits — the register now holds 232.
Typed a negative in Unsigned mode — -5 at 8 bits−5 is negative, which unsigned cannot represent — stored as two's complement, which reads back as 251.
Typed a float past the format's range — 1e39 in Float321e39 is beyond the single-precision range — stored as infinity.

The value is still stored in every case — wrapped, truncated or saturated to infinity, exactly as hardware would. The indicator tells you that what came out is not what you put in.

The bit field

The register drawn out bit by bit.

Bits run from the most significant on the left to bit 0 on the right, in rows of 16 (8 on a narrow screen). The numbers in the margins are the bit indices at each end of the row, and the small gaps fall on byte boundaries. Click any bit to flip it — every other panel updates as you do.

In the float modes each bit is tinted by the field it belongs to, and the coloured underline shows how far each field reaches even where the bits are zero.

ToolDoes
ClearAll bits to 0.
InvertOne's complement — every bit flipped.
Set allAll bits to 1: the unsigned maximum, or −1 in Signed.
Shift ‹Left one place. The top bit falls off the end.
Shift ›Right one place. Arithmetic in Signed mode, so the sign is preserved; logical otherwise, so a 0 comes in at the top.
RandomFills the whole width with random bits — handy for exercising a decoder.

IEEE-754 decomposition

Appears in the Float32 and Float64 modes.

A float is three fields packed into one word: a sign bit, a biased exponent and a mantissa. For -22.5 in Float32 (0xC1B40000) they come out like this:

1sign · bit 31
1000 0011exponent · bits 30–23
011 0100 0000 0000 0000 0000mantissa · bits 22–0

The panel reads each one back for you. The sign bit is 1, so the number is negative. The exponent field holds 131; subtract the bias of 127 and the real exponent is 4. The mantissa is 0x340000, which with its implied leading 1 makes a significand of 1.40625. Put together: (−1)1 × 24 × 1.40625 = −22.5.

The exponent field is also how you tell the classes apart, which is worth knowing when you are staring at a bit pattern:

Exponent fieldMantissaClassMeaning
all zeroszeroZero±0 — the sign bit still distinguishes them
all zerosnon-zeroSubnormalGradual underflow: no implied leading 1, fixed exponent
all oneszeroInfinity±∞
all onesnon-zeroNaNQuiet if the top mantissa bit is set, signalling if not
anything elseanyNormalImplied leading 1, exponent minus bias

Two facts underneath are worth singling out:

  • Exact decimal is the value in full, every digit of it. A binary float always terminates in decimal, so this is not a rounded display — it is why single-precision 0.1 reads as 0.100000001490116119384765625. This is the number your program is actually working with.
  • Step to next value is the gap to the next representable float — one unit in the last place. It is how much precision you have left at this magnitude, and it grows as the value does.

Memory layout

The same value as bytes, in both byte orders.

Addresses run left to right from 0, so each row reads in the order the bytes appear in memory. Big-endian puts the most significant byte first; little-endian puts the least significant byte first, which is what x86 and ARM do by default. The highlighted byte is the one holding bit 0 — last in big-endian, first in little-endian.

So 0xC1B40000 is stored as C1 B4 00 00 on a big-endian machine and 00 00 B4 C1 on a little-endian one. Reading a memory dump from the wrong end is the usual reason a float comes out as nonsense.

Widths that are not a whole number of bytes are padded up with zeros at the top, and the panel says so.

Arithmetic

Both operands are read at the current width and representation.

Each operand has its own base selector, so you can add a hex value to a decimal one without converting first. Load converter value into A pulls in whatever the converter is holding; Send result to converter pushes the answer back. Press Enter in either operand to calculate.

Integer division truncates toward zero, so −7 ÷ 2 is −3, not −4, and mod takes its sign from the left operand. Dividing by zero is refused in integer modes; in the float modes it produces infinity, as IEEE-754 requires.

The result is shown in all four bases at once, and flags appear as chips:

ChipMeans
overflowThe true answer doesn't fit the width. An Exact (unbounded) row appears alongside the wrapped result so you can see both.
carryUnsigned addition carried out of the top bit.
borrowUnsigned subtraction went below zero.
operand overflowOne of the operands you typed didn't fit before the sum even started.
nanAn undefined float operation, such as 0 ÷ 0 or ∞ − ∞.
div0Float division by zero — the result is ±infinity.

Float arithmetic is rounded to the working precision after every step, which is why 0.1 + 0.2 lands exactly on 0.3 in Float32 but gives 0.30000000000000004 in Float64. Switch between the two modes and run it again to watch it happen.

Worked examples

Five things people actually come here to do.

See how −1 is stored in a 16-bit register

  1. Set the width to 16 and the representation to Signed.
  2. Type -1 in the decimal field.

Every bit lights up: FFFF. The readout shows the same pattern read as unsigned — 65 535 — which is what your code would print if the variable were declared unsigned by mistake.

Find out why 0.1 + 0.2 isn't 0.3

  1. Choose Float64.
  2. Type 0.1 in the decimal field and read the Exact decimal fact.
  3. In Arithmetic, set A to 0.1, B to 0.2, and calculate.

0.1 is stored as 0.1000000000000000055511151231257827…, and the sum comes out as 0.30000000000000004. Switch to Float32 and run it again: there the error falls below the precision available and you get exactly 0.3.

Check whether an 8-bit addition overflows

  1. Set the width to 8 and pick Unsigned or Signed.
  2. In Arithmetic, enter the two operands and calculate.

200 + 100 unsigned gives 44 with overflow and carry chips, and an Exact (unbounded) row showing the 300 that didn't fit. The same sum in Signed wraps differently — that is the whole point of checking both.

Decode a little-endian memory dump

  1. Set the width to match the field — 32 bits for four bytes.
  2. Reverse the dumped bytes and type them into the hex field: a dump of 00 00 B4 C1 becomes C1B40000.
  3. Check the Memory layout panel — its little-endian row should match your dump exactly.

Now switch to Float32 and the same bytes read as −22.5. That round trip is the fastest way to confirm you have the byte order right.

Build a bit mask by hand

  1. Set the width you need and choose Unsigned.
  2. Press Clear, then click the bits you want set.
  3. Copy the hex field.

The bit indices in the margins are the same numbers you would put in a shift, so a bit clicked at index 12 is the mask 1 << 12.

Good to know

Keyboard

KeyWhereDoes
TabanywhereMoves through every control, including each bit. The focus outline is always visible.
Entera conversion fieldNormalises what you typed to the current display settings.
Enteran operand fieldRuns the calculation.
Spacea bitFlips it.

What is remembered

Your width, representation, display options, current value and colour theme are saved in this browser and restored when you come back. Clearing site data resets everything to a 32-bit unsigned zero. Nothing is stored anywhere else.

Small print

  • Everything runs in this tab. No value you type is sent anywhere, and the app works offline once loaded.
  • Integer maths is exact at any width — a 256-bit multiply is computed in full before it is wrapped into the register.
  • Float maths uses your machine's own IEEE-754 arithmetic rather than a simulation of it, so results match what your compiler would produce.
  • In the decimal field of a float mode, e on its own means Euler's number. Exponent notation needs a mantissa in front of it — 1e5, not e5.

Open the converter