Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
670 views
in Technique[技术] by (71.8m points)

assembly - Turn float into string

I have proceeded to state when I need to turn IEEE-754 single and double precision numbers into strings with base 10. There is FXTRACT instruction available, but it provides only exponent and mantissa for base 2, as the number calculation formula is:

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

If I had some logarithmic instructions for specific bases, I would be able to change base of 2exponent - bias part in expression, but currently I don't know what to do. I was also thinking of using standard rounded conversion into integer, but it seems to be unusable as it doesn't offer precise conversion. Does anybody know what is the way/basic principe for doing it? Please help.

I finally found another solution (it's in 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);
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Formatting a floating point number is rather non-trivial. Search e.g. for the Dragon4 algorithm (here is one result).

Very, very naively, you could try this:

  1. Handle NaN and Infinity.

  2. Print the sign (check < 0). Assume henceforth the number is positive real.

  3. If >= 1, truncate and use familiar integer formatting to print the integral part. (There should be a machine instruction for that on any hardware that has a floating point unit.)

  4. Print the decimal separator; now keep multiplying by 10 and print the truncated integral digit.

  5. Stop when you've reached the desired precision; think about rounding the last digit correctly.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...