1

I am trying to get the amount of decimals a number has in c: 0.0001 -> 4 decimals, 3,54235 -> 5 decimals, and so on (If you don't get it, the number of numbers behind the comma.) our teacher sais it can be done in two ways, using a string and not using a string. I figured i would go ahead not using a string because I have NO experiance with strings.

So this is what I came up with

int funzione1(float decimals){
  int x=1,c=0,y=1;
  while (x!=0){
      if((decimals - y) > 0){
          y = y / 10;
          c++;
      }else{
          decimals = decimals - y;
      }
      if(decimals == 0)
          x=0;
  }
  return c-1;
}

When calling the function it should return the amount of decimals I figured, but it does not, actually it gets stuck in an infinite loop.

the Idea behind this code was to for every number in the "string" of numbers to get them to 0 and then check if the total number was 0

3.456 c=0

0.456 c=1

0.056 c=2

0.006 c=3

0.000 return c

But That leaves me with two problems 1 how to detirmine tha amount of numbers before the comma for like 5564.34234 this code will not work because it will count to 8 before the full number is a solid 0. and therefor not return the right number of decimals.2. the code I designed isn't working. Just gets stuck in an infinite loop. I don't know where the infiniteness of the loop is created.

How do i get this code to work?

PS. I found this article about this problem in Java: How to find out how many decimals a number has? but it is using strings and I would not like that because of the fact that I don't know how to use strings.

edit: Here is another piece of code i tried and which faild really bad givving an output of 50 when you enter a number higher than 1 and 0 if the number is lower than 0(I don't get it, not a little bit) anyway here is the code:

int funzione1(float decimals){
    int i=0;
    while(decimals!=((int)decimals)){
        i++;
        decimals=decimals*10;
    }
    return i;
}
Community
  • 1
  • 1
BRHSM
  • 854
  • 3
  • 13
  • 48
  • `numbers behind the "comma"`.. are you sure about this? – Sourav Ghosh Feb 05 '15 at 08:59
  • ahh I get it I might try it this way – BRHSM Feb 05 '15 at 09:01
  • 1
    also, IMHO, `I don't know how to use strings` may be the case, but why not start learning? Believe me, at times, it will make your life a little bit easy. :-) – Sourav Ghosh Feb 05 '15 at 09:01
  • That's true but I kinda want this to work aswell just to not be a faliure at this peice of code, also changeing d to decimals and removing decimals as an intergrated variable from the function does not work. still the same infinite loop – BRHSM Feb 05 '15 at 09:03
  • did you try to `printf("%.50f\n", decimals);` in the loop to see what's going on? – mch Feb 05 '15 at 09:31
  • that will not work because I need the number later in the program to make calcolations not just an output – BRHSM Feb 05 '15 at 09:32
  • Latest edit worked for me.. what's the failing condition ? – Kavindu Dodanduwa Feb 05 '15 at 09:34
  • what is a falling condition? I don't know what that means – BRHSM Feb 05 '15 at 09:35
  • 1
    @CoderGuy: In your first function, doesn't the `>` want to be a `<`? I still think that implementation will have problems, due to the inexactness of floating point numbers (as others have mentioned), but that should get you closer I think. – psmears Feb 05 '15 at 09:36
  • nope gives the same output as the code in the edit: 50 which has no sense – BRHSM Feb 05 '15 at 09:39

4 Answers4

2

Your best bet would be to read the input as string and just count the digits after '.'. Floating point numbers are not exact representation i.e. the decimal values are stored in binary internally and may not exactly represent the true decimal value. However every binary representation is some decimal number with finite digits.

Have a look at this answer in SO.

Community
  • 1
  • 1
a_pradhan
  • 3,285
  • 1
  • 18
  • 23
  • that might be an awnser but as I said in the comments on the question I would like to try it without the strings because I want to finish what I starded – BRHSM Feb 05 '15 at 09:11
  • Getting the correct answer without using strings is hard as you have to do the rounding yourself. The binary representation of 0.2 doesn't equal exactly 0.2 so unless whatever algorithm you make converts the number into base 10 and rounds before it starts you will get the wrong answer. Converting to a string will normally do this for you. – James Snook Feb 05 '15 at 09:36
2

If you don't care about rounding then you don't need to count the number of decimal places, you can just count the number of binary places. This is because 10 contains 2 as a factor exactly once so 10^n and 2^n have the same number of 2s as factors. The fastest way to count the number of binary places is to get the exponent of the floating point number.

e.g. binary 0.001 takes 3 decimal places to represent 0.125, 0.0001 takes 4 0.0625.

You can either get the fractional part of the value and keep multiplying by 2 and removing the integer as people have suggested doing with 10 (it will give you the same answer).

Or you can have a bit more fun over optimising the solution (the places function does most of the work):

#include <math.h>

int saturateLeft (unsigned int n) {
  n |= (n <<  1);
  n |= (n <<  2);
  n |= (n <<  4);
  n |= (n <<  8);
  n |= (n << 16);
  return n;
}

int NumberOfSetBits(int i)
{
  i = i - ((i >> 1) & 0x55555555);
  i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
  return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
}

int places (double num) {
  int exponent;
  float mantissa = frexp (num, &exponent);

  /* The answer we are looking for is given by the 
     (number of bits used by mantissa) - the exponent.
  */

  unsigned intMantissa = scalbnf (mantissa, 32);
  /* Could also be got by doing:
     intMantissa = *(unsigned *)&mantissa << 9;
  */

  /* To work out how many bits the mantissa covered we 
     need no gaps in the mantissa, this removes any gaps.
  */

  intMantissa = saturateLeft (intMantissa);
  int bitCount = NumberOfSetBits (intMantissa);

  /* bitCount could also be found like this:
     intMantissa = ~intMantissa;
     int bitCount = 32 - ilogb (intMantissa) - 1;
  */

  int result = bitCount - exponent;
  if (result < 0)
    return 0;

  return result;
}

The bitCounting algorithm was found here.

Community
  • 1
  • 1
James Snook
  • 4,063
  • 2
  • 18
  • 30
  • How would this help me answering the problem? I am just curious how to implement rour foundings in the code I have and get the right output – BRHSM Feb 05 '15 at 10:14
1

Here's an idea:

  • Start with a floating point number, say a = 3.0141589
  • Make the part before the decimal point 0 by subtracting the integral part, leaving 0.0141589
  • In a loop, multiply a by 10 and save the integral part, this gives you a list of digits from 0 to 9.
  • From this list, derive the number of decimals

There are some interesting details in this algorithm for you to find out, and I won't spoil the fun or surprises waiting for you.

Jens
  • 69,818
  • 15
  • 125
  • 179
  • just if I mess up really bad, fiured from you "Not spoiling the fun" you know the answer to the problem – BRHSM Feb 05 '15 at 09:08
  • There's no single answer; there are several ways to count decimals after the decimal point. This is what I came up with after thinking a little bit, so it's likely not optimal, but nevertheless instructive. The fun part is what happens when you run the algo on numbers like 1/3. The finite precision of floats may yield some surprising results. – Jens Feb 05 '15 at 09:13
  • but do you know one of them? I tried something else and I messed up – BRHSM Feb 05 '15 at 09:26
  • @Jens A good answer. And i think CoderGuy have found the hidden surprise ;) – Kavindu Dodanduwa Feb 05 '15 at 09:37
  • @CoderGuy Yes I know one of them. This answer is one of them. No matter what solution you use, the results are the same (assuming your notion of *decimal digits after the comma* is implemented the same way). – Jens Feb 05 '15 at 10:16
0

Consider my string-based solution:

#include <stdio.h>
#include <string.h>
#include <locale.h>
#include <math.h>
#include <float.h>
int countDecimals(double x)
{
    int cnt;
    char * ptr;
    char str[20] = {0};
    // take  fractional part from x
    double ip;
    double fp = modf (x , &ip);
    // printf("%lg + %.15lg\n", ip, fp); // uncomment for debugging
    // to be sure that Decimal-point character is '.'
    setlocale(LC_NUMERIC, "C");
    // make string from number's fractional part asking maximum digits (DBL_DIG)
    sprintf(str,"%.*lg", DBL_DIG, fp);
    // find point
    if( ptr = strchr(str, '.') )
    {
        // calculate length of string after point
        // length - (point position from beginning) - point = number of decimals
        cnt = strlen(str) - (ptr - str) - 1;
    }
    else
    {
        cnt = 0;
    }
    return cnt;
}

int main (void)
{
    double fn;
    printf("Enter a float number: ");
    scanf("%lf", &fn);
    printf("Your number has %d decimals.\n" , countDecimals(fn) );
    return 0;
}

But you should remember about possible rounding and accuracy errors.

Note: I have used double type, for float function modff should be used instead of modf, and FLT_DIG instead of DBL_DIG

VolAnd
  • 6,367
  • 3
  • 25
  • 43
  • you said you had to use double, why? – BRHSM Feb 05 '15 at 15:08
  • I used `double`, but `float` also possible. `Double` just has better accuracy – VolAnd Feb 05 '15 at 15:13
  • If you need only float try to rewrite for float, and if you have trouble, just write in the comments – VolAnd Feb 05 '15 at 15:14
  • Okey, so using a double would be more accurate? – BRHSM Feb 05 '15 at 15:30
  • Yes, double use more memory and DBL_DIG always is bigger than FLT_DIG (for my compiler FLT_DIG just 6 digits accuracy, but DBL_DIG defines 15 decimal digits accuracy, see in `float.h`) – VolAnd Feb 05 '15 at 15:32
  • ahh okey so the precicion depends on the statement not on the variable type, and the statement has to be for the correct variable type – BRHSM Feb 05 '15 at 15:49
  • Actually, accuracy depends on type, statements (functions, constants, etc.) depend on data type. – VolAnd Feb 05 '15 at 16:16
  • That's what I ment, if it is a double the function will be more accurate because a double is more accurate. – BRHSM Feb 08 '15 at 12:31
  • Yes. You are right. But sometimes initial data or output requirements setup restrictions on datatype choice. – VolAnd Feb 08 '15 at 13:56
  • so some calculationsight not work when using a floar but will work when using double, like this one – BRHSM Feb 08 '15 at 14:02
  • Yes, underflow and overflow are less expected with double. But double need more memory to store data. – VolAnd Feb 08 '15 at 14:57
  • It worth if it is possible. I think in your case it is possible. – VolAnd Feb 08 '15 at 16:35
  • You can do two variants: for float and for double, and test at different numbers – VolAnd Feb 08 '15 at 16:43