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