Tricky double operations

  • Thread starter Christopher Benson-Manica
  • Start date
C

Christopher Benson-Manica

I just ran across this code (assume that buf is valid and large
enough to hold all characters printed to it):

const char *foo( double d, char *buf )
{
char *cp;

if( d == (int)d ) { /* 1 */
sprintf( buf, "%d", (int)d ); /* 2 */
}
else { /* 3 */
sprintf( buf, "%.3lf", d );
cp=buf+strlen( buf );
while( cp > buf && cp[-1] == '0' ) {
*(--cp)=0;
}
if( cp > buf && cp[-1] == '.' ) {
cp[-1]=0;
}
}
return buf;
}

1. Obviously this cast is unsafe - is it unsafe even if 0 < d < INT_MAX?
The code wants to verify that d has no decimal part, apparently.
Is floor(d) == ceil(d) an acceptable alternative? Will it work?

2. Presumably this line should be

printf( buf, "%.0lf", d );

Is that correct?

3. As near as I can make out, this attempts to ensure that there are
no trailing 0's printed, and that there is not a bare decimal
point either. Is there a better way to do that?
 
E

Eric Sosman

Christopher said:
I just ran across this code (assume that buf is valid and large
enough to hold all characters printed to it):

const char *foo( double d, char *buf )
{
char *cp;

if( d == (int)d ) { /* 1 */
sprintf( buf, "%d", (int)d ); /* 2 */
}
else { /* 3 */
sprintf( buf, "%.3lf", d );
cp=buf+strlen( buf );
while( cp > buf && cp[-1] == '0' ) {
*(--cp)=0;
}
if( cp > buf && cp[-1] == '.' ) {
cp[-1]=0;
}
}
return buf;
}

1. Obviously this cast is unsafe - is it unsafe even if 0 < d < INT_MAX?
The code wants to verify that d has no decimal part, apparently.
Is floor(d) == ceil(d) an acceptable alternative? Will it work?

The cast is safe if INT_MIN-1 < d < INT_MAX+1, and will
"work" as intended for that range. The floor/ceil test looks
all right, and maybe there's something you could do with modf().
2. Presumably this line should be

printf( buf, "%.0lf", d );

Is that correct?

Yes, perhaps, but probably not. The "corrected" version
assumes that `buf' already contains something like "%s%g" --
either that, or the wrong function is being called. Note, too,
that the "l" length modifier has no effect on the "%f" specifier.
3. As near as I can make out, this attempts to ensure that there are
no trailing 0's printed, and that there is not a bare decimal
point either. Is there a better way to do that?

Sure: you can get rid of the strlen() call by making use of
the value returned by sprintf(). But beyond that, I'm not so
sure that "123498487123123123198398734" is all that great an
improvement over "123498487123123123198398734.123" ... What's
the wider context? Making axis labels for a graph, perhaps?
 
K

Keith Thompson

Eric Sosman said:
Christopher said:
I just ran across this code (assume that buf is valid and large
enough to hold all characters printed to it):
const char *foo( double d, char *buf )
{
char *cp;
if( d == (int)d ) { /* 1 */
sprintf( buf, "%d", (int)d ); /* 2 */
} [snip]
2. Presumably this line should be
printf( buf, "%.0lf", d );
Is that correct?

Yes, perhaps, but probably not. The "corrected" version
assumes that `buf' already contains something like "%s%g" --
either that, or the wrong function is being called. Note, too,
that the "l" length modifier has no effect on the "%f" specifier.

Actually, I think it merely assumes that "sprintf" is spelled without
a leading 's'.
 
C

Christopher Benson-Manica

Christopher Benson-Manica said:
const char *foo( double d, char *buf )
{
char *cp;
if( d == (int)d ) { /* 1 */
sprintf( buf, "%d", (int)d ); /* 2 */
}
else { /* 3 */
sprintf( buf, "%.3lf", d );
cp=buf+strlen( buf );
while( cp > buf && cp[-1] == '0' ) {
*(--cp)=0;
}
if( cp > buf && cp[-1] == '.' ) {
cp[-1]=0;
}
}
return buf;
}

Is the following code a legitemate re-implementation of the function?

const char *foo( double d, char *buf )
{
unsigned int real_d, pos;
modf( d*1000, &d );
real_d=(unsigned int)d; /* assume d is in range */
pos=sprintf( buf, "%u", real_d/1000 );
if( real_d%1000 ) {
sprintf( buf+pos, ".%u", real_acc%1000 );
}
}
 
B

Barry Schwarz

Christopher Benson-Manica said:
const char *foo( double d, char *buf )
{
char *cp;
if( d == (int)d ) { /* 1 */
sprintf( buf, "%d", (int)d ); /* 2 */
}
else { /* 3 */
sprintf( buf, "%.3lf", d );
cp=buf+strlen( buf );
while( cp > buf && cp[-1] == '0' ) {
*(--cp)=0;
}
if( cp > buf && cp[-1] == '.' ) {
cp[-1]=0;
}
}
return buf;
}

Is the following code a legitemate re-implementation of the function?

const char *foo( double d, char *buf )
{
unsigned int real_d, pos;
modf( d*1000, &d );
real_d=(unsigned int)d; /* assume d is in range */
pos=sprintf( buf, "%u", real_d/1000 );
if( real_d%1000 ) {
sprintf( buf+pos, ".%u", real_acc%1000 );
}
}

What is real_acc??


<<Remove the del for email>>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top