Printing -0 as 0?

D

David Mathog

IEEE 754 math rounds -.1, or -0 itself, to -0. Not 0. Fine, that has
some specific uses numerically, as in 1/-inf. However, a displaying
value of -0 is a mistake in most real world applications, were no one
expects "your balance is -0.00 dollars"!

http://www.gnu.org/s/hello/manual/libc/Rounding.html

says "Negative zero behaves IDENTICALLY to zero except when the
copysign or signbit functions are used to check the sign bit
directly." (Emphasis added). Sadly nobody told printf about this:

double dv=0;
dv=-dv;
printf("Prints -0, not 0: %f\n",dv)

I could not find any IEEE bits to set to disable math using -0. Is
there a flag somewhere in C99
for printf that causes -0 to print as 0 (without also causing -1 to
print as 1)? One solution is to add 0.0 to all printf arguments, but
that is really ugly. For instance this:

#include <stdlib.h>
#include <stdio.h>
int main(void){
double dv=0.0;
fprintf(stdout,"%f\n",dv);
fprintf(stdout,"%f\n",-dv);
fprintf(stdout,"%f\n",-dv+0.0);
}

prints

0.000000
-0.000000
0.000000

Thanks,

David Mathog
 
D

David Mathog

  fprintf(stdout,"%f\n",-dv+0.0);

Turns out that isn't a general solution.

dv=-0.000000000000001;
fprintf(stdout,"%f\n",dv+0.0);

prints as -0.

Regards,

David Mathog
 
D

David Mathog

(Sorry if this double posts, an earlier reply never showed up)

  fprintf(stdout,"%f\n",-dv+0.0);

Not a general solution unfortunately:

dv=-0.000000000000001;
fprintf(stdout,"%f\n",dv+0.0);

prints as -0.

Regards,

David Mathog
 
B

Ben Pfaff

David Mathog said:
Turns out that isn't a general solution.

This ought to work, since -0 == 0, barring compiler "optimization":
printf("%f\n", dv == 0.0 ? 0.0 : dv);
 
D

David Mathog

This ought to work, since -0 == 0, barring compiler "optimization":
        printf("%f\n", dv == 0.0 ? 0.0 : dv);

Doesn't handle dv=-0.000000001 correctly, that prints as -0.
The printf man page says that it rounds and then prints, so the
value doesn't become precisely -0.0 until after it enters printf.
(And maybe not even then, depending on how printf goes about its
business.)

Regards,

David Mathog
 
M

Mickey Mouse

Turns out that isn't a general solution.

dv=-0.000000000000001;
fprintf(stdout,"%f\n",dv+0.0);

prints as -0.

Regards,

David Mathog

I ran into the same problem calclating the x y coordinates of evenly
spaced points around an inscribed circle. (for drilling holers in a
circular pattern an a pipe flange).

My solution is not elegant but it works well enough for the
requirements.



double side_a;
double side_b;

/* the sides of the tringle that is calculated where side_a is the x
coordinate abd side_b the y coordinate */

long a;
long b;

double side_a_fixed;
double side_b_fixed;

int precision; /*decimal precission usually 3 for inches and 2 for
metric */


a = side_a * 10 * precision;
b = side_b * 10 * precision;


side_a_fixed = a / 10 / precision;
side_b_fixed = b / 10 / precision;

printf("%11.*f , %11.*f", precision, side_a_fixed, precision,
side_b_fixed);
 
D

David Mathog

a = side_a * 10 * precision;
b = side_b * 10 * precision;

side_a_fixed = a / 10 / precision;
side_b_fixed = b / 10 /  precision;

Ah, I see. Here's another way with more tests but not requiring
multiply
and divide at each fprintf:

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#define fltprec(A,B) ((A) >= 0.0 ? 0.0 + (A) :\
((A) < (B) ? (A) : 0.0 ))
int main(void){
double dv=0.0;
double dlim;
int precision=6;
fprintf(stdout,"%f\n",0.0000005);
fprintf(stdout,"%f\n",0.00000051);
fprintf(stdout,"%f\n",0.00000049);

dlim=-5*pow(10.0,-(precision+1));
fprintf(stdout,"dlim %.9f\n",dlim);

dv=-0.0; fprintf(stdout,"%f\n",fltprec(dv,dlim));
dv= 0.0; fprintf(stdout,"%f\n",fltprec(dv,dlim));
dv=-0.00000005; fprintf(stdout,"%f\n",fltprec(dv,dlim));
dv= 0.00000005; fprintf(stdout,"%f\n",fltprec(dv,dlim));
dv=-0.0000005; fprintf(stdout,"%f\n",fltprec(dv,dlim));
dv= 0.0000005; fprintf(stdout,"%f\n",fltprec(dv,dlim));
dv=-0.000005; fprintf(stdout,"%f\n",fltprec(dv,dlim));
dv= 0.000005; fprintf(stdout,"%f\n",fltprec(dv,dlim));
}

Which emits:

0.000000
0.000001
0.000000
dlim -0.000000500
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
-0.000005
0.000005


The odd thing is the rounding of .0000005, which rounds down
when I expected it would round up. In the first pass the define
was (A)<=(B), but that emitted a -0.000000 when -.0000005 was printed.

I need to test this more and make sure it works at all precisions, or
if
the strange rounding is a numerical representation problem.

Thanks for the hint,

David Mathog
 
D

David Mathog

This seems to do the trick:

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#define fltprec(A,B) ((A) > (B) ? (A) : ((A) < -(B) ? (A) : 0.0 ))
int main(void){
double dv=0.0;
double dlim;
int precision;
for(precision=1; precision<15; precision++){
dlim=5*pow(10.0,-(precision+1));
fprintf(stdout,"dlim %.15f ",dlim);
fprintf(stdout," %.*f",precision,1.0001*dlim);
fprintf(stdout," %.*f",precision,dlim);
fprintf(stdout," %.*f\n",precision,0.9999*dlim);
}

for(precision=1; precision<15; precision++){
dlim=5*pow(10.0,-(precision+1));
fprintf(stdout,"dlim %.15f ",dlim);
fprintf(stdout," %.*f ",precision,fltprec(-dlim*10.0,dlim));
fprintf(stdout," %.*f ",precision,fltprec(dlim*10.0,dlim));
fprintf(stdout," %.*f ",precision,fltprec(-dlim,dlim));
fprintf(stdout," %.*f ",precision,fltprec(dlim,dlim));
fprintf(stdout," %.*f ",precision,fltprec(-dlim/10.0,dlim));
fprintf(stdout," %.*f\n",precision,fltprec(dlim/10.0,dlim));
}
}

The first loop shows that there are rounding issues for various
precisions
right at the cutoff (sometimes rounds up, sometimes down). So the
slightly modified #define handles those, resulting in zero in all
columns which were supposed to be (not -0).

Hopefully that is the final solution.

Regards,

David Mathog
 
D

David Mathog

On Jun 9, 12:53 pm, Mickey Mouse <[email protected]> wrote:
Hopefully that is the final solution.

Aargh, of course it wasn't. NAN compares false with everything, so
NAN
was printing as 0.

This change handles nan, +inf, and -inf too.

#define fltprec(A,B) ((A) > (B) ? (A) :\
((A) < -(B) ? (A) :\
(isnan(A) ? (A) : 0.0) ))

I guess it isn't that much less efficient than the preceding version,
since 1/2 - epsilon of the domain will pass the first test, and the
other 1/2 - epsilon will pass the second, leaving only 2*epsilon of
the domain to undergo the final test.

Still, it sure would be nice if printf had a "do not print negative
zero" switch!

Regards,

David Mathog
 

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,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top