File: s_lround.c

package info (click to toggle)
picolibc 1.8-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 31,616 kB
  • sloc: ansic: 312,308; asm: 22,739; perl: 2,414; sh: 1,619; python: 1,019; pascal: 329; exp: 287; makefile: 164; xml: 40; cpp: 10
file content (140 lines) | stat: -rw-r--r-- 3,966 bytes parent folder | download
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
 * ====================================================
 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
 *
 * Developed at SunPro, a Sun Microsystems, Inc. business.
 * Permission to use, copy, modify, and distribute this
 * software is freely granted, provided that this notice 
 * is preserved.
 * ====================================================
 */
/*
FUNCTION
<<lround>>, <<lroundf>>, <<llround>>, <<llroundf>>---round to integer, to nearest
INDEX
	lround
INDEX
	lroundf
INDEX
	llround
INDEX
	llroundf

SYNOPSIS
	#include <math.h>
	long int lround(double <[x]>);
	long int lroundf(float <[x]>);
	long long int llround(double <[x]>);
	long long int llroundf(float <[x]>);

DESCRIPTION
	The <<lround>> and <<llround>> functions round their argument to the
	nearest integer value, rounding halfway cases away from zero, regardless
	of the current rounding direction.  If the rounded value is outside the
	range of the return type, the numeric result is unspecified (depending
	upon the floating-point implementation, not the library).  A range
	error may occur if the magnitude of x is too large.

RETURNS
<[x]> rounded to an integral value as an integer.

SEEALSO
See the <<round>> functions for the return being the same floating-point type
as the argument.  <<lrint>>, <<llrint>>.

PORTABILITY
ANSI C, POSIX

*/

#include "fdlibm.h"
#include <limits.h>

#ifdef _NEED_FLOAT64

long int
lround64(__float64 x)
{
  __int32_t sign, exponent_less_1023;
  /* Most significant word, least significant word. */
  __uint32_t msw, lsw;
  long int result;

  EXTRACT_WORDS(msw, lsw, x);

  /* Extract sign. */
  sign = ((msw & 0x80000000) ? -1 : 1);
  /* Extract exponent field. */
  exponent_less_1023 = ((msw & 0x7ff00000) >> 20) - 1023;
  msw &= 0x000fffff;
  msw |= 0x00100000;
  /* exponent_less_1023 in [-1023,1024] */
  if (exponent_less_1023 < 20)
    {
      /* exponent_less_1023 in [-1023,19] */
      if (exponent_less_1023 < 0)
        {
          if (exponent_less_1023 < -1)
            return 0;
          else
            return sign;
        }
      else
        {
          /* exponent_less_1023 in [0,19] */
	  /* shift amt in [0,19] */
          msw += 0x80000 >> exponent_less_1023;
	  /* shift amt in [20,1] */
          result = msw >> (20 - exponent_less_1023);
        }
    }
  else if (exponent_less_1023 < (__int32_t) ((8 * sizeof (long int)) - 1))
    {
      /* 32bit long: exponent_less_1023 in [20,30] */
      /* 64bit long: exponent_less_1023 in [20,62] */
      if (exponent_less_1023 >= 52)
	/* 64bit long: exponent_less_1023 in [52,62] */
	/* 64bit long: shift amt in [32,42] */
        result = ((long int) msw << (exponent_less_1023 - 20))
		/* 64bit long: shift amt in [0,10] */
            | ((long int) lsw << (exponent_less_1023 - 52));
      else
        {
	  /* 32bit long: exponent_less_1023 in [20,30] */
	  /* 64bit long: exponent_less_1023 in [20,51] */
          unsigned int tmp = lsw
		    /* 32bit long: shift amt in [0,10] */
		    /* 64bit long: shift amt in [0,31] */
                    + (0x80000000 >> (exponent_less_1023 - 20));
          if (tmp < lsw)
            ++msw;
	  /* 32bit long: shift amt in [0,10] */
	  /* 64bit long: shift amt in [0,31] */
          result = ((long int) msw << (exponent_less_1023 - 20))
		    /* ***32bit long: shift amt in [32,22] */
		    /* ***64bit long: shift amt in [32,1] */
                    | SAFE_RIGHT_SHIFT (tmp, (52 - exponent_less_1023));
        }
    }
  else
  {
    /* Result is too large to be represented by a long int. */
    if (sign == 1 ||
        !((sizeof(long) == 4 && x > LONG_MIN - 0.5) ||
          (sizeof(long) > 4 && x >= LONG_MIN)))
    {
      __math_set_invalid();
      return sign == 1 ? LONG_MAX : LONG_MIN;
    }
    return (long int)x;
  }

  if (sizeof (long) == 4 && sign == 1 && result == LONG_MIN)
    __math_set_invalid();

  return sign * result;
}

_MATH_ALIAS_j_d(lround)

#endif /* _NEED_FLOAT64 */