xref: /openbsd-src/lib/libm/src/ld80/s_truncl.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /*
2  * ====================================================
3  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
4  *
5  * Developed at SunPro, a Sun Microsystems, Inc. business.
6  * Permission to use, copy, modify, and distribute this
7  * software is freely granted, provided that this notice
8  * is preserved.
9  * ====================================================
10  *
11  * From: @(#)s_floor.c 5.1 93/09/24
12  */
13 
14 #include <sys/cdefs.h>
15 #if 0
16 __FBSDID("$FreeBSD: src/lib/msun/src/s_truncl.c,v 1.9 2008/02/14 15:10:34 bde Exp $");
17 #endif
18 
19 /*
20  * truncl(x)
21  * Return x rounded toward 0 to integral value
22  * Method:
23  *	Bit twiddling.
24  * Exception:
25  *	Inexact flag raised if x not equal to truncl(x).
26  */
27 
28 #include <sys/types.h>
29 #include <machine/ieee.h>
30 
31 #include <float.h>
32 #include <math.h>
33 #include <stdint.h>
34 
35 #include "math_private.h"
36 
37 #ifdef LDBL_IMPLICIT_NBIT
38 #define	MANH_SIZE	(EXT_FRACHBITS + 1)
39 #else
40 #define	MANH_SIZE	EXT_FRACHBITS
41 #endif
42 
43 static const long double huge = 1.0e300;
44 static const float zero[] = { 0.0, -0.0 };
45 
46 long double
47 truncl(long double x)
48 {
49 	int e, es;
50 	uint32_t ix0, ix1;
51 
52 	GET_LDOUBLE_WORDS(es,ix0,ix1,x);
53 	e = (es&0x7fff) - LDBL_MAX_EXP + 1;
54 
55 	if (e < MANH_SIZE - 1) {
56 		if (e < 0) {			/* raise inexact if x != 0 */
57 			if (huge + x > 0.0)
58 				return (zero[(es&0x8000)!=0]);
59 		} else {
60 			uint64_t m = ((1llu << MANH_SIZE) - 1) >> (e + 1);
61 			if (((ix0 & m) | ix1) == 0)
62 				return (x);	/* x is integral */
63 			if (huge + x > 0.0) {	/* raise inexact flag */
64 				ix0 &= ~m;
65 				ix1 = 0;
66 			}
67 		}
68 	} else if (e < LDBL_MANT_DIG - 1) {
69 		uint64_t m = (uint64_t)-1 >> (64 - LDBL_MANT_DIG + e + 1);
70 		if ((ix1 & m) == 0)
71 			return (x);	/* x is integral */
72 		if (huge + x > 0.0)		/* raise inexact flag */
73 			ix1 &= ~m;
74 	}
75 	SET_LDOUBLE_WORDS(x,es,ix0,ix1);
76 	return (x);
77 }
78