C/C++ counting the number of decimals?

63,742

Solution 1

Two ways I know of, neither very clever unfortunately but this is more a limitation of the environment rather than me :-)

The first is to sprintf the number to a big buffer with a "%.50f" format string, strip off the trailing zeros then count the characters after the decimal point. This will be limited by the printf family itself. Or you could use the string as input by the user (rather than sprintfing a floating point value), so as to avoid floating point problems altogether.

The second is to subtract the integer portion then iteratively multiply by 10 and again subtract the integer portion until you get zero. This is limited by the limits of computer representation of floating point numbers - at each stage you may get the problem of a number that cannot be represented exactly (so .2155 may actually be .215499999998). Something like the following (untested, except in my head, which is about on par with a COMX-35):

count = 0
num = abs(num)
num = num - int(num)
while num != 0:
    num = num * 10
    count = count + 1
    num = num - int(num)

If you know the sort of numbers you'll get (e.g., they'll all be 0 to 4 digits after the decimal point), you can use standard floating point "tricks" to do it properly. For example, instead of:

while num != 0:

use

while abs(num) >= 0.0000001:

Solution 2

Once the number is converted from the user representation (string, OCR-ed gif file, whatever) into a floating point number, you are not dealing with the same number necessarily. So the strict, not very useful answer is "No".

If (case A) you can avoid converting the number from the string representation, the problem becomes much easier, you only need to count the digits after the decimal point and subtract the number of trailing zeros.

If you cannot do it (case B), then you need to make an assumption about the maximum number of decimals, convert the number back into string representation and round it to this maximum number using the round-to-even method. For example, if the user supplies 1.1 which gets represented as 1.09999999999999 (hypothetically), converting it back to string yields, guess what, "1.09999999999999". Rounding this number to, say, four decimal points gives you "1.1000". Now it's back to case A.

Solution 3

Off the top of my head:

start with the fractional portion: .2155

repeatedly multiply by 10 and throw away the integer portion of the number until you get zero. The number of steps will be the number of decimals. e.g:

.2155 * 10 = 2.155
.155 * 10 = 1.55
.55 * 10 = 5.5
.5 * 10 = 5.0

4 steps = 4 decimal digits

Solution 4

Something like this might work as well:

float i = 5.2154;
std::string s;
std::string t;
std::stringstream out;
out << i;
s = out.str();

t = s.substr(s.find(".")+1);
cout<<"number of decimal places: " << t.length();

Solution 5

using the Scientific Notation format (to avoid rounding errors):

#include <stdio.h>
#include <string.h>

/* Counting the number of decimals
 *
 * 1. Use Scientific Notation format
 * 2. Convert it to a string
 * 3. Tokenize it on the exp sign, discard the base part
 * 4. convert the second token back to number
*/

int main(){

   int counts;
   char *sign;
   char str[15];
   char *base;
   char *exp10;
   float real = 0.00001;

   sprintf (str, "%E",  real);
   sign= ( strpbrk ( str, "+"))? "+" : "-";

   base = strtok (str, sign);
   exp10 = strtok (NULL, sign);

   counts=atoi(exp10);

   printf("[%d]\n", counts);

   return 0;
}

[5]

Share:
63,742
Milan
Author by

Milan

Updated on July 11, 2022

Comments

  • Milan
    Milan almost 2 years

    Lets say that input from the user is a decimal number, ex. 5.2155 (having 4 decimal digits). It can be stored freely (int,double) etc.

    Is there any clever (or very simple) way to find out how many decimals the number has? (kinda like the question how do you find that a number is even or odd by masking last bit).

  • Luis Vito
    Luis Vito almost 15 years
    .2155 is not going to become .21559999999999, but .2156 could
  • Mike Kale
    Mike Kale almost 15 years
    You'd somehow need to account for numbers that don't fit neatly into a float, ie if you end up with 5.215399999999999, you probably want to report 4 decimal places.
  • Luis Vito
    Luis Vito almost 15 years
    It's (almost) never a good if you need to compute anything quickly.
  • ojblass
    ojblass almost 15 years
    I would classify as clever only because of how thoroughly you answered the question.
  • Guillaume Algis
    Guillaume Algis almost 11 years
    Shouldn't while abs(num) <= 0.0000001: be while abs(num) >= 0.0000001: ?
  • paxdiablo
    paxdiablo almost 11 years
    @Guillaume, yes, congrats on being the first person to pick up that error in four years. Fixed as per your suggestion.
  • chux - Reinstate Monica
    chux - Reinstate Monica over 9 years
    Certainly code should be while fabs(num) >= 0.0000001 (fabs vs. abs). Code posted may be pseudo code, yet important to use the proper absolute value function in real code.
  • Bim
    Bim over 7 years
    This gives you rounding errors really easily. Try it.
  • sɐunıɔןɐqɐp
    sɐunıɔןɐqɐp almost 6 years
    Welcome to Stack Overflow! Please don't answer just with source code. Try to provide a nice description about how your solution works. See: How do I write a good answer?. Thanks
  • Andrzej Ziółek
    Andrzej Ziółek almost 6 years
    Please explain how does it solve OP's issue, not just post code.
  • Tryer
    Tryer almost 6 years
    Within the while loop, the ending num is the fractional part. If this is 0.99999999999, then the loop will go on forever. What works for me is the following: while abs(num - roundtonearestinteger(num)) >= epsilon
  • keith
    keith over 3 years
    This counts the number of digits in an integer, not the number of decimal digits as the question asks.
  • Eric Postpischil
    Eric Postpischil over 3 years
    Code without explanation is not a good answer.
  • Eric Postpischil
    Eric Postpischil over 3 years
    Consider what this code does when user enters a number using scientific notation, such as “5.1e3”.
  • Eric Postpischil
    Eric Postpischil over 3 years
    For the “5.2155” given as an example in the question and using IEEE-754 binary64 arithmetic for double, this code returns 6.
  • keith
    keith over 3 years
    @Eric Postpischil, thanks I've updated my answer.
  • Russell Trahan
    Russell Trahan about 3 years
    I posted an answer below which is similar. while val - std::numeric_limits<T>::epsilon() > std::numeric_limits<T>::epsilon() is I think the "correct" comparison rather than hard coding an arbitrary 0.00000001 value.