The Arduino map() Function, Explained

By Anatolie · Updated 2026-09-03

Arduino's map() re-scales a number from one range to another. It's the standard way to turn a 0–1023 analog reading into a 0–255 PWM value, a 0–180 servo angle, or a percentage. It's also a frequent source of quiet bugs, because it does integer maths and doesn't clamp its output.

What it computes

long map(long x, long in_min, long in_max, long out_min, long out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

It's a linear transformation: find where x sits as a fraction of the input range, then place it at the same fraction of the output range. map(512, 0, 1023, 0, 255) is (512 × 255) / 1023 = 127.

0 1023 512 0 255 127
512 sits at the same fractional position (about 50%) on 0–1023 as 127 does on 0–255 — that fraction is all map() computes.

The Arduino map() calculator evaluates it for any set of five values so you can check a call before flashing.

Trap 1: integer truncation

Every operation is integer. The division truncates toward zero — it does not round. map(20, 0, 100, 0, 3) is (20 × 3) / 100 = 60 / 100 = 0, not 1. Across a full sweep this means the output steps unevenly and rarely reaches the top of its range until the very last input value. If you map 0–1023 to 0–100, you get 100 only at exactly 1023; 1013 already gives 99.

If you need rounding or a smooth fractional result, don't use map() — do the maths in float:

float pct = (x - 0.0) * (100.0 - 0.0) / (1023.0 - 0.0);

Trap 2: no clamping

map() happily extrapolates. If x is outside in_min..in_max, the result goes outside out_min..out_max — which can send a servo past its limit or wrap a byte. Always follow it with constrain():

int angle = constrain(map(sensor, 100, 900, 0, 180), 0, 180);

Trap 3: overflow

The intermediate product (x - in_min) * (out_max - out_min) is computed as a long (32-bit). It's usually fine, but with large ranges it can overflow — e.g. mapping a microsecond count in the millions to another large range. If your numbers are big, scale them down first or use 64-bit maths.

Trap 4: reversed ranges are fine, zero-width ranges are not

You can reverse direction: map(x, 0, 1023, 255, 0) inverts the reading, which is useful for a sensor wired backwards. But if in_min == in_max the function divides by zero and the result is undefined — guard against a flat input range.

Reversing a map()

To go back the other way, swap the input and output pairs: if y = map(x, a, b, c, d), then x ≈ map(y, c, d, a, b). It's only approximate because truncation isn't reversible — you won't always recover the exact original x.

When map() is the wrong tool

  • Non-linear sensors. A thermistor or a log-taper pot isn't linear, so a straight-line map() is wrong across the range. Use a lookup table or the sensor's actual equation.
  • You need precision. Truncation loses up to one unit per call. For anything cumulative, use floats.
  • Calibration drift. If in_min/in_max are "what I measured once", re-measure — a mapped value is only as good as its endpoints.

For converting an ADC count to an actual voltage rather than an arbitrary range, use the analog voltage calculator. For plain proportion maths off the board, the percentage calculator and the percentages guide.