/* Correctly-rounded atan2 function for two binary64 values.

Copyright (c) 2024-2025 Paul Zimmermann and Alexei Sibidanov

This file is part of the CORE-MATH project
(https://core-math.gitlabpages.inria.fr/).

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

/* This implementation was possible with the help of Silviu-Ioan Filip,
   who designed the code to generate a rational approximation of atan(z)
   over (0,1). See comments before P[] and Q[] below. */

#include <fenv.h> // for fenv_t, feholdexcept, fetestexcept, ...
#include <stdio.h> // needed in case of correct rounding failure
#include <stdint.h>
#ifdef CORE_MATH_SUPPORT_ERRNO
#include <errno.h>
#endif

// Warning: clang also defines __GNUC__
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#endif

#pragma STDC FENV_ACCESS ON

typedef union { double f; uint64_t u; } d64u64;

#include "tint.h"

#define MASK 0x7fffffffffffffffull // 2^63-1 (mask the sign bit)

// PI_H+PI_L approximates pi with error bounded by 2^-108.041
#define PI_H 0x1.921fb54442d18p+1
#define	PI_L 0x1.1a62633145c07p-53
// PI_OVER2_H+PI_OVER2_L approximates pi/2 with error bounded by 2^-109.041
#define PI_OVER2_H 0x1.921fb54442d18p+0
#define	PI_OVER2_L 0x1.1a62633145c07p-54
// PI_OVER4_H+PI_OVER4_L approximates pi/4 with error bounded by 2^-110.041
#define PI_OVER4_H 0x1.921fb54442d18p-1
#define	PI_OVER4_L 0x1.1a62633145c07p-55

/* The following polynomials z*P(z) and Q(z) are a rational approximation
   of atan(z) on [0,1] generated by the test_atan program from
   rminimax (revision 94902ef):
   The relative approximation error output by rminimax is:
   fpminimax error = 3.99613e-59 (this is the relative error for P(x)/Q(x)
   with respect to atan(x)/x, which equals the relative error for x*P(x)/Q(x)
   with respect to atan(x)).
   The content of the output file atan_fpminimax.sollya is the following
   (Numerator is P(x), and Denominator is Q(x)):
Numerator = [|
0x2.09c0fe2d4c44bb29c73989e7519ea91406726ca119adbfp-12,
0xb.3cf74b427d53e03ee590b839e751890f2570b12bcb2381ap-12,
0x2.c21262c5ee230e68478de0875e1363e89e56c52e12e75e3p-8,
0x7.ea5d53dda9586c1d92a12df585026e1c90046cfd9a5b47f8p-8,
0x1.2ca8329170bf670dc1702b59c84b50b37d942f8d3769ef4p-4,
0x2.5aaa9752ebff1643c8f6de0edb933954b15381534eda7df8p-4,
0x4.1e6a0dafd431588d6c7ceb71f5cec19a77a386c00fd01e5p-4,
0x6.5de3ba90cbe60835e3367d9f6f7d371ab4597cf27f5c488p-4,
0x8.cf8f7c585767042cd92a5b9ac13d8c8043bd4a023dbe04dp-4,
0xa.fdc36d6b36139bf11df63474e3859d442b30b2c089a2b6cp-4,
0xc.6f8fb14638225192f9f04cf55c103771c44675c6d483606p-4,
0xc.ce79f10f754e31591ce47edcbc8a4eeb2a6f721ac656b42p-4,
0xc.090384dbd77132e1dfb4d9a1d595de7e506ca899a394f7p-4,
0xa.556ac9eee25e867d84dafa25141d203f1c7c2a5156b3ec3p-4,
0x8.1bd2677ddfcbc381df33f27dbb60939cb4c2c73286a6c29p-4,
0x5.cf6890b4eb9746ce40ecaee7789e113cba5cabcb5c9e199p-4,
0x3.cb7db6a1d6d99beb0a774e9a709d31960ee49825db23c314p-4,
0x2.40b4d3536e443b61bcfb377f5abc2a7e3a5435f9c2a3a6c8p-4,
0x1.35df4832c39c240f59a062ecccea6ea27d5e854a7f98ca68p-4,
0x9.5db9977c5e6e26385367a63fab8a720fc2b63bd115998d8p-8,
0x4.0be5b6c11b6afa6b863c0af94484ecd862a74b8aae890acp-8,
0x1.8bdd8845186a4130f13cad7c3bdd36cf744b7b5025259982p-8,
0x8.40c38ccfcb5dc64b55a44095bf7f3126668b8792d4ecd08p-12,
0x2.5c1d2bdeca1ac67b082ab087cc4c3c74da7a7f6f75214a28p-12,
0x9.054011c32d4b7a5c68d3c5d525f4af4eeb3c98615dee188p-16,
0x1.bbb6945d5565762aea6ec351e1d3551a7e40c419a7c0eb76p-16,
0x4.077cd0d9f2cd5f28c7357f0328fefa4e8e0194f353816ce8p-20,
0x6.50b6ea4e69842a65d6c651bca00813e0fe3fa3cc2a4378bp-24,
0x5.05d00dc3a15d400f36e0a54a8b6bf820fa981ec3c482e978p-28,
-0x1.38088112d9cca2b819e68e1f4fe2158753b900d05822353ap-60|];
Denominator = [|
0x2.09c0fe2d4c44bb29c73989e7519ea91406726ca119adbfp-12,
0xb.3cf74b427d53e03ee590b839e751890f2570b12bcb238cfp-12,
0x2.ccf112bc350f27a3d109be11851c076e5e7927716e161108p-8,
0x8.264d256f0bf4d61ee21431cc0f29764ce0cc1b593ac9952p-8,
0x1.3b2f8928ed0f65ddde810f893bbca452e8578dc057f6dbfp-4,
0x2.83e22371eaae527bd88fc66b104f6c8e151d128593dc3b34p-4,
0x4.7ece38b955841470d4fb97d6d7e1efdd7cb50c07514b8bcp-4,
0x7.1c0b45bc528f70ab02523c0ae4048f5cfd5521189747598p-4,
0xa.164ccdbb65ee133e623433c5e086402cb228afd335a245fp-4,
0xc.ed0c0cbe44fac2fd7c2adfc7c5dda9ea22b4a311cf5a5b1p-4,
0xf.0e6660438c903713dca1a0f58f0d9438a92b9de68c4488cp-4,
0x1p+0,
0xf.8ea68f9ad849103b257e4bfc606967f818fa2816928c4aap-4,
0xd.dc64eeee350623447a33ea40a2b22e4a6a2c129ace2470ap-4,
0xb.52ddfba2d37c8e224551a9b19fa064a3d78c68b54bc385p-4,
0x8.7ac113d26b683a14e97756c38785b0bf75f0a4506931ba8p-4,
0x5.d0328385c8079eaf24ec7cf91c78f75b402ea46b3f8ee6c8p-4,
0x3.a40b4a92ff0891065173f9b20e96e0a1467aed15fe33328p-4,
0x2.1390172457ddda6c3eabcd30f14774e6a5fe82ba64e0b24cp-4,
0x1.12db48d8fcd9d767c15f816db67b77ea0c399fedcf1dffe8p-4,
0x8.01a0c1a0dfefc92f8e0a97902e08d4781898e0b7d8ef0bcp-8,
0x3.56742224c37c1f6ea32c00086127eebfe033246a82f77e24p-8,
0x1.3b6ad4d3096ee4639ef840e9c09012b2662dd954d548c09cp-8,
0x6.5ba286ceb1697344bc3da132cbbe8025d30ae77005420eb8p-12,
0x1.c254a5c056c9647d2f92273519dae2d8e142ed5a56be2da4p-12,
0x6.82bdb6848076986af025d8bf5c3cd2f11f689adb05f5038p-16,
0x1.363e39445fdef5ca334d0fe1480e7ddc0b5399791828af16p-16,
0x2.bae9c43c14eab0ecc3a975bec45bddd62a6f3fbd5a63e3c4p-20,
0x4.25cd6d03b66803e89f2a803039fbb58a67a12ccb411479fp-24,
0x3.3292e4119e1a4df48cf079a47049f07fd24f82de8f791668p-28|];
*/
static const tint_t P[30] = {
   {.h=0x82703f8b53112eca, .m=0x71ce6279d467aa45, .l=0x19c9b28466b6fc0, .ex=-10, .sgn=0},
   {.h=0xb3cf74b427d53e03, .m=0xee590b839e751890, .l=0xf2570b12bcb2381a, .ex=-8, .sgn=0},
   {.h=0xb08498b17b88c39a, .m=0x11e37821d784d8fa, .l=0x2795b14b84b9d78c, .ex=-6, .sgn=0},
   {.h=0xfd4baa7bb52b0d83, .m=0xb25425beb0a04dc3, .l=0x92008d9fb34b68ff, .ex=-5, .sgn=0},
   {.h=0x96541948b85fb386, .m=0xe0b815ace425a859, .l=0xbeca17c69bb4f7a0, .ex=-3, .sgn=0},
   {.h=0x96aaa5d4baffc590, .m=0xf23db783b6e4ce55, .l=0x2c54e054d3b69f7e, .ex=-2, .sgn=0},
   {.h=0x83cd41b5fa862b11, .m=0xad8f9d6e3eb9d833, .l=0x4ef470d801fa03ca, .ex=-1, .sgn=0},
   {.h=0xcbbc7752197cc106, .m=0xbc66cfb3edefa6e3, .l=0x568b2f9e4feb8910, .ex=-1, .sgn=0},
   {.h=0x8cf8f7c585767042, .m=0xcd92a5b9ac13d8c8, .l=0x43bd4a023dbe04d, .ex=0, .sgn=0},
   {.h=0xafdc36d6b36139bf, .m=0x11df63474e3859d4, .l=0x42b30b2c089a2b6c, .ex=0, .sgn=0},
   {.h=0xc6f8fb1463822519, .m=0x2f9f04cf55c10377, .l=0x1c44675c6d483606, .ex=0, .sgn=0},
   {.h=0xcce79f10f754e315, .m=0x91ce47edcbc8a4ee, .l=0xb2a6f721ac656b42, .ex=0, .sgn=0},
   {.h=0xc090384dbd77132e, .m=0x1dfb4d9a1d595de7, .l=0xe506ca899a394f70, .ex=0, .sgn=0},
   {.h=0xa556ac9eee25e867, .m=0xd84dafa25141d203, .l=0xf1c7c2a5156b3ec3, .ex=0, .sgn=0},
   {.h=0x81bd2677ddfcbc38, .m=0x1df33f27dbb60939, .l=0xcb4c2c73286a6c29, .ex=0, .sgn=0},
   {.h=0xb9ed12169d72e8d9, .m=0xc81d95dcef13c227, .l=0x974b95796b93c332, .ex=-1, .sgn=0},
   {.h=0xf2df6da875b666fa, .m=0xc29dd3a69c274c65, .l=0x83b9260976c8f0c5, .ex=-2, .sgn=0},
   {.h=0x902d34d4db910ed8, .m=0x6f3ecddfd6af0a9f, .l=0x8e950d7e70a8e9b2, .ex=-2, .sgn=0},
   {.h=0x9aefa41961ce1207, .m=0xacd0317666753751, .l=0x3eaf42a53fcc6534, .ex=-3, .sgn=0},
   {.h=0x95db9977c5e6e263, .m=0x85367a63fab8a720, .l=0xfc2b63bd115998d8, .ex=-4, .sgn=0},
   {.h=0x817cb6d8236d5f4d, .m=0x70c7815f28909d9b, .l=0xc54e97155d12158, .ex=-5, .sgn=0},
   {.h=0xc5eec4228c352098, .m=0x789e56be1dee9b67, .l=0xba25bda81292ccc1, .ex=-7, .sgn=0},
   {.h=0x840c38ccfcb5dc64, .m=0xb55a44095bf7f312, .l=0x6668b8792d4ecd08, .ex=-8, .sgn=0},
   {.h=0x97074af7b286b19e, .m=0xc20aac21f3130f1d, .l=0x369e9fdbdd48528a, .ex=-10, .sgn=0},
   {.h=0x9054011c32d4b7a5, .m=0xc68d3c5d525f4af4, .l=0xeeb3c98615dee188, .ex=-12, .sgn=0},
   {.h=0xdddb4a2eaab2bb15, .m=0x753761a8f0e9aa8d, .l=0x3f20620cd3e075bb, .ex=-15, .sgn=0},
   {.h=0x80ef9a1b3e59abe5, .m=0x18e6afe0651fdf49, .l=0xd1c0329e6a702d9d, .ex=-17, .sgn=0},
   {.h=0xca16dd49cd30854c, .m=0xbad8ca379401027c, .l=0x1fc7f47985486f16, .ex=-21, .sgn=0},
   {.h=0xa0ba01b8742ba801, .m=0xe6dc14a9516d7f04, .l=0x1f5303d878905d2f, .ex=-25, .sgn=0},
   {.h=0x9c0440896ce6515c, .m=0xcf3470fa7f10ac3, .l=0xa9dc80682c111a9d, .ex=-59, .sgn=1},
};

static const tint_t Q[30] = {
   {.h=0x82703f8b53112eca, .m=0x71ce6279d467aa45, .l=0x19c9b28466b6fc0, .ex=-10, .sgn=0},
   {.h=0xb3cf74b427d53e03, .m=0xee590b839e751890, .l=0xf2570b12bcb238cf, .ex=-8, .sgn=0},
   {.h=0xb33c44af0d43c9e8, .m=0xf4426f84614701db, .l=0x979e49dc5b858442, .ex=-6, .sgn=0},
   {.h=0x8264d256f0bf4d61, .m=0xee21431cc0f29764, .l=0xce0cc1b593ac9952, .ex=-4, .sgn=0},
   {.h=0x9d97c4947687b2ee, .m=0xef4087c49dde5229, .l=0x742bc6e02bfb6df8, .ex=-3, .sgn=0},
   {.h=0xa0f888dc7aab949e, .m=0xf623f19ac413db23, .l=0x854744a164f70ecd, .ex=-2, .sgn=0},
   {.h=0x8fd9c7172ab0828e, .m=0x1a9f72fadafc3dfb, .l=0xaf96a180ea297178, .ex=-1, .sgn=0},
   {.h=0xe38168b78a51ee15, .m=0x604a47815c8091eb, .l=0x9faaa42312e8eb30, .ex=-1, .sgn=0},
   {.h=0xa164ccdbb65ee133, .m=0xe623433c5e086402, .l=0xcb228afd335a245f, .ex=0, .sgn=0},
   {.h=0xced0c0cbe44fac2f, .m=0xd7c2adfc7c5dda9e, .l=0xa22b4a311cf5a5b1, .ex=0, .sgn=0},
   {.h=0xf0e6660438c90371, .m=0x3dca1a0f58f0d943, .l=0x8a92b9de68c4488c, .ex=0, .sgn=0},
   {.h=0x8000000000000000, .m=0x0, .l=0x0, .ex=1, .sgn=0},
   {.h=0xf8ea68f9ad849103, .m=0xb257e4bfc606967f, .l=0x818fa2816928c4aa, .ex=0, .sgn=0},
   {.h=0xddc64eeee3506234, .m=0x47a33ea40a2b22e4, .l=0xa6a2c129ace2470a, .ex=0, .sgn=0},
   {.h=0xb52ddfba2d37c8e2, .m=0x24551a9b19fa064a, .l=0x3d78c68b54bc3850, .ex=0, .sgn=0},
   {.h=0x87ac113d26b683a1, .m=0x4e97756c38785b0b, .l=0xf75f0a4506931ba8, .ex=0, .sgn=0},
   {.h=0xba065070b900f3d5, .m=0xe49d8f9f238f1eeb, .l=0x6805d48d67f1dcd9, .ex=-1, .sgn=0},
   {.h=0xe902d2a4bfc22441, .m=0x945cfe6c83a5b828, .l=0x519ebb457f8ccca0, .ex=-2, .sgn=0},
   {.h=0x84e405c915f7769b, .m=0xfaaf34c3c51dd39, .l=0xa97fa0ae99382c93, .ex=-2, .sgn=0},
   {.h=0x896da46c7e6cebb3, .m=0xe0afc0b6db3dbbf5, .l=0x61ccff6e78efff4, .ex=-3, .sgn=0},
   {.h=0x801a0c1a0dfefc92, .m=0xf8e0a97902e08d47, .l=0x81898e0b7d8ef0bc, .ex=-4, .sgn=0},
   {.h=0xd59d088930df07db, .m=0xa8cb00021849fbaf, .l=0xf80cc91aa0bddf89, .ex=-6, .sgn=0},
   {.h=0x9db56a6984b77231, .m=0xcf7c2074e0480959, .l=0x3316ecaa6aa4604e, .ex=-7, .sgn=0},
   {.h=0xcb7450d9d62d2e68, .m=0x9787b4265977d004, .l=0xba615cee00a841d7, .ex=-9, .sgn=0},
   {.h=0xe12a52e02b64b23e, .m=0x97c9139a8ced716c, .l=0x70a176ad2b5f16d2, .ex=-11, .sgn=0},
   {.h=0xd057b6d0900ed30d, .m=0x5e04bb17eb879a5e, .l=0x23ed135b60bea070, .ex=-13, .sgn=0},
   {.h=0x9b1f1ca22fef7ae5, .m=0x19a687f0a4073eee, .l=0x5a9ccbc8c14578b, .ex=-15, .sgn=0},
   {.h=0xaeba710f053aac3b, .m=0x30ea5d6fb116f775, .l=0x8a9bcfef5698f8f1, .ex=-18, .sgn=0},
   {.h=0x84b9ada076cd007d, .m=0x13e55006073f76b1, .l=0x4cf4259968228f3e, .ex=-21, .sgn=0},
   {.h=0xcca4b9046786937d, .m=0x233c1e691c127c1f, .l=0xf493e0b7a3de459a, .ex=-26, .sgn=0},
};

// use a type [29,29] rational approximation of atan(z) for 0 <= z <= 1
static double __attribute__((noinline))
atan2_accurate (double y, double x)
{
  fenv_t env;
  feholdexcept(&env);
  int underflow;
  int overflow = fetestexcept (FE_OVERFLOW);
  double res;
  /* First check when t=y/x is small and exact and x > 0, since for
     |t| <= 0x1.d12ed0af1a27fp-27, atan(t) rounds to t (to nearest). */
  double t = y / x;

  /* If t = y/x did underflow for x > 0, then atan(y/x) will underflow
     too, since the Taylor expansion of atan(z) is z - z^3/3 + o(z^3).
     If |t| < 2^-1022 and is exact, then atan(y/x) underflows, and also
     when |t| = 2^-1022, is exact, and rounding is toward zero. */
  int inexact = fetestexcept (FE_INEXACT);
  double u = __builtin_copysign (1.0, y);
  double v = __builtin_fma (u, -0x1p-54, u);
  // when rounding toward zero, v != u, otherwise v = u
  underflow = x > 0 && (fetestexcept (FE_UNDERFLOW) ||
                        (!inexact &&
                         (__builtin_fabs (t) < 0x1p-1022 ||
                          (__builtin_fabs (t) <= 0x1p-1022 && v != u))));

  /* If t is exact and underflows, then atan(y/x) rounds to t for x > 0,
     to pi for y > 0 and x < 0, and to -pi for x, y < 0. */
  if (t == 0) {
    if (x > 0) {
#ifdef CORE_MATH_SUPPORT_ERRNO
      if (underflow)
        errno = ERANGE; // underflow
#endif
      feupdateenv(&env);
      return t;
    }
    res = (y > 0) ? PI_H + PI_L : -PI_H - PI_L;
    goto end;
  }
  double corr = __builtin_fma (t, x, -y);
  if (corr == 0 && x > 0) // t is exact
    if (__builtin_fabs (t) <= 0x1.d12ed0af1a27fp-27)
    {
      // Warning: if y is in the subnormal range, t might differ from y/x
      /* If |y| >= 2^-969, then since t*x has at most 106 significant bits,
         and t*x ~ y, the lower bit of t*x is >= 2^-1074, thus there is no
         underflow in t*x-y. */
      if (__builtin_fabs (y) >= 0x1p-915) {
#ifdef CORE_MATH_SUPPORT_ERRNO
        if (underflow)
          errno = ERANGE; // underflow
#endif
        feupdateenv(&env);
        return __builtin_fma (t, -0x1p-54, t);
      }
      /* Now |y| < 2^-969, since x >= 2^-1074, then t <= 2^105, thus we can
         scale y and t by 2^105, which will ensure t*x-y does not underflow. */
      corr = __builtin_fma (t * 0x1p105, x, -y * 0x1p105);
      if (corr == 0) {
        res = __builtin_fma (t, -0x1p-54, t);
#ifdef CORE_MATH_SUPPORT_ERRNO
        if (underflow)
          errno = ERANGE; // underflow
#endif
        feupdateenv(&env);
        return res;
      }
    }

  int inv = __builtin_fabs (y) > __builtin_fabs (x);
  tint_t z[1], p[1], q[1];
  if (inv)
    div_tint_d (z, x, y);
  else
    div_tint_d (z, y, x);

  /* When |y/x| < 2^-27, x > 0, atan(y/x) rounds to the same value as y/x
     pertubed by a small amount towards zero (here we subtract 2 to z->l).
     But since the Taylor expansion of atan(t) is t - t^3/3 + O(t^5),
     we have a relative error bounded by t^2/2 for t small enough.
     We thus need |y/x| < 2^-96 so that this error is less than 1 ulp. */
  if (inv == 0 && x > 0 && z->ex <= -96)
    {
      z->l -= 2;
      z->m -= (z->l < 2);
      z->h -= (z->m < 1);
      res = tint_tod (z, 1, y, x);
      goto end;
    }

  // below when we write y/x it should be read x/y when |x/y| < 1
  // |z - y/x| < 2^-185.53 * |z| (relative error from div_tint_d)
  // the rational approximation is only for z > 0, it is not antisymmetric
  int sz = z->sgn;
  z->sgn = 0;
  cp_tint (p, P + 29);
  cp_tint (q, Q + 29);
  for (int i = 28; i >= 0; i--)
  {
    mul_tint (p, p, z);
    mul_tint (q, q, z);
    add_tint (p, p, P + i);
    add_tint (q, q, Q + i);
  }
  // multiply p by z
  mul_tint (p, p, z);
  /* The routine errPsplit(e,13) in atan2.sage gives a relative error bound
     of 2^-184.14 for |p - z*P(z)|, for -11 <= e <= 0, which corresponds
     to 2^-12 <= z <= 1. */
  /* The routine errQsplit(e,12) in atan2.sage gives a relative error bound
     of 2^-184.19 for |q - Q(z)|, for -11 <= e <= 0, which corresponds
     to 2^-12 <= z <= 1. */
  // divide p by q
  div_tint (z, p, q);
  /* The relative error of div_tint() is <= 2^-185.53, thus we have:
     z*P(z)/Q(z) = atan(z) * (1 + eps0) with |eps0| < 3.99613e-59
     z = y/x * (1 + eps1) with |eps1| < 2^-185.53
     p = z*P(z) * (1 + eps2) with |eps2| < 2^-184.14
     q = Q(z) * (1 + eps3)   with |eps3| < 2^-184.19
     newz = p/q * (1 + eps4) with |eps4| < 2^-185.53
     The equality z = y/x * (1 + eps1) gives
     atan(z) = atan(y/x) + eps1*y/x * 1/(1+theta^2) for theta in (z,y/x).
     Thus |atan(z) - atan(y/x)| <= |eps1*y/x| which yields
     |atan(z) - atan(y/x)|/|atan(y/x)| <= |eps1*y/x|/|atan(y/x)|
     Since t/atan(t) is bounded by 1/atan(1) for 0 <= x <= 1, this yields:
     atan(z) = atan(y/x) * (1 + eps5) with |eps5| <= eps1/atan(1) < 2^-185.18.
     In summary we have:
     newz = atan(y/x)*(1+eps0)*(1+eps2)*(1+eps4)*(1+eps5)/(1+eps3)
     thus:
     newz = atan(y/x)*(1+eps6) with |eps6| < 2^-182.63.
     This corresponds to a maximal error of 2^-182.63*2^192 <= 662 ulps.
  */
  uint64_t err = 662; // error bound in case inv=0 and x > 0
  z->sgn = sz; // restore sign
  /* Now z approximates atan(y/x) for inv=0, and atan(x/y) for inv=1,
     with -pi/4 < z < pi/4.
  */
  if (inv)
  {
    // if x/y > 0 thus atan(x/y) > 0 we apply pi/2 - atan(x/y)
    // if x/y < 0 thus atan(x/y) < 0 we apply -pi/2 - atan(x/y)
    if (z->sgn == 0) { // 0 < atan(x/y) < pi/4
      z->sgn = 1;
      add_tint (z, &PI2, z);
      /* Now pi/4 < z < pi/2. The absolute error on z was bounded by
         2^-182.63*pi/4, the error on PI2 is bounded by 2^-197.96, and
         the add_tint() error is bounded by 2 ulp(pi/2) = 2^-190,
         which yields a total error < 2^-182.63*pi/4 + 2^-197.96 + 2^-190
         < 2^-182.967. Relatively to ulp(pi/4) this is less than 524. */
    }
    else // -pi/4 < atan(x/y) < 0
    {
      add_tint (z, &PI2, z);
      z->sgn = 1;
      /* Now -pi/2 < z < -pi/4. The same error analysis as above applies,
         thus we get the same bound of 524 ulps. */
    }
    err = 524;
  }
  // now -pi/2 < z < pi/2
  // if x is negative we go to the opposite quadrant
  if (x < 0) {
    if (z->sgn == 0) { // 1st quadrant -> 3rd quadrant (subtract pi)
      z->sgn = 1;
      add_tint (z, &PI, z);
      z->sgn = 1;
      /* We had 0 < z < pi/2 thus now -pi < z < -pi/2.
         The absolute error on z was bounded by max(2^-182.63*pi/4,2^-182.967)
         = 2^-182.967, that on PI is bounded by 2^-196.96, and the add_tint()
         error is bounded by 2 ulp(pi) = 2^-189, which yields a total error
         < 2^-182.967 + 2^-196.96 + 2^-189 < 2^-182.945.
         Relatively to ulp(pi/2) this is less than 266 ulps. */
    }
    else // 4th quadrant -> 2nd quadrant (add pi)
    {
      add_tint (z, &PI, z);
      /* If inv=0 we had -pi/4 < z < 0 thus now 3pi/4 < z < pi.
         If inv=1 we had -pi/2 < z < -pi/4 thus now pi/2 < z < 3pi/4.
         The same analysis as above applies, and we get the same bound
         of 266 ulps. */
    }
    err = 266;
  }
  res = tint_tod (z, err, y, x);
 end:
  if (!overflow)
    feclearexcept (FE_OVERFLOW);
  if (!underflow)
    feclearexcept (FE_UNDERFLOW);
#ifdef CORE_MATH_SUPPORT_ERRNO
  else
    errno = ERANGE; // underflow
#endif
  feupdateenv(&env);
  return res;
}

typedef uint64_t u64;
typedef int64_t i64;
static inline double fasttwosum(double x, double y, double *e){
  double s = x + y, z = s - x;
  *e = y - z;
  return s;
}

static inline double fastsum(double xh, double xl, double yh, double yl, double *e){
  double sl, sh = fasttwosum(xh, yh, &sl);
  *e = (xl + yl) + sl;
  return sh;
}

static double __attribute__((noinline)) as_atan2_special(double y0, double x0){
  d64u64 iy = {.f = y0}, ix = {.f = x0};
  u64 aiy = iy.u<<1, aix = ix.u<<1;

  if (__builtin_expect (aiy >= 0x7ffull<<53 || aix >= 0x7ffull<<53, 0)){ // NaN or Inf
    if (aiy > 0x7ffull<<53 || aix > 0x7ffull<<53)
      // return y0 + x0; // if y or x is sNaN, returns qNaN and raises invalid
      return y0 + x0;
    // Now neither y nor x is NaN, but at least one is +Inf or -Inf
    if (aiy == 0x7ffull<<53 && aix == 0x7ffull<<53){ // both y and x are +/-Inf
      static const double finf[][2] = {{0x1p-55, 0x1.921fb54442d18p-1}, {0x1p-54, 0x1.2d97c7f3321d2p+1}};
      // atan2 (+/-Inf,-Inf) = +/-3pi/4
      // atan2 (+/-Inf,+Inf) = +/-pi/4
      return __builtin_copysign(finf[ix.u>>63][1], y0) + __builtin_copysign(finf[ix.u>>63][0], y0);
    }
    // now only one of y and x is +/-Inf
    if (aix == 0x7ffull<<53) {
      if (x0 < 0)
        return __builtin_copysign (PI_H,y0) + __builtin_copysign (PI_L,y0);
      // atan2(+/-0,x) = +/-0 for x > 0
      // atan2(+/-y,+Inf) = +/-0 for finite y>0
      return __builtin_copysign (0, y0);
    }
    // now y = +/-Inf
    // atan2(+/-Inf,x) = +/-pi/2 for finite x
    return __builtin_copysign (PI_OVER2_H,y0) + __builtin_copysign (PI_OVER2_L, y0);
  }

  if (__builtin_expect (aiy == 0 || aix == 0, 0)){
    if (aiy == 0 && aix == 0){
      if (ix.u == 0) // atan2(+/-0, +0) = +/-0
        return y0;
      // atan2(+/-0, +0) = +/-pi
      return (iy.u == 0) ? PI_H + PI_L : -PI_H - PI_L;
    }
    // only one of y and x is zero
    if (aiy==0){
      // atan2(+/-0,x) = +/-0 for x>0
      if (x0 > 0) return y0/x0;
      // atan2(+/-0,x) = +/-pi for x<0
      return (!(iy.u>>63)) ? PI_H + PI_L : -PI_H - PI_L;
    }
    // now only x is zero
    // atan2(y,+/-0) = -pi/2 for y<0
    // atan2(y,+/-0) = +pi/2 for y>0
    return (y0 > 0) ? PI_OVER2_H + PI_OVER2_L : -PI_OVER2_H - PI_OVER2_L;
  }
  return 0;
}

double cr_atan2 (double y0, double x0){
  static const double asgn[2] = {0.0, -0.0};
  static const double T2[] = {
    0x0p+0, 0x1p-6, 0x1p-5, 0x1.8p-5, 0x1p-4, 0x1.4p-4, 0x1.8p-4, 0x1.cp-4,
    0x1p-3, 0x1.2p-3, 0x1.4p-3, 0x1.6p-3, 0x1.8p-3, 0x1.ap-3, 0x1.cp-3, 0x1.ep-3,
    0x1p-2, 0x1.1p-2, 0x1.2p-2, 0x1.3p-2, 0x1.4p-2, 0x1.5p-2, 0x1.6p-2, 0x1.7p-2,
    0x1.8p-2, 0x1.9p-2, 0x1.ap-2, 0x1.bp-2, 0x1.cp-2, 0x1.dp-2, 0x1.ep-2, 0x1.fp-2,
    0x1p-1, 0x1.08p-1, 0x1.1p-1, 0x1.18p-1, 0x1.2p-1, 0x1.28p-1, 0x1.3p-1, 0x1.38p-1,
    0x1.4p-1, 0x1.48p-1, 0x1.5p-1, 0x1.58p-1, 0x1.6p-1, 0x1.68p-1, 0x1.7p-1, 0x1.78p-1,
    0x1.8p-1, 0x1.88p-1, 0x1.9p-1, 0x1.98p-1, 0x1.ap-1, 0x1.a8p-1, 0x1.bp-1, 0x1.b8p-1,
    0x1.cp-1, 0x1.c8p-1, 0x1.dp-1, 0x1.d8p-1, 0x1.ep-1, 0x1.e8p-1, 0x1.fp-1, 0x1.f8p-1, 0x1p+0};
  static const double f2[][2] = {
    {0x0p+0, 0x0p+0}, {-0x1.95220c39d4dffp-53, 0x1.fff555bbb73p-7},
    {0x1.2542779d776dep-53, 0x1.ffd55bba976p-6}, {-0x1.6061bbe3de53cp-53, 0x1.7fb818430da4p-5},
    {-0x1.639269b0da47ep-53, 0x1.ff55bb72cfep-5}, {-0x1.4a7663af440f7p-55, 0x1.3f59f0e7c55ap-4},
    {0x1.d1824d59f9e13p-53, 0x1.7ee182602f1p-4}, {0x1.bef71e5340b31p-55, 0x1.be39ebe6f07cp-4},
    {0x1.b8cb225e627dp-53, 0x1.fd5ba9aac2f6p-4}, {0x1.b92de9bac94c2p-53, 0x1.1e1fafb04372p-3},
    {-0x1.d3cb89e62dafdp-54, 0x1.3d6eee8c6627p-3}, {-0x1.882a55960087ap-53, 0x1.5c9811e3ec27p-3},
    {0x1.1347b0b4f881dp-54, 0x1.7b97b4bce5bp-3}, {0x1.873d8079ed0d2p-53, 0x1.9a6a8e96c862p-3},
    {0x1.022f621a5c1cbp-54, 0x1.b90d7529260ap-3}, {0x1.9c648d1534598p-53, 0x1.d77d5df20573p-3},
    {-0x1.4ea9238610a08p-54, 0x1.f5b75f92c80ep-3}, {0x1.2c5c8e721970dp-53, 0x1.09dc597d8636p-2},
    {0x1.30ca4748b1bf9p-57, 0x1.18bf5a30bf178p-2}, {-0x1.20ef9ba6dbf9p-53, 0x1.278372057ef48p-2},
    {0x1.e69c5abb498d2p-53, 0x1.362773707ebc8p-2}, {0x1.a8a86f0ea9311p-54, 0x1.44aa436c2af08p-2},
    {0x1.db5336feef7fp-54, 0x1.530ad9951cd48p-2}, {0x1.9636a3aa3b84p-54, 0x1.614840309cfep-2},
    {0x1.1ce2a8c848b74p-55, 0x1.6f61941e4defp-2}, {-0x1.4b1bbd1ea6db3p-55, 0x1.7d5604b63b3f8p-2},
    {-0x1.4925e8b916e0bp-53, 0x1.8b24d394a1b28p-2}, {0x1.9e6c988fd0a77p-56, 0x1.98cd5454d6b18p-2},
    {-0x1.a49bd836a17p-53, 0x1.a64eec3cc24p-2}, {-0x1.ca3cf09c6b5f8p-53, 0x1.b3a911da65c7p-2},
    {-0x1.cc1ce70934c34p-56, 0x1.c0db4c94ec9fp-2}, {0x1.2e982ddf3872ap-55, 0x1.cde53432c135p-2},
    {-0x1.2ea406ee84d0fp-55, 0x1.dac670561bb5p-2}, {-0x1.de35847c81979p-53, 0x1.e77eb7f175a38p-2},
    {-0x1.a3992dc382a23p-57, 0x1.f40dd0b541418p-2}, {-0x1.b32c949c9d593p-55, 0x1.0039c73c1a40cp-1},
    {-0x1.d5b495f6349e6p-56, 0x1.0657e94db30dp-1}, {-0x1.f34582f6255fep-53, 0x1.0c6145b5b43dcp-1},
    {0x1.ed42511e3f11dp-54, 0x1.1255d9bfbd2a8p-1}, {-0x1.1cef189ff9e7fp-54, 0x1.1835a88be7c14p-1},
    {-0x1.928df287a668fp-58, 0x1.1e00babdefeb4p-1}, {-0x1.e3bde360c7ddbp-53, 0x1.23b71e2cc9e6cp-1},
    {0x1.bd86313ce4fdep-54, 0x1.2958e59308e3p-1}, {-0x1.8e8a85803cc1dp-53, 0x1.2ee628406cbccp-1},
    {-0x1.77ef7641c777fp-54, 0x1.345f01cce37bcp-1}, {0x1.b73ef3389d02fp-53, 0x1.39c391cd41718p-1},
    {0x1.ecf8b492644fp-56, 0x1.3f13fb89e96f4p-1}, {0x1.c1125fd3810c7p-53, 0x1.445065b795b54p-1},
    {0x1.2483350fe548bp-53, 0x1.4978fa3269eep-1}, {0x1.4a33dbeb3796cp-55, 0x1.4e8de5bb6ec04p-1},
    {-0x1.46edd2af69483p-53, 0x1.538f57b89062p-1}, {-0x1.2bcb93b18b52ap-53, 0x1.587d81f732fbcp-1},
    {0x1.0028e4bc5e7cap-57, 0x1.5d58987169b18p-1}, {0x1.ed487acaf1174p-53, 0x1.6220d115d7b8cp-1},
    {-0x1.2dd4dfd7d1777p-53, 0x1.66d663923e088p-1}, {0x1.2bfe3cf3b9d79p-54, 0x1.6b798920b3d98p-1},
    {-0x1.8c34d25aadef6p-56, 0x1.700a7c5784634p-1}, {-0x1.f426acf4d3bdbp-54, 0x1.748978fba8e1p-1},
    {-0x1.afe57dd9ff23p-53, 0x1.78f6bbd5d316p-1}, {-0x1.54fbef0e862abp-54, 0x1.7d528289fa094p-1},
    {0x1.90227758b11bap-54, 0x1.819d0b7158a4cp-1}, {0x1.16b66e7fc8b8cp-53, 0x1.85d69576cc2c4p-1},
    {-0x1.55b9a5e177a1bp-55, 0x1.89ff5ff57f1f8p-1}, {0x1.c27cfaa9f7a14p-53, 0x1.8e17aa99cc05cp-1},
    {0x1.1a62633145c07p-55, 0x1.921fb54442d18p-1}};
  static const double O[8][2] = {
    {0,0}, {0x1.921fb54442d18p+0,0x1.1a62633145c07p-54},
    {0,0}, {-0x1.921fb54442d18p+0,-0x1.1a62633145c07p-54},
    {0x1.921fb54442d18p+1,0x1.1a62633145c07p-53}, {0x1.921fb54442d18p+0,0x1.1a62633145c07p-54},
    {-0x1.921fb54442d18p+1,-0x1.1a62633145c07p-53}, {-0x1.921fb54442d18p+0,-0x1.1a62633145c07p-54}};

  d64u64 iy = {.f = y0}, ix = {.f = x0};
  u64 aiy = iy.u & MASK;
  if(__builtin_expect( aiy==0 || aiy>=0x7ffull<<52, 0)) return as_atan2_special(y0,x0);
  u64 aix = ix.u & MASK;
  if(__builtin_expect( aix==0 || aix>=0x7ffull<<52, 0)) return as_atan2_special(y0,x0);
  double ax = __builtin_fabs(x0), ay = __builtin_fabs(y0);
  double x = __builtin_fmax(ax, ay), y = __builtin_fmin(ax, ay);
  u64 sy = iy.u>>63, sx = ix.u>>63;
  u64 GT = aix<aiy;
  u64 dxy = (aix-aiy)^-GT;
  if(__builtin_expect( dxy>=53ull<<52, 0)) return atan2_accurate(y0,x0);
  d64u64 sgn = {.f = asgn[GT^sx^sy]};
  u64 kw = sx<<2|sy<<1|GT;
  d64u64 jj = {.f = y/x + (2 + 1/128.)};
  i64 jt = ((jj.u>>(52-7))&127);
  double fh = f2[jt][1]*__builtin_copysign(1,sgn.f);
  double fl = f2[jt][0]*__builtin_copysign(1,sgn.f);
  fh += O[kw][0];
  fl += O[kw][1];
  if(__builtin_expect(x<0x1p-920, 0)){x *= 0x1p920; y *= 0x1p920;}
  if(__builtin_expect(x>0x1p1022, 0)){
    if(__builtin_expect(jt != 0,1)){
      x *= 0x1p-1; y *= 0x1p-1;
    }
  }
  double t0 = T2[jt];
  double zn = __builtin_fma(-t0,x,y), zd = __builtin_fma(t0,y,x);
  double z = zn/zd;
  static const double b[] = {-0x1.55555555554d2p-2, 0x1.999999860e1cap-3, -0x1.248ad469844a1p-3};
  double z2 = z*z;
  z *= __builtin_copysign(1,sgn.f);
  double dz = (z*z2)*(b[0] + z2*(b[1] + z2*b[2]));
  // this bound is obtained with 1.1e10 random argument pairs in the roundup mode;
  // the obtained maximal difference is increased by 2.5% for safety
  double eps = __builtin_fabs(z)*0x1.051p-51 + 0x1p-90;
  double rh = fasttwosum(fh, z, &z);
  double rl = (fl + dz) + z;
  double lb = rh + (rl - eps), ub = rh + (rl + eps);
  if(lb!=ub){
    double dh = y*t0, dl = __builtin_fma(y,t0,-dh), e, rdh;
    dh = fasttwosum(x, dh, &e);
    // avoid spurious underflow in 1/dh
    if (__builtin_expect (__builtin_fabs (dh) <= 0x1p1022, 1))
      rdh = 1/dh;
    else {
      fexcept_t flag;
      fegetexceptflag (&flag, FE_UNDERFLOW);
      rdh = 1/dh;
      fesetexceptflag (&flag, FE_UNDERFLOW);
    }
    dl += e;
    double nh = x*t0, nl = __builtin_fma(x,t0,-nh);
    double dt = y-nh, y1 = dt+nh;
    if( __builtin_expect(y1 == y, 1)){
      nh = fasttwosum(dt, -nl, &nl);
    } else {
      nh = fasttwosum(dt, (y - y1) - nl, &nl);
    }
    double zh = nh * rdh;
    z2 = zh*zh;
    double zl = rdh * (__builtin_fma(dh, -zh, nh) + (nl - (nh*rdh)*dl));
    static const double b2[] =
      {-0x1.5555555555555p-2, 0x1.999999999755ep-3, -0x1.24924883596f8p-3, 0x1.c6f7d73531bc2p-4};
    zl += zh*z2*((b2[0] + z2*b2[1]) + (z2*z2)*(b2[2] + z2*b2[3]));
    zh *= __builtin_copysign(1,sgn.f);
    zl *= __builtin_copysign(1,sgn.f);
    eps = 0x1.4p-50*(__builtin_fabs(zh)*z2 + 0x1p-51);
    fh = fastsum(fh,fl,zh,zl,&fl);
    lb = fh + (fl - eps);
    ub = fh + (fl + eps);
    if(lb!=ub)
      return atan2_accurate(y0,x0);
  }
  return ub;
}
