1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "glk/glulx/glulx.h"
24 
25 namespace Glk {
26 namespace Glulx {
27 
encode_float(gfloat32 val)28 uint Glulx::encode_float(gfloat32 val) {
29 	gfloat32 absval;
30 	uint sign;
31 	int expo;
32 	gfloat32 mant;
33 	uint fbits;
34 
35 	if (signbit(val)) {
36 		sign = 0x80000000;
37 		absval = -val;
38 	} else {
39 		sign = 0x0;
40 		absval = val;
41 	}
42 
43 	if (isinf(val)) {
44 		return sign | 0x7f800000; /* infinity */
45 	}
46 
47 	if (isnan(val)) {
48 		return sign | 0x7fc00000;
49 	}
50 
51 	mant = frexpf(absval, &expo);
52 
53 	/* Normalize mantissa to be in the range [1.0, 2.0) */
54 	if (0.5 <= mant && mant < 1.0) {
55 		mant *= 2.0;
56 		expo--;
57 	} else if (mant == 0.0) {
58 		expo = 0;
59 	} else {
60 		return sign | 0x7f800000; /* infinity */
61 	}
62 
63 	if (expo >= 128) {
64 		return sign | 0x7f800000; /* infinity */
65 	} else if (expo < -126) {
66 		/* Denormalized (very small) number */
67 		mant = ldexpf(mant, 126 + expo);
68 		expo = 0;
69 	} else if (!(expo == 0 && mant == 0.0)) {
70 		expo += 127;
71 		mant -= 1.0; /* Get rid of leading 1 */
72 	}
73 
74 	mant *= 8388608.0; /* 2^23 */
75 	fbits = (uint)(mant + 0.5); /* round mant to nearest int */
76 	if (fbits >> 23) {
77 		/* The carry propagated out of a string of 23 1 bits. */
78 		fbits = 0;
79 		expo++;
80 		if (expo >= 255) {
81 			return sign | 0x7f800000; /* infinity */
82 		}
83 	}
84 
85 	return (sign) | ((uint)(expo << 23)) | (fbits);
86 }
87 
decode_float(uint val)88 gfloat32 Glulx::decode_float(uint val) {
89 	int sign;
90 	int expo;
91 	uint mant;
92 	gfloat32 res;
93 
94 	/* First byte */
95 	sign = ((val & 0x80000000) != 0);
96 	expo = (val >> 23) & 0xFF;
97 	mant = val & 0x7FFFFF;
98 
99 	if (expo == 255) {
100 		if (mant == 0) {
101 			/* Infinity */
102 			return (sign ? (-INFINITY) : (INFINITY));
103 		} else {
104 			/* Not a number */
105 			return (sign ? (-NAN) : (NAN));
106 		}
107 	}
108 
109 	res = (gfloat32)mant / 8388608.0;
110 
111 	if (expo == 0) {
112 		expo = -126;
113 	} else {
114 		res += 1.0;
115 		expo -= 127;
116 	}
117 	res = ldexpf(res, expo);
118 
119 	return (sign ? (-res) : (res));
120 }
121 
122 } // End of namespace Glulx
123 } // End of namespace Glk
124