{
  "category": "Statistical functions",
  "display_name": "FREQUENCY",
  "entry_kind": "built_in_function",
  "eval_api": {
    "method": "POST",
    "url": "https://handbook.dnacalc.com/api/eval"
  },
  "function_id": "FUNC.FREQUENCY",
  "implementation_state": {
    "answer_bank": null,
    "detail": "Recorded: 7 workbook cells.",
    "dnacalc_commit": "9e1884369a678158dd82d3d74188daf986995e87",
    "in_catalogue": true,
    "state": "matches",
    "state_label": "Matches every recorded Excel answer",
    "summary": "Matches all 7 recorded answers",
    "workbook_corpus": {
      "cells": 7,
      "matched": 7
    }
  },
  "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/statistics.rs#L419-L423",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/statistics.rs#L519-L534"
      ],
      "repository": "https://github.com/DnaCalc/DnaCalc",
      "shared_code": [
        "catalogue/statistics::list"
      ],
      "source": "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/statistics.rs#L419-L423",
      "state": "matches",
      "suite": null,
      "summary": "Matches all 7 recorded answers"
    }
  ],
  "json_url": "https://handbook.dnacalc.com/api/functions/FUNC.FREQUENCY.json",
  "name": "FREQUENCY",
  "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- **`COUNTIF` / `COUNTIFS`** — the per-bin alternative. One `COUNTIFS` per interval reproduces\n  `FREQUENCY`, and doing so makes the boundary convention explicit instead of implicit, which is\n  why it is the usual debugging move when a histogram looks wrong by one.\n- **`COUNTIF` with `\">\"` and `\"<=\"`** — the direct spelling of a single half-open bin.\n- **`MATCH` with match type 1** — the same \"largest boundary not exceeding\" search that a\n  sorted-bin implementation performs internally, exposed as a lookup.\n- **`HISTOGRAM` (Analysis ToolPak)** and Excel's chart histogram — separate machinery with its\n  own binning rules; agreement with `FREQUENCY` is not to be assumed.\n- **`GROUPBY` / `PIVOTBY`** — the modern aggregation route, which supersedes `FREQUENCY` for\n  most reporting uses without superseding it as a function.\n\n\n",
    "how-to-implement": "\n### Numerical notes\n\n\n`FREQUENCY` has no arithmetic in it, and that makes its numerical behaviour easier to state and\nno less consequential.\n\n**The whole function is a comparison predicate.** Every count depends only on `value ≤ boundary`\nevaluated in IEEE double precision. Two things follow. First, values that a user thinks are\nequal to a boundary may not be: `0.1 + 0.2` is not `0.3`, and a data point produced by\narithmetic lands on the wrong side of a boundary typed as a literal. This is not a defect in\n`FREQUENCY`; it is the boundary convention meeting binary floating point, and it is why bin\nedges chosen midway between achievable data values are the robust choice. Second, the\ncomparison is exact, so the function is *deterministic and reproducible* in a way almost no\nother member of the Statistical category is — there is no summation order, no cancellation, no\ntranscendental.\n\n**Counts are exact.** Integers up to 2⁵³ are exactly representable, and no spreadsheet range\nreaches that, so the returned counts are exact integers with no accumulation error. Any\ndisagreement between two implementations of `FREQUENCY` is therefore a *semantic* disagreement —\nabout the boundary convention, the ignore rule, or the sortedness requirement — never a rounding\none. That is unusual in this category and it makes disagreements here unusually diagnostic.\n\n\n",
    "quirks": "\n### The bin convention\n\n\nWorth isolating, because it is where readers get the wrong answer while believing they got the\nright one.\n\n| Given bins | Interval for c₁ | for c₂ | … | for c_{m+1} |\n|---|---|---|---|---|\n| b₁, b₂, …, b_m | (−∞, b₁] | (b₁, b₂] | … | (b_m, +∞) |\n\nConsequences:\n\n- A data value equal to b₁ is counted in the **first** bin.\n- A data value equal to b_m is counted in bin m, **not** in the overflow bin.\n- Duplicate boundaries produce an empty interval between them, whose count is necessarily zero.\n- Reversing a \"greater than or equal\" intuition by shifting boundaries down by one unit works\n  for integers and fails for continuous data. There is no option to switch the convention.\n\n\n### Result and edge cases\n\n\nReturns `Array` — a vertical array of numbers, of length `LEN(bins_array) + 1`.\n\n- **No admitted values in `data_array`**: documented as an array of zeros. The array still has\n  one element more than the bin count.\n- **No admitted values in `bins_array`**: documented as \"the number of elements in data_array\",\n  which is the degenerate m = 0 case — a single-element array holding the total count. Note the\n  documented wording says *elements of data_array*, while the same page says text and blanks are\n  ignored; whether an ignored cell is an \"element\" for this rule is not stated.\n- **Both empty**: falls under both rules at once, which the documentation does not disambiguate.\n- **Duplicate boundaries** give a zero count for the collapsed interval.\n- **The counts are exact integers** held as doubles, so there is no accuracy question about the\n  counts themselves. The only comparison performed is `value ≤ boundary`, which is exact IEEE\n  comparison — and that is where the numerical content of this function actually lives; see\n  **Numerical notes**.\n- **Errors inside the scanned ranges** propagate under the shared coercion discipline; see\n  [Coercion and lifting](../model/02-coercion-and-lifting.md).\n\n\n\n### Errors\n\n\nMicrosoft's documentation for this function lists **no error conditions at all**. The Remarks\ndescribe entry mode, the extra element, and the ignore rule; there is no error table.\n\nNeither has a documented counterpart, and neither has been compared against Excel by the\nHandbook. The `#REF!` is the more surprising of the two: `#REF!` is the invalid-reference error,\nand nothing in the documented behaviour of `FREQUENCY` suggests a route to it from\nwell-formed array literals.\n\n\n",
    "sources": "- Handbook, [The value universe](../model/01-value-universe.md) — array as a value kind and the\n  raw-versus-published boundary.\n- Handbook, [Coercion and lifting](../model/02-coercion-and-lifting.md) — scan policy versus\n  elementwise lift, and error propagation.\n- Handbook projections `data/functions/FUNC.FREQUENCY.json` (arity, custom coercion and kernel\n  classes, reference-visible argument preparation) and `data/presence/FUNC.FREQUENCY.json` (the\n  `lookup_prob_frequency_family` module, shared with `LOOKUP`, `PROB` and `MODE.MULT`).\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`FREQUENCY(data_array, bins_array)` counts how many values of `data_array` fall into each\ninterval defined by `bins_array`, and returns those counts as a **vertical array with one more\nelement than `bins_array` has**.\n\nGiven m bin boundaries b₁ ≤ b₂ ≤ … ≤ b_m, the returned counts c₁ … c_{m+1} are\n\n    c₁      = #{ v : v ≤ b₁ }\n    c_k     = #{ v : b_{k−1} < v ≤ b_k }        for 2 ≤ k ≤ m\n    c_{m+1} = #{ v : v > b_m }\n\nThree properties define the function and all three are documented.\n\n**The intervals are half-open, closed on the right.** A value exactly equal to a boundary falls\ninto the interval *ending* at that boundary, not the one starting there. This is the opposite\nconvention from most histogram tooling — NumPy, R's `hist`, and most plotting libraries default\nto left-closed, right-open bins — and it is the single most common source of off-by-one\ndisagreement when a spreadsheet histogram is reproduced elsewhere. Microsoft's own worked\ndescription is the \"count of test scores in ranges of scores\" framing; the boundary rule\nfollows from the extra-element description quoted below.\n\n**The result has one more element than there are bins.** Microsoft states this directly, and\nexplains the extra element: it \"returns the count of any values above the highest interval\".\nThe m boundaries cut the real line into m + 1 pieces, and the function returns all m + 1\ncounts. Entering `FREQUENCY` over the same number of cells as bins silently discards the\noverflow count.\n\n**The result is a vertical array.** Not a row, not a scalar, whatever the shapes of the\ninputs. Microsoft's wording — \"returns a vertical array of numbers\" — is a shape guarantee, and\nit means an implementation cannot echo the orientation of `bins_array`.\n\nCounts are returned as numbers; the sum of all m + 1 counts equals the number of *admitted*\nvalues in `data_array`, which is not the same as the number of cells in it — see the\nignore rule under **Arguments**.\n\n\n\n### Arguments\n\n| Argument | Meaning |\n|---|---|\n| `data_array` | The values whose frequencies are counted. Documented: if it \"contains no values, FREQUENCY returns an array of zeros.\" |\n| `bins_array` | The interval boundaries. Documented: if it \"contains no values, FREQUENCY returns the number of elements in data_array.\" |\n\n**`FREQUENCY` ignores blank cells and text.** That is Microsoft's sentence, verbatim in\nsubstance, and it is the scan policy for both arguments. Note what it does not say: it says\nnothing about logical values, and nothing about text that looks like a number. Those are\nunsettled here and are on the probe list.\n\nBoth arguments are consumed by scanning. This is not a lift kernel and there is no elementwise\nbroadcast; an array argument is data, not a call to repeat the function.\n\nMicrosoft's remark that `FREQUENCY` \"must be entered as an array formula\" is a pre-dynamic-array\nstatement. On a build with dynamic arrays the result spills from a single cell. The Handbook has\nnot checked how the two entry modes differ on this function, and the difference is exactly the\nkind that changes what a reader sees without changing what the function computes.\n\n\n"
  },
  "signature": {
    "display": "FREQUENCY(data_array, bins_array)",
    "parameters": [
      {
        "description": null,
        "name": "data_array",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "bins_array",
        "optional": false,
        "repeats": false
      }
    ],
    "trailing_repeats": false
  },
  "sources": {
    "metadata": {
      "admission": {
        "label": "implemented",
        "reason": null
      },
      "arity": {
        "max": 2,
        "min": 2
      },
      "category": "Statistical functions",
      "classification": {
        "arg_preparation_profile": "RefsVisibleInAdapter",
        "coercion_lift_profile": "Custom",
        "determinism_class": "Deterministic",
        "error_collapse_profile": "None",
        "fec_dependency_profile": "RefOnly",
        "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": "How many values fall into each bin, as a vertical array",
        "short_source": "dna-calc-own"
      },
      "docs": {
        "english_description": "Returns a frequency distribution as a vertical array",
        "microsoft_url": "https://support.microsoft.com/en-us/office/frequency-function-44e3be2b-eca0-42cd-a3f7-fd9ea898fdb9"
      },
      "entry_kind": "built_in_function",
      "localized_family_names": null,
      "localized_names": [
        {
          "locale": "ar-SA",
          "name": "FREQUENCY"
        },
        {
          "locale": "bg-BG",
          "name": "FREQUENCY"
        },
        {
          "locale": "cs-CZ",
          "name": "ČETNOSTI"
        },
        {
          "locale": "da-DK",
          "name": "FREKVENS"
        },
        {
          "locale": "de-DE",
          "name": "FREQUENCY"
        },
        {
          "locale": "el-GR",
          "name": "FREQUENCY"
        },
        {
          "locale": "en-AU",
          "name": "FREQUENCY"
        },
        {
          "locale": "en-GB",
          "name": "FREQUENCY"
        },
        {
          "locale": "en-US",
          "name": "FREQUENCY"
        },
        {
          "locale": "es-ES",
          "name": "FRECUENCIA"
        },
        {
          "locale": "et-EE",
          "name": "FREQUENCY"
        },
        {
          "locale": "fi-FI",
          "name": "TAAJUUS"
        },
        {
          "locale": "fr-FR",
          "name": "FREQUENCE*"
        },
        {
          "locale": "he-IL",
          "name": "FREQUENCY"
        },
        {
          "locale": "hr-HR",
          "name": "FREQUENCY"
        },
        {
          "locale": "hu-HU",
          "name": "GYAKORISÁG"
        },
        {
          "locale": "id-ID",
          "name": "FREQUENCY"
        },
        {
          "locale": "it-IT",
          "name": "FREQUENCY"
        },
        {
          "locale": "ja-JP",
          "name": "FREQUENCY"
        },
        {
          "locale": "ko-KR",
          "name": "빈도"
        },
        {
          "locale": "lt-LT",
          "name": "FREQUENCY"
        },
        {
          "locale": "lv-LV",
          "name": "FREQUENCY"
        },
        {
          "locale": "nb-NO",
          "name": "FREKVENS"
        },
        {
          "locale": "nl-NL",
          "name": "INTERVAL"
        },
        {
          "locale": "pl-PL",
          "name": "CZĘSTOŚĆ"
        },
        {
          "locale": "pt-BR",
          "name": "FREQUÊNCIA"
        },
        {
          "locale": "pt-PT",
          "name": "FREQUÊNCIA"
        },
        {
          "locale": "ro-RO",
          "name": "FREQUENCY"
        },
        {
          "locale": "ru-RU",
          "name": "ЧАСТОТА"
        },
        {
          "locale": "sk-SK",
          "name": "FREQUENCY"
        },
        {
          "locale": "sl-SI",
          "name": "FREQUENCY"
        },
        {
          "locale": "sr-Latn-RS",
          "name": "FREKVENCIJA"
        },
        {
          "locale": "sv-SE",
          "name": "FREKVENS"
        },
        {
          "locale": "th-TH",
          "name": "FREQUENCY"
        },
        {
          "locale": "tr-TR",
          "name": "SIKLIK işlevi"
        },
        {
          "locale": "uk-UA",
          "name": "FREQUENCY"
        },
        {
          "locale": "vi-VN",
          "name": "FREQUENCY"
        },
        {
          "locale": "zh-CN",
          "name": "FREQUENCY"
        },
        {
          "locale": "zh-HK",
          "name": "FREQUENCY"
        },
        {
          "locale": "zh-TW",
          "name": "FREQUENCY"
        }
      ],
      "signature": {
        "display": "FREQUENCY(data_array, bins_array)",
        "parameters": [
          {
            "description": null,
            "name": "data_array",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "bins_array",
            "optional": false,
            "repeats": false
          }
        ],
        "trailing_repeats": false
      },
      "surface_name": "FREQUENCY",
      "version_marker": null,
      "xlcall": {
        "code": "252",
        "symbol": "xlfFrequency"
      }
    },
    "microsoft": "https://support.microsoft.com/en-us/office/frequency-function-44e3be2b-eca0-42cd-a3f7-fd9ea898fdb9"
  },
  "try_it": {
    "formula": "=FREQUENCY({1;2;3;4;5},{2;4})"
  },
  "url": "https://handbook.dnacalc.com/functions/FREQUENCY.html",
  "variants": [],
  "versions": []
}