{
  "category": "Statistical functions",
  "display_name": "SMALL",
  "entry_kind": "built_in_function",
  "eval_api": {
    "method": "POST",
    "url": "https://handbook.dnacalc.com/api/eval"
  },
  "function_id": "FUNC.SMALL",
  "implementation_state": {
    "answer_bank": null,
    "detail": "Recorded: 6 workbook cells.",
    "dnacalc_commit": "9e1884369a678158dd82d3d74188daf986995e87",
    "in_catalogue": true,
    "state": "matches",
    "state_label": "Matches every recorded Excel answer",
    "summary": "Matches all 6 recorded answers",
    "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/statistics.rs#L298-L298"
      ],
      "repository": "https://github.com/DnaCalc/DnaCalc",
      "shared_code": [
        "catalogue/statistics::list",
        "catalogue/statistics::sorted",
        "catalogue/statistics::nth"
      ],
      "source": "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/statistics.rs#L298-L298",
      "state": "matches",
      "suite": null,
      "summary": "Matches all 6 recorded answers"
    }
  ],
  "json_url": "https://handbook.dnacalc.com/api/functions/FUNC.SMALL.json",
  "name": "SMALL",
  "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\n- **[LARGE](FUNC.LARGE.md)** is the descending counterpart, with the exact identity\n  `SMALL(A,k) = LARGE(A, COUNT(A)-k+1)`. The two are the same selection with the comparison\n  reversed.\n- **[MIN](FUNC.MIN.md)** is `SMALL(A, 1)` and **[MAX](FUNC.MAX.md)** is `LARGE(A, 1)`. `MIN` and\n  `MAX` are the ones to use for the extremes — they need no count and no `k`, and they do not\n  error on an empty range (they return `0`), which is a behavioural difference worth knowing when\n  a range might be empty.\n- **[MEDIAN](FUNC.MEDIAN.md)** is `SMALL(A, (n+1)/2)` for odd `n` and the mean of the two middle\n  order statistics for even `n`.\n- **[QUARTILE.INC](FUNC.QUARTILE.INC.md) and [PERCENTILE.INC](FUNC.PERCENTILE.INC.md)** are the\n  interpolating relatives. They return quantiles, which may be values that occur nowhere in the\n  data; `SMALL` returns observations. Choosing between them is a choice about what the number is\n  supposed to mean, not a choice of formula.\n- **[RANK.EQ](FUNC.RANK.EQ.md)** is the inverse map: `LARGE(ref, RANK.EQ(x, ref))` recovers `x`,\n  because competition rank and the descending order-statistic index coincide. The ascending\n  version composes with `RANK.EQ(x, ref, 1)`.\n- **[SORT](FUNC.SORT.md)** and **[SORTBY](FUNC.SORTBY.md)** return the whole ordering as a spilled\n  array. Where several order statistics are wanted at once, one `SORT` beats several `SMALL`\n  calls by an order of magnitude in work.\n- The idiom `SMALL(IF(cond, range), k)` is the classic way to get the `k`-th smallest among rows\n  meeting a condition, and depends on the `FALSE` branch producing values `SMALL` skips.\n- Readers confuse `SMALL` with `MINIFS`, which returns the minimum under criteria — the `k = 1`\n  case of the conditional idiom, with the condition expressed properly rather than through an\n  array formula.\n\n\n",
    "how-to-implement": "\n### Numerical notes\n\n\n`SMALL` performs no arithmetic on the data. It sorts and it indexes, so there is **no rounding\nerror in the result at all** — the returned value is bit-identical to the input value that was\nselected. That makes it one of the few statistical functions whose correctness is entirely a\nquestion of ordering and admissibility rather than of accuracy. Three ordering questions\nnonetheless deserve attention.\n\n**Signed zeros.** IEEE-754 defines `-0.0 == +0.0` as true and neither as less than the other, so\na data set containing both admits two valid sorted orders and `SMALL` may return either zero. The\nvalues compare equal and print identically, so this is invisible in a spreadsheet — but it is\nvisible to any comparison of raw bits, and a vector suite comparing bit patterns must decide\nwhether it cares. The mathematically honest position is that `SMALL` is well defined as a\nmultiset selection and under-determined as a bit selection.\n\n**Stability and cost.** The kernel performs a **full sort**, `O(n log n)`, to answer a question\nthat quickselect answers in expected `O(n)` — the classical result of Blum, Floyd, Pratt, Rivest\nand Tarjan (1973) gives a worst-case linear bound. For a single `SMALL` over a large column the\nsort is the entire cost of the call, and a column of `SMALL` formulas over the same range re-sorts\nthe same data once per formula. That is a performance property rather than a correctness one, but\nit is the reason a `k`-th-smallest column is slow and a `SORT` spill is not, and no amount of\nformula rewriting inside `SMALL` fixes it.\n\n**The truncation of `k`.** `trunc(k)` before validation means the admissible interval for `k` is\nthe half-open `[1, n+1)` rather than the closed `[1, n]`: `k = n + 0.5` truncates to `n` and\nsucceeds. Nothing documents this, and the alternative — validate first, then truncate — would\nreject it. Which one Excel does is a one-cell experiment nobody has run.\n\n\n",
    "quirks": "\n### Result and edge cases\n\n\nReturns `Number` — one of the values from `array`, returned unchanged.\n\n- **`array` contains no numeric values.** `n = 0`, so every `k` fails: `#NUM!`. A range holding\n  only text produces `#NUM!`, not `#VALUE!`.\n- **`k` greater than the count of numeric values.** `#NUM!`. Note again that the count is of\n  numeric cells, so adding a header row to a range does not increase the admissible `k`.\n- **`k` less than 1 after truncation.** `#NUM!`.\n- **Repeated values** are indexed as they occur; `n` counts them all.\n- **The result is the stored value, not a rounded one.** `SMALL` never computes; whatever double\n  was in the cell is what comes back, including its exact bit pattern.\n- **Errors in `array`** propagate as themselves.\n- **`array` given as a rectangular grid** is flattened; shape is irrelevant.\n- **`SMALL` returns a scalar, not a spilled array**, even when `k` is array-valued — whether\n  Excel lifts over an array-valued `k` in a modern build is a lifting question this page does not\n  settle.\n\n\n\n### Errors\n\n\n| Error | Condition | Source |\n|---|---|---|\n| `#NUM!` | `array` is empty of numeric values | documented |\n| `#NUM!` | `k <= 0` | documented |\n| `#NUM!` | `k` exceeds the number of numeric data points | documented |\n| `#VALUE!` | `k` is non-numeric text | shared coercion rule |\n| propagated | An error value in `array` or in `k` surfaces as that error | shared coercion rule |\n\n\n",
    "sources": "- Microsoft, *SMALL function* —\n  <https://support.microsoft.com/en-us/office/small-function-17da8222-7c82-42b2-961b-14c45384df07>\n  (signature, and the `#NUM!` conditions for an empty array, for `k <= 0` and for `k` exceeding\n  the number of data points). Retrieval was blocked by the upstream host for this page; the\n  documented behaviour above is stated as documented behaviour and should be re-checked against\n  the page.\n- M. Blum, R. W. Floyd, V. Pratt, R. L. Rivest and R. E. Tarjan, \"Time Bounds for Selection\",\n  *Journal of Computer and System Sciences* 7(4), 1973, pp. 448–461 — worst-case linear\n  selection, the algorithm the sort-based implementation forgoes.\n- IEEE Std 754-2019, clause 5.11 (comparison predicates) — the signed-zero equality and the\n  unordered outcome for NaN that make the ordering under-determined in the two cases named above.\n- Handbook [coercion and lifting](../model/02-coercion-and-lifting.md) — the range-scan policy\n  that decides what counts toward `n`, and the direct-argument contrast.\n- Handbook `data/functions/FUNC.SMALL.json`, `data/presence/FUNC.SMALL.json`.\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`SMALL(array, k)` returns the **`k`-th order statistic** of the numeric values in `array`,\ncounting from the bottom.\n\nLet the numeric values of `array`, sorted ascending, be `x_(1) <= x_(2) <= … <= x_(n)`. Then\n\n    SMALL(array, k)  =  x_(k)\n\nfor `1 <= k <= n`, and `#NUM!` otherwise.\n\nThis is selection, not estimation. Unlike [PERCENTILE.INC](FUNC.PERCENTILE.INC.md) or\n[QUARTILE.INC](FUNC.QUARTILE.INC.md), `SMALL` performs no interpolation: the result is always a\nvalue that actually occurs in the data, returned unchanged. That property is the reason to reach\nfor it — when a report must cite a real observation rather than a computed quantile, `SMALL` is\nthe function that guarantees it.\n\nThe two ends are the familiar aggregates:\n\n    SMALL(A, 1)  =  MIN(A)          SMALL(A, n)  =  MAX(A)\n\nand the ascending/descending duality with [LARGE](FUNC.LARGE.md) is exact:\n\n    SMALL(A, k)  =  LARGE(A, n - k + 1)\n\nwhere `n` is the count of *numeric* values, which is `COUNT(A)` and not the size of the range.\nThat last qualification is where the identity is usually got wrong in practice: a range with text\nlabels in it has an `n` smaller than its cell count, and a formula written as\n`LARGE(A, ROWS(A)-k+1)` silently indexes the wrong statistic.\n\n**Ties are not deduplicated.** `SMALL` indexes the sorted multiset, not the sorted set of distinct\nvalues. On `{5, 5, 5}`, `SMALL(A, 2)` is `5`, not an error and not the second distinct value.\nReaders wanting the second *distinct* smallest need a different construction entirely.\n\n`SMALL` is monotone non-decreasing in `k`, and monotone non-decreasing in each data value — it is\nan order-preserving selector, which is what makes it safe to compose with itself.\n\n\n\n### Arguments\n\n\n| Argument | Meaning | Required |\n|---|---|---|\n| `array` | The data set. | yes |\n| `k` | The position from the bottom, 1-based. | yes |\n\n`array` is consumed by scanning. Text, logical values and blank cells reached through a range or\narray are skipped rather than converted — they do not become zeros and they do not enlarge `n`.\nValues passed directly as scalars go through ordinary to-number coercion under the dual policy of\n[coercion and lifting](../model/02-coercion-and-lifting.md).\n\n"
  },
  "signature": {
    "display": "SMALL(array, k)",
    "parameters": [
      {
        "description": null,
        "name": "array",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "k",
        "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": "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 k-th smallest value",
        "short_source": "dna-calc-own"
      },
      "docs": {
        "english_description": "Returns the k-th smallest value in a data set",
        "microsoft_url": "https://support.microsoft.com/en-us/office/small-function-17da8222-7c82-42b2-961b-14c45384df07"
      },
      "entry_kind": "built_in_function",
      "localized_family_names": null,
      "localized_names": [
        {
          "locale": "ar-SA",
          "name": "SMALL"
        },
        {
          "locale": "bg-BG",
          "name": "SMALL"
        },
        {
          "locale": "cs-CZ",
          "name": "SMALL"
        },
        {
          "locale": "da-DK",
          "name": "MINDSTE"
        },
        {
          "locale": "de-DE",
          "name": "KKLEINSTE"
        },
        {
          "locale": "el-GR",
          "name": "SMALL"
        },
        {
          "locale": "en-AU",
          "name": "SMALL"
        },
        {
          "locale": "en-GB",
          "name": "SMALL"
        },
        {
          "locale": "en-US",
          "name": "SMALL"
        },
        {
          "locale": "es-ES",
          "name": "K.ESIMO.MENOR"
        },
        {
          "locale": "et-EE",
          "name": "SMALL"
        },
        {
          "locale": "fi-FI",
          "name": "PIENI"
        },
        {
          "locale": "fr-FR",
          "name": "PETITE.VALEUR"
        },
        {
          "locale": "he-IL",
          "name": "SMALL"
        },
        {
          "locale": "hr-HR",
          "name": "SMALL"
        },
        {
          "locale": "hu-HU",
          "name": "KICSI"
        },
        {
          "locale": "id-ID",
          "name": "SMALL"
        },
        {
          "locale": "it-IT",
          "name": "PICCOLO"
        },
        {
          "locale": "ja-JP",
          "name": "SMALL"
        },
        {
          "locale": "ko-KR",
          "name": "SMALL"
        },
        {
          "locale": "lt-LT",
          "name": "SMALL"
        },
        {
          "locale": "lv-LV",
          "name": "SMALL"
        },
        {
          "locale": "nb-NO",
          "name": "N.MINST"
        },
        {
          "locale": "nl-NL",
          "name": "KLEINSTE"
        },
        {
          "locale": "pl-PL",
          "name": "MIN.K"
        },
        {
          "locale": "pt-BR",
          "name": "MENOR"
        },
        {
          "locale": "pt-PT",
          "name": "MENOR"
        },
        {
          "locale": "ro-RO",
          "name": "SMALL"
        },
        {
          "locale": "ru-RU",
          "name": "НАИМЕНЬШИЙ"
        },
        {
          "locale": "sk-SK",
          "name": "SMALL"
        },
        {
          "locale": "sl-SI",
          "name": "SMALL"
        },
        {
          "locale": "sr-Latn-RS",
          "name": "SMALL"
        },
        {
          "locale": "sv-SE",
          "name": "MINSTA"
        },
        {
          "locale": "th-TH",
          "name": "SMALL"
        },
        {
          "locale": "tr-TR",
          "name": "KÜÇÜK"
        },
        {
          "locale": "uk-UA",
          "name": "SMALL"
        },
        {
          "locale": "vi-VN",
          "name": "SMALL"
        },
        {
          "locale": "zh-CN",
          "name": "SMALL"
        },
        {
          "locale": "zh-HK",
          "name": "SMALL"
        },
        {
          "locale": "zh-TW",
          "name": "SMALL"
        }
      ],
      "signature": {
        "display": "SMALL(array, k)",
        "parameters": [
          {
            "description": null,
            "name": "array",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "k",
            "optional": false,
            "repeats": false
          }
        ],
        "trailing_repeats": false
      },
      "surface_name": "SMALL",
      "version_marker": null,
      "xlcall": {
        "code": "326",
        "symbol": "xlfSmall"
      }
    },
    "microsoft": "https://support.microsoft.com/en-us/office/small-function-17da8222-7c82-42b2-961b-14c45384df07"
  },
  "try_it": {
    "formula": "=SMALL({10,20,30}, 2.9)"
  },
  "url": "https://handbook.dnacalc.com/functions/SMALL.html",
  "variants": [],
  "versions": []
}