-1

I have an issue with the following code I have been writing. I am trying to compare capacitors to standard values on a chart to see if they are in the array I created or not. I am having issues when I enter 0.01, 0.001, 0.0001 etc. With the following code, all of these numbers should be multiplied by a certain factor of 10 to get the number within a range of 10 to 99. When I enter 0.01 for example, it multiplies it by 10,000 instead of 1000 where it should be. If you see any error with the code let me know.

void checkstd_cap (float c)
{
    if(c >= .000001 && c <= 10000)   // This if statement is used to get the users entered capacitor 
    value between 10 and 99, 
                                 // which is the range in the array for capacitor standard values
    {
    if(c >= 10000)
    c /= 1000;
    
    if(c >= 1000 && c <= 9999)
    c /= 100;
    
    if(c >= 100 && c <= 999)
    c /= 10;
    
    if(c >= 10 && c <= 99)
    c /= 1;
    
    if(c >= 1.0 && c <= 9.999999)
    c *= 10;

    if(c >= 0.1 && c <= 0.999999)
    c *= 100;
    
    if(c >= 0.01 && c <= 0.0999999)
    c *= 1000;
    
    if(c >= 0.001 && c <= 0.00999999)
    c *= 10000;
    
    if(c >= 0.0001 && c <= 0.000999999)
    c *= 100000;
    
    if(c >= 0.00001 && c <= 0.0000999999)
    c *= 1000000;
    
    if(c >= 0.000001 && c <= 0.00000999999)
    c *= 10000000;
    }

        int i = 0; // i is initilized to 0
    
        while( i<6 ) /* If i reaches 12, this proves resistor B is not standard
                     and a warning message is printed */
        {
            if (fabs(c - STDVC[i]) <= 0.01)
            {
                printf("Capacitor is a standard value");
                break; /* while loop breaks if this statement above is true as this 
                         proves capacitor is a standard value */
            }
            else
            {
            i++; // if the capacitor is not standard, i keeps incrementing to 6
            }       
        }
        
        while (i == 6) /* If i reaches 6, this proves the capacitor is not standard
                     and a warning message is printed */
        {
            printf("Warning: Capacitor is not a standard value\n");
            break;
        }
}
  • 4
    Related: [language agnostic - Is floating point math broken? - Stack Overflow](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – MikeCAT Oct 02 '20 at 18:14
  • 1. No math is being done, it is simply comparing an input. 2. I used the greater than or equal to account for possible extra digits. If 0.0100000001 ends up being the input the computer reads, it should still be in the same if statement as 0.01 –  Oct 02 '20 at 18:17
  • 2
    Values may be smaller than written. [demo: 0.01 became 0.009999999776482582092285156250](https://ideone.com/1Z6wS1) – MikeCAT Oct 02 '20 at 18:21
  • Also note that you are comparing `float` and `double`. [floating point - Comparing float and double in C - Stack Overflow](https://stackoverflow.com/questions/59115928/comparing-float-and-double-in-c) – MikeCAT Oct 02 '20 at 18:25
  • Don't use floating point numbers, use integer numbers with a prescaler-factor, like pF (1 pico Farad = 10^-12 Farad = 0.000000000001 Farad). As an example: instead of `if(c >= 1.0 && c <= 9.999999) c *= 10;`, using floating point numbers, use `if(c >= 1000000000000 && c <= 9999999000000) c *= 10000000000000;`, using integer numbers. – paladin Oct 02 '20 at 19:13
  • PS dont compare like `if(c >= 100 && c <= 999)`, this is stupid. Better compare like: `if(c >= 100 && c < 1000)` – paladin Oct 02 '20 at 19:19

1 Answers1

1

The values 0.1, 0.01, 0.001 can't be expressed exactly in binary floating point. For example, on my system this:

float x= 0.01;
printf("x=%.15f\n", x);

prints this:

x=0.009999999776483

The main problem here is how you're doing the comparisons:

if(c >= 0.01 && c < 0.0999999)
c *= 1000;

if(c >= 0.001 && c <= 0.00999999)
c *= 10000;

When 0.01 is assigned to c, the actual value appears in between some of these ranges. You need to change your comparisons so that the ranges are adjacent:

if(c >= 0.01 && c < 0.1)
c *= 1000;

if(c >= 0.001 && c < 0.01)
c *= 10000;

Or better yet, use an if...else chain and just check the lower bound:

if (c >= 10000) {
    c /= 1000;
} else if (c >= 1000) {
    c /= 100;
} else if (c >= 100) {
    c /= 10;
} else  if (c >= 10) {
    c /= 1;
} else if (c >= 1.0) {
    c *= 10;
} else  if (c >= 0.1) {
    c *= 100;
} else if (c >= 0.01) {
    c *= 1000;
} else if (c >= 0.001) {
    c *= 10000;
} else if (c >= 0.0001) {
    c *= 100000;
} else if (c >= 0.00001) {
    c *= 1000000;
} else if (c >= 0.000001) {
    c *= 10000000;
}

Better still, get rid of the long chain of ifs and just use a pair of loops:

while (c < 10) {
    c *= 10;
}
c = round(c);
while (c >= 100) {
    c /= 10;
}

Here we deal with smaller numbers first to get the value larger than 10, then we round it to an integer and deal with larger numbers.

dbush
  • 205,898
  • 23
  • 218
  • 273