-1

I searched but couldn't find anyone with my problem.
I have this :

    float num;
    scanf("%f" , &num);

But actually when I enter 4.2 it assumes it is 4.199999999. Why?
what should I do with this issue? I want to use 4.2, but all my calculations ruined.

edit: Wow @chux 's answer was wonderful. I didn't know that function exists. this:

num = roundf(n * 100);

is the trick I needed.

Nahid Ataei
  • 59
  • 2
  • 9
  • 1
    `float` type has a limited number of bits so has limited precision. – ouah Mar 21 '14 at 20:34
  • [What every programmer should know about floating point](http://floating-point-gui.de/). – Richard J. Ross III Mar 21 '14 at 20:38
  • For me `4.199999999...` is an acceptable representation of `4.2` in computer realm. – masoud Mar 21 '14 at 20:40
  • @dandan78 alright. I found the answer to why. But how to overcome. is there any trick? – Nahid Ataei Mar 21 '14 at 20:42
  • @MM. But it's not acceptable for my code. I need to decrement 4.2*100 until I reach 0. But now it never reaches. It will always have fractions remained. – Nahid Ataei Mar 21 '14 at 20:48
  • 2
    @NahidAtaei You could use a very small epsilon to test. Basically set a variable to a very specific number (less than 1), and check whether or not the number is outside of the parameters of your number, and if so, throw an exception or a flag. – ciphermagi Mar 21 '14 at 20:49
  • @Nahid, since you were REQUIRED to use a float, I think your instructor was trying to teach you exactly what you discovered: That floating point is treacherous when you need precise values. – Joshua Clayton Mar 21 '14 at 21:36

5 Answers5

4

Some fractional numbers cannot be represented precisely in binary.

In the binary system, you can represent

Binary     Decimal
 0.1        0.5
 0.01       0.25
 0.001      0.125
 0.0001     0.0625
 0.00001    0.03125
 0.000001   0.015625
 0.0000001  0.0078125
 0.00000001 0.00390625

As you might imagine, there is no way to combine these binary digits to form the value 0.1 or 0.2. You can only get an approximate value, which is 0.199999999 in your case.

If you need precise arithmetic, you must not use floating point values.

Depending on your need (e.g. represent money values), you might want to look into Fixed-point arithmetic.

Olaf Dietsche
  • 72,253
  • 8
  • 102
  • 198
1

It's just a small precision error which is present in every machine. Look up IEEE's standards. This might help.

ciphermagi
  • 747
  • 3
  • 14
1

If you MUST have a precise decimal value, you have to use an integer type internally. There is some care to be taken, but its not hard to do:

#include <stdio.h>

int main(int argc, char **argv)
{
    int temp1;
    int temp2;
    int factor = 100;
    int result;
    scanf("%i.%i", &temp1, &temp2);
    result = temp1 * factor;
    while (temp2 >= factor)
    {
        temp2 /= 10;
    }
    while (temp2 < factor / 10)
    {
        temp2 *= 10;
    }
    result += temp2;

    printf("%i is exacty %i times the input\n", result, factor);
}

EDIT: There is a problem with the code I posted. It does not properly handle a value like 4.02. this can be overcome by parsing the number string. Below is better (if still basic)

#include <stdio.h>

int strntofixed(char * str, size_t len, int decimal_places)
{
    int result = 0;
    /* gobble up white space */
    while (len && isblank(*str)){
        --len;
        ++str;
    }
    /* get the whole number */
    while (len && isdigit(*str)) {
        result = result * 10 + (int)(*str - '0');
        --len;
        ++str;
    }
    /* check for a decimal point */
    if (len && *str == '.')
    {
        --len;
        ++str;
    }
    /* get as many decimalplaces as called for */
    while (decimal_places) {
        result *= 10;
        --decimal_places;
        if (len && isdigit(*str)) {
            result += (int)(*str - '0');
            --len;
            ++str;
        }
    }
    return result;
}

int main(int argc, char **argv)
{
    int num;
    char str[50];
    scanf("%s", str);
    num = strntofixed(str, 50, 2);
    printf("%i is exacty the input * 10 to the %i \n", num, 2);
}                
Joshua Clayton
  • 1,669
  • 18
  • 29
  • 1
    Some thoughts: use `isspace()` for white-space. No detection for +,- sign. Use wider `int` like `long long` as `int` is only guaranteed to 16 bits. What to do if extra decimal places - should not it round? – chux - Reinstate Monica Mar 21 '14 at 21:44
  • @chux Thanks for the comments on how to take a code example and make it usable – Joshua Clayton Mar 21 '14 at 21:56
1

If the overall goal is to decrement num*100 until 0, then

float num;
scanf("%f" , &num);
num = roundf(num * 100);
while (num > 0.0) num -= 1.0;

As long as num * 100 less than about power(10,FLT_DECIMAL_DIG) and (positive), you are OK.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • 2
    This does gloss over finer details of FP like what happens when you enter 4.205 - will it decrement 420 or 421 times. But to answer that we need more detail of the coding goals. The others' references to FP math issues if worth the time. – chux - Reinstate Monica Mar 21 '14 at 21:31
  • This is nice. In some cases (e.g. financials) you have to completely avoid rounding errors. See my answer for completely avoiding any rounding – Joshua Clayton Mar 21 '14 at 21:31
  • @chux Actually 'num' is the money in dollars. I don't use dollars in my country :D ,but I think we don't say $4.205 and there is just 2 fractions. Yeah? So I won't have that kind of problem when rounding. Do I? – Nahid Ataei Mar 21 '14 at 21:46
  • I see gas prices here like $3.129. Of course the payment is rounded to the nearest $0.01. Sales tax rate maybe 7.125%. There are all sorts of rounding considerations. BTW: I'd used `double`. the exact range of `float` is too small. `double` exact range exceeds the US national debt by about 10x – chux - Reinstate Monica Mar 21 '14 at 21:51
-2

try using double instead of float. double has better precision

adikshit
  • 205
  • 3
  • 10