newlib-cygwin/newlib/libm/common/s_lround.c

110 lines
2.7 KiB
C

/*
* ====================================================
* 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
ANSI_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"
#ifndef _DOUBLE_IS_32BITS
#ifdef __STDC__
long int lround(double x)
#else
long int lround(x)
double x;
#endif
{
__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;
if (exponent_less_1023 < 20)
{
if (exponent_less_1023 < 0)
{
if (exponent_less_1023 < -1)
return 0;
else
return sign;
}
else
{
msw += 0x80000 >> exponent_less_1023;
result = msw >> (20 - exponent_less_1023);
}
}
else if (exponent_less_1023 < (8 * sizeof (long int)) - 1)
{
if (exponent_less_1023 >= 52)
result = ((long int) msw << (exponent_less_1023 - 20)) | (lsw << (exponent_less_1023 - 52));
else
{
unsigned int tmp = lsw + (0x80000000 >> (exponent_less_1023 - 20));
if (tmp < lsw)
++msw;
result = ((long int) msw << (exponent_less_1023 - 20)) | (tmp >> (52 - exponent_less_1023));
}
}
else
/* Result is too large to be represented by a long int. */
return (long int)x;
return sign * result;
}
#endif /* _DOUBLE_IS_32BITS */