//   Copyright Naoki Shibata and contributors 2010 - 2021.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

#ifndef __SLEEFQUAD_H__
#define __SLEEFQUAD_H__

#define SLEEF_VERSION_MAJOR @SLEEF_VERSION_MAJOR@
#define SLEEF_VERSION_MINOR @SLEEF_VERSION_MINOR@
#define SLEEF_VERSION_PATCHLEVEL @SLEEF_VERSION_PATCH@

#include "sleef.h"
#include <string.h>

#ifdef __cplusplus
extern "C"
{
#endif

#if (defined(__MINGW32__) || defined(__MINGW64__) || defined(__CYGWIN__) || defined(_MSC_VER)) && !defined(SLEEF_STATIC_LIBS)
#ifdef SLEEF_IMPORT_IS_EXPORT
#define SLEEF_IMPORT __declspec(dllexport)
#else // #ifdef SLEEF_IMPORT_IS_EXPORT
#define SLEEF_IMPORT __declspec(dllimport)
#if (defined(_MSC_VER))
#pragma comment(lib,"sleefquad.lib")
#endif // #if (defined(_MSC_VER))
#endif // #ifdef SLEEF_IMPORT_IS_EXPORT
#else // #if (defined(__MINGW32__) || defined(__MINGW64__) || defined(__CYGWIN__) || defined(_MSC_VER)) && !defined(SLEEF_STATIC_LIBS)
#define SLEEF_IMPORT
#endif // #if (defined(__MINGW32__) || defined(__MINGW64__) || defined(__CYGWIN__) || defined(_MSC_VER)) && !defined(SLEEF_STATIC_LIBS)

//

#if defined (__GNUC__) || defined (__clang__) || defined(__INTEL_COMPILER)
#define SLEEF_CONST __attribute__((const))
#define SLEEF_INLINE __attribute__((always_inline))
#elif defined(_MSC_VER)
#define SLEEF_CONST
#define SLEEF_INLINE __forceinline
#endif

//

#if (defined(__SIZEOF_FLOAT128__) && __SIZEOF_FLOAT128__ == 16) || (defined(__linux__) && defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) || (defined(__PPC64__) && defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 8)
#define SLEEF_FLOAT128_IS_IEEEQP
#endif

#if !defined(SLEEF_FLOAT128_IS_IEEEQP) && defined(__SIZEOF_LONG_DOUBLE__) && __SIZEOF_LONG_DOUBLE__ == 16 && (defined(__aarch64__) || defined(__zarch__))
#define SLEEF_LONGDOUBLE_IS_IEEEQP
#endif

#if !defined(Sleef_quad_DEFINED)
#define Sleef_quad_DEFINED
typedef struct { uint64_t x, y; } Sleef_uint64_2t;
#if defined(SLEEF_FLOAT128_IS_IEEEQP)
typedef __float128 Sleef_quad;
#define SLEEF_QUAD_C(x) (x ## Q)
#elif defined(SLEEF_LONGDOUBLE_IS_IEEEQP)
typedef long double Sleef_quad;
#define SLEEF_QUAD_C(x) (x ## L)
#else
typedef Sleef_uint64_2t Sleef_quad;
#endif
#endif

//

#if !defined(Sleef_quadx1_DEFINED)
#define Sleef_quadx1_DEFINED
typedef struct {
  uint64_t x, y;
} Sleef_quadx1;
#endif

#if !defined(Sleef_quadx2_DEFINED)

#if defined(__SSE2__)
#define Sleef_quadx2_DEFINED
typedef struct {
  __m128i x, y;
} Sleef_quadx2;
#endif

#if defined(__aarch64__)
#define Sleef_quadx2_DEFINED
typedef struct {
  uint32x4_t x, y;
} Sleef_quadx2;
#endif

#if defined(__VSX__)
#define Sleef_quadx2_DEFINED
typedef struct {
  __vector unsigned int x, y;
} Sleef_quadx2;
#endif

#if defined(__VX__) && (defined(__VECTOR_KEYWORD_SUPPORTED__) || defined(__VEC__))
#define Sleef_quadx2_DEFINED
typedef struct {
  __vector unsigned long long x, y;
} Sleef_quadx2;
#endif

#endif // #if !defined(Sleef_quadx2_DEFINED)

#if !defined(Sleef_rvvm1quad_DEFINED)
#if defined(__riscv) && defined(__riscv_v)
#define Sleef_rvvm1quadDEFINED
typedef vuint64m1x2_t Sleef_rvvm1quad;
#endif
#endif

#if !defined(Sleef_rvvm2quad_DEFINED)
#if defined(__riscv) && defined(__riscv_v)
#define Sleef_rvvm2quadDEFINED
typedef vuint64m2x2_t Sleef_rvvm2quad;
#endif
#endif

#if !defined(Sleef_quadx4_DEFINED)
#if defined(__AVX__)
#define Sleef_quadx4_DEFINED
typedef struct {
  __m256i x, y;
} Sleef_quadx4;
#endif
#endif

#if !defined(Sleef_quadx8_DEFINED)
#if defined(__AVX512F__)
#define Sleef_quadx8_DEFINED
typedef struct {
  __m512i x, y;
} Sleef_quadx8;
#endif
#endif

#if !defined(Sleef_svquad_DEFINED)
#if defined(__ARM_FEATURE_SVE)
#define Sleef_svquad_DEFINED
typedef svfloat64x2_t Sleef_svquad;
#endif
#endif

//

#if !defined(SLEEF_Q_DEFINED)
#define SLEEF_Q_DEFINED
static inline Sleef_quad sleef_q(int64_t H, uint64_t L, int E) {
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
  struct { uint64_t h, l; } c;
#else
  struct { uint64_t l, h; } c;
#endif
  c.h = (((int64_t)(H) < 0 ? 1ULL : 0ULL) << 63) |
    ((0x7fff & (uint64_t)((E) + 16383)) << 48) |
    ((int64_t)(H) < 0 ? -(int64_t)(H) : (int64_t)(H) & 0xffffffffffffULL);
  c.l = (uint64_t)(L);

  Sleef_quad q;
  memcpy(&q, &c, 16);
  return q;
}
#endif

//

#ifdef SLEEF_QUAD_C

#define SLEEF_M_Eq SLEEF_QUAD_C(+0x1.5bf0a8b1457695355fb8ac404e7ap+1)
#define SLEEF_M_LOG2Eq SLEEF_QUAD_C(+0x1.71547652b82fe1777d0ffda0d23ap+0)
#define SLEEF_M_LOG10Eq SLEEF_QUAD_C(+0x1.bcb7b1526e50e32a6ab7555f5a68p-2)
#define SLEEF_M_LN2q SLEEF_QUAD_C(+0x1.62e42fefa39ef35793c7673007e6p-1)
#define SLEEF_M_LN10q SLEEF_QUAD_C(+0x1.26bb1bbb5551582dd4adac5705a6p+1)
#define SLEEF_M_PIq SLEEF_QUAD_C(+0x1.921fb54442d18469898cc51701b8p+1)
#define SLEEF_M_PI_2q SLEEF_QUAD_C(+0x1.921fb54442d18469898cc51701b8p+0)
#define SLEEF_M_PI_4q SLEEF_QUAD_C(+0x1.921fb54442d18469898cc51701b8p-1)
#define SLEEF_M_1_PIq SLEEF_QUAD_C(+0x1.45f306dc9c882a53f84eafa3ea6ap-2)
#define SLEEF_M_2_PIq SLEEF_QUAD_C(+0x1.45f306dc9c882a53f84eafa3ea6ap-1)
#define SLEEF_M_2_SQRTPIq SLEEF_QUAD_C(+0x1.20dd750429b6d11ae3a914fed7fep+0)
#define SLEEF_M_SQRT2q SLEEF_QUAD_C(+0x1.6a09e667f3bcc908b2fb1366ea95p+0)
#define SLEEF_M_SQRT3q SLEEF_QUAD_C(+0x1.bb67ae8584caa73b25742d7078b8p+0)
#define SLEEF_M_INV_SQRT3q SLEEF_QUAD_C(+0x1.279a74590331c4d218f81e4afb25p-1)
#define SLEEF_M_SQRT1_2q SLEEF_QUAD_C(+0x1.6a09e667f3bcc908b2fb1366ea95p-1)
#define SLEEF_M_INV_SQRTPIq SLEEF_QUAD_C(+0x1.20dd750429b6d11ae3a914fed7fep-1)
#define SLEEF_M_EGAMMAq SLEEF_QUAD_C(+0x1.2788cfc6fb618f49a37c7f0202a6p-1)
#define SLEEF_M_PHIq SLEEF_QUAD_C(+0x1.9e3779b97f4a7c15f39cc0605ceep+0)
#define SLEEF_QUAD_MAX SLEEF_QUAD_C(+0x1.ffffffffffffffffffffffffffffp+16383)
#define SLEEF_QUAD_MIN SLEEF_QUAD_C(+0x1p-16382)
#define SLEEF_QUAD_EPSILON SLEEF_QUAD_C(+0x1p-112)
#define SLEEF_QUAD_DENORM_MIN SLEEF_QUAD_C(+0x0.0000000000000000000000000001p-16382)

#else // #ifdef SLEEF_QUAD_C

#define SLEEF_M_Eq sleef_q(+0x15bf0a8b14576LL, 0x95355fb8ac404e7aULL, 1)
#define SLEEF_M_LOG2Eq sleef_q(+0x171547652b82fLL, 0xe1777d0ffda0d23aULL, 0)
#define SLEEF_M_LOG10Eq sleef_q(+0x1bcb7b1526e50LL, 0xe32a6ab7555f5a68ULL, -2)
#define SLEEF_M_LN2q sleef_q(+0x162e42fefa39eLL, 0xf35793c7673007e6ULL, -1)
#define SLEEF_M_LN10q sleef_q(+0x126bb1bbb5551LL, 0x582dd4adac5705a6ULL, 1)
#define SLEEF_M_PIq sleef_q(+0x1921fb54442d1LL, 0x8469898cc51701b8ULL, 1)
#define SLEEF_M_PI_2q sleef_q(+0x1921fb54442d1LL, 0x8469898cc51701b8ULL, 0)
#define SLEEF_M_PI_4q sleef_q(+0x1921fb54442d1LL, 0x8469898cc51701b8ULL, -1)
#define SLEEF_M_1_PIq sleef_q(+0x145f306dc9c88LL, 0x2a53f84eafa3ea6aULL, -2)
#define SLEEF_M_2_PIq sleef_q(+0x145f306dc9c88LL, 0x2a53f84eafa3ea6aULL, -1)
#define SLEEF_M_2_SQRTPIq sleef_q(+0x120dd750429b6LL, 0xd11ae3a914fed7feULL, 0)
#define SLEEF_M_SQRT2q sleef_q(+0x16a09e667f3bcLL, 0xc908b2fb1366ea95ULL, 0)
#define SLEEF_M_SQRT3q sleef_q(+0x1bb67ae8584caLL, 0xa73b25742d7078b8ULL, 0)
#define SLEEF_M_INV_SQRT3q sleef_q(+0x1279a74590331LL, 0xc4d218f81e4afb25ULL, -1)
#define SLEEF_M_SQRT1_2q sleef_q(+0x16a09e667f3bcLL, 0xc908b2fb1366ea95ULL, -1)
#define SLEEF_M_INV_SQRTPIq sleef_q(+0x120dd750429b6LL, 0xd11ae3a914fed7feULL, -1)
#define SLEEF_M_EGAMMAq sleef_q(+0x12788cfc6fb61LL, 0x8f49a37c7f0202a6ULL, -1)
#define SLEEF_M_PHIq sleef_q(+0x19e3779b97f4aLL, 0x7c15f39cc0605ceeULL, 0)
#define SLEEF_QUAD_MAX sleef_q(+0x1ffffffffffffLL, 0xffffffffffffffffULL, 16383)
#define SLEEF_QUAD_MIN sleef_q(+0x1000000000000LL, 0x0000000000000000ULL, -16382)
#define SLEEF_QUAD_EPSILON sleef_q(+0x1000000000000LL, 0x0000000000000000ULL, -112)
#define SLEEF_QUAD_DENORM_MIN sleef_q(+0x0000000000000LL, 0x0000000000000001ULL, -16382)

#endif // #ifdef SLEEF_QUAD_C

#define SLEEF_QUAD_MANT_DIG 113
#define SLEEF_QUAD_MIN_EXP (-16381)
#define SLEEF_QUAD_MAX_EXP 16384
#define SLEEF_QUAD_DIG 33
#define SLEEF_QUAD_MIN_10_EXP (-4931)
#define SLEEF_QUAD_MAX_10_EXP 4932

//

#include <stdio.h>
#include <stdarg.h>

SLEEF_IMPORT Sleef_quad Sleef_strtoq(const char *str, char **endptr);

SLEEF_IMPORT int Sleef_fprintf(FILE *fp, const char *fmt, ...);
SLEEF_IMPORT int Sleef_vfprintf(FILE *fp, const char *fmt, va_list ap);
SLEEF_IMPORT int Sleef_printf(const char *fmt, ...);
SLEEF_IMPORT int Sleef_vprintf(const char *fmt, va_list ap);
SLEEF_IMPORT int Sleef_snprintf(char *str, size_t size, const char *fmt, ...);
SLEEF_IMPORT int Sleef_vsnprintf(char *str, size_t size, const char *fmt, va_list ap);

SLEEF_IMPORT int Sleef_registerPrintfHook();
SLEEF_IMPORT void Sleef_unregisterPrintfHook();

//

