wsieee754.c
资源名称:gateway-1.2.1 [点击查看]
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:8k
源码类别:
手机WAP编程
开发平台:
WINDOWS
- /*
- *
- * wsieee754.h
- *
- * Author: Markku Rossi <mtr@iki.fi>
- *
- * Copyright (c) 2000 WAPIT OY LTD.
- * All rights reserved.
- *
- * Functions to manipulate ANSI/IEEE Std 754-1985 binary floating-point
- * numbers.
- *
- */
- #include "wsint.h"
- /********************* Types and definitions ****************************/
- #define WS_IEEE754_SINGLE_EXP_SIZE 8
- #define WS_IEEE754_SINGLE_MANT_SIZE 23
- #define WS_IEEE754_SINGLE_BIAS 127
- #define WS_IEEE754_SINGLE_EXP_MIN -126
- #define WS_IEEE754_SINGLE_EXP_MAX 127
- #define WS_IEEE754_POSITIVE_INFINITY 0x7f800000
- /********************* Special values ***********************************/
- unsigned char ws_ieee754_nan[4] = {0xff, 0xff, 0xff, 0xff};
- unsigned char ws_ieee754_positive_inf[4] = {0x7f, 0x80, 0x00, 0x00};
- unsigned char ws_ieee754_negative_inf[4] = {0xff, 0x80, 0x00, 0x00};
- /********************* Global functions *********************************/
- WsIeee754Result ws_ieee754_encode_single(double value, unsigned char *buf)
- {
- int sign = 0;
- WsInt32 exp = 0;
- WsUInt32 mant = 0;
- int i;
- WsIeee754Result result = WS_IEEE754_OK;
- /* The sign bit. */
- if (value < 0.0) {
- sign = 1;
- value = -value;
- }
- /* Scale the value so that: 1 <= mantissa < 2. */
- if (value > 1.0) {
- /* The exponent is positive. */
- while (value >= 2.0 && exp <= WS_IEEE754_SINGLE_EXP_MAX) {
- value /= 2.0;
- exp++;
- }
- if (exp > WS_IEEE754_SINGLE_EXP_MAX) {
- /* Overflow => infinity. */
- exp = 0xff;
- if (sign)
- result = WS_IEEE754_NEGATIVE_INF;
- else
- result = WS_IEEE754_POSITIVE_INF;
- goto done;
- }
- /* The 1 is implicit. */
- value -= 1;
- } else {
- /* The exponent is negative. */
- while (value < 1.0 && exp > WS_IEEE754_SINGLE_EXP_MIN) {
- value *= 2.0;
- exp--;
- }
- if (value >= 1.0) {
- /* We managed to get the number to the normal form. Let's
- remote the implicit 1 from the value. */
- gw_assert(value >= 1.0);
- value -= 1.0;
- } else {
- /* The number is still smaller than 1. We just try to
- present the remaining stuff in our mantissa. If that
- fails, we fall back to 0.0. We mark exp to -127 (after
- bias it is 0) to mark this unnormalized form. */
- exp--;
- gw_assert(exp == -127);
- }
- }
- for (i = 0; i < WS_IEEE754_SINGLE_MANT_SIZE; i++) {
- value *= 2.0;
- mant <<= 1;
- if (value >= 1.0) {
- mant |= 1;
- value -= 1.0;
- }
- }
- /* Handle rounding. Intel seems to round 0.5 down so to be
- compatible, our check is > instead of >=. */
- if (value * 2.0 > 1.0) {
- mant++;
- if (mant == 0x800000) {
- /* This we the really worst case. The rounding rounds the
- mant up to 2.0. So we must increase the exponent by one.
- This may then result an overflow in the exponent which
- converts our number to infinity. */
- mant = 0;
- exp++;
- if (exp > WS_IEEE754_SINGLE_EXP_MAX) {
- /* Overflow => infinity. */
- exp = 0xff;
- goto done;
- }
- }
- }
- /* Handle biased exponent. */
- exp += WS_IEEE754_SINGLE_BIAS;
- done:
- /* Encode the value to the buffer. */
- mant |= exp << 23;
- mant |= sign << 31;
- buf[3] = (mant & 0x000000ff);
- buf[2] = (mant & 0x0000ff00) >> 8;
- buf[1] = (mant & 0x00ff0000) >> 16;
- buf[0] = (mant & 0xff000000) >> 24;
- return result;
- }
- WsIeee754Result ws_ieee754_decode_single(unsigned char *buf,
- double *value_return)
- {
- WsUInt32 sign = ws_ieee754_single_get_sign(buf);
- WsInt32 exp = (WsInt32) ws_ieee754_single_get_exp(buf);
- WsUInt32 mant = ws_ieee754_single_get_mant(buf);
- double value;
- int i;
- /* Check the special cases where exponent is all 1. */
- if (exp == 0xff) {
- if (mant == 0)
- return sign ? WS_IEEE754_NEGATIVE_INF : WS_IEEE754_POSITIVE_INF;
- return WS_IEEE754_NAN;
- }
- /* Expand the mantissa. */
- value = 0.0;
- for (i = 0; i < WS_IEEE754_SINGLE_MANT_SIZE; i++) {
- if (mant & 0x1)
- value += 1.0;
- value /= 2.0;
- mant >>= 1;
- }
- /* Check the `unnormalized' vs. `normal form'. */
- if (exp == 0)
- /* This is a `unnormalized' number. */
- exp = -126;
- else {
- /* This is a standard case. */
- value += 1.0;
- exp -= WS_IEEE754_SINGLE_BIAS;
- }
- /* Handle exponents. */
- while (exp > 0) {
- value *= 2;
- exp--;
- }
- while (exp < 0) {
- value /= 2;
- exp++;
- }
- /* Finally notify sign. */
- if (sign)
- value = -value;
- *value_return = value;
- return WS_IEEE754_OK;
- }
- WsUInt32 ws_ieee754_single_get_sign(unsigned char *buf)
- {
- return (buf[0] & 0x80) >> 7;
- }
- WsUInt32 ws_ieee754_single_get_exp(unsigned char *buf)
- {
- WsUInt32 value = buf[0] & 0x7f;
- value <<= 1;
- value |= (buf[1] & 0x80) >> 7;
- return value;
- }
- WsUInt32 ws_ieee754_single_get_mant(unsigned char *buf)
- {
- WsUInt32 value = buf[1] & 0x7f;
- value <<= 8;
- value |= buf[2];
- value <<= 8;
- value |= buf[3];
- return value;
- }
- #if 0
- /********************* Tests for IEEE754 functions **********************/
- void ws_ieee754_print(unsigned char *buf)
- {
- int i, j;
- for (i = 0; i < 4; i++) {
- unsigned char mask = 0x80;
- unsigned char ch = buf[i];
- for (j = 0; j < 8; j++) {
- if (ch & mask)
- printf("1");
- else
- printf("0");
- if ((i == 0 && j == 0)
- || (i == 1 && j == 0))
- printf(" ");
- mask >>= 1;
- }
- }
- printf("n");
- }
- #include <math.h>
- #include <stdlib.h>
- #include <machine/ieee.h>
- void check_value(double num)
- {
- float native = num;
- unsigned char buf[4];
- struct ieee_single *s = (struct ieee_single *) & native;
- unsigned int *uip = (unsigned int *) s;
- unsigned int n = ntohl(*uip);
- double d;
- ws_ieee754_encode_single(num, buf);
- if (memcmp(buf, &n, 4) != 0) {
- printf("n");
- printf("%f failed:n", num);
- printf("ws: ");
- ws_ieee754_print(buf);
- printf("native: ");
- ws_ieee754_print((unsigned char *) &n);
- abort();
- }
- if (ws_ieee754_decode_single(buf, &d) != WS_IEEE754_OK
- || d != native) {
- printf("ndecode of %f failed: got %fn", num, d);
- abort();
- }
- }
- int main(int argc, char *argv[])
- {
- unsigned char buf[4];
- unsigned int rounds = 0;
- if (argc > 1) {
- int i;
- for (i = 1; i < argc; i++)
- check_value(strtod(argv[1], NULL));
- return 0;
- }
- ws_ieee754_encode_single(5.75, buf);
- ws_ieee754_print(buf);
- check_value(5.75);
- ws_ieee754_encode_single(340282346638528859811704183484516925440.0, buf);
- ws_ieee754_print(buf);
- check_value(340282346638528859811704183484516925440.0);
- ws_ieee754_encode_single( -340282346638528859811704183484516925440.0, buf);
- ws_ieee754_print(buf);
- check_value( -340282346638528859811704183484516925440.0);
- ws_ieee754_encode_single(3.0 * pow(2, -129), buf);
- ws_ieee754_print(buf);
- check_value(3.0 * pow(2, -129));
- ws_ieee754_encode_single(pow(2, -149), buf);
- ws_ieee754_print(buf);
- check_value(pow(2, -149));
- ws_ieee754_encode_single(pow(2, -149) * .1, buf);
- ws_ieee754_print(buf);
- check_value(pow(2, -149) * .1);
- ws_ieee754_encode_single( -pow(2, -149), buf);
- ws_ieee754_print(buf);
- check_value( -pow(2, -149));
- ws_ieee754_encode_single( -pow(2, -149) * .1, buf);
- ws_ieee754_print(buf);
- while (1) {
- double a = random();
- double b = random();
- if (b == 0.0)
- continue;
- check_value(a / b);
- check_value(a * b);
- if ((++rounds % 100000) == 0) {
- printf("%d ", rounds);
- fflush(stdout);
- }
- }
- return 0;
- }
- #endif