⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 float.c

📁 汇编编译器的最新版本的源码.买了自己动手写操作系统这本书的人一定要下
💻 C
📖 第 1 页 / 共 2 页
字号:
	} else {
	    ROUND_ABS_DOWN;
	}
    }
    return false;
}

/* Returns a value >= 16 if not a valid hex digit */
static unsigned int hexval(char c)
{
    unsigned int v = (unsigned char) c;

    if (v >= '0' && v <= '9')
        return v - '0';
    else
        return (v|0x20) - 'a' + 10;
}

/* Handle floating-point numbers with radix 2^bits and binary exponent */
static bool ieee_flconvert_bin(const char *string, int bits,
			       fp_limb *mant, int32_t *exponent)
{
    static const int log2tbl[16] =
        { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 };
    fp_limb mult[MANT_LIMBS + 1], *mp;
    int ms;
    int32_t twopwr;
    bool seendot, seendigit;
    unsigned char c;
    const int radix = 1 << bits;
    fp_limb v;

    twopwr = 0;
    seendot = seendigit = false;
    ms = 0;
    mp = NULL;

    memset(mult, 0, sizeof mult);

    while ((c = *string++) != '\0') {
        if (c == '.') {
            if (!seendot)
                seendot = true;
            else {
                error(ERR_NONFATAL|ERR_PASS1,
                      "too many periods in floating-point constant");
                return false;
            }
        } else if ((v = hexval(c)) < (unsigned int)radix) {
            if (!seendigit && v) {
                int l = log2tbl[v];

                seendigit = true;
                mp = mult;
                ms = (LIMB_BITS-1)-l;

                twopwr = seendot ? twopwr-bits+l : l+1-bits;
            }

            if (seendigit) {
                if (ms <= 0) {
                    *mp |= v >> -ms;
                    mp++;
                    if (mp > &mult[MANT_LIMBS])
                        mp = &mult[MANT_LIMBS]; /* Guard slot */
                    ms += LIMB_BITS;
                }
                *mp |= v << ms;
                ms -= bits;

                if (!seendot)
                    twopwr += bits;
            } else {
                if (seendot)
                    twopwr -= bits;
            }
        } else if (c == 'p' || c == 'P') {
	    int32_t e;
	    e = read_exponent(string, 20000);
	    if (e == INT32_MAX)
		return false;
	    twopwr += e;
            break;
	} else if (c == '_') {
	    /* ignore */
        } else {
            error(ERR_NONFATAL|ERR_PASS1,
                  "floating-point constant: `%c' is invalid character", c);
            return false;
        }
    }

    if (!seendigit) {
        memset(mant, 0, MANT_LIMBS*sizeof(fp_limb)); /* Zero */
        *exponent = 0;
    } else {
        memcpy(mant, mult, MANT_LIMBS*sizeof(fp_limb));
        *exponent = twopwr;
    }

    return true;
}

/*
 * Shift a mantissa to the right by i bits.
 */
static void ieee_shr(fp_limb *mant, int i)
{
    fp_limb n, m;
    int j = 0;
    int sr, sl, offs;

    sr = i % LIMB_BITS; sl = LIMB_BITS-sr;
    offs = i/LIMB_BITS;

    if (sr == 0) {
	if (offs)
	    for (j = MANT_LIMBS-1; j >= offs; j--)
		mant[j] = mant[j-offs];
    } else {
	n = mant[MANT_LIMBS-1-offs] >> sr;
	for (j = MANT_LIMBS-1; j > offs; j--) {
	    m = mant[j-offs-1];
	    mant[j] = (m << sl) | n;
	    n = m >> sr;
	}
	mant[j--] = n;
    }
    while (j >= 0)
	mant[j--] = 0;
}

/* Produce standard IEEE formats, with implicit or explicit integer
   bit; this makes the following assumptions:

   - the sign bit is the MSB, followed by the exponent,
     followed by the integer bit if present.
   - the sign bit plus exponent fit in 16 bits.
   - the exponent bias is 2^(n-1)-1 for an n-bit exponent */

struct ieee_format {
    int bytes;
    int mantissa;               /* Fractional bits in the mantissa */
    int explicit;		/* Explicit integer */
    int exponent;               /* Bits in the exponent */
};

/*
 * The 16- and 128-bit formats are expected to be in IEEE 754r.
 * AMD SSE5 uses the 16-bit format.
 *
 * The 32- and 64-bit formats are the original IEEE 754 formats.
 *
 * The 80-bit format is x87-specific, but widely used.
 *
 * The 8-bit format appears to be the consensus 8-bit floating-point
 * format.  It is apparently used in graphics applications.
 */
static const struct ieee_format ieee_8   = {  1,   3, 0,  4 };
static const struct ieee_format ieee_16  = {  2,  10, 0,  5 };
static const struct ieee_format ieee_32  = {  4,  23, 0,  8 };
static const struct ieee_format ieee_64  = {  8,  52, 0, 11 };
static const struct ieee_format ieee_80  = { 10,  63, 1, 15 };
static const struct ieee_format ieee_128 = { 16, 112, 0, 15 };

/* Types of values we can generate */
enum floats {
    FL_ZERO,
    FL_DENORMAL,
    FL_NORMAL,
    FL_INFINITY,
    FL_QNAN,
    FL_SNAN
};

static int to_packed_bcd(const char *str, const char *p,
			 int s, uint8_t *result,
			 const struct ieee_format *fmt)
{
    int n = 0;
    char c;
    int tv = -1;

    if (fmt != &ieee_80) {
	error(ERR_NONFATAL|ERR_PASS1,
	      "packed BCD requires an 80-bit format");
	return 0;
    }

    while (p >= str) {
	c = *p--;
	if (c >= '0' && c <= '9') {
	    if (tv < 0) {
		if (n == 9) {
		    error(ERR_WARNING|ERR_PASS1,
			  "packed BCD truncated to 18 digits");
		}
		tv = c-'0';
	    } else {
		if (n < 9)
		    *result++ = tv + ((c-'0') << 4);
		n++;
		tv = -1;
	    }
	} else if (c == '_') {
	    /* do nothing */
	} else {
	    error(ERR_NONFATAL|ERR_PASS1,
		  "invalid character `%c' in packed BCD constant", c);
	    return 0;
	}
    }
    if (tv >= 0) {
	if (n < 9)
	    *result++ = tv;
	n++;
    }
    while (n < 9) {
	*result++ = 0;
	n++;
    }
    *result = (s < 0) ? 0x80 : 0;

    return 1;			/* success */
}

static int to_float(const char *str, int s, uint8_t *result,
                    const struct ieee_format *fmt)
{
    fp_limb mant[MANT_LIMBS];
    int32_t exponent = 0;
    const int32_t expmax = 1 << (fmt->exponent - 1);
    fp_limb one_mask = LIMB_TOP_BIT >>
	((fmt->exponent+fmt->explicit) % LIMB_BITS);
    const int one_pos = (fmt->exponent+fmt->explicit)/LIMB_BITS;
    int i;
    int shift;
    enum floats type;
    bool ok;
    const bool minus = s < 0;
    const int bits = fmt->bytes * 8;
    const char *strend;

    if (!str[0]) {
	error(ERR_PANIC,
	      "internal errror: empty string passed to float_const");
	return 0;
    }

    strend = strchr(str, '\0');
    if (strend[-1] == 'P' || strend[-1] == 'p')
	return to_packed_bcd(str, strend-2, s, result, fmt);

    if (str[0] == '_') {
	/* Special tokens */

        switch (str[2]) {
        case 'n':              /* __nan__ */
        case 'N':
        case 'q':              /* __qnan__ */
        case 'Q':
	    type = FL_QNAN;
            break;
        case 's':              /* __snan__ */
        case 'S':
	    type = FL_SNAN;
            break;
        case 'i':              /* __infinity__ */
        case 'I':
	    type = FL_INFINITY;
            break;
	default:
	    error(ERR_NONFATAL|ERR_PASS1,
		  "internal error: unknown FP constant token `%s'\n", str);
	    type = FL_QNAN;
	    break;
        }
    } else {
        if (str[0] == '0') {
	    switch (str[1]) {
	    case 'x': case 'X':
	    case 'h': case 'H':
		ok = ieee_flconvert_bin(str+2, 4, mant, &exponent);
		break;
	    case 'o': case 'O':
	    case 'q': case 'Q':
		ok = ieee_flconvert_bin(str+2, 3, mant, &exponent);
		break;
	    case 'b': case 'B':
	    case 'y': case 'Y':
		ok = ieee_flconvert_bin(str+2, 1, mant, &exponent);
		break;
	    case 'd': case 'D':
	    case 't': case 'T':
		ok = ieee_flconvert(str+2, mant, &exponent);
		break;
	    case 'p': case 'P':
		return to_packed_bcd(str+2, strend-1, s, result, fmt);
	    default:
		/* Leading zero was just a zero? */
		ok = ieee_flconvert(str, mant, &exponent);
		break;
	    }
	} else if (str[0] == '$') {
	    ok = ieee_flconvert_bin(str+1, 4, mant, &exponent);
	} else {
            ok = ieee_flconvert(str, mant, &exponent);
	}

	if (!ok) {
	    type = FL_QNAN;
	} else if (mant[0] & LIMB_TOP_BIT) {
            /*
             * Non-zero.
             */
            exponent--;
            if (exponent >= 2 - expmax && exponent <= expmax) {
		type = FL_NORMAL;
            } else if (exponent > 0) {
		if (pass0 == 1)
		    error(ERR_WARNING|ERR_WARN_FL_OVERFLOW|ERR_PASS1,
			  "overflow in floating-point constant");
		type = FL_INFINITY;
	    } else {
		/* underflow or denormal; the denormal code handles
		   actual underflow. */
		type = FL_DENORMAL;
	    }
	} else {
	    /* Zero */
	    type = FL_ZERO;
	}
    }

    switch (type) {
    case FL_ZERO:
    zero:
	memset(mant, 0, sizeof mant);
	break;

    case FL_DENORMAL:
    {
	shift = -(exponent + expmax - 2 - fmt->exponent)
	    + fmt->explicit;
	ieee_shr(mant, shift);
	ieee_round(minus, mant, bits);
	if (mant[one_pos] & one_mask) {
	    /* One's position is set, we rounded up into normal range */
	    exponent = 1;
	    if (!fmt->explicit)
		mant[one_pos] &= ~one_mask;	/* remove explicit one */
	    mant[0] |= exponent << (LIMB_BITS-1 - fmt->exponent);
	} else {
	    if (daz || is_zero(mant)) {
		/* Flush denormals to zero */
		error(ERR_WARNING|ERR_WARN_FL_UNDERFLOW|ERR_PASS1,
		      "underflow in floating-point constant");
		goto zero;
	    } else {
		error(ERR_WARNING|ERR_WARN_FL_DENORM|ERR_PASS1,
		      "denormal floating-point constant");
	    }
	}
	break;
    }

    case FL_NORMAL:
	exponent += expmax - 1;
	ieee_shr(mant, fmt->exponent+fmt->explicit);
	ieee_round(minus, mant, bits);
	/* did we scale up by one? */
	if (test_bit(mant, fmt->exponent+fmt->explicit-1)) {
	    ieee_shr(mant, 1);
	    exponent++;
	    if (exponent >= (expmax << 1)-1) {
		    error(ERR_WARNING|ERR_WARN_FL_OVERFLOW|ERR_PASS1,
			  "overflow in floating-point constant");
		type = FL_INFINITY;
		goto overflow;
	    }
	}

	if (!fmt->explicit)
	    mant[one_pos] &= ~one_mask;	/* remove explicit one */
	mant[0] |= exponent << (LIMB_BITS-1 - fmt->exponent);
	break;

    case FL_INFINITY:
    case FL_QNAN:
    case FL_SNAN:
    overflow:
	memset(mant, 0, sizeof mant);
	mant[0] = (((fp_limb)1 << fmt->exponent)-1)
	    << (LIMB_BITS-1 - fmt->exponent);
	if (fmt->explicit)
	    mant[one_pos] |= one_mask;
	if (type == FL_QNAN)
	    set_bit(mant, fmt->exponent+fmt->explicit+1);
	else if (type == FL_SNAN)
	    set_bit(mant, fmt->exponent+fmt->explicit+fmt->mantissa);
	break;
    }

    mant[0] |= minus ? LIMB_TOP_BIT : 0;

    for (i = fmt->bytes - 1; i >= 0; i--)
	*result++ = mant[i/LIMB_BYTES] >> (((LIMB_BYTES-1)-(i%LIMB_BYTES))*8);

    return 1;                   /* success */
}

int float_const(const char *number, int sign, uint8_t *result,
                int bytes, efunc err)
{
    error = err;

    switch (bytes) {
    case 1:
        return to_float(number, sign, result, &ieee_8);
    case 2:
        return to_float(number, sign, result, &ieee_16);
    case 4:
        return to_float(number, sign, result, &ieee_32);
    case 8:
        return to_float(number, sign, result, &ieee_64);
    case 10:
        return to_float(number, sign, result, &ieee_80);
    case 16:
        return to_float(number, sign, result, &ieee_128);
    default:
        error(ERR_PANIC, "strange value %d passed to float_const", bytes);
        return 0;
    }
}

/* Set floating-point options */
int float_option(const char *option)
{
    if (!nasm_stricmp(option, "daz")) {
	daz = true;
	return 0;
    } else if (!nasm_stricmp(option, "nodaz")) {
	daz = false;
	return 0;
    } else if (!nasm_stricmp(option, "near")) {
	rc = FLOAT_RC_NEAR;
	return 0;
    } else if (!nasm_stricmp(option, "down")) {
	rc = FLOAT_RC_DOWN;
	return 0;
    } else if (!nasm_stricmp(option, "up")) {
	rc = FLOAT_RC_UP;
	return 0;
    } else if (!nasm_stricmp(option, "zero")) {
	rc = FLOAT_RC_ZERO;
	return 0;
    } else if (!nasm_stricmp(option, "default")) {
	rc = FLOAT_RC_NEAR;
	daz = false;
	return 0;
    } else {
	return -1;		/* Unknown option */
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -