📄 wsieee754.c
字号:
/* * * 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 %f\n", 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -