455,515 Members | 1,772 Online Need help? Post your question and get tips & solutions from a community of 455,515 IT Pros & Developers. It's quick & easy.

# floating point to ASCII conversion

 P: n/a Hello, I want to efficient convert floating point numbers (IEEE754) into a string. I have no library routines that do the job (like sprintf etc.), because I work in an embedded environment. My actual algorithm uses multiplying with 10 to shift the fraction into an integer value and to aquire the used exponent. But the drawback is obvious: When I have very small numbers like 3.141E-300 I have to make 300 time consuming floating point multiplies to convert this number. But, since I know the IEEE754 structure and have directly access to the exponent (of base 2) of a fp number, is there a faster method to convert fp numbers to ASCII? Regards Peter May 24 '07 #1
14 Replies

 P: n/a Peter Sprenger wrote: Hello, I want to efficient convert floating point numbers (IEEE754) into a string. I have no library routines that do the job (like sprintf etc.), because I work in an embedded environment. My actual algorithm uses multiplying with 10 to shift the fraction into an integer value and to aquire the used exponent. But the drawback is obvious: When I have very small numbers like 3.141E-300 I have to make 300 time consuming floating point multiplies to convert this number. But, since I know the IEEE754 structure and have directly access to the exponent (of base 2) of a fp number, is there a faster method to convert fp numbers to ASCII? If you have the frexp() function available, that might make a good starting point. -- Eric Sosman es*****@acm-dot-org.invalid May 24 '07 #2

 P: n/a Eric Sosman wrote: Peter Sprenger wrote: >Hello,I want to efficient convert floating point numbers (IEEE754) into astring. I have no library routines that do the job (like sprintfetc.), because I work in an embedded environment.My actual algorithm uses multiplying with 10 to shift the fractioninto an integer value and to aquire the used exponent. But thedrawback is obvious: When I have very small numbers like 3.141E-300 Ihave to make 300 time consuming floating point multiplies to convertthis number.But, since I know the IEEE754 structure and have directly access tothe exponent (of base 2) of a fp number, is there a faster method toconvert fp numbers to ASCII? If you have the frexp() function available, that might make a good starting point. Nope, no frexp() available either. May 24 '07 #3

 P: n/a Peter Sprenger wrote: Eric Sosman wrote: >Peter Sprenger wrote: >>Hello,I want to efficient convert floating point numbers (IEEE754) into astring. I have no library routines that do the job (like sprintfetc.), because I work in an embedded environment.My actual algorithm uses multiplying with 10 to shift the fractioninto an integer value and to aquire the used exponent. But thedrawback is obvious: When I have very small numbers like 3.141E-300 Ihave to make 300 time consuming floating point multiplies to convertthis number.But, since I know the IEEE754 structure and have directly access tothe exponent (of base 2) of a fp number, is there a faster method toconvert fp numbers to ASCII? If you have the frexp() function available, that mightmake a good starting point. Nope, no frexp() available either. I'd suggest writing your own frexp() work-alike, using your knowledge of the floating-point representation. The advantage of using Standard-like tools for the task is that you'll easily be able to move the code to other platforms; something like a float-to-string-without-sprintf operation seems of sufficiently wide applicability that you may well want it again. So: invest a little non-portable work to get yourself up to the frexp()-ish baseline, and write portable C from there upwards. Good luck! -- Eric Sosman es*****@acm-dot-org.invalid May 24 '07 #4

 P: n/a > I'd suggest writing your own frexp() work-alike, using your knowledge of the floating-point representation. The advantage of using Standard-like tools for the task is that you'll easily be able to move the code to other platforms; something like a float-to-string-without-sprintf operation seems of sufficiently wide applicability that you may well want it again. So: invest a little non-portable work to get yourself up to the frexp()-ish baseline, and write portable C from there upwards. Good luck! I was a little bit quick. In fact I can write a frexp() myself, that separates exponent and mantissa. But then? I have a mantissa and an exponent of base 2. I have no right idea to transform it from here to an ascii string. Regards Peter May 24 '07 #5

 P: n/a On Thu, 24 May 2007 14:44:39 +0200, Peter Sprenger wrote: Hello, I want to efficient convert floating point numbers (IEEE754) into a string. I have no library routines that do the job (like sprintf etc.), because I work in an embedded environment. My actual algorithm uses multiplying with 10 to shift the fraction into an integer value and to aquire the used exponent. But the drawback is obvious: When I have very small numbers like 3.141E-300 I have to make 300 time consuming floating point multiplies to convert this number. But, since I know the IEEE754 structure and have directly access to the exponent (of base 2) of a fp number, is there a faster method to convert fp numbers to ASCII? Regards Peter If you have log, pow and floor then given a positive x double log10 = log(x)/log(10.0); int f = floor( log10); double y = x*pow( 10.0, -f); gets you y with 1<=y<10 and x = y * pow(10,f); Duncan May 24 '07 #6

 P: n/a On Thu, 24 May 2007 16:46:06 +0200, Peter Sprenger wrote: >> I'd suggest writing your own frexp() work-alike, usingyour knowledge of the floating-point representation. Theadvantage of using Standard-like tools for the task is thatyou'll easily be able to move the code to other platforms;something like a float-to-string-without-sprintf operationseems of sufficiently wide applicability that you may wellwant it again. So: invest a little non-portable work to getyourself up to the frexp()-ish baseline, and write portable Cfrom there upwards. Good luck! I was a little bit quick. In fact I can write a frexp() myself, that separates exponent and mantissa. But then? I have a mantissa and an exponent of base 2. I have no right idea to transform it from here to an ascii string. Regards Peter If x is positive int expon; double frac = frexp(x, &expon); int f = floor( expon*log_10_2); double y = x*pow( 10.0, -f); gets you y with 1<=y<10 and x = y*pow(10,f) here log_10_2 is log base 10 of 2, ie around 0.301029995663981143 You can get the digits of f by eg iterating d = (int)y; y = 10.0*(y-d); Note that you're only doing this for the number of digits required. If you don't have pow (and maybe even if you do) it can be written fairly easily & efficiently since its second argument is an integer. Duncan May 24 '07 #7

 P: n/a On Thu, 24 May 2007 16:57:28 +0100, Duncan Muirhead wrote: On Thu, 24 May 2007 16:46:06 +0200, Peter Sprenger wrote: >>> I'd suggest writing your own frexp() work-alike, usingyour knowledge of the floating-point representation. Theadvantage of using Standard-like tools for the task is thatyou'll easily be able to move the code to other platforms;something like a float-to-string-without-sprintf operationseems of sufficiently wide applicability that you may wellwant it again. So: invest a little non-portable work to getyourself up to the frexp()-ish baseline, and write portable Cfrom there upwards. Good luck! I was a little bit quick. In fact I can write a frexp() myself, thatseparates exponent and mantissa. But then? I have a mantissa and anexponent of base 2. I have no right idea to transform it from here toan ascii string.RegardsPeter If x is positive int expon; double frac = frexp(x, &expon); int f = floor( expon*log_10_2); double y = x*pow( 10.0, -f); gets you y with 1<=y<10 and x = y*pow(10,f) here log_10_2 is log base 10 of 2, ie around 0.301029995663981143 You can get the digits of f by eg iterating d = (int)y; y = 10.0*(y-d); Note that you're only doing this for the number of digits required. If you don't have pow (and maybe even if you do) it can be written fairly easily & efficiently since its second argument is an integer. Duncan Oops! Sorry, that's not quite right. In fact f above could be one too small, and so we could have 10<=y<=100. I think the easiest thing too do is to check for y being at least10, and if so fix it up. Duncan May 24 '07 #8

 P: n/a Peter Sprenger wrote On 05/24/07 10:46,: > I'd suggest writing your own frexp() work-alike, usingyour knowledge of the floating-point representation. Theadvantage of using Standard-like tools for the task is thatyou'll easily be able to move the code to other platforms;something like a float-to-string-without-sprintf operationseems of sufficiently wide applicability that you may wellwant it again. So: invest a little non-portable work to getyourself up to the frexp()-ish baseline, and write portable Cfrom there upwards. Good luck! I was a little bit quick. In fact I can write a frexp() myself, that separates exponent and mantissa. But then? I have a mantissa and an exponent of base 2. I have no right idea to transform it from here to an ascii string. You wrote originally about the time eaten up by the very many multiplications by ten needed to scale a value like 3.141E-300 to a reasonable range. I'm suggesting that you use the exponent of two to figure out how many "decades" of scaling you need, and do them all in one multiplication. You could use a precomputed array with the exponents as indices, or multiply the two's exponent by log10(2) and do a little rounding and/or truncating to get the ten's exponent. x = m * 2**e = m * (10**log10(2))**e = m * 10**(log10(2)*e) = m * 10**f = m * 10**floor(f) * 10**(f - floor(f)) = (m * 10**(f - floor(f))) * 10**floor(f) -- Er*********@sun.com May 24 '07 #9

 P: n/a > You wrote originally about the time eaten up by the very many multiplications by ten needed to scale a value like 3.141E-300 to a reasonable range. I'm suggesting that you use the exponent of two to figure out how many "decades" of scaling you need, and do them all in one multiplication. You could use a precomputed array with the exponents as indices, or multiply the two's exponent by log10(2) and do a little rounding and/or truncating to get the ten's exponent. x = m * 2**e = m * (10**log10(2))**e = m * 10**(log10(2)*e) = m * 10**f = m * 10**floor(f) * 10**(f - floor(f)) = (m * 10**(f - floor(f))) * 10**floor(f) Hello Eric, you are right, x = m * 2**e is correct. But if I have use log10 in some way, isn't it easier to directly get the exponent with directly log10(f) ? (f is my fp number) And then multiply f to get it in the range 1.0 <= f < 10.0 ? Your solution will not bring the answer on how many decimal places in the fraction f has. So I have to multiply it anyway in turns to get the decimal places after the comma. Peter May 25 '07 #10

 P: n/a >>Peter If x is positiveint expon;double frac = frexp(x, &expon);int f = floor( expon*log_10_2);double y = x*pow( 10.0, -f);gets you y with 1<=y<10 and x = y*pow(10,f)here log_10_2 is log base 10 of 2, ie around 0.301029995663981143You can get the digits of f by eg iterating d = (int)y; y = 10.0*(y-d);Note that you're only doing this for the number of digits required.If you don't have pow (and maybe even if you do) it can be writtenfairly easily & efficiently since its second argument is an integer.Duncan Oops! Sorry, that's not quite right. In fact f above could be one too small, and so we could have 10<=y<=100. I think the easiest thing too do is to check for y being at least10, and if so fix it up. Duncan Hello Duncan, you know the IEEE754 floating point format? The exponent says, where in the mantissa the decimal point is (or should I say the binary point :-) ) and the fraction part begins. Your terms don't use the mantissa, so I think they are not correct. But like I wrote to Eric, if I can make a log10(x), I can bring x into 1<= x < 10 with one multiplication. Peter May 25 '07 #11

 P: n/a On Fri, 25 May 2007 09:28:13 +0200, Peter Sprenger wrote: > >>>PeterIf x is positiveint expon;double frac = frexp(x, &expon);int f = floor( expon*log_10_2);double y = x*pow( 10.0, -f);gets you y with 1<=y<10 and x = y*pow(10,f)here log_10_2 is log base 10 of 2, ie around 0.301029995663981143You can get the digits of f by eg iterating d = (int)y; y = 10.0*(y-d);Note that you're only doing this for the number of digits required.If you don't have pow (and maybe even if you do) it can be writtenfairly easily & efficiently since its second argument is an integer.Duncan Oops! Sorry, that's not quite right. In fact f above could be onetoo small, and so we could have 10<=y<=100. I think the easiest thingtoo do is to check for y being at least10, and if so fix it up.Duncan Hello Duncan, you know the IEEE754 floating point format? The exponent says, where in the mantissa the decimal point is (or should I say the binary point :-) ) and the fraction part begins. Your terms don't use the mantissa, so I think they are not correct. But like I wrote to Eric, if I can make a log10(x), I can bring x into 1<= x < 10 with one multiplication. Peter Indeed, you want a log10 and a pow. However all you really need is the largest integer less than log10(x). Above I was musing about how you could do that if you had frexp. The point is that if y = frexp( x, &p) then we have x = pow(2,p)*y and 0.5<=y<=1 Taking logs (base 10) of this log10(x) = p*log10(2) + log10(y) but -log10(2)<=log10(y) <= 0 so the largest integer less than log10(x) is either the largest integer less than p*log10(2), or one less than this, You can figure out which by computing f = floor( p*log10) and then computing y = x*pow(10,-p). if 1<=y<10 we're done; otherwise (ie 0.1<=y<10) multiply y by 0.1 and increase p by one. Duncan May 25 '07 #12

 P: n/a Peter Sprenger wrote: >> You wrote originally about the time eaten up by thevery many multiplications by ten needed to scale a valuelike 3.141E-300 to a reasonable range. I'm suggestingthat you use the exponent of two to figure out how many"decades" of scaling you need, and do them all in onemultiplication. You could use a precomputed array withthe exponents as indices, or multiply the two's exponentby log10(2) and do a little rounding and/or truncatingto get the ten's exponent. x = m * 2**e = m * (10**log10(2))**e = m * 10**(log10(2)*e) = m * 10**f = m * 10**floor(f) * 10**(f - floor(f)) = (m * 10**(f - floor(f))) * 10**floor(f) Hello Eric, you are right, x = m * 2**e is correct. But if I have use log10 in some way, isn't it easier to directly get the exponent with directly log10(f) ? (f is my fp number) And then multiply f to get it in the range 1.0 <= f < 10.0 ? You only need an approximation to log10(f) to determine the initial scaling amount. You can get that by extracting the binary exponent (which is close to lg(f)) and multiplying by the precomputed constant log10(2), then truncating or rounding to a nearby integer. Your solution will not bring the answer on how many decimal places in the fraction f has. So I have to multiply it anyway in turns to get the decimal places after the comma. Yes, but you avoid the nearly three hundred multiplications by ten that work through the leading zeroes of 3.141E-300. If you get to 0.1 <= abs(f)*scale < 1 in one step, you only need as many additional multiplications as you want digits.[*] [*] Optimization: multiply by 1E8 instead of by 10, and work on groups of eight digits at a time in `long' instead of one digit at a time in floating-point. -- Eric Sosman es*****@acm-dot-org.invalid May 25 '07 #13

 P: n/a Eric Sosman wrote: Peter Sprenger wrote: *** and deleted attributions *** >>>You wrote originally about the time eaten up by the very manymultiplications by ten needed to scale a value like 3.141E-300 .... snip ... >>is correct. But if I have use log10 in some way, isn't it easierto directly get the exponent with directly log10(f) ? (f is my fpnumber) And then multiply f to get it in the range 1.0 <= f < 10.0 ? .... snip ... >[*] Optimization: multiply by 1E8 instead of by 10, and work on groups of eight digits at a time in `long' instead of one digit at a time in floating-point. To maintain accuracy, that 1E8 should be some value that is expressed exactly in the FP system in use, and as large as possible. For division, use the same value, and not it's inverse (which will not be exact in most systems). -- cbfalconer at maineline dot net -- Posted via a free Usenet account from http://www.teranews.com May 25 '07 #14

 P: n/a Peter Sprenger wrote: >>If x is positiveint expon;double frac = frexp(x, &expon);int f = floor( expon*log_10_2);double y = x*pow( 10.0, -f);gets you y with 1<=y<10 and x = y*pow(10,f)here log_10_2 is log base 10 of 2, ie around 0.301029995663981143You can get the digits of f by eg iterating d = (int)y; y = 10.0*(y-d);Note that you're only doing this for the number of digits required.If you don't have pow (and maybe even if you do) it can be writtenfairly easily & efficiently since its second argument is an integer.Duncan Oops! Sorry, that's not quite right. In fact f above could be onetoo small, and so we could have 10<=y<=100. I think the easiest thingtoo do is to check for y being at least10, and if so fix it up. you know the IEEE754 floating point format? The exponent says, where in the mantissa the decimal point is (or should I say the binary point :-) ) and the fraction part begins. Your terms don't use the mantissa, so I think they are not correct. But like I wrote to Eric, if I can make a log10(x), I can bring x into 1<= x < 10 with one multiplication. Peter, Duncan has a good approach. It uses an frexp(), which you can write, a floating multiplication and conversion to integer, then the pow() function, which can be implemented with some combination of table lookups and multiplication. And, as Duncan noted later, you may need to do a final adjustment on the power of 10. In general, the larger the lookup table, the fewer multiplications that are needed. For example, there are 81 different powers of 10 from 1e-40 to 1e+40. You can use a table of powers of 1e9 from 1e-36 to 1e+36, then powers of 10 from 1e-4 to 1e8. With 22 entries and one multiplication you get any power of 10 from 1e-40 to 1e+40. Or you can use a table with 81 entries and no multiplication. There are other feasible combinations, as well. -- Thad May 27 '07 #15

### This discussion thread is closed

Replies have been disabled for this discussion. 