Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

wsieee754.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /*
00058  *
00059  * wsieee754.h
00060  *
00061  * Author: Markku Rossi <mtr@iki.fi>
00062  *
00063  * Copyright (c) 2000 WAPIT OY LTD.
00064  *       All rights reserved.
00065  *
00066  * Functions to manipulate ANSI/IEEE Std 754-1985 binary floating-point
00067  * numbers.
00068  *
00069  */
00070 
00071 #include "wsint.h"
00072 
00073 /********************* Types and definitions ****************************/
00074 
00075 #define WS_IEEE754_SINGLE_EXP_SIZE  8
00076 #define WS_IEEE754_SINGLE_MANT_SIZE 23
00077 #define WS_IEEE754_SINGLE_BIAS      127
00078 
00079 #define WS_IEEE754_SINGLE_EXP_MIN   -126
00080 #define WS_IEEE754_SINGLE_EXP_MAX   127
00081 
00082 #define WS_IEEE754_POSITIVE_INFINITY    0x7f800000
00083 
00084 /********************* Special values ***********************************/
00085 
00086 unsigned char ws_ieee754_nan[4] = {0xff, 0xff, 0xff, 0xff};
00087 
00088 unsigned char ws_ieee754_positive_inf[4] = {0x7f, 0x80, 0x00, 0x00};
00089 
00090 unsigned char ws_ieee754_negative_inf[4] = {0xff, 0x80, 0x00, 0x00};
00091 
00092 /********************* Global functions *********************************/
00093 
00094 WsIeee754Result ws_ieee754_encode_single(double value, unsigned char *buf)
00095 {
00096     int sign = 0;
00097     WsInt32 exp = 0;
00098     WsUInt32 mant = 0;
00099     int i;
00100     WsIeee754Result result = WS_IEEE754_OK;
00101 
00102     /* The sign bit. */
00103     if (value < 0.0) {
00104         sign = 1;
00105         value = -value;
00106     }
00107 
00108     /* Scale the value so that: 1 <= mantissa < 2. */
00109     if (value > 1.0) {
00110         /* The exponent is positive. */
00111         while (value >= 2.0 && exp <= WS_IEEE754_SINGLE_EXP_MAX) {
00112             value /= 2.0;
00113             exp++;
00114         }
00115         if (exp > WS_IEEE754_SINGLE_EXP_MAX) {
00116             /* Overflow => infinity. */
00117             exp = 0xff;
00118 
00119             if (sign)
00120                 result = WS_IEEE754_NEGATIVE_INF;
00121             else
00122                 result = WS_IEEE754_POSITIVE_INF;
00123 
00124             goto done;
00125         }
00126 
00127         /* The 1 is implicit. */
00128         value -= 1;
00129     } else {
00130         /* The exponent is negative. */
00131         while (value < 1.0 && exp > WS_IEEE754_SINGLE_EXP_MIN) {
00132             value *= 2.0;
00133             exp--;
00134         }
00135         if (value >= 1.0) {
00136             /* We managed to get the number to the normal form.  Let's
00137                       remote the implicit 1 from the value. */
00138             gw_assert(value >= 1.0);
00139             value -= 1.0;
00140         } else {
00141             /* The number is still smaller than 1.  We just try to
00142                       present the remaining stuff in our mantissa.  If that
00143                       fails, we fall back to 0.0.  We mark exp to -127 (after
00144                       bias it is 0) to mark this unnormalized form. */
00145             exp--;
00146             gw_assert(exp == -127);
00147         }
00148     }
00149 
00150     for (i = 0; i < WS_IEEE754_SINGLE_MANT_SIZE; i++) {
00151         value *= 2.0;
00152         mant <<= 1;
00153 
00154         if (value >= 1.0) {
00155             mant |= 1;
00156             value -= 1.0;
00157         }
00158     }
00159 
00160     /* Handle rounding.  Intel seems to round 0.5 down so to be
00161        compatible, our check is > instead of >=. */
00162     if (value * 2.0 > 1.0) {
00163         mant++;
00164         if (mant == 0x800000) {
00165             /* This we the really worst case.  The rounding rounds the
00166                mant up to 2.0.  So we must increase the exponent by one.
00167                This may then result an overflow in the exponent which
00168                converts our number to infinity. */
00169             mant = 0;
00170             exp++;
00171 
00172             if (exp > WS_IEEE754_SINGLE_EXP_MAX) {
00173                 /* Overflow => infinity. */
00174                 exp = 0xff;
00175                 goto done;
00176             }
00177         }
00178     }
00179 
00180     /* Handle biased exponent. */
00181     exp += WS_IEEE754_SINGLE_BIAS;
00182 
00183 done:
00184 
00185     /* Encode the value to the buffer. */
00186 
00187     mant |= exp << 23;
00188     mant |= sign << 31;
00189 
00190     buf[3] = (mant & 0x000000ff);
00191     buf[2] = (mant & 0x0000ff00) >> 8;
00192     buf[1] = (mant & 0x00ff0000) >> 16;
00193     buf[0] = (mant & 0xff000000) >> 24;
00194 
00195     return result;
00196 }
00197 
00198 
00199 WsIeee754Result ws_ieee754_decode_single(unsigned char *buf,
00200                                          double *value_return)
00201 {
00202     WsUInt32 sign = ws_ieee754_single_get_sign(buf);
00203     WsInt32 exp = (WsInt32) ws_ieee754_single_get_exp(buf);
00204     WsUInt32 mant = ws_ieee754_single_get_mant(buf);
00205     double value;
00206     int i;
00207 
00208     /* Check the special cases where exponent is all 1. */
00209     if (exp == 0xff) {
00210         if (mant == 0)
00211             return sign ? WS_IEEE754_NEGATIVE_INF : WS_IEEE754_POSITIVE_INF;
00212 
00213         return WS_IEEE754_NAN;
00214     }
00215 
00216     /* Expand the mantissa. */
00217     value = 0.0;
00218     for (i = 0; i < WS_IEEE754_SINGLE_MANT_SIZE; i++) {
00219         if (mant & 0x1)
00220             value += 1.0;
00221 
00222         value /= 2.0;
00223         mant >>= 1;
00224     }
00225 
00226     /* Check the `unnormalized' vs. `normal form'. */
00227     if (exp == 0)
00228         /* This is a `unnormalized' number. */
00229         exp = -126;
00230     else {
00231         /* This is a standard case. */
00232         value += 1.0;
00233         exp -= WS_IEEE754_SINGLE_BIAS;
00234     }
00235 
00236     /* Handle exponents. */
00237     while (exp > 0) {
00238         value *= 2;
00239         exp--;
00240     }
00241     while (exp < 0) {
00242         value /= 2;
00243         exp++;
00244     }
00245 
00246     /* Finally notify sign. */
00247     if (sign)
00248         value = -value;
00249 
00250     *value_return = value;
00251 
00252     return WS_IEEE754_OK;
00253 }
00254 
00255 
00256 WsUInt32 ws_ieee754_single_get_sign(unsigned char *buf)
00257 {
00258     return (buf[0] & 0x80) >> 7;
00259 }
00260 
00261 
00262 WsUInt32 ws_ieee754_single_get_exp(unsigned char *buf)
00263 {
00264     WsUInt32 value = buf[0] & 0x7f;
00265 
00266     value <<= 1;
00267     value |= (buf[1] & 0x80) >> 7;
00268 
00269     return value;
00270 }
00271 
00272 
00273 WsUInt32 ws_ieee754_single_get_mant(unsigned char *buf)
00274 {
00275     WsUInt32 value = buf[1] & 0x7f;
00276 
00277     value <<= 8;
00278     value |= buf[2];
00279 
00280     value <<= 8;
00281     value |= buf[3];
00282 
00283     return value;
00284 }
00285 
00286 #if 0
00287 /********************* Tests for IEEE754 functions **********************/
00288 
00289 void ws_ieee754_print(unsigned char *buf)
00290 {
00291     int i, j;
00292 
00293     for (i = 0; i < 4; i++) {
00294         unsigned char mask = 0x80;
00295         unsigned char ch = buf[i];
00296 
00297         for (j = 0; j < 8; j++) {
00298             if (ch & mask)
00299                 printf("1");
00300             else
00301                 printf("0");
00302 
00303             if ((i == 0 && j == 0)
00304                 || (i == 1 && j == 0))
00305                 printf(" ");
00306 
00307             mask >>= 1;
00308         }
00309     }
00310     printf("\n");
00311 }
00312 
00313 #include <math.h>
00314 #include <stdlib.h>
00315 #include <machine/ieee.h>
00316 
00317 void check_value(double num)
00318 {
00319     float native = num;
00320     unsigned char buf[4];
00321     struct ieee_single *s = (struct ieee_single *) & native;
00322     unsigned int *uip = (unsigned int *) s;
00323     unsigned int n = ntohl(*uip);
00324     double d;
00325 
00326     ws_ieee754_encode_single(num, buf);
00327     if (memcmp(buf, &n, 4) != 0) {
00328         printf("\n");
00329         printf("%f failed:\n", num);
00330         printf("ws:     ");
00331         ws_ieee754_print(buf);
00332         printf("native: ");
00333         ws_ieee754_print((unsigned char *) &n);
00334         abort();
00335     }
00336 
00337     if (ws_ieee754_decode_single(buf, &d) != WS_IEEE754_OK
00338         || d != native) {
00339         printf("\ndecode of %f failed: got %f\n", num, d);
00340         abort();
00341     }
00342 }
00343 
00344 
00345 int main(int argc, char *argv[])
00346 {
00347     unsigned char buf[4];
00348     unsigned int rounds = 0;
00349 
00350     if (argc > 1) {
00351         int i;
00352 
00353         for (i = 1; i < argc; i++)
00354             check_value(strtod(argv[1], NULL));
00355 
00356         return 0;
00357     }
00358 
00359     ws_ieee754_encode_single(5.75, buf);
00360     ws_ieee754_print(buf);
00361     check_value(5.75);
00362 
00363     ws_ieee754_encode_single(340282346638528859811704183484516925440.0, buf);
00364     ws_ieee754_print(buf);
00365     check_value(340282346638528859811704183484516925440.0);
00366 
00367     ws_ieee754_encode_single( -340282346638528859811704183484516925440.0, buf);
00368     ws_ieee754_print(buf);
00369     check_value( -340282346638528859811704183484516925440.0);
00370 
00371     ws_ieee754_encode_single(3.0 * pow(2, -129), buf);
00372     ws_ieee754_print(buf);
00373     check_value(3.0 * pow(2, -129));
00374 
00375     ws_ieee754_encode_single(pow(2, -149), buf);
00376     ws_ieee754_print(buf);
00377     check_value(pow(2, -149));
00378 
00379     ws_ieee754_encode_single(pow(2, -149) * .1, buf);
00380     ws_ieee754_print(buf);
00381     check_value(pow(2, -149) * .1);
00382 
00383     ws_ieee754_encode_single( -pow(2, -149), buf);
00384     ws_ieee754_print(buf);
00385     check_value( -pow(2, -149));
00386 
00387     ws_ieee754_encode_single( -pow(2, -149) * .1, buf);
00388     ws_ieee754_print(buf);
00389 
00390     while (1) {
00391         double a = random();
00392         double b = random();
00393 
00394         if (b == 0.0)
00395             continue;
00396 
00397         check_value(a / b);
00398         check_value(a * b);
00399 
00400         if ((++rounds % 100000) == 0) {
00401             printf("%d ", rounds);
00402             fflush(stdout);
00403         }
00404 
00405     }
00406 
00407     return 0;
00408 }
00409 #endif
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.