Kannel: Open Source WAP and SMS gateway  svn-r5335
wsieee754.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2018 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  *
59  * wsieee754.h
60  *
61  * Author: Markku Rossi <mtr@iki.fi>
62  *
63  * Copyright (c) 2000 WAPIT OY LTD.
64  * All rights reserved.
65  *
66  * Functions to manipulate ANSI/IEEE Std 754-1985 binary floating-point
67  * numbers.
68  *
69  */
70 
71 #include "wsint.h"
72 
73 /********************* Types and definitions ****************************/
74 
75 #define WS_IEEE754_SINGLE_EXP_SIZE 8
76 #define WS_IEEE754_SINGLE_MANT_SIZE 23
77 #define WS_IEEE754_SINGLE_BIAS 127
78 
79 #define WS_IEEE754_SINGLE_EXP_MIN -126
80 #define WS_IEEE754_SINGLE_EXP_MAX 127
81 
82 #define WS_IEEE754_POSITIVE_INFINITY 0x7f800000
83 
84 /********************* Special values ***********************************/
85 
86 unsigned char ws_ieee754_nan[4] = {0xff, 0xff, 0xff, 0xff};
87 
88 unsigned char ws_ieee754_positive_inf[4] = {0x7f, 0x80, 0x00, 0x00};
89 
90 unsigned char ws_ieee754_negative_inf[4] = {0xff, 0x80, 0x00, 0x00};
91 
92 /********************* Global functions *********************************/
93 
94 WsIeee754Result ws_ieee754_encode_single(double value, unsigned char *buf)
95 {
96  int sign = 0;
97  WsInt32 exp = 0;
98  WsUInt32 mant = 0;
99  int i;
101 
102  /* The sign bit. */
103  if (value < 0.0) {
104  sign = 1;
105  value = -value;
106  }
107 
108  /* Scale the value so that: 1 <= mantissa < 2. */
109  if (value > 1.0) {
110  /* The exponent is positive. */
111  while (value >= 2.0 && exp <= WS_IEEE754_SINGLE_EXP_MAX) {
112  value /= 2.0;
113  exp++;
114  }
115  if (exp > WS_IEEE754_SINGLE_EXP_MAX) {
116  /* Overflow => infinity. */
117  exp = 0xff;
118 
119  if (sign)
120  result = WS_IEEE754_NEGATIVE_INF;
121  else
122  result = WS_IEEE754_POSITIVE_INF;
123 
124  goto done;
125  }
126 
127  /* The 1 is implicit. */
128  value -= 1;
129  } else {
130  /* The exponent is negative. */
131  while (value < 1.0 && exp > WS_IEEE754_SINGLE_EXP_MIN) {
132  value *= 2.0;
133  exp--;
134  }
135  if (value >= 1.0) {
136  /* We managed to get the number to the normal form. Let's
137  remote the implicit 1 from the value. */
138  gw_assert(value >= 1.0);
139  value -= 1.0;
140  } else {
141  /* The number is still smaller than 1. We just try to
142  present the remaining stuff in our mantissa. If that
143  fails, we fall back to 0.0. We mark exp to -127 (after
144  bias it is 0) to mark this unnormalized form. */
145  exp--;
146  gw_assert(exp == -127);
147  }
148  }
149 
150  for (i = 0; i < WS_IEEE754_SINGLE_MANT_SIZE; i++) {
151  value *= 2.0;
152  mant <<= 1;
153 
154  if (value >= 1.0) {
155  mant |= 1;
156  value -= 1.0;
157  }
158  }
159 
160  /* Handle rounding. Intel seems to round 0.5 down so to be
161  compatible, our check is > instead of >=. */
162  if (value * 2.0 > 1.0) {
163  mant++;
164  if (mant == 0x800000) {
165  /* This we the really worst case. The rounding rounds the
166  mant up to 2.0. So we must increase the exponent by one.
167  This may then result an overflow in the exponent which
168  converts our number to infinity. */
169  mant = 0;
170  exp++;
171 
172  if (exp > WS_IEEE754_SINGLE_EXP_MAX) {
173  /* Overflow => infinity. */
174  exp = 0xff;
175  goto done;
176  }
177  }
178  }
179 
180  /* Handle biased exponent. */
181  exp += WS_IEEE754_SINGLE_BIAS;
182 
183 done:
184 
185  /* Encode the value to the buffer. */
186 
187  mant |= exp << 23;
188  mant |= sign << 31;
189 
190  buf[3] = (mant & 0x000000ff);
191  buf[2] = (mant & 0x0000ff00) >> 8;
192  buf[1] = (mant & 0x00ff0000) >> 16;
193  buf[0] = (mant & 0xff000000) >> 24;
194 
195  return result;
196 }
197 
198 
200  double *value_return)
201 {
205  double value;
206  int i;
207 
208  /* Check the special cases where exponent is all 1. */
209  if (exp == 0xff) {
210  if (mant == 0)
212 
213  return WS_IEEE754_NAN;
214  }
215 
216  /* Expand the mantissa. */
217  value = 0.0;
218  for (i = 0; i < WS_IEEE754_SINGLE_MANT_SIZE; i++) {
219  if (mant & 0x1)
220  value += 1.0;
221 
222  value /= 2.0;
223  mant >>= 1;
224  }
225 
226  /* Check the `unnormalized' vs. `normal form'. */
227  if (exp == 0)
228  /* This is a `unnormalized' number. */
229  exp = -126;
230  else {
231  /* This is a standard case. */
232  value += 1.0;
233  exp -= WS_IEEE754_SINGLE_BIAS;
234  }
235 
236  /* Handle exponents. */
237  while (exp > 0) {
238  value *= 2;
239  exp--;
240  }
241  while (exp < 0) {
242  value /= 2;
243  exp++;
244  }
245 
246  /* Finally notify sign. */
247  if (sign)
248  value = -value;
249 
250  *value_return = value;
251 
252  return WS_IEEE754_OK;
253 }
254 
255 
257 {
258  return (buf[0] & 0x80) >> 7;
259 }
260 
261 
263 {
264  WsUInt32 value = buf[0] & 0x7f;
265 
266  value <<= 1;
267  value |= (buf[1] & 0x80) >> 7;
268 
269  return value;
270 }
271 
272 
274 {
275  WsUInt32 value = buf[1] & 0x7f;
276 
277  value <<= 8;
278  value |= buf[2];
279 
280  value <<= 8;
281  value |= buf[3];
282 
283  return value;
284 }
285 
286 #if 0
287 /********************* Tests for IEEE754 functions **********************/
288 
289 void ws_ieee754_print(unsigned char *buf)
290 {
291  int i, j;
292 
293  for (i = 0; i < 4; i++) {
294  unsigned char mask = 0x80;
295  unsigned char ch = buf[i];
296 
297  for (j = 0; j < 8; j++) {
298  if (ch & mask)
299  printf("1");
300  else
301  printf("0");
302 
303  if ((i == 0 && j == 0)
304  || (i == 1 && j == 0))
305  printf(" ");
306 
307  mask >>= 1;
308  }
309  }
310  printf("\n");
311 }
312 
313 #include <math.h>
314 #include <stdlib.h>
315 #include <machine/ieee.h>
316 
317 void check_value(double num)
318 {
319  float native = num;
320  unsigned char buf[4];
321  struct ieee_single *s = (struct ieee_single *) & native;
322  unsigned int *uip = (unsigned int *) s;
323  unsigned int n = ntohl(*uip);
324  double d;
325 
326  ws_ieee754_encode_single(num, buf);
327  if (memcmp(buf, &n, 4) != 0) {
328  printf("\n");
329  printf("%f failed:\n", num);
330  printf("ws: ");
331  ws_ieee754_print(buf);
332  printf("native: ");
333  ws_ieee754_print((unsigned char *) &n);
334  abort();
335  }
336 
338  || d != native) {
339  printf("\ndecode of %f failed: got %f\n", num, d);
340  abort();
341  }
342 }
343 
344 
345 int main(int argc, char *argv[])
346 {
347  unsigned char buf[4];
348  unsigned int rounds = 0;
349 
350  if (argc > 1) {
351  int i;
352 
353  for (i = 1; i < argc; i++)
354  check_value(strtod(argv[1], NULL));
355 
356  return 0;
357  }
358 
359  ws_ieee754_encode_single(5.75, buf);
360  ws_ieee754_print(buf);
361  check_value(5.75);
362 
363  ws_ieee754_encode_single(340282346638528859811704183484516925440.0, buf);
364  ws_ieee754_print(buf);
365  check_value(340282346638528859811704183484516925440.0);
366 
367  ws_ieee754_encode_single( -340282346638528859811704183484516925440.0, buf);
368  ws_ieee754_print(buf);
369  check_value( -340282346638528859811704183484516925440.0);
370 
371  ws_ieee754_encode_single(3.0 * pow(2, -129), buf);
372  ws_ieee754_print(buf);
373  check_value(3.0 * pow(2, -129));
374 
375  ws_ieee754_encode_single(pow(2, -149), buf);
376  ws_ieee754_print(buf);
377  check_value(pow(2, -149));
378 
379  ws_ieee754_encode_single(pow(2, -149) * .1, buf);
380  ws_ieee754_print(buf);
381  check_value(pow(2, -149) * .1);
382 
383  ws_ieee754_encode_single( -pow(2, -149), buf);
384  ws_ieee754_print(buf);
385  check_value( -pow(2, -149));
386 
387  ws_ieee754_encode_single( -pow(2, -149) * .1, buf);
388  ws_ieee754_print(buf);
389 
390  while (1) {
391  double a = random();
392  double b = random();
393 
394  if (b == 0.0)
395  continue;
396 
397  check_value(a / b);
398  check_value(a * b);
399 
400  if ((++rounds % 100000) == 0) {
401  printf("%d ", rounds);
402  fflush(stdout);
403  }
404 
405  }
406 
407  return 0;
408 }
409 #endif
unsigned char ws_ieee754_nan[4]
Definition: wsieee754.c:86
#define WS_IEEE754_SINGLE_BIAS
Definition: wsieee754.c:77
WsIeee754Result ws_ieee754_decode_single(unsigned char *buf, double *value_return)
Definition: wsieee754.c:199
gw_assert(wtls_machine->packet_to_send !=NULL)
unsigned long WsUInt32
Definition: wsint.h:122
WsUInt32 ws_ieee754_single_get_exp(unsigned char *buf)
Definition: wsieee754.c:262
WsUInt32 ws_ieee754_single_get_mant(unsigned char *buf)
Definition: wsieee754.c:273
WsUInt32 ws_ieee754_single_get_sign(unsigned char *buf)
Definition: wsieee754.c:256
WsIeee754Result ws_ieee754_encode_single(double value, unsigned char *buf)
Definition: wsieee754.c:94
WsIeee754Result
Definition: wsieee754.h:77
unsigned char ws_ieee754_positive_inf[4]
Definition: wsieee754.c:88
#define WS_IEEE754_SINGLE_MANT_SIZE
Definition: wsieee754.c:76
int main(int argc, char **argv)
Definition: opensmppbox.c:2620
signed long WsInt32
Definition: wsint.h:121
#define WS_IEEE754_SINGLE_EXP_MIN
Definition: wsieee754.c:79
#define WS_IEEE754_SINGLE_EXP_MAX
Definition: wsieee754.c:80
unsigned char ws_ieee754_negative_inf[4]
Definition: wsieee754.c:90
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.