Pelles C forum

C language => Beginner questions => Topic started by: boral on February 20, 2013, 08:41:39 AM

Title: What is meant by -0.0 ?
Post by: boral on February 20, 2013, 08:41:39 AM
I know that in mathematics, 0 is neither positive nor negative. But look at the following screenshot. I was writing a program to find the rank of a matrix and I found that a mysterious thing happened.

1) See the first red line. There should be 0.000000 but there is -0.000000 . Trust me I haven't entered the - sign spontaneously.

2) See the 2nd red line. There it is given that a[3][4] = -0.000000 .

3) Now see the 3rd red line. a[3][4] = a[3][4]/-0.000000 = 1. How is this possible ?

---------------------------
In order to know, whether 0.0 and -0.0 are treated as same or not on Pelles C, I wrote this simple program.

#include<stdio.h>

main()
{
   float a = -0.0 ;
   if( a != 0.0)
      printf("abnormal thing \n");
}

But Pelles C displays a warning that it could not reach the code printf("abnormal thing \n");
Why is this so ?
Title: Re: What is meant by -0.0 ?
Post by: frankie on February 20, 2013, 08:50:09 AM
Floating point math is not always exact (google around for more info), moreover conversion of a float to ascii represantion is subject to rounding. This means that your result should be something like -0.000000000000000000000000000000001, rounded or trunked to -0.0. You can try to enlarge precision in printf to see it.
i.e.
Code: [Select]
  printf("%20.20f", val);
In your code the constant -0.0 is encoded exactly as 0.0, so the if is resolved to compiler level as never true, and the optimizer removes the not reachable code. try to change to
Code: [Select]
float a = -0.000000000000000000001 ;and you will see something.
Title: Re: What is meant by -0.0 ?
Post by: boral on February 20, 2013, 09:49:09 AM
Yes you are right. I wrote the following program:

#include<stdio.h>

main()
{
   float a = 1/3.0 ;
   printf("a = %f \n",a);
   printf("%20.20f \n", a);
}

We know that 1 divided by 3 is equal to 0.333333333333333333..... ( the 3 goes on and on ) - This is a recurring decimal.

But the second printf gives the answer as 0.33333334326744079589 - which is obviously not true. So the mysterious result in my rank program is just for this.

Thank you frankie for your good reply. It has helped a lot.

--------------------------------
One thing more. Is it possible to store 1/3.0 to a variable ( a say ) correct upto 4 places.
I meant to say that

a = 1/3.0 ;

will store 0.333 in a. Is it possible to do this in any way ? If so, please show it .
Title: Re: What is meant by -0.0 ?
Post by: frankie on February 20, 2013, 11:13:34 AM
Boral, the problem is that computer must represent numbers as powers of 2, while we use powers of 10. Unfortunately happens that some numbers simply cannot be reduced to power of 2 (they are irreducible in base 2) so they rappresentation is unaccurate.
One solution is to use double instead of float. The latter have more mantissa bits allowing better representation.
Title: Re: What is meant by -0.0 ?
Post by: Tino on February 20, 2013, 11:55:23 AM
Hi :)

CommonTater once gave a perfect hint to treat everything connected to money as integer.
If you have for example 2,73 $ make it 273 cent and add the cosmetically "," by hand.

You will gain 100 % correct results that way.

If it gets more breached like 0,3 % of 50 % of 0,70 $ it sure is more conversion work
but in the end result s will be correct while float lead to undefined behaviour.

Just make sure to cover scopes carefully.

Have fun :)
Title: Re: What is meant by -0.0 ?
Post by: Bitbeisser on February 20, 2013, 06:12:50 PM
We know that 1 divided by 3 is equal to 0.333333333333333333..... ( the 3 goes on and on ) - This is a recurring decimal.

But the second printf gives the answer as 0.33333334326744079589 - which is obviously not true. So the mysterious result in my rank program is just for this.
Sorry, but this result isn't mysterious at all...

First of all, Pelle's C is using the IEEE 754 format for real numbers, just like pretty much any other compiler out there.

For your example, you are using a 'float' to calculate your value. If you would bother to read the documentation, you would see that a float is a "single precision" real number format using only 32bit to represent the number, with a defined precision of only 7 digits. So if you print using printf without a specific width, you will get shown the result in exactly 7 digits. In the second printf you complain about, you explicitly decided to ignore the maximum precision and force an output of 20 digits. Hence, the output after the first 7 digits is garbage by definition.

If you for example change the variable type from a "float" to a "double", which as the name implies is a double precision real number, using 64bits and with a defined precision of 16 digits, you will see that your second printf output changes to 0.33333333333333330301. Though while this still exceeds the usable precision, you will see that only the last 4 digits are now garbage.

You need to realize that any usage of real math, including such (partially) workarounds like suggested by CommonTater once, will never be possible to be represented in a limited binary format of standard defined data types...

Ralf
Title: Re: What is meant by -0.0 ?
Post by: Tino on February 20, 2013, 08:36:59 PM
Hi :)

This http://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic is how theoretically infinite large numbers are handled.

Under the hood there is no float needed since if numbers exceed float precision
they have to be broken down anyway.

In the past people said "integers are faster" wich might change
with the trend to use graphiccard for float calculations.

CommonTaters solution is scalable once one starts breaking down big numbers,
i know of no solution to do that with float s.
( no solution wich would require less operations then on int s )

I m curious of how float s could be used more performant ?

Have fun :)
Title: Re: What is meant by -0.0 ?
Post by: jj2007 on February 21, 2013, 02:20:26 AM
You can try to enlarge precision in printf to see it.
i.e.
Code: [Select]
  printf("%20.20f", val);

Enlarging to 20 digit precision won't work well with printf.
For example, PI will be displayed as
3.14159265358979310000
Which is wrong already at the 17th digit. With a print routine that can handle 10-byte floats aka REAL10, you can achieve
3.141592653589793238
- and that is the limit for "simple" algos. Beyond that you need a bignum library.
Title: Re: What is meant by -0.0 ?
Post by: JohnF on February 21, 2013, 08:03:07 AM
If anyone has the time and inclination it would be good to have a bignum library working with PellesC. If one is forthcoming I'll add it to my web site.

John
Title: Re: What is meant by -0.0 ?
Post by: frankie on February 21, 2013, 09:03:15 AM
I would excuse myself on the ground to have put the first number that come to my mind as printf digits ;D 8) ;D ;D ;D ;D
Now seriously, I would come back to the point, and it is that float format has a lot of limits, and they have to be taken in account especially when using that numbers in comparisons.
If the range you need to work on is very large the solution is a bignum as John suggested.
Title: Re: What is meant by -0.0 ?
Post by: TimoVJL on February 21, 2013, 04:37:50 PM
With MAPM
http://www.tc.umn.edu/~ringx004/mapm-main.html
Code: [Select]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "m_apm.h"

#pragma comment(lib, "mapm.lib")

#define DECIMAL_PLACES 40

int main(void)
{
/*
   float a = 1/3.0 ;
   printf("a = %f \n",a);
   printf("%20.20f \n", a);
*/
char buffer[100];
M_APM mapm1, mapm2, mapm3;
mapm1 = m_apm_init();
mapm2 = m_apm_init();
mapm3 = m_apm_init();
m_apm_set_long(mapm1, 1);
m_apm_set_long(mapm2, 3);
m_apm_divide(mapm3, DECIMAL_PLACES, mapm1, mapm2);
m_apm_to_string(buffer, DECIMAL_PLACES, mapm3);
printf("%s\n", buffer);
m_apm_free(mapm1);
m_apm_free(mapm2);
m_apm_free(mapm3);
return 0;
}
Code: [Select]
3.3333333333333333333333333333333333333333E-1
Title: Re: What is meant by -0.0 ?
Post by: JohnF on February 21, 2013, 06:04:21 PM
Thanks timovjl, the zip file has been added to my web site in the libraries section.

John


Title: Re: What is meant by -0.0 ?
Post by: Arijit Pal on March 15, 2013, 08:10:45 AM
hmm valo question soumya.. amio dekhe6i eta.. amio forum e register karlam  8) :D hehe. toke jananor jnya reply di6i
Title: Re: What is meant by -0.0 ?
Post by: Bitbeisser on March 15, 2013, 10:08:54 PM
hmm valo question soumya.. amio dekhe6i eta.. amio forum e register karlam  8) :D hehe. toke jananor jnya reply di6i
In case you missed it, this is an English language forum. And posting such crap as your first post will likely get you banned as a spammer.... >:(

Ralf
Title: Re: What is meant by -0.0 ?
Post by: PlezzeR on March 27, 2013, 10:33:43 AM
Yet another example:
Code: [Select]
#include <stdio.h>

int main(int argc, char *argv[ ])
{
float a = 1;
a = -1 * (a - a);
printf("a = %f\n", a);
a = 0;
a = -1 * a;
printf("b = %f\n", a);
return 0;
}

Result:
Code: [Select]
a = -0.000000
b = -0.000000
Title: Re: What is meant by -0.0 ?
Post by: Bitbeisser on March 27, 2013, 04:07:06 PM
Yet another example:
But still the same answer...

Ralf
Title: Re: What is meant by -0.0 ?
Post by: PlezzeR on March 27, 2013, 04:24:46 PM
More testing
Code: [Select]
#include <stdio.h>
#include <math.h>

#define NUM_A "-0.0000000000000000000000000001"

int main(int argc, char *argv[ ])
{
float a = 1;
float a2 = -0.0000000000000000000000000001;
double b;
a = -10 * (a - a);
printf("-10 * (1 - 1) = %e\n", a);

a = 0;
a = -10 * a;
printf("-10 * 0 = %e\n", a);
a = a / a;
printf("-0 / -0 = %e\n", a);

a = -1.0E-28;
printf("-1.0e-28 = %f\n", a);
printf("-1.0e-28 = %e\n", a);
printf(NUM_A" = %f\n", a2);
printf(NUM_A" = %e\n", a2);
a = powf(a, 2.0);
printf("powf(-1.0E-28, 2.0) = %e\n", a);
a = powf(a2, 2.0);
printf("powf("NUM_A", 2.0) = %e\n", a);
a = powf(-1.0E-28, 15.0);
printf("powf(-1.0E-28, 15.0) = %e\n", a);
a = powf(a2, 15.0);
printf("powf("NUM_A", 15.0) = %e\n", a);

a = a2 / a2;
printf(NUM_A" / "NUM_A" = %e\n", a);

a = a2 / 1.0e+30;
printf(NUM_A" / 1.0e+30 = %e\n", a);
b = a2 / 1.0e+300;
printf(NUM_A" / 1.0e+300 = %e\n", b);

a = 10 / -INFINITY;
printf("10 / -inf = %e\n", a);
return 0;
}

Result:
Code: [Select]
-10 * (1 - 1) = -0.000000e+00
-10 * 0 = -0.000000e+00
-0 / -0 = nan
-1.0e-28 = -0.000000
-1.0e-28 = -1.000000e-28
-0.0000000000000000000000000001 = -0.000000
-0.0000000000000000000000000001 = -1.000000e-28
powf(-1.0E-28, 2.0) = inf
powf(-0.0000000000000000000000000001, 2.0) = inf
powf(-1.0E-28, 15.0) = -inf
powf(-0.0000000000000000000000000001, 15.0) = -inf
-0.0000000000000000000000000001 / -0.0000000000000000000000000001 = 1.000000e+00
-0.0000000000000000000000000001 / 1.0e+30 = -1.000000e-58
-0.0000000000000000000000000001 / 1.0e+300 = -0.000000e+00
10 / -inf = -0.000000e+00

Interesting, if compiler Optimizations = None then:
Code: [Select]
a = a2 / 1.0e+30;
printf(NUM_A" / 1.0e+30 = %e\n", a);

Given the result:
Code: [Select]
-0.0000000000000000000000000001 / 1.0e+30 = -0.000000e+00