Operators

Percentage (%)

Implemented; no recorded answers are attributed to this entry

How we measure this · See the Rust code

No local names are recorded for this entry.

What it does

number%

A% converts its operand to a number and returns that number scaled by one hundredth. 50% is 0.5; A1% is a hundredth of whatever A1 holds.

The interesting content is in the word "scaled", because binary64 gives two inequivalent spellings of it:

  • x / 100 — divide by an exactly representable integer, one rounding.
  • x * 0.01 — multiply by the double nearest to one hundredth, which is not one hundredth, and then round.

These do not agree for every x. The literal 0.01 is already a rounded approximation, so the multiplication rounds twice in effect; the division rounds once against an exact divisor and is the more accurate of the two. For most operands both spellings land on the same double, and for some they do not — which makes this a real, if small, last-bit question about a function whose definition looks trivial.

The percent format is a separate thing entirely. Formatting a cell as a percentage changes how a number is displayed and how typed input is interpreted by the host; % as an operator changes the value. A cell holding 0.5 formatted as a percentage shows 50% without this operator ever running. Chapter 01's rule applies: dates, currency and percentages are numbers wearing formats.

Arguments

PositionNameMeaning
0AThe operand to scale. Required.

Arity is exactly 1; no optional arguments, no defaults. The operator is postfix — it follows its operand — which makes it the only member of the arithmetic family with that shape.

Postfix position raises a precedence question (-2%, 2^3%, 2%%) that this Handbook does not answer: formula grammar and precedence are explicitly out of scope (CHARTER.md section 4), and the operator-inventory decision register in the sources records precedence ownership as an open item. What the Handbook can say is that % is a one-argument function of a value, and that chaining it (A%%) applies it twice.

Try it

Input cells (optional)

Example: {"B2": 3, "B3": 4}. A1 holds the formula. Other cells need values before a formula can read them.

Enter a formula, then calculate.

Runs locally in your browser with OneCalc. Its answer may differ from Excel. Use English function names and commas between arguments.

Quirks

Result and edge cases

  • Text and logical operands. Shared to-number rules from coercion and lifting. Note the overlap: chapter 02 records that Excel's text-to-number recognizer itself accepts percent signs in some locale-dependent forms, so "50%" as text may already convert to 0.5 before this operator is reached — and "50%"% would then scale it again. That interaction is unrecorded here and is a good probe.
  • Empty and omitted. Per-family policy under chapter 02; unrecorded for this row.
  • Arrays. CoercionLiftProfile::UnaryNumericScalarOrArrayElementwise — mapped elementwise, with element-local failures.
  • Underflow. Scaling a subnormal by a hundredth flushes it toward zero; scaling any tiny value repeatedly reaches zero. Nothing about this is specific to %, but % is a cheap way to reach the subnormal range from ordinary-looking data.
  • Overflow. Not reachable: scaling down cannot overflow.

How to implement

Notes for implementers

  • Pick a spelling and record which one: x / 100 or x * 0.01. They are not the same function of a double, and a compatibility implementation that guesses will disagree with Excel on some operands. The Handbook cannot yet tell you which to pick.
  • Do not implement % by string manipulation of the formula or by adjusting the cell format. It is a value transformation.
  • Chained application (A%%) must scale twice; there is no idempotence to exploit.
  • The elementwise array path must preserve element-local failures.

Rust code

Show the CalcFunc source of this function

Quoted from the public repository DnaCalc/DnaCalc, crates calc-func and calc-fml, at commit 9e1884369a67. Comments are the source's own. A kernel shared with other functions appears once, on its module page.

% postfix · 1 lines · calc-func/src/catalogue/arithmetic.rs on GitHub
CatalogueEntry::operator(PERCENT, "%", Notation::Postfix, NUMBER, percent)
percent · 13 lines · calc-func/src/catalogue/arithmetic.rs on GitHub
/// `x%` is `x / 100`.
fn percent(
    arguments: &[CalcValue],
    services: &mut EvalServices<'_>,
) -> Result<CalcValue, FunctionFault> {
    let site = Site::new(PERCENT, services);
    Site::finish(
        site.scalar_operands(arguments)
            .and_then(|()| site.number_argument(0, &arguments[0]))
            .and_then(|x| site.divide(x, 100.0))
            .and_then(|x| site.number(x)),
    )
}

Kernels shared with other functions

Argument and result plumbing

No implementation has been published with a Handbook test suite for this function.

Version differences

No comparison between specific Excel builds is recorded here yet. This does not establish that all builds behave alike.

Alternatives

Relationships

  • FUNC.OP_DIVIDE and FUNC.OP_MULTIPLY — the two operators % might be implemented in terms of, and the reason the ambiguity above matters.
  • FUNC.OP_NEGATE, FUNC.OP_UNARY_PLUS — the other unary members of the family.
  • PERCENTILE, PERCENTRANK, PERCENTOF — statistical functions whose names share the word and share nothing else.
  • TEXT(x, "0%") — the formatting route. If the goal is display, %-the-operator is the wrong tool; if the goal is arithmetic, the format is.

Named variants

No named variants are recorded yet.

Suggest a correction or contribute an implementation · For agents