1145170Sdas/*
2145170Sdas * ====================================================
3145170Sdas * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
4145170Sdas *
5145170Sdas * Developed at SunPro, a Sun Microsystems, Inc. business.
6145170Sdas * Permission to use, copy, modify, and distribute this
7145170Sdas * software is freely granted, provided that this notice
8145170Sdas * is preserved.
9145170Sdas * ====================================================
10145170Sdas *
11145170Sdas * From: @(#)s_floor.c 5.1 93/09/24
12145170Sdas */
13145170Sdas
14176245Sbde#include <sys/cdefs.h>
15176245Sbde__FBSDID("$FreeBSD$");
16145170Sdas
17145170Sdas/*
18145170Sdas * truncl(x)
19145170Sdas * Return x rounded toward 0 to integral value
20145170Sdas * Method:
21145170Sdas *	Bit twiddling.
22145170Sdas * Exception:
23145170Sdas *	Inexact flag raised if x not equal to truncl(x).
24145170Sdas */
25145170Sdas
26145170Sdas#include <float.h>
27145170Sdas#include <math.h>
28145170Sdas#include <stdint.h>
29145170Sdas
30145170Sdas#include "fpmath.h"
31145170Sdas
32145170Sdas#ifdef LDBL_IMPLICIT_NBIT
33145170Sdas#define	MANH_SIZE	(LDBL_MANH_SIZE + 1)
34145170Sdas#else
35145170Sdas#define	MANH_SIZE	LDBL_MANH_SIZE
36145170Sdas#endif
37145170Sdas
38145637Sstefanfstatic const long double huge = 1.0e300;
39176102Sbdestatic const float zero[] = { 0.0, -0.0 };
40145394Sstefanf
41145170Sdaslong double
42145170Sdastruncl(long double x)
43145170Sdas{
44145170Sdas	union IEEEl2bits u = { .e = x };
45145170Sdas	int e = u.bits.exp - LDBL_MAX_EXP + 1;
46145170Sdas
47145170Sdas	if (e < MANH_SIZE - 1) {
48145170Sdas		if (e < 0) {			/* raise inexact if x != 0 */
49145637Sstefanf			if (huge + x > 0.0)
50176102Sbde				u.e = zero[u.bits.sign];
51145170Sdas		} else {
52145170Sdas			uint64_t m = ((1llu << MANH_SIZE) - 1) >> (e + 1);
53145170Sdas			if (((u.bits.manh & m) | u.bits.manl) == 0)
54145170Sdas				return (x);	/* x is integral */
55145637Sstefanf			if (huge + x > 0.0) {	/* raise inexact flag */
56145394Sstefanf				u.bits.manh &= ~m;
57145394Sstefanf				u.bits.manl = 0;
58145394Sstefanf			}
59145170Sdas		}
60145170Sdas	} else if (e < LDBL_MANT_DIG - 1) {
61145170Sdas		uint64_t m = (uint64_t)-1 >> (64 - LDBL_MANT_DIG + e + 1);
62145170Sdas		if ((u.bits.manl & m) == 0)
63145170Sdas			return (x);	/* x is integral */
64145637Sstefanf		if (huge + x > 0.0)		/* raise inexact flag */
65145394Sstefanf			u.bits.manl &= ~m;
66145170Sdas	}
67145170Sdas	return (u.e);
68145170Sdas}
69