{
  "category": "Math and trigonometry functions",
  "display_name": "ATAN2",
  "entry_kind": "built_in_function",
  "eval_api": {
    "method": "POST",
    "url": "https://handbook.dnacalc.com/api/eval"
  },
  "function_id": "FUNC.ATAN2",
  "implementation_state": {
    "answer_bank": null,
    "detail": "Recorded: 124 workbook cells.",
    "dnacalc_commit": "9e1884369a678158dd82d3d74188daf986995e87",
    "in_catalogue": true,
    "state": "matches",
    "state_label": "Matches every recorded Excel answer",
    "summary": "Matches all 124 recorded answers",
    "workbook_corpus": {
      "cells": 124,
      "matched": 124
    }
  },
  "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/math.rs#L54-L56",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/ported/atan2.rs#L3-L28",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/ported/excel_numeric/mod.rs#L578-L590"
      ],
      "repository": "https://github.com/DnaCalc/DnaCalc",
      "shared_code": [
        "catalogue/math::binary",
        "ported/excel_numeric::atan_with",
        "ported/excel_numeric/soft87::pack_raw",
        "ported/excel_numeric/soft87::zero",
        "ported/excel_numeric/soft87::inf",
        "ported/excel_numeric/soft87::pack",
        "ported/excel_numeric/soft87::ext_one",
        "ported/excel_numeric/x87::atan"
      ],
      "source": "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/math.rs#L54-L56",
      "state": "matches",
      "suite": null,
      "summary": "Matches all 124 recorded answers"
    }
  ],
  "json_url": "https://handbook.dnacalc.com/api/functions/FUNC.ATAN2.json",
  "name": "ATAN2",
  "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- **`ATAN`** — the one-argument form. `ATAN2(x, y) = ATAN(y/x)` for `x > 0` only, and the\n  restriction is the reason `ATAN2` exists. Note that `ATAN` itself never overflows, because the\n  caller has already done the division and taken the consequences.\n- **`ACOT`** — `ACOT(x) = ATAN2(x, 1)` in Excel's order, and that formulation is better conditioned\n  at large `|x|` than `PI()/2 - ATAN(x)`. See the [ACOT](FUNC.ACOT.md) page.\n- **`IMARGUMENT`** — the complex-number surface computing the same quantity, `arg(x + iy)`. If the\n  two disagree anywhere, one of them is wrong, and that is a cheap cross-check the Handbook has not\n  run.\n- **`ASIN` / `ACOS`** — both are better computed through `ATAN2` than through their own closed\n  forms when the endpoints matter: `asin(t) = ATAN2(SQRT(1-t^2), t)` and\n  `acos(t) = ATAN2(t, SQRT(1-t^2))` in Excel's order.\n- **`DEGREES`** — the usual consumer; the Learn reference gives the 180/PI() remark.\n- **`SQRT`, `SUMSQ`** — the magnitude half of a polar conversion, of which `ATAN2` is the angle\n  half.\n- **Confused with**: `ATAN`, whenever the quadrant matters; and with every other language's\n  `atan2`, whose argument order is reversed.\n\n\n",
    "how-to-implement": "\n### Numerical notes\n\n\n**How a correct two-argument arctangent is built.** The standard construction has three steps and\nnever forms a quotient larger than 1:\n\n1. Compare `|x|` and `|y|`. Compute `r = min(|x|,|y|) / max(|x|,|y|)`, which lies in `[0, 1]` and\n   cannot overflow. If both are zero, the angle is undefined — that is the only true failure.\n2. Evaluate `atan(r)`, which is the accurate, well-conditioned part.\n3. Reflect into the correct octant and quadrant using the signs of `x` and `y` and whether the\n   swap happened, adding `pi/2`, `pi` or negating as required.\n\nThe construction is total on the punctured plane, never overflows, never underflows in a way that\nmatters, and is accurate for every direction including the extremely elongated ones. IEEE 754\nclause 9.2 specifies the behaviour including at zeros and infinities.\n\n**Why the ratio form is worse than it looks.** Beyond the overflow, `y/x` loses the homogeneity\nproperty: `atan2(t*x, t*y)` should be independent of `t`, and forming a quotient makes it depend on\nwhether that quotient happens to be representable. So a formula that scales its coordinates — a\ncompletely ordinary thing to do — can change its answer from an angle to an error. There is no\nscaling that fixes it in general, because the failing cases are exactly the ones with extreme\naspect ratios.\n\n**Underflow is the mirror hazard.** If `y` is tiny and `x` is huge, `y/x` underflows to zero and\nthe angle comes back as exactly `0` or `pi` rather than as a tiny nonzero angle. That is the same\ndefect at the other end, and it produces a *wrong number* rather than an error — the worse of the\ntwo outcomes. Whether it occurs is a separate question from the overflow, and the Handbook does not\nknow the answer for Excel; no record addresses it.\n\n**The `pi` constant appears twice.** The quadrant adjustments add `pi` or `pi/2`. As with `ATAN`,\na careful implementation uses a two-part split constant so the addition does not eat the accuracy\nof a result that may be small. An angle just below `pi` computed as `pi_double - small` inherits\nthe representation error of `pi_double`.\n\n**Signed zero decides the cut.** `atan2(-1, +0) = pi` and `atan2(-1, -0) = -pi` under IEEE; this is\nhow the standard lets a computation stay on the correct side of the branch cut. Excel's documented\nrange excludes `-pi`, which means either that the distinction is not expressible or that the\ndocumented range is approximate. Nobody has checked which.\n\n\n",
    "quirks": "\n### Result and edge cases\n\n\nReturns `Number` — an angle in radians in `(-pi, pi]`.\n\n- **On the axes.** `x = 0` with `y` nonzero gives `±pi/2`, documented. `y = 0` with `x > 0` gives\n  `0`; `y = 0` with `x < 0` gives `pi` — note that the documented identity table routes this\n  through the `y >= 0, x < 0` row, so `pi` and not `-pi`, consistent with the half-open range.\n- **Signed zero.** The IEEE two-argument arctangent uses the *sign* of a zero argument to decide\n  which side of the branch cut a point lies on: `atan2(-1, +0)` is `pi` and `atan2(-1, -0)` is\n  `-pi`. Whether Excel's value model can express that distinction at all is an open question — see\n  [The value universe](../model/01-value-universe.md) — and it interacts with the fact that Excel's\n  range excludes `-pi`.\n- **Equal-magnitude arguments** give the diagonal angles exactly, or as exactly as the constants\n  allow.\n\n\n### The ratio-overflow departure\n\nThis is the substantive finding on the page, and it follows directly from the documented identity\ntable.\n\nMathematically, the angle of a point is finite for *every* point except the origin, and depends\nonly on the point's direction. A genuine two-argument arctangent never forms `y/x`; it compares\nmagnitudes and works with the smaller-over-larger ratio, which is always at most 1. Forming `y/x`\ndirectly reintroduces exactly the overflow the two-argument form exists to avoid: if `y` is huge\nand `x` is tiny, the quotient overflows to infinity even though the answer is an ordinary angle\nvery close to `±pi/2`.\n\n**`EV-MATH-0007` and `EV-MISC-0013` both carry `FUNC.ATAN2` as a subject**, and both concern the\nsame upstream math-deviation row: an error is published exactly when `x` is nonzero and the\nimplicit `y/x` ratio overflows, while the axis case `x = 0` — where the ratio is undefined rather\nthan overflowing — keeps its `±pi/2` value. `EV-MISC-0013`'s own status text puts it plainly: the\nfour-quadrant angle is finite everywhere off the origin, so this is the ratio being formed first\nand the overflow being inherited; a two-argument `atan2` would never do it.\n\nBoth records carry counts, and both carry a warning the Handbook must repeat rather than\nparaphrase away: **what was counted is an error-placement boundary, not the bits of the returned\nangle.** `EV-MISC-0013` states that it publishes the weaker reading — the boundary was measured,\nnot the angle — and that its count rides on the numeric axis only by the register's convention.\nThe figures are rendered with the records and are not restated here. **No claim about the accuracy\nof the angle itself follows from either record**, and this page makes none.\n\n**The documentation predicts the departure.** Microsoft's own identity table says\n`ATAN2(x,y) = ATAN(y/x)` for `x > 0`. Taken as a specification of the *evaluation*, that identity\nrequires forming the ratio, and forming it in binary64 requires it to be representable. So the\ndocumented identity and the identified behaviour agree with each other — and both depart from the\nmathematical function they claim to compute. That is an unusually clean example of a specification\nwritten in mathematics being implemented as arithmetic.\n\n\n\n### Errors\n\nThe second row is the interesting one: an error condition that exists on record and appears in no\ndocumentation the Handbook has retrieved.\n\n\n",
    "sources": "- Microsoft Learn, \"WorksheetFunction.Atan2 method (Excel)\" —\n  <https://learn.microsoft.com/en-us/office/vba/api/excel.worksheetfunction.atan2> (retrieved: the\n  x-first parameter table, the `(-pi, pi]` range, the five quadrant identities including\n  `ATAN2(x,y) = ATAN(y/x)` for `x > 0`, and the unnamed error value at the origin).\n- IEEE Std 754-2019, clause 9.2 — the standard two-argument arctangent and its signed-zero\n  conventions.\n- Kahan, *Branch Cuts for Complex Elementary Functions* — why the two-argument form exists and how\n  signed zero selects the side of the cut.\n- Abramowitz & Stegun, *Handbook of Mathematical Functions*, chapter 4 section 4.4 — the\n  arctangent and the quadrant adjustments.\n- Handbook evidence records `EV-MATH-0007` and `EV-MISC-0013` (subject `FUNC.ATAN2`) — the\n  `y/x`-overflow error boundary, each with its own warning that the boundary and not the angle was\n  what was counted; and `EV-STRUCT-0011` (subjects `FUNC.ATAN2`, `FUNC.BASE`) — the array-lift\n  tranche, whose counts are group totals with no per-surface split.\n- Handbook projections `data/functions/FUNC.ATAN2.json` (arity 2, `NumsToNum`, `Custom` lift\n  profile) and `data/presence/FUNC.ATAN2.json` (implementing module; math-deviation entries; the\n  `BUG-FUNC-017` and `BUG-FUNC-027` defect streams).\n- Handbook [The value universe](../model/01-value-universe.md) and\n  [Coercion and lifting](../model/02-coercion-and-lifting.md); related page\n  [ATAN](FUNC.ATAN.md).\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| 19929 | Windows, bitness not recorded, CPU not recorded | 116 |\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.ATAN2.json).",
    "what-it-does": "\n`ATAN2(x_num, y_num)` is the four-quadrant inverse tangent: the angle from the positive x-axis to\nthe ray through the origin and the point `(x, y)`.\n\n    atan2: R^2 \\ {(0,0)} -> (-pi, pi]\n\nMicrosoft's Learn reference states the geometry and the range directly: the arctangent is the angle\nfrom the x-axis to a line containing the origin and a point with coordinates `(x_num, y_num)`, and\nthe angle is given in radians between `-pi` and `pi`, excluding `-pi`.\n\n### The argument order is the trap\n\n**Excel takes `x` first.** Nearly every other implementation of this function in nearly every other\nlanguage — C, Python, Java, JavaScript, Fortran, Rust — takes `y` first, as `atan2(y, x)`. Excel's\nsignature is `ATAN2(x_num, y_num)`. Microsoft's Learn parameter table is unambiguous: `Arg1` is the\nx-coordinate, `Arg2` is the y-coordinate.\n\nA formula ported in either direction without swapping the arguments computes the reflection of the\nintended angle about the line `y = x`, which is wrong by an amount that varies with the point and\nis therefore not detectable by a spot check. This is the single most consequential fact on the\npage and it is why the Handbook states it before the mathematics.\n\n### The mathematics\n\nThe function is the **argument** (phase) of the point, the same object as `arg(x + iy)` in the\ncomplex plane. Microsoft's Learn reference documents it as a set of quadrant identities:\n\n| Condition | Documented identity |\n|---|---|\n| `x > 0` | `ATAN2(x,y) = ATAN(y/x)` |\n| `y >= 0`, `x < 0` | `ATAN2(x,y) = ATAN(y/x) + PI()` |\n| `y < 0`, `x < 0` | `ATAN2(x,y) = ATAN(y/x) - PI()` |\n| `y > 0`, `x = 0` | `ATAN2(x,y) = PI()/2` |\n| `y < 0`, `x = 0` | `ATAN2(x,y) = -PI()/2` |\n| `x = 0` and `y = 0` | returns an error value |\n\nStructural properties:\n\n- **Domain**: the punctured plane. Every point except the origin has a well-defined argument;\n  at the origin the angle is genuinely undefined, not merely inconvenient.\n- **Range**: `(-pi, pi]`. The value `pi` is attained (on the negative x-axis with `y >= 0`) and\n  `-pi` is not — the half-open convention that makes the function single-valued.\n- **Branch cut**: the negative x-axis. Crossing it, the value jumps by `2pi`. `ATAN2` is\n  continuous on the plane minus that ray and discontinuous across it; this is not an artefact but\n  the unavoidable consequence of representing a circle-valued quantity by a real number.\n- **Homogeneity**: `atan2(t*x, t*y) = atan2(x, y)` for every `t > 0`. The function depends only on\n  the *direction* of the point, not on its magnitude. **This is the property that matters most\n  numerically, and it is the one the departure described below violates.**\n- **Symmetries**: `atan2(x, -y) = -atan2(x, y)` when `y != 0`; and `atan2(-x, y) = pi - atan2(x, y)`\n  for `y > 0`.\n- **Relation to the one-argument form**: `atan2(x, y) = atan(y/x)` only for `x > 0`. The whole\n  reason the two-argument function exists is that the ratio `y/x` discards the information needed\n  to place the quadrant — and, as the next section shows, discards more than that.\n\n\n\n### Arguments\n\n\n| Argument | Meaning | Default |\n|---|---|---|\n| `x_num` | The **x**-coordinate of the point. Required. | — |\n| `y_num` | The **y**-coordinate of the point. Required. | — |\n\nThe misunderstood position is, of course, the order — see above. A secondary one: these are\n*coordinates*, not a slope and a length. `ATAN2(1, 1)` is `pi/4` because the point is on the\ndiagonal, not because `1/1 = 1`.\n\n\n"
  },
  "signature": {
    "display": "ATAN2(x_num, y_num)",
    "parameters": [
      {
        "description": null,
        "name": "x_num",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "y_num",
        "optional": false,
        "repeats": false
      }
    ],
    "trailing_repeats": false
  },
  "sources": {
    "metadata": {
      "admission": {
        "label": "implemented",
        "reason": null
      },
      "arity": {
        "max": 2,
        "min": 2
      },
      "category": "Math and trigonometry 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": "NumsToNum",
        "rich_value_usage": "RichBlind",
        "surface_fec_dependency_profile": "RefOnly",
        "thread_safety_class": "SafePure",
        "volatility_class": "NonVolatile"
      },
      "descriptions": {
        "long": null,
        "short": "Angle in radians from the positive x-axis to the point (x, y), between -pi and pi",
        "short_source": "dna-calc-own"
      },
      "docs": {
        "english_description": "Returns the arctangent from x- and y-coordinates",
        "microsoft_url": "https://support.microsoft.com/en-us/office/atan2-function-c04592ab-b9e3-4908-b428-c96b3a565033"
      },
      "entry_kind": "built_in_function",
      "localized_family_names": null,
      "localized_names": [
        {
          "locale": "ar-SA",
          "name": "ATAN2"
        },
        {
          "locale": "bg-BG",
          "name": "ATAN2"
        },
        {
          "locale": "cs-CZ",
          "name": "ARCTG2"
        },
        {
          "locale": "da-DK",
          "name": "ARCTAN2"
        },
        {
          "locale": "de-DE",
          "name": "ATAN2"
        },
        {
          "locale": "el-GR",
          "name": "ATAN2"
        },
        {
          "locale": "en-AU",
          "name": "ATAN2"
        },
        {
          "locale": "en-GB",
          "name": "ATAN2"
        },
        {
          "locale": "en-US",
          "name": "ATAN2"
        },
        {
          "locale": "es-ES",
          "name": "ATAN2"
        },
        {
          "locale": "et-EE",
          "name": "ATAN2"
        },
        {
          "locale": "fi-FI",
          "name": "ATAN2"
        },
        {
          "locale": "fr-FR",
          "name": "ATAN2*"
        },
        {
          "locale": "he-IL",
          "name": "ATAN2"
        },
        {
          "locale": "hr-HR",
          "name": "ATAN2"
        },
        {
          "locale": "hu-HU",
          "name": "ARCTAN2"
        },
        {
          "locale": "id-ID",
          "name": "ATAN2"
        },
        {
          "locale": "it-IT",
          "name": "ATAN2"
        },
        {
          "locale": "ja-JP",
          "name": "ATAN2"
        },
        {
          "locale": "ko-KR",
          "name": "ATAN2"
        },
        {
          "locale": "lt-LT",
          "name": "ATAN2"
        },
        {
          "locale": "lv-LV",
          "name": "ATAN2"
        },
        {
          "locale": "nb-NO",
          "name": "ATAN2"
        },
        {
          "locale": "nl-NL",
          "name": "ATAN2"
        },
        {
          "locale": "pl-PL",
          "name": "ATAN2"
        },
        {
          "locale": "pt-BR",
          "name": "ATAN2"
        },
        {
          "locale": "pt-PT",
          "name": "ATAN2"
        },
        {
          "locale": "ro-RO",
          "name": "ATAN2"
        },
        {
          "locale": "ru-RU",
          "name": "ATAN2"
        },
        {
          "locale": "sk-SK",
          "name": "ATAN2"
        },
        {
          "locale": "sl-SI",
          "name": "ATAN2"
        },
        {
          "locale": "sr-Latn-RS",
          "name": "ATAN2"
        },
        {
          "locale": "sv-SE",
          "name": "ARCTAN2"
        },
        {
          "locale": "th-TH",
          "name": "ATAN2"
        },
        {
          "locale": "tr-TR",
          "name": "ATAN2 işlevi"
        },
        {
          "locale": "uk-UA",
          "name": "ATAN2"
        },
        {
          "locale": "vi-VN",
          "name": "ATAN2"
        },
        {
          "locale": "zh-CN",
          "name": "ATAN2"
        },
        {
          "locale": "zh-HK",
          "name": "ATAN2"
        },
        {
          "locale": "zh-TW",
          "name": "ATAN2"
        }
      ],
      "signature": {
        "display": "ATAN2(x_num, y_num)",
        "parameters": [
          {
            "description": null,
            "name": "x_num",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "y_num",
            "optional": false,
            "repeats": false
          }
        ],
        "trailing_repeats": false
      },
      "surface_name": "ATAN2",
      "version_marker": null,
      "xlcall": {
        "code": "97",
        "symbol": "xlfAtan2"
      }
    },
    "microsoft": "https://support.microsoft.com/en-us/office/atan2-function-c04592ab-b9e3-4908-b428-c96b3a565033"
  },
  "try_it": {
    "formula": "=ATAN2(1,1)"
  },
  "url": "https://handbook.dnacalc.com/functions/ATAN2.html",
  "variants": [],
  "versions": [
    {
      "behaviour": "116 captured inputs are indexed for this environment. Capture dates are not recorded. This is a reading count, not a comparison with another build.",
      "excel_build": "16.0 build 19929",
      "platform": "Windows, bitness not recorded, CPU not recorded",
      "sources": [
        "https://github.com/DnaCalc/ExcelFunctionsHandbook/blob/5dc75391aa5125ccc5abdb095da85950980d6fd8/content/evidence/environments/FUNC.ATAN2.json"
      ]
    }
  ]
}