]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/ieee754/ldbl-128/s_fma.c
Update copyright dates with scripts/update-copyrights
[thirdparty/glibc.git] / sysdeps / ieee754 / ldbl-128 / s_fma.c
CommitLineData
5e908464 1/* Compute x * y + z as ternary operation.
2b778ceb 2 Copyright (C) 2010-2021 Free Software Foundation, Inc.
5e908464
JJ
3 This file is part of the GNU C Library.
4 Contributed by Jakub Jelinek <jakub@redhat.com>, 2010.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
59ba27a6 17 License along with the GNU C Library; if not, see
5a82c748 18 <https://www.gnu.org/licenses/>. */
5e908464
JJ
19
20#include <math.h>
21#include <fenv.h>
22#include <ieee754.h>
f85a176f 23#include <libm-alias-double.h>
628d90c5 24#include <math-use-builtins.h>
5e908464
JJ
25
26/* This implementation relies on long double being more than twice as
27 precise as double and uses rounding to odd in order to avoid problems
28 with double rounding.
29 See a paper by Boldo and Melquiond:
30 http://www.lri.fr/~melquion/doc/08-tc.pdf */
31
32double
33__fma (double x, double y, double z)
34{
628d90c5
VG
35#if USE_FMA_BUILTIN
36 return __builtin_fma (x, y, z);
37#else
5e908464
JJ
38 fenv_t env;
39 /* Multiplication is always exact. */
40 long double temp = (long double) x * (long double) y;
8ec5b013
JM
41
42 /* Ensure correct sign of an exact zero result by performing the
43 addition in the original rounding mode in that case. */
44 if (temp == -z)
45 return (double) temp + z;
46
5e908464
JJ
47 union ieee854_long_double u;
48 feholdexcept (&env);
49 fesetround (FE_TOWARDZERO);
50 /* Perform addition with round to odd. */
51 u.d = temp + (long double) z;
52 if ((u.ieee.mantissa3 & 1) == 0 && u.ieee.exponent != 0x7fff)
53 u.ieee.mantissa3 |= fetestexcept (FE_INEXACT) != 0;
54 feupdateenv (&env);
55 /* And finally truncation with round to nearest. */
56 return (double) u.d;
628d90c5 57#endif /* ! USE_FMA_BUILTIN */
5e908464
JJ
58}
59#ifndef __fma
f85a176f 60libm_alias_double (__fma, fma)
5e908464 61#endif