xref: /minix3/lib/libm/src/s_truncl.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
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 __RCSID("$NetBSD: s_truncl.c,v 1.4 2013/11/13 12:58:11 joerg Exp $");
16 #if 0
17 __FBSDID("$FreeBSD: head/lib/msun/src/s_truncl.c 176280 2008-02-14 15:10:34Z bde $");
18 #endif
19 
20 /*
21  * truncl(x)
22  * Return x rounded toward 0 to integral value
23  * Method:
24  *	Bit twiddling.
25  * Exception:
26  *	Inexact flag raised if x not equal to truncl(x).
27  */
28 #include "namespace.h"
29 
30 #include <float.h>
31 #include <math.h>
32 #include <stdint.h>
33 #include <machine/ieee.h>
34 
35 #ifdef __HAVE_LONG_DOUBLE
36 
37 #ifdef __weak_alias
38 __weak_alias(truncl, _truncl)
39 #endif
40 
41 #ifdef LDBL_IMPLICIT_NBIT
42 #define	MANH_SIZE	(EXT_FRACHBITS + 1)
43 #else
44 #define	MANH_SIZE	EXT_FRACHBITS
45 #endif
46 
47 static const long double huge = 1.0e300;
48 static const float zero[] = { 0.0, -0.0 };
49 
50 long double
truncl(long double x)51 truncl(long double x)
52 {
53 	union ieee_ext_u ux = { .extu_ld = x, };
54 	int e = ux.extu_exp - LDBL_MAX_EXP + 1;
55 
56 	if (e < MANH_SIZE - 1) {
57 		if (e < 0) {			/* raise inexact if x != 0 */
58 			if (huge + x > 0.0)
59 				ux.extu_ld = zero[ux.extu_sign];
60 		} else {
61 			uint64_t m = ((1llu << MANH_SIZE) - 1) >> (e + 1);
62 			if (((ux.extu_frach & m) | ux.extu_fracl) == 0)
63 				return (x);	/* x is integral */
64 			if (huge + x > 0.0) {	/* raise inexact flag */
65 				ux.extu_frach &= ~m;
66 				ux.extu_fracl = 0;
67 			}
68 		}
69 	} else if (e < LDBL_MANT_DIG - 1) {
70 		uint64_t m = (uint64_t)-1 >> (64 - LDBL_MANT_DIG + e + 1);
71 		if ((ux.extu_fracl & m) == 0)
72 			return (x);	/* x is integral */
73 		if (huge + x > 0.0)		/* raise inexact flag */
74 			ux.extu_fracl &= ~m;
75 	}
76 	return (ux.extu_ld);
77 }
78 
79 #endif /* __HAVE_LONG_DOUBLE */
80