C++ Difference Between 0 and 0.0

C++: difference between 0. and 0.0?

There is no difference. Both literals are double. From the C++-Grammar:

fractional-constant:
digit-sequenceopt . digit-sequence
digit-sequence .

See: Hyperlinked C++ BNF Grammar

What is the significance of 0.0f when initializing (in C)?

float x = 0 has an implicit typecast from int to float.

float x = 0.0f does not have such a typecast.

float x = 0.0 has an implicit typecast from double to float.

Depending on the compiler, implicit typecast can require the compiler to generate extra code.

What operations and functions on +0.0 and -0.0 give different arithmetic results?

There are a few standard operations and functions that form numerically different answers between f(+0.0) and f(-0.0).

Different rounding modes or other floating point implementations may give different results.

#include <math.h>

double inverse(double x) { return 1/x; }

double atan2m1(double y) { return atan2(y, -1.0); }

double sprintf_d(double x) {
char buf[20];
// sprintf(buf, "%+f", x); Changed to e
sprintf(buf, "%+e", x);
return buf[0]; // returns `+` or `-`
}

double copysign_1(double x) { return copysign(1.0, x); }

double signbit_d(double x) {
int sign = signbit(x); // my compile returns 0 or INT_MIN
return sign;
}

double pow_m1(double x) { return pow(x, -1.0); }

void zero_test(const char *name, double (*f)(double)) {
double fzp = (f)(+0.0);
double fzn = (f)(-0.0);
int differ = fzp != fzn;
if (fzp != fzp && fzn != fzn) differ = 0; // if both NAN
printf("%-15s f(+0):%-+15e %s f(-0):%-+15e\n",
name, fzp, differ ? "!=" : "==", fzn);
}

void zero_tests(void) {
zero_test("1/x", inverse);
zero_test("atan2(x,-1)", atan2m1);
zero_test("printf(\"%+e\")", sprintf_d);
zero_test("copysign(x,1)", copysign_1);
zero_test("signbit()", signbit_d);
zero_test("pow(x,-odd)", pow_m1);; // @Pascal Cuoq
zero_test("tgamma(x)", tgamma); // @vinc17 @Pascal Cuoq
}

Output:
1/x f(+0):+inf != f(-0):-inf
atan2(x,-1) f(+0):+3.141593e+00 != f(-0):-3.141593e+00
printf("%+e") f(+0):+4.300000e+01 != f(-0):+4.500000e+01
copysign(x,1) f(+0):+1.000000e+00 != f(-0):-1.000000e+00
signbit() f(+0):+0.000000e+00 != f(-0):-2.147484e+09
pow(x,-odd) f(+0):+inf != f(-0):-inf
tgamma(x) f(+0):+inf != f(-0):+inf

Notes:

tgamma(x) came up == on my gcc 4.8.2 machine, but correctly != on others.

rsqrt(), AKA 1/sqrt() is a maybe future C standard function. May/may not also work.

double zero = +0.0; memcpy(&zero, &x, sizeof x) can show x is a different bit pattern than +0.0 but x could still be a +0.0. I think some FP formats have many bit patterns that are +0.0 and -0.0. TBD.

This is a self-answer as provided by https://stackoverflow.com/help/self-answer.

any difference between x=0 and x=0.0 for a double x variable? c code

In practice, there doesn't have to be any difference although there is an implicit conversion in the first case since 0 is an int.

I tried it (on assembly.ynh.io). This C code:

#include <stdio.h>

int main(void)
{
double x, y;

x = 0;
y = 0.;

printf("x=%g and y=%g\n", x, y);

return 0;
}

generated the following assembly for the two assignments (to x and y):

0008 B8000000 00  movl  $0, %eax
000d 488945F0 movq %rax, -16(%rbp)
0011 B8000000 00 movl $0, %eax
0016 488945F8 movq %rax, -8(%rbp)

In other words, the code is exactly the same. This was built by GCC, without optimization.

I guess this takes advantage of the fact that the bitpatterns are all zero in both cases.

0 vs 0.0 in conditional statements

double a = 0.0000000000001;
int b = 0;

res = a <= b; // False
res2 = b >= a; // False

Given the above test, I'd say C# opts for the least lossy conversion. (Not a preference for left or right side)

So to answer your question, no. There isn't a difference.

Why is C++ implicitly converting 0.0 to some extremly small 'random' value?

Your Vector class never initializes the x and y members.

Since the member variables are uninitialized, they will have an indeterminate value, which you should look at like it was random or garbage. Using indeterminate values of any kind in any way, leads to undefined behavior.

To initialize the member variables, use a constructor initializer list:

Vector(double x = 0.0, double y = 0.0)
: x{ x }, y{ y }
{
}

On another note, floating point arithmetic on a computer will lead to rounding errors. The more operations you perform, the larger the error will be. And sooner or later you will think that floating point math is broken.

All this rounding of course means that it's almost impossible to do exact comparisons of floating point values.

The common way is to use an epsilon, a small margin of error, for your comparisons.



Related Topics



Leave a reply



Submit