{
  "category": "Statistical functions",
  "display_name": "NORM.INV",
  "entry_kind": "built_in_function",
  "eval_api": {
    "method": "POST",
    "url": "https://handbook.dnacalc.com/api/eval"
  },
  "function_id": "FUNC.NORM.INV",
  "implementation_state": {
    "answer_bank": null,
    "detail": "Recorded: 5 workbook cells.",
    "dnacalc_commit": "9e1884369a678158dd82d3d74188daf986995e87",
    "in_catalogue": true,
    "state": "matches",
    "state_label": "Matches every recorded Excel answer",
    "summary": "Matches all 5 recorded answers",
    "workbook_corpus": {
      "cells": 5,
      "matched": 5
    }
  },
  "implementations": [
    {
      "commit": "9e1884369a678158dd82d3d74188daf986995e87",
      "flavour": "excel-compatibility-candidate",
      "language": "Rust",
      "name": "CalcFunc",
      "own_code": [
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/distributions.rs#L60-L63"
      ],
      "repository": "https://github.com/DnaCalc/DnaCalc",
      "shared_code": [
        "catalogue/distributions::nums",
        "ported/excel_numeric::binary_with",
        "ported/excel_numeric::excel_x87_mul",
        "ported/excel_numeric/x87::mul",
        "ported/normal_dist_common::phi_kernel",
        "ported/normal_log_family::validate_positive_sigma",
        "ported/normal_log_family::validate_probability_open_unit",
        "ported/normal_log_family::inverse_standard_normal_acklam_refined",
        "ported/normal_log_family::inverse_standard_normal",
        "ported/normal_log_family::norm_inv_kernel"
      ],
      "source": "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/distributions.rs#L60-L63",
      "state": "matches",
      "suite": null,
      "summary": "Matches all 5 recorded answers"
    }
  ],
  "json_url": "https://handbook.dnacalc.com/api/functions/FUNC.NORM.INV.json",
  "name": "NORM.INV",
  "notes": [],
  "schema": "efh.function-reference/v1",
  "section_order": [
    "what-it-does",
    "try-it",
    "quirks",
    "how-to-implement",
    "version-differences",
    "alternatives"
  ],
  "sections": {
    "alternatives": "\n### Relationships\n\n- **[NORM.DIST](FUNC.NORM.DIST.md)** is the forward function and, per Microsoft's own text, the\n  thing `NORM.INV` searches over. The round trip in both directions is the natural test pair.\n- **[NORM.S.INV](FUNC.NORM.S.INV.md)** is the standardized case, `NORM.INV(p, 0, 1)`.\n- **`CONFIDENCE.NORM`** is a direct consumer: a confidence half-width is `NORM.S.INV` of a\n  tail probability, scaled.\n- **`STANDARDIZE`** is the affine map this function composes with, run the other way.\n- **Confused with**: `NORM.DIST` itself, by readers who want \"the normal function\" and pick the\n  wrong direction; and `NORM.INV(p, μ, σ)` used with `p` expressed as a percentage, where `95`\n  is a `#NUM!` and `0.95` is what was meant.\n\n\n",
    "how-to-implement": "\n### Numerical notes\n\n\n**1. The conditioning is the headline and it is not fixable.** As derived above, the derivative\nof `Φ⁻¹` is `1/φ(Φ⁻¹(p))`, which grows without bound at both ends. Any error in `p` — including\nthe rounding that put `p` into a double in the first place — is multiplied by that factor. At\n`p = 10⁻¹⁰` the amplification is enormous. A function that is *correctly rounded* at every\ninput is still delivering an answer whose meaning is limited by the input's representation.\nThe right way to state accuracy for this function is in terms of the round trip, not the\nforward error.\n\n**2. Direct approximation is the standard route, and it is not what the documentation\ndescribes.** The reference algorithm is Wichura's **AS 241** (*Applied Statistics* 37, 1988),\nwhose `PPND16` gives about 16 significant digits over the whole representable range using three\nrational approximations selected by region: `|p − ½| ≤ 0.425` on the central branch, then two\ntail branches parameterized in `r = √(−ln min(p, 1−p))`. This is what R's `qnorm`, Boost, and\nmost statistical libraries use. Earlier and weaker: A&S 26.2.22 (about `3 × 10⁻³` absolute) and\n26.2.23 (about `4.5 × 10⁻⁴`), the Beasley–Springer algorithm AS 111 with Moro's tail\nmodification, and Acklam's widely copied approximation — all fine for graphics and inadequate\nfor a reference. Anyone implementing this function today should start from AS 241.\n\n**3. A root-finder over the CDF is a defensible design with distinctive failure modes.** If the\ndocumented description is accurate, the properties to expect are:\n\n- **Excellent round-trip in `p`** — the search terminates on that criterion, so\n  `NORM.DIST(NORM.INV(p, …), …, TRUE) ≈ p` by construction;\n- **Possible non-monotonicity** in `x` across adjacent `p`, if the termination tolerance is\n  loose relative to the local `dx/dp`;\n- **Degrading accuracy in the tails** at exactly the rate the conditioning predicts, because\n  each evaluation of the forward CDF carries its own error and the search cannot beat it;\n- **Sensitivity to the bracketing strategy** at extreme `p`, where the initial bracket must\n  already reach `−38` on one side.\n\nEach of those is testable, and together they discriminate a search from a direct rational\napproximation. That is the highest-value experiment on this page.\n\n**4. Newton refinement is the bridge between the two designs.** A standard high-accuracy\nimplementation evaluates a rational approximation and then applies one or two Halley or Newton\nsteps using the exact derivative `φ(z)`:\n\n    z ← z − (Φ(z) − p) / φ(z)                    Newton\n    z ← z − u / (1 + z·u/2),  u = (Φ(z) − p)/φ(z)   Halley\n\nEach step roughly squares (Newton) or cubes (Halley) the accuracy, and the derivative is\navailable in closed form — which is why the inverse normal is one of the pleasanter quantiles to\nrefine. An implementation that does this *is* using the forward CDF, which means its accuracy\nis also derivative of the CDF's, exactly as Microsoft's page says. The two descriptions are not\nas far apart as they first look.\n\n**5. Argument reduction.** `μ + σ z` is a fused-multiply-add opportunity and a cancellation\nopportunity: when `μ` is large and `σ z` is small, the result loses the information in `z`\nentirely. This is the same ceiling described on [NORM.DIST](FUNC.NORM.DIST.md), and it is\ninvisible to any test that uses `μ = 0`.\n\n**6. The published assessment record.** McCullough and Wilson's series in *Computational\nStatistics & Data Analysis*, and Knüsel's assessments of Excel's distribution functions, are\nthe standing published examinations of this lane, with revisions reported around Excel 2003 and\nagain when the dotted names arrived. Morten Welinder's Gnumeric work is the standard practical\naccount of implementing this family in a spreadsheet, including the inverses. Named as\nliterature; no figure from them is restated here.\n\n\n",
    "quirks": "\n### The documented algorithm\n\n\nMicrosoft's `NORM.INV` page states something that documentation of a mathematical function very\nrarely states: **how it is computed.**\n\n> \"Given a value for probability, NORM.INV seeks that value x such that\n> NORM.DIST(x, mean, standard_dev, TRUE) = probability.\"\n>\n> \"Thus, precision of NORM.INV depends on precision of NORM.DIST.\"\n\nThe companion `NORM.S.INV` page says the same thing about its own pair and adds the phrase\n\"uses an iterative search technique\".\n\nThree consequences follow, and the Handbook states them as consequences of the *documentation*,\nnot as observations of Excel:\n\n1. **`NORM.INV` is documented as a root-finder over `NORM.DIST`, not as a direct quantile\n   approximation.** That is architecturally different from every standard library\n   implementation, which evaluates a rational approximation to `Φ⁻¹` directly.\n2. **Its accuracy is documented as bounded above by `NORM.DIST`'s.** Whatever error the forward\n   CDF carries is inherited, and then divided by `φ(z)` through the conditioning above — so the\n   inherited error is *amplified* in the tails, not merely passed along.\n3. **Round-trip consistency is expected to be unusually good, and monotonicity is not\n   guaranteed.** A search that terminates on a tolerance will reproduce `p` well by\n   construction, while adjacent `p` values can land on the same or non-monotone `x` if the\n   termination rule is coarse. Those are opposite predictions from the ones a direct rational\n   approximation makes, which is what makes them worth testing.\n\nWhether Excel today actually performs an iterative search is **not** something this page\nasserts. The documentation says so; the Handbook has not observed it, and no evidence record in\nits possession identifies this surface's op-graph.\n\n\n\n### Result and edge cases\n\n\nReturns `Number`.\n\n- **`p = 0.5`** returns `μ` exactly, for every admissible `σ`.\n- **`p` at the ends.** `p ≤ 0` and `p ≥ 1` are documented `#NUM!`. The smallest positive\n  double is about `4.9 × 10⁻³²⁴`, whose quantile is about `−38.4`; the largest `p` strictly\n  below `1` is `1 − 2⁻⁵³`, whose quantile is about `8.13`. **The reachable range of\n  `NORM.INV(p, 0, 1)` is therefore roughly `[−38.4, +8.13]` and is wildly asymmetric** —\n  because probabilities near `1` are represented with absolute spacing `2⁻⁵³` while\n  probabilities near `0` are represented with relative precision all the way into the\n  subnormals. This asymmetry is a fact about binary64, not about the normal distribution, and\n  it is the reason serious tail work is done with `Φ(−z)` rather than `1 − Φ(z)`.\n- **`σ ≤ 0`** is a documented `#NUM!`, `σ = 0` included.\n- **`standard_dev` very large or `mean` very large**: the result is `μ + σ z` and can overflow;\n  what Excel publishes at overflow is not established here.\n- **Arrays.** The recorded profile is `Custom`; elementwise lifting is not settled.\n\nEmpty, missing and error arguments follow the shared call model; see\n[Coercion and lifting](../model/02-coercion-and-lifting.md).\n\n\n\n### Errors\n\n\nAs documented by Microsoft on the `NORM.INV` page (retrieved for this page):\n\n| Error | Documented condition |\n|---|---|\n| `#VALUE!` | Any argument is nonnumeric |\n| `#NUM!` | `probability ≤ 0` or `probability ≥ 1` |\n| `#NUM!` | `standard_dev ≤ 0` |\n\nNote that this page's `#VALUE!` row says \"any argument\", where the sibling `NORM.DIST` page\nnames only `mean` and `standard_dev`. The two pages describe the same coercion behaviour with\ndifferent completeness; `NORM.INV`'s wording is the better one.\n\nError values in any argument propagate under the ordinary coercion rules.\n\n\n",
    "sources": "- Microsoft, \"NORM.INV function\" —\n  <https://support.microsoft.com/en-us/office/norm-inv-function-54b30935-fee7-493c-bedb-2278a9db7e13>\n  (syntax; the three required arguments and their descriptions; the `#VALUE!` condition on any\n  nonnumeric argument; the `#NUM!` conditions on `probability` and `standard_dev`; the statement\n  that `NORM.INV` seeks the `x` at which `NORM.DIST` equals the probability; and \"precision of\n  NORM.INV depends on precision of NORM.DIST\"). Retrieved for this page.\n- Microsoft, \"NORM.S.INV function\" —\n  <https://support.microsoft.com/en-us/office/norm-s-inv-function-d6d556b4-ab7f-49cd-b526-5a20918452b1>\n  (the companion statement, which adds \"uses an iterative search technique\"). Retrieved.\n- Handbook evidence record `EV-DIST-0018` — the ten-witness normal-group re-sweep; names\n  `NORM.INV` as a subject, excludes `NORMINV`, and carries a reader warning against per-surface\n  attribution of its group figure.\n- M. J. Wichura, \"Algorithm AS 241: The percentage points of the normal distribution\",\n  *Applied Statistics* 37 (1988) 477–484 — `PPND16`, the standard double-precision route.\n- Abramowitz & Stegun, *Handbook of Mathematical Functions*, chapter 26 §26.2.22–26.2.23 — the\n  classical low-order rational approximations, and §26.2.12 for the tail asymptotics that give\n  the `√(2 ln(1/p))` leading behaviour.\n- J. D. Beasley and S. G. Springer, \"Algorithm AS 111\", *Applied Statistics* 26 (1977), with\n  Moro's tail modification — the earlier standard, named for contrast.\n- B. D. McCullough and B. Wilson, *Computational Statistics & Data Analysis* (1999, 2002,\n  2005); L. Knüsel on Excel's distribution functions; M. Welinder's Gnumeric statistical work.\n  Named as literature; no figure restated.\n- Handbook, [Coercion and lifting](../model/02-coercion-and-lifting.md) and\n  [About implementation options](../model/07-implementation-options.md).\n\n\n",
    "version-differences": "No comparison between specific Excel builds is recorded here yet. This does not establish that all builds behave alike.",
    "what-it-does": "\n`NORM.INV(probability, mean, standard_dev)` returns the quantile of the normal distribution\nwith mean `μ` and standard deviation `σ` at probability `p` — the value `x` such that a normal\nrandom variable falls below `x` with probability exactly `p`:\n\n    NORM.INV(p, μ, σ) = x   where   F(x; μ, σ) = p\n\nBecause the normal CDF standardizes, the whole function reduces to the standard normal\nquantile — the **probit** function — composed with an affine map:\n\n    x = μ + σ · Φ⁻¹(p)\n      = μ + σ √2 · erf⁻¹(2p − 1)\n\n**Domain and range.** `p` must lie strictly inside `(0, 1)`; `p ≤ 0` and `p ≥ 1` are documented\n`#NUM!` conditions, and `σ ≤ 0` is another. On `(0, 1)` the function is a strictly increasing\nbijection onto the whole real line — so the *range is unbounded*, and it is unbounded in a very\nsharp way: as `p → 0⁺` and `p → 1⁻` the result runs to `∓∞`. There are no poles in the interior\nand no branch cuts; `Φ⁻¹` is analytic on `(0, 1)`.\n\n**The endpoints are the entire difficulty.** Differentiating the inverse relation,\n\n    d/dp Φ⁻¹(p) = 1 / φ(Φ⁻¹(p))\n\nand `φ` vanishes faster than any power at `±∞`, so the derivative **blows up superpolynomially**\nat both ends. Concretely, near `p = 0`,\n\n    Φ⁻¹(p)  ~  −√( 2 ln(1/p) − ln(2 ln(1/p)) − ln(2π) )      as p → 0⁺\n\nso an absolute error `δ` in `p` produces an absolute error of roughly `δ / φ(z)` in the answer,\nwhich for `z = −6` is a factor of about `10^8`. **The inverse normal is ill-conditioned at the\ntails by nature, not by implementation.** No algorithm can do better than the conditioning\nallows, and the practical consequence is that `NORM.INV` at extreme `p` is only as good as the\nrepresentation of `p` itself.\n\n**Special values and identities.**\n\n    Φ⁻¹(1/2) = 0        exactly, so NORM.INV(0.5, μ, σ) = μ\n    Φ⁻¹(p) = −Φ⁻¹(1 − p)                the reflection identity\n    NORM.INV(Φ(x), μ, σ) = x            round-trip in x\n    Φ(NORM.INV(p, 0, 1)) = p            round-trip in p\n\n`NORM.INV(0.5, μ, σ) = μ` is the one input whose answer is exactly nameable and it is the\ncheapest possible test of this surface.\n\n\n\n### Arguments\n\n\nMicrosoft's page gives three required arguments:\n\n| Argument | Meaning | Required |\n|---|---|---|\n| `probability` | \"A probability corresponding to the normal distribution\" | yes |\n| `mean` | \"The arithmetic mean of the distribution\" | yes |\n| `standard_dev` | \"The standard deviation of the distribution\" | yes |\n\nMicrosoft further notes that with `mean = 0` and `standard_dev = 1`, `NORM.INV` \"uses the\nstandard normal distribution\".\n\nThe pinned catalogue supplies `NORM.INV(probability, mean, standard_dev)` with three required arguments.\n\n\n"
  },
  "signature": {
    "display": "NORM.INV(probability, mean, standard_dev)",
    "parameters": [
      {
        "description": null,
        "name": "probability",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "mean",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "standard_dev",
        "optional": false,
        "repeats": false
      }
    ],
    "trailing_repeats": false
  },
  "sources": {
    "metadata": {
      "admission": {
        "label": "implemented",
        "reason": null
      },
      "arity": {
        "max": 3,
        "min": 3
      },
      "category": "Statistical functions",
      "classification": {
        "arg_preparation_profile": "ValuesOnlyPreAdapter",
        "coercion_lift_profile": "Custom",
        "determinism_class": "Deterministic",
        "error_collapse_profile": "None",
        "fec_dependency_profile": "None",
        "host_interaction_class": "None",
        "kernel_signature_class": "Custom",
        "rich_value_usage": "RichBlind",
        "surface_fec_dependency_profile": "RefOnly",
        "thread_safety_class": "SafePure",
        "volatility_class": "NonVolatile"
      },
      "descriptions": {
        "long": null,
        "short": "The value at which the cumulative normal distribution reaches a given probability",
        "short_source": "dna-calc-own"
      },
      "docs": {
        "english_description": "Returns the inverse of the normal cumulative distribution",
        "microsoft_url": "https://support.microsoft.com/en-us/office/norm-inv-function-54b30935-fee7-493c-bedb-2278a9db7e13"
      },
      "entry_kind": "built_in_function",
      "localized_family_names": null,
      "localized_names": [
        {
          "locale": "ar-SA",
          "name": "NORM.INV"
        },
        {
          "locale": "bg-BG",
          "name": "NORM.INV"
        },
        {
          "locale": "cs-CZ",
          "name": "NORM.INV"
        },
        {
          "locale": "da-DK",
          "name": "NORM.INV"
        },
        {
          "locale": "de-DE",
          "name": "NORM.INV"
        },
        {
          "locale": "el-GR",
          "name": "NORM.INV"
        },
        {
          "locale": "en-AU",
          "name": "NORM.INV"
        },
        {
          "locale": "en-GB",
          "name": "NORM.INV"
        },
        {
          "locale": "en-US",
          "name": "NORM.INV"
        },
        {
          "locale": "es-ES",
          "name": "INV.NORM"
        },
        {
          "locale": "et-EE",
          "name": "NORM.INV"
        },
        {
          "locale": "fi-FI",
          "name": "NORMAALI.JAKAUMA.KÄÄNT"
        },
        {
          "locale": "fr-FR",
          "name": "LOI.NORMALE.INVERSE.N*"
        },
        {
          "locale": "he-IL",
          "name": "NORM.INV"
        },
        {
          "locale": "hr-HR",
          "name": "NORM.INV"
        },
        {
          "locale": "hu-HU",
          "name": "NORM.INVERZ"
        },
        {
          "locale": "id-ID",
          "name": "NORM.INV"
        },
        {
          "locale": "it-IT",
          "name": "NORM.INV"
        },
        {
          "locale": "ja-JP",
          "name": "NORM.INV"
        },
        {
          "locale": "ko-KR",
          "name": "NORM.INV"
        },
        {
          "locale": "lt-LT",
          "name": "NORM.INV"
        },
        {
          "locale": "lv-LV",
          "name": "NORM.INV"
        },
        {
          "locale": "nb-NO",
          "name": "NORM.INV"
        },
        {
          "locale": "nl-NL",
          "name": "NORM.INV"
        },
        {
          "locale": "pl-PL",
          "name": "ROZKŁ.NORMALNY.ODWR"
        },
        {
          "locale": "pt-BR",
          "name": "NORM.INV"
        },
        {
          "locale": "pt-PT",
          "name": "INV.NORMAL"
        },
        {
          "locale": "ro-RO",
          "name": "NORM.INV"
        },
        {
          "locale": "ru-RU",
          "name": "НОРМ.ОБР"
        },
        {
          "locale": "sk-SK",
          "name": "NORM.INV"
        },
        {
          "locale": "sl-SI",
          "name": "NORM.INV"
        },
        {
          "locale": "sr-Latn-RS",
          "name": "NORM.INV"
        },
        {
          "locale": "sv-SE",
          "name": "NORM.INV"
        },
        {
          "locale": "th-TH",
          "name": "NORM.INV"
        },
        {
          "locale": "tr-TR",
          "name": "NORM.TERS"
        },
        {
          "locale": "uk-UA",
          "name": "NORM.INV"
        },
        {
          "locale": "vi-VN",
          "name": "NORM.INV"
        },
        {
          "locale": "zh-CN",
          "name": "NORM.INV"
        },
        {
          "locale": "zh-HK",
          "name": "NORM.INV"
        },
        {
          "locale": "zh-TW",
          "name": "NORM.INV"
        }
      ],
      "signature": {
        "display": "NORM.INV(probability, mean, standard_dev)",
        "parameters": [
          {
            "description": null,
            "name": "probability",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "mean",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "standard_dev",
            "optional": false,
            "repeats": false
          }
        ],
        "trailing_repeats": false
      },
      "surface_name": "NORM.INV",
      "version_marker": null,
      "xlcall": {
        "code": "500",
        "symbol": "xlfNorm_inv"
      }
    },
    "microsoft": "https://support.microsoft.com/en-us/office/norm-inv-function-54b30935-fee7-493c-bedb-2278a9db7e13"
  },
  "try_it": {
    "formula": "=NORM.INV(0.975,0,1)"
  },
  "url": "https://handbook.dnacalc.com/functions/NORM.INV.html",
  "variants": [],
  "versions": []
}