把浮子变成绳子

时间:2013-07-13 16:41:04

标签: string assembly floating-point ieee-754 floating-point-precision

我已经着手说明何时需要将IEEE-754单精度和双精度数转换为基数为10的字符串。有FXTRACT指令可用,但它只为基数2提供指数和尾数,因为数字计算公式为:

value = (-1)^sign * 1.(mantissa) * 2^(exponent-bias)

如果我对特定碱基有一些对数指令,我可以在表达式中更改2 exponent - bias 部分的基数,但目前我不知道该怎么做。我也在考虑使用标准的舍入转换为整数,但它似乎无法使用,因为它不提供精确的转换。有人知道这样做的方法/基本原则是什么?请帮忙。

我终于找到了另一个解决方案(它是用Java编写的)

{
    /* handling -infinity, +infinity and NaN, returns "" if 'f' isn't one of mentioned */
    String ret = "";
    if ((ret = getSpecialFloats(f)).length() != 0)
        return ret;
}
int num = Float.toRawIntBits(f);
int exponent = (int)(((num >> 23) & 0xFF)-127); //8bits, bias 127
int mantissa = num & 0x7FFFFF; //23bits

/* stores decimal exponent */
int decimalExponent = 0;
/* temporary value used for calculations */
int sideMultiplicator = 1;
for (; exponent > 0; exponent--) {
    /* In this loop I'm calculating the value of exponent. MAX(unsigned int) = 2^32-1, while exponent can be 2^127 pr st like that */
    sideMultiplicator *= 2;
    /* because of this, if top two bits of sideMultiplicator are set, we're getting closer to overflow and we need to save some value into decimalExponent*/
    if ((sideMultiplicator >> 30) != 0) {
        decimalExponent += 3;
        sideMultiplicator /= 1000;
    }
}
for(; exponent < 0; exponent++) {
    /* this loop does exactly same thing as the loop before, but vice versa (for exponent < 0, like 2^-3 and so on) */
    if ((sideMultiplicator & 1) != 0) {
        sideMultiplicator *= 10;
        decimalExponent--;
    }
    sideMultiplicator /= 2;
}

/* we know that value of float is:
 *  1.mantissa * 2^exponent * (-1)^sign */
/* that's why we need to store 1 in betweenResult (another temorary value) */
int betweenResult = sideMultiplicator;
for (int fraction = 2, bit = 0; bit < 23; bit++, fraction *= 2) {
    /* this loop is the most important one: it turns binary mantissa to real value by dividing what we got in exponent */
    if (((mantissa >> (22-bit)) & 1) == 1) {
        /* if mantissa[bit] is set, we need to divide whole number by fraction (fraction is 2^(bit+1) ) */
        while (sideMultiplicator % fraction > 0 && (betweenResult >> 28) == 0) {
            /* as we needed it before: if number gets near to overflow, store something in decimalExponent*/
            betweenResult *= 10;
            sideMultiplicator *= 10;
            decimalExponent--;
        }
        betweenResult += sideMultiplicator/fraction;
    }
}

/* small normalization turning numbers like 15700 in betweenResult into 157e2 (storing zero padding in decimalExponent variable)*/
while (betweenResult % 10 == 0) {
    betweenResult /= 10;
    decimalExponent++;
}
/* this method gets string in reqested notation (scientific, multiplication by ten or just normal)*/
return getExponentedString(betweenResult, decimalExponent);

3 个答案:

答案 0 :(得分:5)

格式化浮点数非常重要。搜索例如对于Dragon4算法(here is one result)。

非常,非常天真地,你可以试试这个:

  1. 处理NaN和Infinity。

  2. 打印标志(选中< 0)。从此假设这个数字是正数。

  3. 如果>= 1,请截断并使用熟悉的整数格式来打印整数部分。 (在任何具有浮点单元的硬件上应该有机器指令。)

  4. 打印小数点分隔符;现在继续乘以10并打印截断的整数位。

  5. 达到所需精度后停止;考虑正确地舍入最后一位数字。

答案 1 :(得分:3)

如果可以打印为1.d1d2d3d4d5 ... * 2 ^ e1e2e3,则将浮点数转换为十进制(-ish)表示可以很简单。可以找到实施here

如果你需要科学的1.d1d2 ... * 10 ^ e1e2e3表示,那么天真的方法重复除以10并从浮点格式的数字中提取数字。您将需要某种多精度整数库。 (反复乘以10以提取点后的数字。)

答案 2 :(得分:1)

Kerrek SB's solution是正确的。但是你可以更快地完成它而不需要任何循环(或更少的循环次数)。只需将分数部分乘以10 precision 即可。如果以浮点类型进行数学运算,减少数或乘法也会减少累积误差。要进行精确转换,必须使用更高精度的浮点类型。

例如,您想要转换精度为5位的0.1234567,将数字乘以10000并获取int部分。如果需要舍入,则将其乘以100000并舍入最后一个数字