{
  "category": "Statistical functions",
  "display_name": "NORM.DIST",
  "entry_kind": "built_in_function",
  "eval_api": {
    "method": "POST",
    "url": "https://handbook.dnacalc.com/api/eval"
  },
  "function_id": "FUNC.NORM.DIST",
  "implementation_state": {
    "answer_bank": {
      "excel_builds": [
        "20430"
      ],
      "larger_numeric": 0,
      "last_bit": 244,
      "matched": 24002,
      "other_mismatch": 0,
      "refused": 0,
      "rows": 24246,
      "unread": 0,
      "worst_ulp": 6
    },
    "detail": "Everything else matches (24,246 in the answer bank and 6 workbook cells). Last-bit means a finite number within 16 ULP of Excel's.",
    "dnacalc_commit": "9e1884369a678158dd82d3d74188daf986995e87",
    "in_catalogue": true,
    "state": "close",
    "state_label": "Close: last-bit deviations remain",
    "summary": "Close: 244 of 24,252 recorded answers differ in the last bits, worst 6 ULP",
    "workbook_corpus": {
      "cells": 6,
      "matched": 6
    }
  },
  "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#L52-L55"
      ],
      "repository": "https://github.com/DnaCalc/DnaCalc",
      "shared_code": [
        "catalogue/distributions::nums",
        "ported/excel_numeric::binary_with",
        "ported/excel_numeric::excel_x87_add",
        "ported/excel_numeric::excel_x87_sub",
        "ported/excel_numeric::excel_x87_mul",
        "ported/excel_numeric::excel_x87_div",
        "ported/excel_numeric/x87::mul",
        "ported/excel_numeric/x87::add",
        "ported/excel_numeric/x87::sub",
        "ported/excel_numeric/x87::div",
        "ported/normal_dist_common::stored_horner",
        "ported/normal_dist_common::erf_approx",
        "ported/normal_dist_common::erfc_upper",
        "ported/normal_log_family::flush_subnormal",
        "ported/normal_log_family::identified_std_normal_cdf",
        "ported/normal_log_family::norm_cdf",
        "ported/normal_log_family::validate_positive_sigma",
        "ported/normal_log_family::norm_dist_kernel",
        "ported/special_dist_family::erfc_kernel",
        "ported/special_dist_family::erfc_precise_kernel"
      ],
      "source": "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/distributions.rs#L52-L55",
      "state": "close",
      "suite": null,
      "summary": "Close: 244 of 24,252 recorded answers differ in the last bits, worst 6 ULP"
    }
  ],
  "json_url": "https://handbook.dnacalc.com/api/functions/FUNC.NORM.DIST.json",
  "name": "NORM.DIST",
  "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.S.DIST](FUNC.NORM.S.DIST.md)** is the standardized case. Microsoft's page states the\n  identity `NORM.DIST(x, 0, 1, TRUE) = NORM.S.DIST(x, TRUE)` as documented behaviour. The\n  Handbook publishes that as a documented identity, and separately notes that no evidence in\n  its record demonstrates the two surfaces agree in their last bits.\n- **[NORM.INV](FUNC.NORM.INV.md)** is the functional inverse in the first argument:\n  `NORM.INV(NORM.DIST(x, μ, σ, TRUE), μ, σ) = x` mathematically. Microsoft's `NORM.INV` page\n  states that `NORM.INV` *searches* for the `x` at which `NORM.DIST` equals the given\n  probability, and that \"precision of `NORM.INV` depends on precision of `NORM.DIST`\" — a\n  documented dependency between the two surfaces, and an unusually explicit one.\n- **[PHI](FUNC.PHI.md)** is `NORM.DIST(x, 0, 1, FALSE)` under a shorter name.\n- **[GAUSS](FUNC.GAUSS.md)** is `NORM.DIST(z, 0, 1, TRUE) − 0.5`.\n- **`ERF` / `ERFC`** are the underlying special functions: `Φ(z) = ½ erfc(−z/√2)`.\n- **`CONFIDENCE.NORM`** and **`Z.TEST`** are consumers: both are `NORM.S.INV` or `NORM.S.DIST`\n  applied to a standardized statistic.\n- **Confused with**: `NORM.DIST(x, μ, σ)` written without the fourth argument, which is not a\n  legal call — the argument is required, and omitting it is refused at entry rather than\n  defaulting.\n\n\n",
    "how-to-implement": "\n### Numerical notes\n\n\nThe normal CDF is the most-studied function in applied statistics and the place where Excel's\nstatistical lane has historically been assessed hardest. Four things are worth stating.\n\n**1. The tail is the function.** The naive route — compute the density, integrate a series —\nis fine near the centre and useless in the tails. Every serious implementation reduces to\n`erf`/`erfc` and switches representation by region:\n\n    |z| small          series or rational approximation for erf(z/√2)\n    |z| moderate       rational approximation for erfc\n    |z| large          erfc via the asymptotic expansion or a continued fraction,\n                       scaled by e^(−z²/2) to avoid underflow\n\nCody's rational Chebyshev approximations (1969, and the `CALERF`/`ANORM` routines in SPECFUN)\nare the canonical accurate double-precision route and are what most modern libraries descend\nfrom. Cephes's `ndtr` is a widely used independent implementation. A&S 26.2.17 gives the\nHastings-style rational approximation that older code used, and its accuracy — around seven\ndecimal digits — is exactly the kind of legacy standard that shows up as a visible defect when\ndouble precision is expected.\n\n**2. Cancellation is where the naive form dies.** Two distinct failures:\n\n- `1 − Φ(z)` for large positive `z` is catastrophic subtraction: the answer is tiny, the\n  operands are both near `1`, and the result has no significant digits left once\n  `1 − Φ(z) < 2^−53`. The remedy is not a better `Φ` — it is to compute `Φ(−z)` instead, using\n  the exact symmetry, or to expose a complementary surface. Excel's normal family has no\n  complementary surface (there is no `NORM.DIST.RT` beside `CHISQ.DIST.RT` and `F.DIST.RT`),\n  so **the reflection is the user's responsibility**.\n- `½[1 + erf(u)]` for `u` very negative is the same failure in the other direction: `erf(u)`\n  approaches `−1` and the sum loses digits. Writing it as `½ erfc(−u)` avoids the subtraction\n  entirely. This is why the `erfc` form is the one to implement.\n\n**3. Argument reduction has its own error.** `z = (x − μ)/σ` is computed in floating point\nbefore the special function ever runs. When `x` and `μ` are close and large, `x − μ` loses\ndigits; the resulting relative error in `z` is amplified into the result by a factor of about\n`z` for the CDF (since `Φ'(z)/Φ(z) → z` in the left tail) and by about `z²` for the density\n(the squaring bottleneck described on [PHI](FUNC.PHI.md)). A two-parameter normal function\ntherefore has an accuracy ceiling set by the subtraction, before any special-function code\nruns. This is invisible in any test that uses `μ = 0`.\n\n**4. The published assessment record.** Excel's statistical functions have been examined in\nprint for two decades — McCullough and Wilson's series in *Computational Statistics & Data\nAnalysis*, and Knüsel's assessments of the distribution functions specifically, both report\naccuracy shortfalls in Excel's statistical lane across several versions, with revisions in\nExcel 2003 and again around Excel 2010 when the dotted names were introduced. Morten Welinder's\nwork on Gnumeric's statistical functions is the standard practical account of what it takes to\nget these functions right in a spreadsheet and of where Excel's answers came from. The Handbook\nnames these as literature; it has not re-run their tests and does not restate their figures.\n\n**What a careful independent implementation does**: standardize with care (compensated\nsubtraction if the arguments warrant it), route the CDF through `erfc` with a\nregion-switched rational approximation, evaluate the density through a double-double `z²/2` as\ndescribed on [PHI](FUNC.PHI.md), and state a bound. See\n[About implementation options](../model/07-implementation-options.md).\n\n\n",
    "quirks": "\n### Result and edge cases\n\n\nReturns `Number`.\n\n- **`σ ≤ 0`** is a documented `#NUM!`, including `σ = 0`. The degenerate \"distribution\" that\n  puts all its mass at `μ` is therefore not reachable, and neither the step-function CDF nor\n  the unbounded density has to be represented.\n- **`cumulative` coerced from a number.** Excel's logical slots accept numbers, with zero\n  reading as `FALSE`. That means `NORM.DIST(x, μ, σ, 0)` is the density and\n  `NORM.DIST(x, μ, σ, 1)` is the CDF, and any nonzero value selects the CDF. The reference\n  engine's battery renders the all-`TRUE` and all-zero rows, and their outcomes show beside\n  this page.\n- **Far left tail.** The current CDF wrapper flushes a final value below `2^-1022` to zero, including its `z=-37.52` source control. IEEE binary64 itself can represent smaller positive values; the worksheet publication policy is a separate stage.\n- **Far right tail.** Once the stored CDF is one, subtracting it from one loses the upper-tail probability. For symmetric mathematical tails, evaluate a reflected lower-tail argument instead. Building that reflected argument introduces its own rounding, so the identity alone does not establish identical worksheet results.\n- **Density at large `|z|`.** The current density route flushes its final result after scaling by sigma and the normal constant. It checks the staged square for overflow first. Calling worksheet PHI and then dividing by sigma can flush an intermediate too early.\n- **Arrays.** The recorded profile is `Custom`; whether `NORM.DIST` lifts elementwise over\n  array arguments is not settled here.\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.DIST` page (retrieved for this page):\n\n| Error | Documented condition |\n|---|---|\n| `#VALUE!` | `mean` or `standard_dev` is nonnumeric |\n| `#NUM!` | `standard_dev ≤ 0` |\n\nTwo observations about what that table does *not* say, both worth recording rather than\npapering over:\n\n1. **The `#VALUE!` row names only `mean` and `standard_dev`.** It does not name `x`. Read\n   literally, the documentation says nothing about a nonnumeric `x` — which surely also\n   produces `#VALUE!` under the ordinary coercion rules, but is not documented as such on this\n   page. This is a documentation gap, not a behavioural claim.\n2. **No `#NUM!` for extreme `x`.** The documentation states no domain restriction on `x` at\n   all, consistent with the mathematics.\n\nError values in any argument propagate under the ordinary coercion rules.\n\n\n",
    "sources": "- Microsoft, \"NORM.DIST function\" —\n  <https://support.microsoft.com/en-us/office/norm-dist-function-edb1cc14-a21c-4e53-839d-8082074c9f8d>\n  (syntax; the four required arguments and their descriptions; the `#VALUE!` condition on\n  `mean`/`standard_dev`; the `#NUM!` condition on `standard_dev ≤ 0`; the density equation; the\n  statement that the cumulative form is the integral from negative infinity to `x`; and the\n  identity with `NORM.S.DIST` at `mean = 0`, `standard_dev = 1`, `cumulative = TRUE`).\n  Retrieved for this page.\n- Handbook evidence record `EV-DIST-0018` — the ten-witness normal-group re-sweep, whose group\n  figure carries a reader warning against per-surface attribution and which excludes `NORMDIST`\n  and `NORMINV`.\n- Abramowitz & Stegun, *Handbook of Mathematical Functions*, chapter 26 §26.2 — the normal\n  probability function `P(x)`, the density `Z(x)`, the tail asymptotic expansion 26.2.12, and\n  the rational approximations 26.2.16–26.2.19.\n- W. J. Cody, \"Rational Chebyshev approximation for the error function\", *Mathematics of\n  Computation* 23 (1969); and the `CALERF`/`ANORM` routines of SPECFUN.\n- S. L. Moshier, Cephes `ndtr.c` — an independent double-precision normal integral.\n- B. D. McCullough and B. Wilson, \"On the accuracy of statistical procedures in Microsoft\n  Excel\", *Computational Statistics & Data Analysis* (1999, 2002, 2005); and L. Knüsel's\n  assessments of Excel's distribution functions. Named as the published assessment record; no\n  figure from them is restated here.\n- M. Welinder's work on Gnumeric's statistical functions — the standard practical account of\n  implementing this family in a spreadsheet.\n- Handbook, [Coercion and lifting](../model/02-coercion-and-lifting.md) and\n  [About implementation options](../model/07-implementation-options.md).\n- [Normal wrapper and publication stages](https://github.com/DnaCalc/DnaCalc/blob/481f4ab85d3bf5a95b6daf959bb75ccb2f8b40f8/crates/calc-func/src/ported/normal_log_family.rs) and [shared density kernel](https://github.com/DnaCalc/DnaCalc/blob/481f4ab85d3bf5a95b6daf959bb75ccb2f8b40f8/crates/calc-func/src/ported/normal_dist_common.rs).\n\n",
    "version-differences": "The recorded environments below distinguish a reading from a same-input comparison. Counts describe captured inputs in each environment; overlapping captures and comparisons are not totals of unique worksheet calls.\n\n| Excel 16.0 build | Platform and CPU | Captured inputs |\n|---|---|---:|\n| 20430 | Windows, 64-bit, CPU not recorded | 24,246 |\n\nThe record contains no same-input comparison between these environments. Reading different inputs on different builds does not establish either a version change or cross-build agreement.\n\n[Recorded environments and comparison details](https://github.com/DnaCalc/ExcelFunctionsHandbook/blob/5dc75391aa5125ccc5abdb095da85950980d6fd8/content/evidence/environments/FUNC.NORM.DIST.json).",
    "what-it-does": "\n`NORM.DIST(x, mean, standard_dev, cumulative)` evaluates the normal distribution with mean `μ`\nand standard deviation `σ` at `x`, returning either its density or its cumulative distribution\nfunction according to the fourth argument.\n\n**Density** (`cumulative = FALSE`) — Microsoft's page carries this equation as an image; it is\nthe standard one:\n\n    f(x; μ, σ) = 1 / (σ √(2π)) · exp( −(x − μ)² / (2σ²) )\n\n**Cumulative** (`cumulative = TRUE`) — Microsoft's page states that this is the integral from\nnegative infinity to `x` of the density:\n\n    F(x; μ, σ) = ∫₋∞ˣ f(t; μ, σ) dt\n               = Φ( (x − μ) / σ )\n               = ½ · [ 1 + erf( (x − μ) / (σ √2) ) ]\n               = ½ · erfc( −(x − μ) / (σ √2) )\n\nThe three closed forms for `F` are algebraically identical and numerically are not: the\n`erfc` form is the one that survives in the left tail, and the choice among them is the whole\nsubject of the Numerical notes below.\n\n**Domain and range.** `x` and `μ` range over the reals; `σ > 0` is required — `σ ≤ 0` is a\ndocumented `#NUM!`. The density is strictly positive with range `(0, 1/(σ√(2π))]`, attaining\nits maximum at `x = μ`. The cumulative is strictly increasing with range `(0, 1)`, never\nreaching either endpoint mathematically. Stored worksheet results can nevertheless be zero or one. The current DnaCalc implementation flushes final subnormal CDF and density values to zero; that policy must be distinguished from ordinary IEEE binary64 rounding. Both mathematical forms are entire in `x`.\n\n**Standardization is the whole structure of this family.** Writing `z = (x − μ)/σ`:\n\n    F(x; μ, σ) = Φ(z)                and    f(x; μ, σ) = φ(z) / σ\n\nso the two-parameter surface is a one-parameter surface composed with an affine map. Every\nmember of the normal group is `Φ` or `φ` wearing a change of variable — which is why\nMicrosoft's page states the identity directly: with `mean = 0`, `standard_dev = 1` and\n`cumulative = TRUE`, `NORM.DIST` \"returns the standard normal distribution, `NORM.S.DIST`\".\n\nThat sentence is a documented *mathematical* identity. It is not, and must not be read as, a\nstatement that the two Excel surfaces return the same bits. See Relationships.\n\n**Limiting cases and special values.**\n\n    F(μ; μ, σ) = 1/2                        exactly, for every σ > 0\n    F(x; μ, σ) + F(2μ − x; μ, σ) = 1        the reflection identity\n    f(μ; μ, σ) = 1 / (σ √(2π))\n    1 − F(z) ~ φ(z)/z · (1 − 1/z² + 3/z⁴ − …)   as z → ∞   (A&S 26.2.12)\n\nThe last of these is the asymptotic expansion that governs the right tail and explains why the\ntail is where implementations diverge. The value at the mean is the cheapest exactness probe\nthis function has: `F(μ; μ, σ)` must be `0.5` with no rounding at all.\n\n\n\n### Arguments\n\n\nMicrosoft's page gives four required arguments:\n\n| Argument | Meaning | Required |\n|---|---|---|\n| `x` | The value for which you want the distribution | yes |\n| `mean` | The arithmetic mean of the distribution | yes |\n| `standard_dev` | The standard deviation of the distribution | yes |\n| `cumulative` | A logical: `TRUE` gives the cumulative distribution function, `FALSE` the probability density function | yes |\n\n`cumulative` has **no default**. This is a real difference from the shape readers expect: many\ndistribution functions in other systems default to the CDF, and here the switch must be\nwritten. Its argument descriptions above are Microsoft's own wording.\n\nThe pinned catalogue supplies `NORM.DIST(x, mean, standard_dev, cumulative)` with four required arguments. The table above explains the documented roles of those arguments.\n\n\n"
  },
  "signature": {
    "display": "NORM.DIST(x, mean, standard_dev, cumulative)",
    "parameters": [
      {
        "description": null,
        "name": "x",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "mean",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "standard_dev",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "cumulative",
        "optional": false,
        "repeats": false
      }
    ],
    "trailing_repeats": false
  },
  "sources": {
    "metadata": {
      "admission": {
        "label": "implemented",
        "reason": null
      },
      "arity": {
        "max": 4,
        "min": 4
      },
      "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": "Normal distribution with a given mean and standard deviation: density or cumulative",
        "short_source": "dna-calc-own"
      },
      "docs": {
        "english_description": "Returns the normal cumulative distribution",
        "microsoft_url": "https://support.microsoft.com/en-us/office/norm-dist-function-edb1cc14-a21c-4e53-839d-8082074c9f8d"
      },
      "entry_kind": "built_in_function",
      "localized_family_names": null,
      "localized_names": [
        {
          "locale": "ar-SA",
          "name": "NORM.DIST"
        },
        {
          "locale": "bg-BG",
          "name": "NORM.DIST"
        },
        {
          "locale": "cs-CZ",
          "name": "NORM.DIST"
        },
        {
          "locale": "da-DK",
          "name": "NORMAL.FORDELING"
        },
        {
          "locale": "de-DE",
          "name": "NORM.DIST"
        },
        {
          "locale": "el-GR",
          "name": "NORM.DIST"
        },
        {
          "locale": "en-AU",
          "name": "NORM.DIST"
        },
        {
          "locale": "en-GB",
          "name": "NORM.DIST"
        },
        {
          "locale": "en-US",
          "name": "NORM.DIST"
        },
        {
          "locale": "es-ES",
          "name": "DISTR.NORM.N"
        },
        {
          "locale": "et-EE",
          "name": "NORM.DIST"
        },
        {
          "locale": "fi-FI",
          "name": "NORMAALI.JAKAUMA"
        },
        {
          "locale": "fr-FR",
          "name": "LOI.NORMALE.N*"
        },
        {
          "locale": "he-IL",
          "name": "NORM.DIST"
        },
        {
          "locale": "hr-HR",
          "name": "NORM.DIST"
        },
        {
          "locale": "hu-HU",
          "name": "NORM.ELOSZLÁS"
        },
        {
          "locale": "id-ID",
          "name": "NORM.DIST"
        },
        {
          "locale": "it-IT",
          "name": "NORM.DIST"
        },
        {
          "locale": "ja-JP",
          "name": "NORM.DIST"
        },
        {
          "locale": "ko-KR",
          "name": "NORM.DIST"
        },
        {
          "locale": "lt-LT",
          "name": "NORM.DIST"
        },
        {
          "locale": "lv-LV",
          "name": "NORM.DIST"
        },
        {
          "locale": "nb-NO",
          "name": "NORM.DIST"
        },
        {
          "locale": "nl-NL",
          "name": "NORM.DIST"
        },
        {
          "locale": "pl-PL",
          "name": "ROZKŁ.NORMALNY"
        },
        {
          "locale": "pt-BR",
          "name": "NORM.DIST"
        },
        {
          "locale": "pt-PT",
          "name": "DIST.NORMAL"
        },
        {
          "locale": "ro-RO",
          "name": "NORM.DIST"
        },
        {
          "locale": "ru-RU",
          "name": "НОРМ.РАСП"
        },
        {
          "locale": "sk-SK",
          "name": "NORM.DIST"
        },
        {
          "locale": "sl-SI",
          "name": "NORM.DIST"
        },
        {
          "locale": "sr-Latn-RS",
          "name": "NORM.DIST"
        },
        {
          "locale": "sv-SE",
          "name": "NORM.FÖRD"
        },
        {
          "locale": "th-TH",
          "name": "NORM.DIST"
        },
        {
          "locale": "tr-TR",
          "name": "NORM.DAĞ"
        },
        {
          "locale": "uk-UA",
          "name": "NORM.DIST"
        },
        {
          "locale": "vi-VN",
          "name": "NORM.DIST"
        },
        {
          "locale": "zh-CN",
          "name": "NORM.DIST"
        },
        {
          "locale": "zh-HK",
          "name": "NORM.DIST"
        },
        {
          "locale": "zh-TW",
          "name": "NORM.DIST"
        }
      ],
      "signature": {
        "display": "NORM.DIST(x, mean, standard_dev, cumulative)",
        "parameters": [
          {
            "description": null,
            "name": "x",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "mean",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "standard_dev",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "cumulative",
            "optional": false,
            "repeats": false
          }
        ],
        "trailing_repeats": false
      },
      "surface_name": "NORM.DIST",
      "version_marker": null,
      "xlcall": {
        "code": "499",
        "symbol": "xlfNorm_dist"
      }
    },
    "microsoft": "https://support.microsoft.com/en-us/office/norm-dist-function-edb1cc14-a21c-4e53-839d-8082074c9f8d"
  },
  "try_it": {
    "formula": "=NORM.DIST(1,0,1,TRUE)"
  },
  "url": "https://handbook.dnacalc.com/functions/NORM.DIST.html",
  "variants": [],
  "versions": [
    {
      "behaviour": "24,246 captured inputs are indexed for this environment. Capture dates: 2026-09-29 to 2026-09-29. This is a reading count, not a comparison with another build.",
      "excel_build": "16.0 build 20430",
      "platform": "Windows, 64-bit, CPU not recorded",
      "sources": [
        "https://github.com/DnaCalc/ExcelFunctionsHandbook/blob/5dc75391aa5125ccc5abdb095da85950980d6fd8/content/evidence/environments/FUNC.NORM.DIST.json"
      ]
    }
  ]
}