xref: /openbsd-src/lib/libm/src/s_nan.c (revision 2b0358df1d88d06ef4139321dd05bd5e05d91eaf)
1 /*	$OpenBSD: s_nan.c,v 1.6 2008/12/10 01:08:25 martynas Exp $	*/
2 /*-
3  * Copyright (c) 2007 David Schultz
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD: src/lib/msun/src/s_nan.c,v 1.2 2007/12/18 23:46:32 das Exp $
28  */
29 
30 #include <sys/cdefs.h>
31 #include <sys/types.h>
32 #include <sys/endian.h>
33 #include <ctype.h>
34 #include <float.h>
35 #include <math.h>
36 #include <stdint.h>
37 #include <strings.h>
38 
39 #include "math_private.h"
40 
41 /*
42  * OpenBSD's ctype doesn't have digittoint, so we define it here.
43  */
44 static int
45 _digittoint(int c)
46 {
47 	if (!isxdigit(c))
48 		return 0;
49 
50 	if (isdigit(c))
51 		return c - '0';
52 	else
53 		return isupper(c) ? c - 'A' + 10 : c - 'a' + 10;
54 }
55 
56 /*
57  * Scan a string of hexadecimal digits (the format nan(3) expects) and
58  * make a bit array (using the local endianness). We stop when we
59  * encounter an invalid character, NUL, etc.  If we overflow, we do
60  * the same as gcc's __builtin_nan(), namely, discard the high order bits.
61  *
62  * The format this routine accepts needs to be compatible with what is used
63  * in contrib/gdtoa/hexnan.c (for strtod/scanf) and what is used in
64  * __builtin_nan(). In fact, we're only 100% compatible for strings we
65  * consider valid, so we might be violating the C standard. But it's
66  * impossible to use nan(3) portably anyway, so this seems good enough.
67  */
68 void
69 _scan_nan(uint32_t *words, int num_words, const char *s)
70 {
71 	int si;		/* index into s */
72 	int bitpos;	/* index into words (in bits) */
73 
74 	bzero(words, num_words * sizeof(uint32_t));
75 
76 	/* Allow a leading '0x'. (It's expected, but redundant.) */
77 	if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
78 		s += 2;
79 
80 	/* Scan forwards in the string, looking for the end of the sequence. */
81 	for (si = 0; isxdigit(s[si]); si++)
82 		;
83 
84 	/* Scan backwards, filling in the bits in words[] as we go. */
85 #if _BYTE_ORDER == _LITTLE_ENDIAN
86 	for (bitpos = 0; bitpos < 32 * num_words; bitpos += 4) {
87 #else
88 	for (bitpos = 32 * num_words - 4; bitpos >= 0; bitpos -= 4) {
89 #endif
90 		if (--si < 0)
91 			break;
92 		words[bitpos / 32] |= _digittoint(s[si]) << (bitpos % 32);
93 	}
94 }
95 
96 double
97 nan(const char *s)
98 {
99 	union {
100 		double d;
101 		uint32_t bits[2];
102 	} u;
103 
104 	_scan_nan(u.bits, 2, s);
105 #if _BYTE_ORDER == _LITTLE_ENDIAN
106 	u.bits[1] |= 0x7ff80000;
107 #else
108 	u.bits[0] |= 0x7ff80000;
109 #endif
110 	return (u.d);
111 }
112 
113 float
114 nanf(const char *s)
115 {
116 	union {
117 		float f;
118 		uint32_t bits[1];
119 	} u;
120 
121 	_scan_nan(u.bits, 1, s);
122 	u.bits[0] |= 0x7fc00000;
123 	return (u.f);
124 }
125 
126 #if LDBL_MANT_DIG == 53
127 #ifdef __weak_alias
128 __weak_alias(nanl, nan);
129 #endif /* __weak_alias */
130 #endif /* LDBL_MANT_DIG == 53 */
131