- Fast conversion of a float to character string ( C language )
- Posted by flair on September 8th, 2004
Hi,
I'm looking for a fast way to convert a float into a character string.
The sprintf() function is too slow for the needs of my program.
Can you help me?
Thank you!
Frederic
- Posted by Paul Lutus on September 8th, 2004
flair wrote:
You are not likely to improve on the speed of sprintf(). It is not as though
this function was added a few months ago as an afterthought. It is central
to the performance of many programs that spend their time converting just
as you are doing.
Also, accurate conversion of floats from binary to decimal is not a trivial
undertaking. It is almost an art form.
Will you accept an integer conversion instead? That would be faster. Even
faster would be a routine that simply revealed wheter the original number
was or was not zero. It all depends on the quality of the result you
require.
--
Paul Lutus
http://www.arachnoid.com
- Posted by CBFalconer on September 8th, 2004
flair wrote:
Why? Such an operation would normally not be noticeable amidst
the i/o processing, and other operations should be easier in the
native format. What are you trying to do?
--
"I'm a war president. I make decisions here in the Oval Office
in foreign policy matters with war on my mind." - Bush.
"If I knew then what I know today, I would still have invaded
Iraq. It was the right decision" - G.W. Bush, 2004-08-02
- Posted by flair on September 9th, 2004
Paul Lutus <nospam@nosite.zzz> wrote in message news:<10judt9c936ka99@corp.supernews.com>...
Thank you for your response.
Actually, I have to display float numbers that always have one of the
following formats:
"8888.88"
"888.88"
"88.88"
"8.88"
"-8888.88"
"-888.88"
"-88.88"
"-8.88"
It looks simple.
I have written my own function for the conversion. It improved the
speed of my program but I am sure I can find a better algorithm.
- Posted by CBFalconer on September 9th, 2004
flair wrote:
Well, you may with to use or fool around with the following:
/* ---------- FILE putflt.h ---------- */
/* Print out floating point numbers
Public Domain, by C.B. Falconer.
Attribution appreciated */
#ifndef H_putflt_h
# define H_putflt_h 1
# ifdef __cplusplus
extern "C" {
# endif
/* (putchar) is a suitable value */
typedef int (*putchr)(int ch);
/* ------------ */
/* Returns the count of columns used, or -ve for error
Calling with a dummy dest allows evaluating fields */
int putflt(double val, int sigdigs, putchr dest);
/* ------------ */
/* write the value right justified in field, do not truncate
* Negative value for field left justifies.
* return value signifies field actually used */
int putfltfld(double val, int sigdigs, int field, putchr dest);
/* ------------ */
# ifdef __cplusplus
}
# endif
#endif
/* ---------- EOF FILE putflt.h ---------- */
/* Print out floating point numbers demo, file putflt.c */
/* Public Domain, by C.B. Falconer. Attribution appreciated */
#include "putflt.h"
/* ------------ */
/* Returns the count of columns used, or -ve for error
Calling with a dummy dest allows evaluating fields */
int putflt(double val, int sigdigs, putchr dest)
{
int dp;
int ch;
int used;
used = 0;
if (sigdigs <= 0) sigdigs = 1;
if (val < 0) {
dest('-'); used++;
val = - val;
}
/* Normalize */
dp = 0;
if (val != 0.0) {
while (val >= 10.0) {
val = val / 10.0; dp++;
}
while (val < 1.0) {
val = 10.0 * val; dp--;
}
}
/* Handle leading zeroes */
if (dp < 0) {
dest('0'); dest('.'); used += 2;
while (++dp) {
dest('0'); used++;
}
dp--;
}
/* The real work */
do {
ch = val; val = val - ch;
dest(ch + '0'); used++;
val = 10.0 * val;
if (0 == dp--) {
dest('.'); used++;
}
} while (--sigdigs > 0);
/* handle trailing zeroes */
while (dp >= 0) {
dest('0'); used++;
if (0 == dp--) {
dest('.'); used++;
}
}
/* Handle isolated '.' at end */
if (-1 == dp) {
dest('0'); used++;
}
return used; /* no errors handled yet */
} /* putflt */
/* ------------ */
/* do nothing, to allow evaluating field needed */
static int dummy(int ch)
{
return ch;
} /* dummy */
/* ------------ */
/* write the value right justified in field, do not truncate
* Negative value for field left justifies.
* return value signifies field actually used */
int putfltfld(double val, int sigdigs, int field, putchr dest)
{
int needed;
needed = putflt(val, sigdigs, dummy);
if (field > 0)
while (needed < field) {
dest(' '); needed++;
}
putflt(val, sigdigs, dest);
if (field < 0)
while ((needed + field) < 0) {
dest(' '); needed++;
}
return needed;
} /* putfltfld */
/* ------------ */
#ifdef TESTING
#include <stdio.h>
#define show(fld) printf(" Field = %d\n", fld)
int main(void)
{
double val;
int i, fld;
val = 10.0 / 7.0; /* A normalized value, 6 dig rep */
fld = putflt(-val / 100, 10, (putchar)); show(fld);
fld = putflt(-val, 10, (putchar)); show(fld);
fld = putflt(-val * 100, 10, (putchar)); show(fld);
fld = putflt(val / 100, 10, (putchar)); show(fld);
fld = putflt(val, 10, (putchar)); show(fld);
for (i = 12; i > 0; i--) {
val = 10 * val;
fld = putflt(val, 10, (putchar)); show(fld);
}
fld = putflt(0.0, 10, (putchar)); show(fld);
fld = putflt(1e-30, 10, (putchar)); show(fld);
fld = putflt(1e30, 10, (putchar)); show(fld);
fld = putflt(0.1e-30, 10, (putchar)); show(fld);
fld = putflt(0.2e-30, 10, (putchar)); show(fld);
fld = putflt(0.3e-30, 10, (putchar)); show(fld);
fld = putflt(0.01e-30, 10, (putchar)); show(fld);
fld = putflt(0.001e-30, 10, (putchar)); show(fld);
val = 30.0 / 13.0; /* Another normalized value */
fld = putfltfld(-val, 10, 20, (putchar)); show(fld);
fld = putfltfld(-val * 100, 10, -20, (putchar)); show(fld);
fld = putfltfld(val / 100, 10, -20, (putchar)); show(fld);
fld = putfltfld(val, 10, 20, (putchar)); show(fld);
fld = putfltfld(val, 25, 35, (putchar)); show(fld);
val = 5419351.0 / 1725033.0; /* Another normalized value */
fld = putfltfld(val, 25, 35, (putchar)); show(fld);
return 0;
} /* main putflt demo */
#endif
/* ---------- EOF FILE putflt.c ---------- */
--
"Churchill and Bush can both be considered wartime leaders, just
as Secretariat and Mr Ed were both horses." - James Rhodes.
"We have always known that heedless self-interest was bad
morals. We now know that it is bad economics" - FDR
- Posted by Paul Lutus on September 9th, 2004
flair wrote:
/ ...
Those are not formats per se, they represent properties of the data. I mean,
8.88 looks different than 888.88, not because of a formatting choice, but
because it is a different number.
I am willing to bet your algorithm cannot handle an entire class of rounding
problems that come up with conversion from binary to decimal. If your
algorithm is faster than sprintf(), it does it by taking shortcuts that
don't matter in 99% of cases.
Example. Show your algorithm's output with different numbers of decimal
places (or absolute magnitude) for a double variable loaded with the
results for 4.0/9.0 and 5.0/9.0 respectively.
On the other hand, if your program must format currency values and that is
its only purpose, you may be better off using a method that converts the
doubles to a properly rounded long that is aligned with pennies (e.g. it
resesents an integer number of pennies). In this arrangement, after the
conversion, formatting and printing the numbers in decimal form is
deterministic and reliable.
--
Paul Lutus
http://www.arachnoid.com
- Posted by Paul Hsieh on September 10th, 2004
CBFalconer <cbfalconer@yahoo.com> wrote:
Not if its server application with some kind of pipelined I/O, over a
network for example. The AMD Opteron Optimization guide:
http://www.amd.com/us-en/assets/cont...docs/25112.PDF
(see section 8.7) gives an extremely well optimized int->ASCII
conversion function, for example. I think AMD is aware of at least
some people interested in that application.
So splitting the floating point number into integer and fractional
part, then figuring out which portions need to be actually converted
and putting a "." in between as necessary then using the AMD algorithm
for each part might be reasonable algorithm for some ranges of
doubles.
--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/
- Posted by Randy Howard on September 10th, 2004
In article <796f488f.0409091858.363ce821@posting.google.com>, qed@pobox.com
says...
:
Thanks for that link, I had not seen it before.
--
Randy Howard
To reply, remove FOOBAR.
- Posted by Randy Howard on September 10th, 2004
In article <MPG.1baad6d222221f2f9899e9@news.verizon.net>,
randyhoward@FOOverizonBAR.net says...
Uh oh, looks like AMD and EGN are at a difference of opinion. Please note
section 2.14 in the link above, "Generic Loop Hoisting", which they claim
applies to "32-bit Software" and "64-bit Software", rather than compiler
optimizer implementors only, and, my but they seem to have some sample
code as well. I hope EGN will be telling AMD how stupid they are to be using
that terminology inappropriately.
--
Randy Howard
To reply, remove FOOBAR.
- Posted by James Kanze on September 11th, 2004
Paul Lutus <nospam@nosite.zzz> writes:
|> flair wrote:
|> / ...
|> > Thank you for your response.
|> > Actually, I have to display float numbers that always have one of
|> > the following formats:
|> > "8888.88"
|> > "888.88"
|> > "88.88"
|> > "8.88"
|> > "-8888.88"
|> > "-888.88"
|> > "-88.88"
|> > "-8.88"
|> > It looks simple.
|> Those are not formats per se, they represent properties of the data.
|> I mean, 8.88 looks different than 888.88, not because of a
|> formatting choice, but because it is a different number.
Always two digits after the decimal. And the values aren't that large,
either. The easiest way to handle that would be to multiply by 100,
convert to int, convert the int to a string, and then insert the
decimal.
|> > I have written my own function for the conversion. It improved the
|> > speed of my program but I am sure I can find a better algorithm.
|> I am willing to bet your algorithm cannot handle an entire class of
|> rounding problems that come up with conversion from binary to
|> decimal. If your algorithm is faster than sprintf(), it does it by
|> taking shortcuts that don't matter in 99% of cases.
|> Example. Show your algorithm's output with different numbers of
|> decimal places (or absolute magnitude) for a double variable loaded
|> with the results for 4.0/9.0 and 5.0/9.0 respectively.
|> On the other hand, if your program must format currency values and
|> that is its only purpose, you may be better off using a method that
|> converts the doubles to a properly rounded long that is aligned with
|> pennies (e.g. it resesents an integer number of pennies). In this
|> arrangement, after the conversion, formatting and printing the
|> numbers in decimal form is deterministic and reliable.
If his program must deal with currency values, there is a good chance
that he has to get some sort of package which does decimal arithmetic.
--
James Kanze
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
- Posted by gerard46 on September 11th, 2004
| James Kanze wrote:
|> Paul Lutus wrote:
||> flair wrote:
||> / ...
||>> Thank you for your response.
||>> Actually, I have to display float numbers that always have one of
||>> the following formats:
||>> "8888.88"
||>> "888.88"
||>> "88.88"
||>> "8.88"
||>> "-8888.88"
||>> "-888.88"
||>> "-88.88"
||>> "-8.88"
||>> It looks simple.
||> Those are not formats per se, they represent properties of the data.
||> I mean, 8.88 looks different than 888.88, not because of a
||> formatting choice, but because it is a different number.
| Always two digits after the decimal. And the values aren't that large,
| either. The easiest way to handle that would be to multiply by 100,
| convert to int, convert the int to a string, and then insert the
| decimal.
It's still not that simple. Consider the trival cases of 0, 1, -9,
12, and also rounding. Also, should -13 be -.13 or rather -0.13 ?
Even though the numbers will ALWAYS be in the above formats, but what
if they ain't ? ______________________________________________Gera rd S.
||>> I have written my own function for the conversion. It improved the
||>> speed of my program but I am sure I can find a better algorithm.
||> I am willing to bet your algorithm cannot handle an entire class of
||> rounding problems that come up with conversion from binary to
||> decimal. If your algorithm is faster than sprintf(), it does it by
||> taking shortcuts that don't matter in 99% of cases.
||> Example. Show your algorithm's output with different numbers of
||> decimal places (or absolute magnitude) for a double variable loaded
||> with the results for 4.0/9.0 and 5.0/9.0 respectively.
||> On the other hand, if your program must format currency values and
||> that is its only purpose, you may be better off using a method that
||> converts the doubles to a properly rounded long that is aligned with
||> pennies (e.g. it resesents an integer number of pennies). In this
||> arrangement, after the conversion, formatting and printing the
||> numbers in decimal form is deterministic and reliable.
| If his program must deal with currency values, there is a good chance
| that he has to get some sort of package which does decimal arithmetic.
- Posted by Paul Lutus on September 12th, 2004
James Kanze wrote:
/ ...
Yes, I agree, and I have suggested this elsewhere.
/ ...
Or he can roll his own. He is, after all, tuning for speed, and the
conversions are not difficult -- we are discussing converting integers from
one base to another.
--
Paul Lutus
http://www.arachnoid.com