Here's my function but it sometimes has unpredicted results with entering different numbers but with the same number of digits getting different results. I figure it has something to do with a computers inaccurate decimal saving tecnique but i would like to know how to make it more accurate.
/////////////////////// Numb_Digits() ////////////////////////////////////////////////////
enum{DECIMALS = 10, WHOLE_NUMBS = 20, ALL = 30};
template<typename T>
unsigned long int Numb_Digits(T numb, int scope)
{
unsigned long int length= 0;
unsigned long int whole_numb= (int)numb;
// gets the number of whole numbers
for(int mod =0; mod!=whole_numb; length++)
mod = whole_numb% (int)pow(10, (double)length);
int numb_of_wholes= length-1; length= 0; bool all = false;
double test = 0, test2= 0;
switch(scope){
case ALL: all = true; // different order to avoid decimal inaccuracies
// like 2.4 being 2.39999 // 10 bil (10 zeros)
case DECIMALS: numb*=10000000000; numb-=whole_numb*10000000000;
for(; numb != 0; length++)
numb-=((int)(numb/pow((double)10, (double)(9-length))))* pow((double)10, (double)(9-length));
if(all != true) break;
case WHOLE_NUMBS: length += numb_of_wholes;
if(all != true) break;
default: break;}
return length;
};
-
2\$\begingroup\$ For one, the formatting of that code looks awful. No room to breath. ;p \$\endgroup\$Steven Jeuris– Steven Jeuris2011年05月15日 12:51:08 +00:00Commented May 15, 2011 at 12:51
-
\$\begingroup\$ If your code doesn't work, it shouldn't be on code review. This is a better question for stackoverflow. \$\endgroup\$Winston Ewert– Winston Ewert2011年05月15日 14:23:02 +00:00Commented May 15, 2011 at 14:23
-
\$\begingroup\$ @Winston: In this case it 'kinda' works. :) \$\endgroup\$Steven Jeuris– Steven Jeuris2011年05月15日 14:52:56 +00:00Commented May 15, 2011 at 14:52
-
1\$\begingroup\$ @Jeuris, kinda doesn't cut it. The FAQ makes it clear that codereview is not for debugging help. \$\endgroup\$Winston Ewert– Winston Ewert2011年05月15日 18:21:06 +00:00Commented May 15, 2011 at 18:21
-
1\$\begingroup\$ Is this just 'log(n)' \$\endgroup\$Loki Astari– Loki Astari2015年04月18日 06:56:44 +00:00Commented Apr 18, 2015 at 6:56
1 Answer 1
To get the number of whole numbers, you can just use log10.
int wholeNumbers = ( number == 0 ) ? 1 : (int)log10( abs( number ) ) + 1;
I implemented your function in C#. By using the decimal type for the calculation of the numbers after the decimal sign, precision issues are automatically solved. Most likely a simple for loop is more performant than using pow as in your solution. The result of numbers after the decimal sign for infinite precise numbers (like PI) is dependent on the precision of the type. With this code, I get 14 digits after comma for PI.
public static int AmountOfDigits( double number, DecimalPart decimalPart = DecimalPart.WholeNumbers )
{
double absNumber = Math.Abs( number );
int amountOfDigits = 0;
// Amount of digits before decimal sign.
if ( decimalPart == DecimalPart.WholeNumbers || decimalPart == DecimalPart.EntireDecimal )
{
amountOfDigits += (absNumber == 0) ? 1 : (int)Math.Log10( absNumber ) + 1;
}
// Amount of digits after decimal sign.
if ( decimalPart == DecimalPart.AfterDecimalSign || decimalPart == DecimalPart.EntireDecimal )
{
// Use decimal for more precision!
decimal afterDecimalSign = (decimal)absNumber;
while ( afterDecimalSign - Math.Truncate( afterDecimalSign ) != 0 )
{
amountOfDigits++;
afterDecimalSign *= 10;
}
}
return amountOfDigits;
}
You do have to ask yourself where you will use this code however. When you are going to use it to calculate correct padding for string output, it's probably better to just convert the numbers to strings and count the amount of characters. It would be an interesting benchmarking test to compare that solution to this one.