File: ldexp.c

package info (click to toggle)
datamash 1.9-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 13,600 kB
  • sloc: ansic: 65,320; sh: 8,982; perl: 5,127; makefile: 250; sed: 16
file content (78 lines) | stat: -rw-r--r-- 1,983 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/* Multiply a 'float' by a power of 2.
   Copyright 2002-2003, 2007-2025 Free Software Foundation, Inc.

   This file is free software: you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as
   published by the Free Software Foundation; either version 2.1 of the
   License, or (at your option) any later version.

   This file is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */

/* Written by Paolo Bonzini and Bruno Haible.  */

#include <config.h>

/* Specification.  */
#include <math.h>

# include <float.h>
#ifdef USE_LONG_DOUBLE
# include "fpucw.h"
#endif

/* Avoid some warnings from "gcc -Wshadow".
   This file doesn't use the exp() function.  */
#undef exp
#define exp exponent

#ifdef USE_LONG_DOUBLE
# define FUNC ldexpl
# define DOUBLE long double
# define ISNAN isnanl
# define DECL_ROUNDING DECL_LONG_DOUBLE_ROUNDING
# define BEGIN_ROUNDING() BEGIN_LONG_DOUBLE_ROUNDING ()
# define END_ROUNDING() END_LONG_DOUBLE_ROUNDING ()
# define L_(literal) literal##L
#else
# define FUNC ldexp
# define DOUBLE double
# define ISNAN isnand
# define DECL_ROUNDING
# define BEGIN_ROUNDING()
# define END_ROUNDING()
# define L_(literal) literal
#endif

DOUBLE
FUNC (DOUBLE x, int exp)
{
  DECL_ROUNDING

  BEGIN_ROUNDING ();

  /* Check for zero, nan and infinity. */
  if (!(ISNAN (x) || x + x == x))
    {
      DOUBLE factor = exp < 0 ? L_(0.5) : L_(2.0);

      while (true)
        {
          if (exp % 2 != 0)
            x *= factor;
          exp /= 2;
          if (exp == 0)
            break;
          factor = factor * factor;
        }
    }

  END_ROUNDING ();

  return x;
}