Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
mangle.cpp
Go to the documentation of this file.
1 /*
2  * Vega Strike
3  * Copyright (C) 2002 David Jeffery
4  *
5  * http://vegastrike.sourceforge.net/
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21 
22 /* NOTES: this documentation on this code was written on 02/04/29. Hopefully it'll
23  * be kept up to date.
24  *
25  * This evil code encodes floats into smaller bit lengths and decodes it back to a
26  * normal float. There are three variables that are used to determine how to encode
27  * and decode the number.
28  *
29  * exponent: exponent is the number of bits to use to encode the exponent portion of
30  * the floating point number.
31  *
32  * significand: significand is the number of bits to use to store the significand of
33  * the floating point number.
34  *
35  * denorm: denorm is a evil little trick. It lets you control at what exponent value
36  * to start storing the number in denormalized form. Making this number
37  * positive enables you to reduce accuracy of small numbers in order to
38  * increase the range possible for the stored number.
39  *
40  * denorm can allow you to "cheat" and get more accuracy at large numbers by
41  * increasing denorm, reducing exponent, and increasing significand. This reduces
42  * accuracy of small numbers, but you probably don't need most of the small number
43  * accuracy anyway
44  */
45 
46 #include "mangle.h"
47 
48 union type_conv
49 {
50  float fl_val;
51  unsigned int u32_val;
52 };
53 
54 unsigned int float_to_uint32( float value, char exponent, char significand, char denorm )
55 {
56  union type_conv tmp;
57  unsigned int newval, tmpsig;
58  int tmpexp;
59 
60  tmp.fl_val = value;
61  //set the sign bit
62  newval = SIGN_MASK&tmp.u32_val;
63  newval >>= EXP_BITS+SIGNIF_BITS-(exponent+significand);
64  //get the exponent and remove its offset
65  tmpexp = (EXP_MASK&tmp.u32_val)>>SIGNIF_BITS;
66  tmpexp -= 127;
67  //get the significand but leave one extra bit for use while performing
68  //rounding later
69  tmpsig = (SIGNIF_MASK&tmp.u32_val)>>(SIGNIF_BITS-significand-1);
70  //if this will be a normalized number, perform rounding
71  if (tmpexp > denorm && tmpsig&1) {
72  tmpsig++;
73  if ( tmpsig&( 1<<(significand+1) ) ) {
74  tmpexp++;
75  tmpsig -= 1<<(significand+1);
76  }
77  }
78  //remove the bit saved for rounding
79  tmpsig >>= 1;
80  if (tmpexp == denorm) {
81  if (tmpsig&1) //more rounding fun
82  tmpsig++;
83  if ( tmpsig&(1<<significand) ) {
84  tmpexp++;
85  tmpsig -= 1<<significand;
86  tmpexp = 1;
87  } else {
88  tmpsig |= 1<<significand;
89  tmpsig >>= 1;
90  tmpexp = 0;
91  }
92  } else if (tmpexp < denorm) {
93  tmpsig |= 1<<significand;
94  tmpsig >>= denorm-tmpexp;
95  if (tmpsig&1)
96  tmpsig++;
97  tmpsig >>= 1;
98  tmpexp = 0;
99  //if the number is too big, clamp it to the maximum represented value
100  } else if (tmpexp >= (1<<exponent)+denorm) {
101  tmpexp = BITMASK( exponent );
102  tmpsig = BITMASK( significand );
103  } else {
104  tmpexp -= denorm;
105  }
106  newval |= (tmpexp<<significand)|tmpsig;
107  return newval;
108 }
109 
110 float uint32_to_float( unsigned int value, char exponent, char significand, char denorm )
111 {
112  union type_conv newval;
113  unsigned int tmpsig;
114  int tmpexp;
115 
116  newval.u32_val = ( 1<<(exponent+significand) )&value;
117  newval.u32_val <<= 31-(exponent+significand);
118  tmpsig = value&BITMASK( significand );
119  tmpexp = value&(BITMASK( exponent )<<significand);
120  tmpexp >>= significand;
121  //if the number should be 0 or -0, go ahead and return
122  if (tmpexp == 0 && tmpsig == 0) {
123  return newval.fl_val;
124  //if a denormalized value, rebuild to normalized form
125  } else if (tmpexp == 0) {
126  tmpsig <<= 1;
127  while ( !( tmpsig&(1<<significand) ) ) {
128  tmpexp -= 1;
129  tmpsig <<= 1;
130  }
131  tmpsig -= 1<<significand;
132  }
133  tmpexp += 127+denorm;
134  tmpsig <<= SIGNIF_BITS-significand;
135 
136  newval.u32_val |= tmpexp<<SIGNIF_BITS;
137  newval.u32_val |= tmpsig;
138 
139  return newval.fl_val;
140 }
141