/* Library libcerf:
 *   Compute complex error functions, based on a new implementation of
 *   Faddeeva's w_of_z. Also provide Dawson and Voigt functions.
 *
 * File exp_z2.h:
 *   Declares the functions that form exp(+-z^2) with a double-word exponent.
 *
 * Copyright:
 *   (C) 2026 Forschungszentrum Jülich GmbH
 *
 * Licence:
 *   ../LICENSE
 *
 * Authors:
 *   Joachim Wuttke, Forschungszentrum Juelich, 2026
 *
 * Website:
 *   https://jugit.fz-juelich.de/mlz/lib/cerf
 *
 * Revision history:
 *   ../CHANGELOG
 */

/* The factor exp(+-z^2), with the exponent carried as an unevaluated sum of
   two doubles, which holds its relative accuracy at about 4 eps whatever |z|
   (issue #32). The two exact products that the double-word is built from are
   declared here as well: w_of_z calls one of them directly, to form the same
   factor on the real axis. See exp_z2.c for the algorithm, the error
   analysis, and why no fused multiply-add is required. */

#ifndef CERF_EXP_Z2_H
#define CERF_EXP_Z2_H

#include "cerf.h"  // defines _cerf_cmplx
#include "defs.h"  // defines C, CERF_LOCAL

//! Returns x*x - h exactly, with h = x*x rounded, so that h + result = x^2.
CERF_LOCAL double cerf_sqr_res(double x, double h);

//! Returns a*b - p exactly, with p = a*b rounded, so that p + result = a*b.
CERF_LOCAL double cerf_prod_res(double a, double b, double p);

//! Returns exp(x^2), with the exponent carried as a double-word.
CERF_LOCAL double cerf_exp_x2(double x);

//! Returns exp(-x^2), with the exponent carried as a double-word.
CERF_LOCAL double cerf_exp_mx2(double x);

//! Returns |exp(-z^2)| = exp(y^2-x^2), with the exponent carried as a double-word.
CERF_LOCAL double cerf_exp_mz2_mod(double x, double y);

//! Returns |exp(-z^2)| divided by *scale, which is 1 unless the exponential
//! overflows; then it is a power of e that brings the quotient back into range.
//! A caller that multiplies by a factor of modulus at most one may thus still
//! obtain a representable product, and rescales it at the end.
CERF_LOCAL double cerf_exp_mz2_mod_scaled(double x, double y, double* scale);

//! Returns exp(-z^2)/|exp(-z^2)| = exp(-2ixy), with the phase carried as a double-word.
CERF_LOCAL _cerf_cmplx cerf_exp_mz2_arg(double x, double y);

//! Returns exp(-z^2) for z = x+iy, with the exponent carried as a double-word.
CERF_LOCAL _cerf_cmplx cerf_cexp_mz2(double x, double y);

#endif // CERF_EXP_Z2_H
