1d4afb5ceSopenharmony_ci/******************************************************************************
2d4afb5ceSopenharmony_ci *
3d4afb5ceSopenharmony_ci * Filename:    ieeehalfprecision.c
4d4afb5ceSopenharmony_ci * Programmer:  James Tursa
5d4afb5ceSopenharmony_ci * Version:     1.0
6d4afb5ceSopenharmony_ci * Date:        March 3, 2009
7d4afb5ceSopenharmony_ci * Copyright:   (c) 2009 by James Tursa, All Rights Reserved
8d4afb5ceSopenharmony_ci *
9d4afb5ceSopenharmony_ci *  This code uses the BSD License:
10d4afb5ceSopenharmony_ci *
11d4afb5ceSopenharmony_ci *  Redistribution and use in source and binary forms, with or without
12d4afb5ceSopenharmony_ci *  modification, are permitted provided that the following conditions are
13d4afb5ceSopenharmony_ci *  met:
14d4afb5ceSopenharmony_ci *
15d4afb5ceSopenharmony_ci *     * Redistributions of source code must retain the above copyright
16d4afb5ceSopenharmony_ci *       notice, this list of conditions and the following disclaimer.
17d4afb5ceSopenharmony_ci *     * Redistributions in binary form must reproduce the above copyright
18d4afb5ceSopenharmony_ci *       notice, this list of conditions and the following disclaimer in
19d4afb5ceSopenharmony_ci *       the documentation and/or other materials provided with the distribution
20d4afb5ceSopenharmony_ci *
21d4afb5ceSopenharmony_ci *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22d4afb5ceSopenharmony_ci *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23d4afb5ceSopenharmony_ci *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24d4afb5ceSopenharmony_ci *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25d4afb5ceSopenharmony_ci *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26d4afb5ceSopenharmony_ci *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27d4afb5ceSopenharmony_ci *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28d4afb5ceSopenharmony_ci *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29d4afb5ceSopenharmony_ci *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30d4afb5ceSopenharmony_ci *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31d4afb5ceSopenharmony_ci *  POSSIBILITY OF SUCH DAMAGE.
32d4afb5ceSopenharmony_ci *
33d4afb5ceSopenharmony_ci * This file contains C code to convert between IEEE double, single, and half
34d4afb5ceSopenharmony_ci * precision floating point formats. The intended use is for standalone C code
35d4afb5ceSopenharmony_ci * that does not rely on MATLAB mex.h. The bit pattern for the half precision
36d4afb5ceSopenharmony_ci * floating point format is stored in a 16-bit unsigned int variable. The half
37d4afb5ceSopenharmony_ci * precision bit pattern definition is:
38d4afb5ceSopenharmony_ci *
39d4afb5ceSopenharmony_ci * 1 bit sign bit
40d4afb5ceSopenharmony_ci * 5 bits exponent, biased by 15
41d4afb5ceSopenharmony_ci * 10 bits mantissa, hidden leading bit, normalized to 1.0
42d4afb5ceSopenharmony_ci *
43d4afb5ceSopenharmony_ci * Special floating point bit patterns recognized and supported:
44d4afb5ceSopenharmony_ci *
45d4afb5ceSopenharmony_ci * All exponent bits zero:
46d4afb5ceSopenharmony_ci * - If all mantissa bits are zero, then number is zero (possibly signed)
47d4afb5ceSopenharmony_ci * - Otherwise, number is a denormalized bit pattern
48d4afb5ceSopenharmony_ci *
49d4afb5ceSopenharmony_ci * All exponent bits set to 1:
50d4afb5ceSopenharmony_ci * - If all mantissa bits are zero, then number is +Infinity or -Infinity
51d4afb5ceSopenharmony_ci * - Otherwise, number is NaN (Not a Number)
52d4afb5ceSopenharmony_ci *
53d4afb5ceSopenharmony_ci * For the denormalized cases, note that 2^(-24) is the smallest number that can
54d4afb5ceSopenharmony_ci * be represented in half precision exactly. 2^(-25) will convert to 2^(-24)
55d4afb5ceSopenharmony_ci * because of the rounding algorithm used, and 2^(-26) is too small and
56d4afb5ceSopenharmony_ci * underflows to zero.
57d4afb5ceSopenharmony_ci *
58d4afb5ceSopenharmony_ci ******************************************************************************/
59d4afb5ceSopenharmony_ci
60d4afb5ceSopenharmony_ci/*
61d4afb5ceSopenharmony_ci  changes by K. Rogovin:
62d4afb5ceSopenharmony_ci  - changed macros UINT16_TYPE, etc to types from stdint.h
63d4afb5ceSopenharmony_ci    (i.e. UINT16_TYPE-->uint16_t, INT16_TYPE-->int16_t, etc)
64d4afb5ceSopenharmony_ci
65d4afb5ceSopenharmony_ci  - removed double conversion routines.
66d4afb5ceSopenharmony_ci
67d4afb5ceSopenharmony_ci  - changed run time checks of endianness to compile time macro.
68d4afb5ceSopenharmony_ci
69d4afb5ceSopenharmony_ci  - removed return value from routines
70d4afb5ceSopenharmony_ci
71d4afb5ceSopenharmony_ci  - changed source parameter type from * to const *
72d4afb5ceSopenharmony_ci
73d4afb5ceSopenharmony_ci  - changed pointer types from void ot uint16_t and uint32_t
74d4afb5ceSopenharmony_ci */
75d4afb5ceSopenharmony_ci
76d4afb5ceSopenharmony_ci/*
77d4afb5ceSopenharmony_ci * andy@warmcat.com:
78d4afb5ceSopenharmony_ci *
79d4afb5ceSopenharmony_ci *  - clean style and indenting
80d4afb5ceSopenharmony_ci *  - convert to single operation
81d4afb5ceSopenharmony_ci *  - export as lws_
82d4afb5ceSopenharmony_ci */
83d4afb5ceSopenharmony_ci
84d4afb5ceSopenharmony_ci#include <string.h>
85d4afb5ceSopenharmony_ci#include <stdint.h>
86d4afb5ceSopenharmony_ci
87d4afb5ceSopenharmony_civoid
88d4afb5ceSopenharmony_cilws_singles2halfp(uint16_t *hp, uint32_t x)
89d4afb5ceSopenharmony_ci{
90d4afb5ceSopenharmony_ci	uint32_t xs, xe, xm;
91d4afb5ceSopenharmony_ci	uint16_t hs, he, hm;
92d4afb5ceSopenharmony_ci	int hes;
93d4afb5ceSopenharmony_ci
94d4afb5ceSopenharmony_ci	if (!(x & 0x7FFFFFFFu)) {
95d4afb5ceSopenharmony_ci		/* Signed zero */
96d4afb5ceSopenharmony_ci		*hp = (uint16_t)(x >> 16);
97d4afb5ceSopenharmony_ci
98d4afb5ceSopenharmony_ci		return;
99d4afb5ceSopenharmony_ci	}
100d4afb5ceSopenharmony_ci
101d4afb5ceSopenharmony_ci	xs = x & 0x80000000u;  // Pick off sign bit
102d4afb5ceSopenharmony_ci	xe = x & 0x7F800000u;  // Pick off exponent bits
103d4afb5ceSopenharmony_ci	xm = x & 0x007FFFFFu;  // Pick off mantissa bits
104d4afb5ceSopenharmony_ci
105d4afb5ceSopenharmony_ci	if (xe == 0) {  // Denormal will underflow, return a signed zero
106d4afb5ceSopenharmony_ci		*hp = (uint16_t) (xs >> 16);
107d4afb5ceSopenharmony_ci		return;
108d4afb5ceSopenharmony_ci	}
109d4afb5ceSopenharmony_ci
110d4afb5ceSopenharmony_ci	if (xe == 0x7F800000u) {  // Inf or NaN (all the exponent bits are set)
111d4afb5ceSopenharmony_ci		if (!xm) { // If mantissa is zero ...
112d4afb5ceSopenharmony_ci			*hp = (uint16_t) ((xs >> 16) | 0x7C00u); // Signed Inf
113d4afb5ceSopenharmony_ci			return;
114d4afb5ceSopenharmony_ci		}
115d4afb5ceSopenharmony_ci
116d4afb5ceSopenharmony_ci		*hp = (uint16_t) 0xFE00u; // NaN, only 1st mantissa bit set
117d4afb5ceSopenharmony_ci
118d4afb5ceSopenharmony_ci		return;
119d4afb5ceSopenharmony_ci	}
120d4afb5ceSopenharmony_ci
121d4afb5ceSopenharmony_ci	/* Normalized number */
122d4afb5ceSopenharmony_ci
123d4afb5ceSopenharmony_ci	hs = (uint16_t) (xs >> 16); // Sign bit
124d4afb5ceSopenharmony_ci	/* Exponent unbias the single, then bias the halfp */
125d4afb5ceSopenharmony_ci	hes = ((int)(xe >> 23)) - 127 + 15;
126d4afb5ceSopenharmony_ci
127d4afb5ceSopenharmony_ci	if (hes >= 0x1F) {  // Overflow
128d4afb5ceSopenharmony_ci		*hp = (uint16_t) ((xs >> 16) | 0x7C00u); // Signed Inf
129d4afb5ceSopenharmony_ci		return;
130d4afb5ceSopenharmony_ci	}
131d4afb5ceSopenharmony_ci
132d4afb5ceSopenharmony_ci	if (hes <= 0) {  // Underflow
133d4afb5ceSopenharmony_ci		if ((14 - hes) > 24)
134d4afb5ceSopenharmony_ci			/*
135d4afb5ceSopenharmony_ci			 * Mantissa shifted all the way off & no
136d4afb5ceSopenharmony_ci			 * rounding possibility
137d4afb5ceSopenharmony_ci			 */
138d4afb5ceSopenharmony_ci			hm = (uint16_t) 0u;  // Set mantissa to zero
139d4afb5ceSopenharmony_ci		else {
140d4afb5ceSopenharmony_ci			xm |= 0x00800000u;  // Add the hidden leading bit
141d4afb5ceSopenharmony_ci			hm = (uint16_t) (xm >> (14 - hes)); // Mantissa
142d4afb5ceSopenharmony_ci			if ((xm >> (13 - hes)) & 1u) // Check for rounding
143d4afb5ceSopenharmony_ci				/* Round, might overflow into exp bit,
144d4afb5ceSopenharmony_ci				 * but this is OK */
145d4afb5ceSopenharmony_ci				hm = (uint16_t)(hm + 1u);
146d4afb5ceSopenharmony_ci		}
147d4afb5ceSopenharmony_ci		/* Combine sign bit and mantissa bits, biased exponent is 0 */
148d4afb5ceSopenharmony_ci		*hp = hs | hm;
149d4afb5ceSopenharmony_ci
150d4afb5ceSopenharmony_ci		return;
151d4afb5ceSopenharmony_ci	}
152d4afb5ceSopenharmony_ci
153d4afb5ceSopenharmony_ci	he = (uint16_t)(hes << 10); // Exponent
154d4afb5ceSopenharmony_ci	hm = (uint16_t)(xm >> 13); // Mantissa
155d4afb5ceSopenharmony_ci
156d4afb5ceSopenharmony_ci	if (xm & 0x00001000u) // Check for rounding
157d4afb5ceSopenharmony_ci		/* Round, might overflow to inf, this is OK */
158d4afb5ceSopenharmony_ci		*hp = (uint16_t)((hs | he | hm) + (uint16_t)1u);
159d4afb5ceSopenharmony_ci	else
160d4afb5ceSopenharmony_ci		*hp = hs | he | hm;  // No rounding
161d4afb5ceSopenharmony_ci}
162d4afb5ceSopenharmony_ci
163d4afb5ceSopenharmony_civoid
164d4afb5ceSopenharmony_cilws_halfp2singles(uint32_t *xp, uint16_t h)
165d4afb5ceSopenharmony_ci{
166d4afb5ceSopenharmony_ci	uint16_t hs, he, hm;
167d4afb5ceSopenharmony_ci	uint32_t xs, xe, xm;
168d4afb5ceSopenharmony_ci	int32_t xes;
169d4afb5ceSopenharmony_ci	int e;
170d4afb5ceSopenharmony_ci
171d4afb5ceSopenharmony_ci	if (!(h & 0x7FFFu)) {  // Signed zero
172d4afb5ceSopenharmony_ci		*xp = ((uint32_t)h) << 16;  // Return the signed zero
173d4afb5ceSopenharmony_ci
174d4afb5ceSopenharmony_ci		return;
175d4afb5ceSopenharmony_ci	}
176d4afb5ceSopenharmony_ci
177d4afb5ceSopenharmony_ci	hs = h & 0x8000u;  // Pick off sign bit
178d4afb5ceSopenharmony_ci	he = h & 0x7C00u;  // Pick off exponent bits
179d4afb5ceSopenharmony_ci	hm = h & 0x03FFu;  // Pick off mantissa bits
180d4afb5ceSopenharmony_ci
181d4afb5ceSopenharmony_ci	if (!he) {  // Denormal will convert to normalized
182d4afb5ceSopenharmony_ci		e = -1;
183d4afb5ceSopenharmony_ci
184d4afb5ceSopenharmony_ci		/* figure out how much extra to adjust the exponent */
185d4afb5ceSopenharmony_ci		do {
186d4afb5ceSopenharmony_ci			e++;
187d4afb5ceSopenharmony_ci			hm = (uint16_t)(hm << 1);
188d4afb5ceSopenharmony_ci			/* Shift until leading bit overflows into exponent */
189d4afb5ceSopenharmony_ci		} while (!(hm & 0x0400u));
190d4afb5ceSopenharmony_ci
191d4afb5ceSopenharmony_ci		xs = ((uint32_t) hs) << 16; // Sign bit
192d4afb5ceSopenharmony_ci
193d4afb5ceSopenharmony_ci		/* Exponent unbias the halfp, then bias the single */
194d4afb5ceSopenharmony_ci		xes = ((int32_t)(he >> 10)) - 15 + 127 - e;
195d4afb5ceSopenharmony_ci		xe = (uint32_t)(xes << 23); // Exponent
196d4afb5ceSopenharmony_ci		xm = ((uint32_t)(hm & 0x03FFu)) << 13; // Mantissa
197d4afb5ceSopenharmony_ci
198d4afb5ceSopenharmony_ci		*xp = xs | xe | xm;
199d4afb5ceSopenharmony_ci
200d4afb5ceSopenharmony_ci		return;
201d4afb5ceSopenharmony_ci	}
202d4afb5ceSopenharmony_ci
203d4afb5ceSopenharmony_ci	if (he == 0x7C00u) {  /* Inf or NaN (all the exponent bits are set) */
204d4afb5ceSopenharmony_ci		if (!hm) { /* If mantissa is zero ...
205d4afb5ceSopenharmony_ci			  * Signed Inf
206d4afb5ceSopenharmony_ci			  */
207d4afb5ceSopenharmony_ci			*xp = (((uint32_t)hs) << 16) | ((uint32_t)0x7F800000u);
208d4afb5ceSopenharmony_ci
209d4afb5ceSopenharmony_ci			return;
210d4afb5ceSopenharmony_ci		}
211d4afb5ceSopenharmony_ci
212d4afb5ceSopenharmony_ci		 /* ... NaN, only 1st mantissa bit set */
213d4afb5ceSopenharmony_ci		*xp = (uint32_t)0xFFC00000u;
214d4afb5ceSopenharmony_ci
215d4afb5ceSopenharmony_ci		return;
216d4afb5ceSopenharmony_ci	}
217d4afb5ceSopenharmony_ci
218d4afb5ceSopenharmony_ci	/* Normalized number */
219d4afb5ceSopenharmony_ci
220d4afb5ceSopenharmony_ci	xs = ((uint32_t)hs) << 16; // Sign bit
221d4afb5ceSopenharmony_ci	/* Exponent unbias the halfp, then bias the single */
222d4afb5ceSopenharmony_ci	xes = ((int32_t)(he >> 10)) - 15 + 127;
223d4afb5ceSopenharmony_ci	xe = (uint32_t)(xes << 23); // Exponent
224d4afb5ceSopenharmony_ci	xm = ((uint32_t)hm) << 13; // Mantissa
225d4afb5ceSopenharmony_ci
226d4afb5ceSopenharmony_ci	/* Combine sign bit, exponent bits, and mantissa bits */
227d4afb5ceSopenharmony_ci	*xp = xs | xe | xm;
228d4afb5ceSopenharmony_ci}
229