1 /*
2  *  rpf.c:      Conversion of float to reduced precision format values
3  *
4  *  Written by:     Stefan Frank
5  *          Richard Krampfl
6  *          Ullrich Hafner
7  *
8  *  This file is part of FIASCO (�F�ractal �I�mage �A�nd �S�equence �CO�dec)
9  *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
10  */
11 
12 /*
13  *  $Date: 2000/06/14 20:49:37 $
14  *  $Author: hafner $
15  *  $Revision: 5.1 $
16  *  $State: Exp $
17  */
18 
19 #include "pm_config.h"
20 #include "config.h"
21 #include "mallocvar.h"
22 
23 #include "types.h"
24 #include "macros.h"
25 #include "error.h"
26 
27 #include "misc.h"
28 #include "rpf.h"
29 
30 int const RPF_ZERO = -1;
31 
32 /*****************************************************************************
33 
34                    private code
35 
36 *****************************************************************************/
37 
38 
39 typedef struct {
40     double fraction;
41     int    exponent;
42 }  FracExp;
43 
44 
45 
46 static FracExp
fracExpFromDouble(double const x)47 fracExpFromDouble(double const x) {
48 
49     FracExp retval;
50 
51     retval.fraction = frexp(x, &retval.exponent);
52 
53     return retval;
54 }
55 
56 
57 
58 int
rtob(real_t const f,const rpf_t * const rpfP)59 rtob (real_t        const f,
60       const rpf_t * const rpfP)
61 /*
62  *  Convert real number 'f' into fixed point format.
63  *  The real number in [-'range'; +'range'] is scaled to [-1 ; +1].
64  *  Sign and the first 'precision' - 1 bits of the mantissa are
65  *  packed into one integer.
66  *
67  *  Return value:
68  *  real value in reduced precision format
69  */
70 {
71     /*
72      *  Extract mantissa (23 Bits), exponent (8 Bits) and sign (1 Bit)
73      */
74 
75     double const normalized = f / rpfP->range;
76         /* 'f' scaled to [-1,+1] */
77     FracExp const fracExp = fracExpFromDouble(normalized);
78     unsigned int const signedMantissa =
79         (unsigned int) (fracExp.fraction * (1<<23));
80 
81     unsigned int mantissa;
82     unsigned int sign;  /* 0 for positive; 1 for negative */
83 
84     if (signedMantissa < 0) {
85         mantissa = -signedMantissa;
86         sign = 1;
87     } else {
88         mantissa = +signedMantissa;
89         sign = 0;
90     }
91 
92     /*
93      *  Generate reduced precision mantissa.
94      */
95     if (fracExp.exponent > 0)
96         mantissa <<= fracExp.exponent;
97     else
98         mantissa >>= -fracExp.exponent;
99 
100     mantissa >>= (23 - rpfP->mantissa_bits - 1);
101 
102     mantissa +=  1;          /* Round last bit. */
103     mantissa >>= 1;
104 
105     if (mantissa == 0)           /* close to zero */
106         return RPF_ZERO;
107     else if (mantissa >= (1U << rpfP->mantissa_bits)) /* overflow */
108         return sign;
109     else
110         return ((mantissa & ((1U << rpfP->mantissa_bits) - 1)) << 1) | sign;
111 }
112 
113 
114 
115 float
btor(int const binary,const rpf_t * const rpfP)116 btor (int           const binary,
117       const rpf_t * const rpfP)
118 /*
119  *  Convert value 'binary' in reduced precision format to a real value.
120  *  For more information refer to function rtob() above.
121  *
122  *  Return value:
123  *  converted value
124  */
125 {
126     unsigned int mantissa;
127     float sign;
128     float f;
129 
130     if (binary == RPF_ZERO)
131         return 0;
132 
133     if (binary < 0 || binary >= 1 << (rpfP->mantissa_bits + 1))
134         error ("Reduced precision format: value %d out of range.", binary);
135 
136     /*
137      *  Restore IEEE float format:
138      *  mantissa (23 Bits), exponent (8 Bits) and sign (1 Bit)
139      */
140 
141     sign       = (binary & 0x1) == 0 ? 1.0 : -1.0;
142     mantissa   = (binary & ((0x1 << (rpfP->mantissa_bits + 1)) - 1)) >> 1;
143     mantissa <<= (23 - rpfP->mantissa_bits);
144 
145     if (mantissa == 0)
146         f = sign;
147     else
148         f =  sign * (float) mantissa / 8388608;
149 
150     return f * rpfP->range;       /* expand [ -1 ; +1 ] to
151                                      [ -range ; +range ] */
152 }
153 
154 
155 
156 
157 rpf_t *
alloc_rpf(unsigned const mantissa,fiasco_rpf_range_e const range)158 alloc_rpf (unsigned           const mantissa,
159            fiasco_rpf_range_e const range)
160 /*
161  *  Reduced precision format constructor.
162  *  Allocate memory for the rpf_t structure.
163  *  Number of mantissa bits is given by `mantissa'.
164  *  The range of the real values is in the interval [-`range', +`range'].
165  *  In case of invalid parameters, a structure with default values is
166  *  returned.
167  *
168  *  Return value
169  *  pointer to the new rpf structure
170  */
171 {
172     rpf_t * rpfP;
173 
174     MALLOCVAR(rpfP);
175 
176     if (mantissa < 2) {
177         warning (_("Size of RPF mantissa has to be in the interval [2,8]. "
178                    "Using minimum value 2.\n"));
179         rpfP->mantissa_bits = 2;
180     } else if (mantissa > 8) {
181         warning (_("Size of RPF mantissa has to be in the interval [2,8]. "
182                    "Using maximum value 8.\n"));
183         rpfP->mantissa_bits = 2;
184     } else
185         rpfP->mantissa_bits = mantissa;
186 
187     switch (range) {
188     case FIASCO_RPF_RANGE_0_75:
189         rpfP->range   = 0.75;
190         rpfP->range_e = range;
191         break;
192     case FIASCO_RPF_RANGE_1_50:
193         rpfP->range   = 1.50;
194         rpfP->range_e = range;
195         break;
196     case FIASCO_RPF_RANGE_2_00:
197         rpfP->range   = 2.00;
198         rpfP->range_e = range;
199         break;
200     case FIASCO_RPF_RANGE_1_00:
201         rpfP->range   = 1.00;
202         rpfP->range_e = range;
203         break;
204     default:
205         warning (_("Invalid RPF range specified. Using default value 1.0."));
206         rpfP->range   = 1.00;
207         rpfP->range_e = FIASCO_RPF_RANGE_1_00;
208         break;
209     }
210     return rpfP;
211 }
212 
213