I can't reproduce this with a simple program, but somewhere in my program I have something like:
float e = f(...);
if (e > 0.0f) {
...
printf("%f", e) shows that e is 0.000000, yet e > 0.0f is true... So is e > 0 and e > 0.0. What am I missing?
The floating point value is larger than zero, but less than 1e-7. It's printing issue. Use scientific notation printf("%e", value); or "%g" for shortest notation.
The problem is that the floating point value is greater than 0, but less than the precision that printf uses to print floating point numbers with %f. You can use %e or %g for better results as illustrated with the following program.
#include <math.h>
#include <stdio.h>
void main(void)
{
int i;
float e;
for (i = 1; i < 64; i++) {
printf("Decimal places: %d\n", i);
e = 1.0 / pow(10, i);
if (e > 0.0f) {
printf("Value displayed with %%e: %e > 0.0f\n", e);
printf("Value displayed with %%f: %f > 0.0f\n", e);
printf("Value displayed with %%g: %g > 0.0f\n\n", e);
}
}
}
You will need to compile this with the maths library. For gcc use: -lm
The fact that printf("%f", e) shows it to be zero doesn't mean anything, because printf rounds the value both to decimal floating point and to the precision of the output, so very small numbers larger than 0 are likely to be put out as 0.
Try printf("%e", e) or printf("%.17f", e) and see what happens.
Your problem is that e is actually not zero. It has some tiny value in it, but that gets hidden because %f converts to decimal, losing precision. Use printf("%e",e) instead as your debug statement, and you will see that there is a nonzero value in there.
Related
I have problem with floating point rounding. I want to calculate floating point numbers and round them to (given) N decimals. In this example I want to round to 1 decimal places.
Calculation 37.1-28.75 will result into floating point 8.349998 (instead of 8.35), which will result printf rounding to 8.3 instead of 8.4 for 1 decimal places.
The actual result in math is 37.10-28.75=8.35000000, but due to floating point imprecision it is converted into 8.349998, which is then converted into 8.3 instead of 8.4 when using 1 decimal place rounding.
Minimum reproducible example:
float a = 37.10;
float b = 28.75;
//a-b = 8.35 = 8.4
printf("%.1f\n", a - b); //outputs 8.3 instead of 8.4
Is it valid to add following to the result:
float result = a - b;
if (result > 0.0f)
{
result += powf(10, -nr_of_decimals - 1) / 2;
}
else
{
result -= powf(10, -nr_of_decimals - 1) / 2;
}
EDIT: corrected that I want 1 decimal place rounded output, not 2 decimal places
EDIT2: negative results are needed as well (28.75-37.1 = -8.4)
On my system I do actually get 8.35. It's possible that you have to set the rounding direction to "nearest" first, try this (compile with e.g. gcc ... -lm):
#include <fenv.h>
#include <stdio.h>
int main()
{
float a = 37.10;
float b = 28.75;
float res = a - b;
fesetround(FE_TONEAREST);
printf("%.2f\n", res);
}
Binary floating point is, after all, binary, and if you do care about the correct decimal rounding this much, then your choices would be:
decimal floating point, or
fixed point.
I'd say the solution is to use fixed point, especially if you're on embedded, and forget about everything else.
With
int32_t a = 3710;
int32_t b = 2875;
the result of
a - b
will exactly be
835
every time; and then you just need to have a simple fixed point printing routine for the desired precision, and check the following digit after the last digit to see if it needs to be rounded up.
If you want to round to 2 decimals, you can add 0.005 to the result and then offset it with floorf:
float f = 37.10f - 28.75f;
float r = floorf((f + 0.005f) * 100.f) / 100.f;
printf("%f\n", r);
The output is 8.350000
Why are you using floats instead of doubles?
Regarding your question:
Is it valid to add following to the result:
float result = a - b;
if (result > 0.0f)
{
result += powf(10, -nr_of_decimals - 1) / 2;
}
else
{
result -= powf(10, -nr_of_decimals - 1) / 2;
}
It doesn't seem so, on my computer I get 8.350498 instead of 8.350000.
After your edit:
Calculation 37.1-28.75 will result into floating point 8.349998, which will result printf rounding to 8.3 instead of 8.4.
Then
float r = roundf((f + (f < 0.f ? -0.05f : +0.05f)) * 10.f) / 10.f;
is what you are looking for.
I'm trying to print out the decimal expansion of a rational number in C. The problem I have is that when I divide the numerator by the denominator I lose precision. C rounds up the repeating part when I don't want it to.
For example, 1562/4995 = 0.3127127127... but in my program I get 1562/4995 = 0.312713. As you can see a part of the number that I need has been lost.
Is there a way to specify C to preserve a higher level of decimal precision?
I have tried to declare the result as a double, long double and float. I also tried to split the expansion into 2 integers seperated by a '.'
However both methods haven't been successful.
int main() {
int numerator, denominator;
numerator = 1562;
denominator = 4995;
double result;
result = (double) numerator / (double) denominator;
printf("%f\n", result);
return 0;
}
I expected the output to be 1562/4995 = 0.3127127127... but the actual output is 1562/4995 = 0.312713
The %f format specifier to printf shows 6 digits after the decimal point by default. If you want to show more digits, use a precision specifier:
printf("%.10f\n", result);
Also, the double type can only accurately store roughly 16 decimal digits of precision.
You need to change your output format, like this:
printf("%.10lf\n", result);
Note two things:
The value after the . specifies the decimal precision required (10 decimal places, here).
Note that I have added an l before the f to explicitly state that the argument is a double rather than a (single-precision) float.
EDIT: Note that, for the printf function, it is not strictly necessary to include the l modifier. However, when you come to use the 'corresponding' scanf function for input, it's absence will generate a warning and (probably) undefined behaviour:
scanf("%f", &result); // Not correct
scanf("%lf", &result); // Correct
If printing is all you want to do, you can do this with the same long division you were taught in elementary school:
#include <stdio.h>
/* Print the decimal representation of N/D with up to
P digits after the decimal point.
*/
#define P 60
static void PrintDecimal(unsigned N, unsigned D)
{
// Print the integer portion.
printf("%u.", N/D);
// Take the remainder.
N %= D;
for (int i = 0; i < P && N; ++i)
{
// Move to next digit position and print next digit.
N *= 10;
printf("%u", N/D);
// Take the remainder.
N %= D;
}
}
int main(void)
{
PrintDecimal(1562, 4995);
putchar('\n');
}
I am making this big program in C, which is a part of my homework. My problem is that my program is outputing x = -0.00 instead of x = 0.00. I have tried comparing like if(x==-0.00) x=fabs(x) but I've read that it won't work like that with doubles. So my question is are there any other ways to check if double is equal to negative zero?
You can use the standard macro signbit(arg) from math.h. It will return nonzero value if arg is negative and 0 otherwise.
From the man page:
signbit() is a generic macro which can work on all real floating-
point types. It returns a nonzero value if the value of x has its
sign bit set.
This is not the same as x < 0.0, because IEEE 754 floating point
allows zero to be signed. The comparison -0.0 < 0.0 is false, but
signbit(-0.0) will return a nonzero value.
NaNs and infinities have a sign bit.
Also, from cppreference.com:
This macro detects the sign bit of zeroes, infinities, and NaNs. Along
with copysign, this macro is one of the only two portable ways to
examine the sign of a NaN.
Very few calculations actually give you a signed negative zero. What you're probably observing is a negative value close to zero that has been truncated by your formatting choice when outputting the value.
Note that -0.0 is defined to be equal to 0.0, so a simple comparison to 0.0 is enough to verify a signed zero.
If you want to convert an exact signed zero -0.0 to 0.0 then add 0.0 to it.
Most likely, your program has a small negative value, not zero, which printf formats as “-0.00”. To print such numbers as “0.00”, you can test how printf will format them and replace the undesired string with the desired string:
#include <stdio.h>
#include <string.h>
void PrintAdjusted(double x)
{
char buffer[6];
int result = snprintf(buffer, sizeof buffer, "%.2f", x);
/* If snprintf produces a result other than "-0.00", including
a result that does not fit in the buffer, use it.
Otherwise, print "0.00".
*/
if (sizeof buffer <= result || strcmp(buffer, "-0.00") != 0)
printf("%.2f", x);
else
printf("0.00");
}
This is portable. Alternatives such as comparing the number to -0.005 have portability issues, due to implementation-dependent details in floating-point formats and rounding methods in printf.
If you truly do want to test whether a number x is −0, you can use:
#include <math.h>
…
signbit(x) && x == 0
There are two functions you need here.
First, the signbit function can tell you if the sign bit is set on a floating point number. Second, the fpclassify function will tell you if a floating point number is some form of 0.
For example:
double x = 0.0;
double y = -0.0;
double a = 3;
double b = -2;
printf("x=%f, y=%f\n", x, y);
printf("x is zero: %d\n", (fpclassify(x) == FP_ZERO));
printf("y is zero: %d\n", (fpclassify(y) == FP_ZERO));
printf("a is zero: %d\n", (fpclassify(a) == FP_ZERO));
printf("b is zero: %d\n", (fpclassify(b) == FP_ZERO));
printf("x sign: %d\n", signbit(x));
printf("y sign: %d\n", signbit(y));
printf("a sign: %d\n", signbit(a));
printf("b sign: %d\n", signbit(b));
Output:
x=0.000000, y=-0.000000
x is zero: 1
y is zero: 1
a is zero: 0
b is zero: 0
x sign: 0
y sign: 1
a sign: 0
b sign: 1
So to check if a value is negative zero, do the following:
if (fpclassify(x) == FP_ZERO)) {
if (signbit(x)) {
printf("x is negative zero\n");
} else {
printf("x is positive zero\n");
}
}
To always get the non-negative version, you don't need the comparison at all.
You can take the absolute value all of the time. If the value is non-negative, fabs should return the original value.
Given this code that my professor gave us in an exam which means we cannot modify the code nor use function from other libraries (except stdio.h):
float x;
(suppose x NOT having an integer part)
while (CONDITION){
x = x*10
}
I have to find the condition that makes sure that x has no valid number to the right of decimal point not giving attention to the problems of precision of a float number (After the decimal point we have to have only zeros). I tried this condition:
while ((fmod((x*10),10))){
X = X*10
}
printf(" %f ",x);
example:
INPUT x=0.456; --------> OUTPUT: 456.000
INPUT X=0.4567;--------> OUTPUT; 4567.000
It is important to be sure that after the decimal point we don't have any
significant number
But I had to include math.h library BUT my professor doesn't allow us to use it in this specific case (I'm not even allowed to use (long) since we never seen it in class).
So what is the condition that solve the problem properly without this library?
As pointed out here previously:Due to the accuracy of floats this is not really possible but I think your Prof wants to get something like
while (x - (int)x != 0 )
or
while (x - (int)x >= 0.00000001 )
You can get rid of the zeroes by using the g modifier instead of f:
printf(" %g \n",x);
There is fuzziness ("not giving attention to the problems of precision of a float number") in the question, yet I think a sought answer is below, assign x to an integer type until x no longer has a fractional part.
Success of this method depends on INT_MIN <= x <= INT_MAX. This is expected when the number of bits in the significant of float does not exceed the value bits of int. Although this is common, it is not specified by C. As an alternative, code could with a wider integer type like long long with a far less chance of the range restriction issue.
Given the rounding introduced with *10, this method is not a good foundation of float to text conversion.
float Dipok(float x) {
int i;
while ((i=x) != x) {
x = x*10;
}
return x;
}
#include <assert.h>
#include <stdio.h>
#include <float.h>
void Dipok_test(float x) {
// suppose x NOT having an integer part
assert(x > -1.0 && x < 1.0);
float y = Dipok(x);
printf("x:%.*f y:%.f\n", FLT_DECIMAL_DIG, x, y);
}
int main(void) {
Dipok_test(0.456);
Dipok_test(0.4567);
return 0;
}
Output
x:0.456000000 y:456
x:0.456699997 y:4567
As already pointed out by 2501, this is just not possible.
Floats are not accurate. Depending on your platform, the float value for 0.001 is represented as something like 0.0010000001 in fact.
What would you expect the code to calculate: 10000001 or 1?
Any solution will work for some values only.
I try to answer to my exam question please if I say something wrong correct me!
It is not possible to find a proper condition that makes sure that there are no valid number after the decimal point. For example : We want to know the result of 0.4*20 which is 8.000 BUT due to imprecision problems the output will be different:
f=0.4;
for(i=1;i<20;i++)
f=f+0.4;
printf("The number f=0.4*20 is ");
if(f!=8.0) {printf(" not ");}
printf(" %f ",8.0);
printf("The real answer is f=0.4*20= %f",f);
Our OUTPUT will be:
The number f=0.4*20 is not 8.000000
The real answer is f=0.4*20= 8.000001
I just encountered a behaviour I don't understand in a C program that I'm using.
I guess it's due to floating numbers, maybe int to float cast, but still I would like someone to explain to me that this is a normal behaviour, and why.
Here is my C program :
#include <stdio.h>
#include <float.h>
int main ()
{
printf("FLT_MIN : %f\n", FLT_MIN);
printf("FLT_MAX : %f\n", FLT_MAX);
float valueFloat = 0.000000;
int valueInt = 0;
if (valueInt < FLT_MIN) {
printf("1- integer %d < FLT_MIN %f\n", valueInt, FLT_MIN);
}
if (valueFloat < FLT_MIN) {
printf("2- float %f < FLT_MIN %f\n", valueFloat, FLT_MIN);
}
if (0 < 0.000000) {
printf("3- 0 < 0.000000\n");
} else if (0 == 0.000000) {
printf("4- 0 == 0.000000\n");
} else {
printf("5- 0 > 0.000000\n");
}
if (valueInt < valueFloat) {
printf("6- %d < %f\n", valueInt, valueFloat);
} else if (valueInt == valueFloat) {
printf("7- %d == %f\n", valueInt, valueFloat);
} else {
printf("8- %d > %f\n", valueInt, valueFloat);
}
return 0;
}
And here is my command to compile and run it :
gcc float.c -o float ; ./float
Here is the output :
FLT_MIN : 0.000000
FLT_MAX : 340282346638528859811704183484516925440.000000
1- integer 0 < FLT_MIN 0.000000
2- float 0.000000 < FLT_MIN 0.000000
4- 0 == 0.000000
7- 0 == 0.000000
A C developper that I know consider normal that the line "1-" displays become of the loss of precision in the comparison. Let's admit that.
But why the line "3-" doesn't appear then, since it's the same comparison ?
Why the line "2-" appears, since I'm comparing the same numbers ? (or at least I hope so)
And why lines "4-" and "7-" appear ? It seems a different behaviour from line "1-".
Thanks for your help.
Your confusion is probably over the line:
printf("FLT_MIN : %f\n", FLT_MIN);
change it to:
printf("FLT_MIN : %g\n", FLT_MIN);
And you will see, that FLT_MIN is actually NOT zero, but a (tiny bit) larger than zero.
FLT_MIN is not 0, it's just above 0, you just need to show more places to see that. FLT_MIN is the smallest floating point number above 0 that the computer can represent, since floating points are almost always an approximation, printf and friends round when printing, unless you ask it for the precision:
printf("FLT_MIN : %.64f\n", FLT_MIN);
3 does not actually appear in your output because 0 is not less than 0
4 is comparing 0 with 0, the computer has no problem representing both of those (0 is a special case for floats) so they compare equal
7 is the same case as 4 just with intermediate assignments
This is correct behaviour. Under IEEE754, zero is exactly representable as a float. Therefore it can be 'equal' to integer zero (although 'equivalent' would be a better term). FLT_MIN is the smallest magnitude number that can be represented as a float and still be distinguished from zero. Even though a standard %f format specifier to printf() will show FLT_MIN as 0.000000, it is not zero. A literal 0.00... will be interpreted by the compiler as float 0, which is not equal to FLT_MIN, even though the default six decimal place %f format will print them the same.