[comp.lang.c] Efficient way to transform float to string

rg2c+@andrew.cmu.edu (Robert Nelson Gasch) (12/07/90)

Hi,
I'm looking for an *efficient* algorithm to transform a float (10< f < 0)
into a string. What I am doing right no is this:

I get the first digit and put the appropriate number in array[0]. 
Array[1] gets the decimal point. I then make f < 1 and multiply it
times 10, and get the aproriate character for the first digit and 
repeat this procedure until the number equals 0. Sounds OK, but when
you do this alot, it's pretty damn slow.

If anybody has any suggestions on how to do this faster, please let me
know. Both actual code or algorithm descriptions are welcome.

Thanx alot --> Rob

peterh@hemel.bull.co.uk (Peter Holditch) (12/07/90)

rg2c+@andrew.cmu.edu (Robert Nelson Gasch) writes:

>Hi,
>I'm looking for an *efficient* algorithm to transform a float (10< f < 0)
>into a string. What I am doing right no is this:

> [ Stuff Deleted ]

>If anybody has any suggestions on how to do this faster, please let me
>know. Both actual code or algorithm descriptions are welcome.

>Thanx alot --> Rob

It may be that you don't consider it efficient enough, but why not just use

char fltno[12];

...

sprintf (fltno,"%10f",your_float);

That's what I'd do anyway.

Peter Holditch.

--

           #       #       #       #       #       #      #        
          # #     # #     # #     # #     # #     # #    # #        
         #   #   #   #   #   #   #   #   #   #   #   #  #   #        
        #      #       #       #       #       #       #     #
       #	From:	Peter.Holditch@hemel.bull.co.uk	      #
       #		Tel:	0442-232222x4826	      #
        #      #       #       #       #       #       #     #
         #   #   #   #   #   #   #   #   #   #   #   #  #   #        
          # #     # #     # #     # #     # #     # #    # #        
           #       #       #       #       #       #      #        

<< If I said it, it was nobody else but me. >>

gordon@osiris.cso.uiuc.edu (John Gordon) (12/08/90)

	Try looking at the function gcvt().

lerman@stpstn.UUCP (Ken Lerman) (12/09/90)

In article <QbLnB1u00WBMM53Wpp@andrew.cmu.edu> rg2c+@andrew.cmu.edu (Robert Nelson Gasch) writes:
->Hi,
->I'm looking for an *efficient* algorithm to transform a float (10< f < 0)
->into a string. What I am doing right no is this:
->
->I get the first digit and put the appropriate number in array[0]. 
->Array[1] gets the decimal point. I then make f < 1 and multiply it
->times 10, and get the aproriate character for the first digit and 
->repeat this procedure until the number equals 0. Sounds OK, but when
->you do this alot, it's pretty damn slow.
->
->If anybody has any suggestions on how to do this faster, please let me
->know. Both actual code or algorithm descriptions are welcome.
->
->Thanx alot --> Rob



You've got the right idea, but:

1 -- You should first convert the number from float to scaled integer.

2 -- Rather than multiplying by 10, shift left two, add the original
     and shift left again.  (A smart compiler might do this for you.)
     [Some might say that a reasonable compiler should do this for you.]

3 -- You didn't say how may digits of precision you want.  The
     multiple-precision scaled integer multiplication can be a pain if
     you want high precision.

Ken

hilfingr@rama.cs.cornell.edu (Paul N. Hilfinger) (12/10/90)

In article <QbLnB1u00WBMM53Wpp@andrew.cmu.edu> rg2c+@andrew.cmu.edu (Robert Nelson Gasch) writes:
>I'm looking for an *efficient* algorithm to transform a float (10< f < 0)
>into a string. What I am doing right [now] is ... [repeatedly peeling off the 
>most significant digit by truncation and subtraction, followed by 
>by 10.0, all in floating-point arithmetic.]
>If anybody has any suggestions on how to do this faster, please let me
>know. Both actual code or algorithm descriptions are welcome.

There have been a couple of responses to this posting suggesting the
use of gcvt or of scaling, conversion to integer, followed by
conversion to ASCII.  I was a little curious about these suggestions.
Some experimentation showed that on a DECstation 3100, using cc, Mr.
Gasch's original program is faster than either of the suggestions for
6 digits of result (at least for my C versions of his algorithm and
the alternatives).  I only find this interesting because it reminded
me (still one more time) that my intuitions about double-precision
floating-point performance---formed 20 years ago---need constant
re-examination.  (Needless to say, however, it would be unwise to
generalize my findings to other processors just now.)

Paul Hilfinger

steve@taumet.com (Stephen Clamage) (12/11/90)

lerman@stpstn.UUCP (Ken Lerman) writes:

>2 -- Rather than multiplying by 10, shift left two, add the original
>     and shift left again.  (A smart compiler might do this for you.)
>     [Some might say that a reasonable compiler should do this for you.]

Except that on some machines shifting is not cheap.  On some machines
an integer multiply by 10 is faster than two shifts and an add along
with creating an intermediate result.  A good rule is to leave it up to
the compiler until performance tests prove you must do low-level coding
like this.  In that case, be sure to conditionalize the code for the
particular compiler.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

kaleb@thyme.jpl.nasa.gov (Kaleb Keithley ) (12/11/90)

Stepping into the middle of the thread.

On Sun; there is econvert and related functions.

     econvert() converts the value to a null-terminated string of
     ndigit  ASCII  digits  in  buf and returns a pointer to buf.
     buf should contain at least ndigit+1 characters.  The  posi-
     tion of the radix character relative to the beginning of the
     string is stored indirectly  through  decpt.   Thus  buf  ==
     "314"  and  *decpt  ==  1 corresponds to the numerical value
     3.14, while buf == "314" and *decpt == -1 corresponds to the
     numerical  value  .0314.  If the sign of the result is nega-
     tive, the word pointed to by sign is nonzero;  otherwise  it
     is zero.  The least significant digit is rounded.

     fconvert works much like econvert, except that  the  correct
     digit  has been rounded as if for sprintf(%w.nf) output with
     n=ndigit digits to the right of the radix character.  ndigit
     can  be  negative  to  indicate  rounding to the left of the
     radix character.  The return value is a pointer to buf.  buf
     should  contain  at  least  310+max(0,ndigit)  characters to
     accomodate any double-precision value.

     gconvert() converts the value  to  a  null-terminated  ASCII
     string  in  buf  and  returns a pointer to buf.  It produces
     ndigit significant  digits  in  fixed-decimal  format,  like
     sprintf(%w.nf),  if  possible,  and  otherwise  in floating-
     decimal format, like sprintf(%w.ne); in either case  buf  is
     ready  for  printing,  with  sign  and exponent.  The result
     corresponds to that obtained by

          (void) sprintf(buf, "%w.ng", value);


-- 
Kaleb Keithley                      Jet Propulsion Labs
kaleb@thyme.jpl.nasa.gov

You can please all of the people some of the time,

gwyn@smoke.brl.mil (Doug Gwyn) (12/11/90)

In article <49508@cornell.UUCP> hilfingr@cs.cornell.edu (Paul N. Hilfinger) writes:
>Gasch's original program is faster than either of the suggestions ...

But the library routines probably round correctly and properly convert
numbers that are approximately an exact power of 10.