C++: how can I test if a number is power of ten?

前端 未结 9 1175
清歌不尽
清歌不尽 2021-02-18 19:12

I want to test if a number double x is an integer power of 10. I could perhaps use cmath\'s log10 and then test if x == (int) x?

<

相关标签:
9条回答
  • 2021-02-18 19:17

    Your solution sounds good but I would replace the exact comparison with a tolerance one.

    double exponent = log10(value);
    double rounded = floor(exponent + 0.5);
    if (fabs(exponent - rounded) < some_tolerance) {
        //Power of ten
    }
    
    0 讨论(0)
  • 2021-02-18 19:26

    A variant of this one:

    double log10_value= log10(value);
    double integer_value;
    double fractional_value= modf(log10_value, &integer_value);
    
    return fractional_value==0.0;
    

    Note that the comparison to 0.0 is exact rather than within a particular epsilon since you want to ensure that log10_value is an integer.

    EDIT: Since this sparked a bit of controversy due to log10 possibly being imprecise and the generic understanding that you shouldn't compare doubles without an epsilon, here's a more precise way of determining if a double is a power of 10 using only properties of powers of 10 and IEEE 754 doubles.

    First, a clarification: a double can represent up to 1E22, as 1e22 has only 52 significant bits. Luckily, 5^22 also only has 52 significant bits, so we can determine if a double is (2*5)^n for n= [0, 22]:

    bool is_pow10(double value)
    {
        int exponent;
        double mantissa= frexp(value, &exponent);
    
        int exponent_adjustment= exponent/10;
    
        int possible_10_exponent= (exponent - exponent_adjustment)/3;
    
        if (possible_10_exponent>=0 && 
            possible_10_exponent<=22)
        {
            mantissa*= pow(2.0, exponent - possible_10_exponent);
    
            return mantissa==pow(5.0, possible_10_exponent);
        }
        else
        {
            return false;
        }
    }
    

    Since 2^10==1024, that adds an extra bit of significance that we have to remove from the possible power of 5.

    0 讨论(0)
  • 2021-02-18 19:31

    how about that:

    bool isPow10(double number, double epsilon)
    {
        if (number > 0)
        {
            for (int i=1; i <16; i++)
            {
                if ( (number >= (pow((double)10,i) - epsilon)) && 
                    (number <= (pow((double)10,i) + epsilon)))
                { 
                    return true;
                }
            }
        }
        return false;
    }
    

    I guess if performance is an issue the few values could be precomputed, with or without the epsilon according to the needs.

    0 讨论(0)
  • 2021-02-18 19:33

    Depending on the platform your code needs to run on the log might be very expensive.

    Since the amount of numbers that are 10^n (where n is natural) is very small, it might be faster to just use a hardcoded lookup table.

    (Ugly pseudo code follows:)

    bool isPowerOfTen( int16 x )
    {
      if( x == 10       // n=1
        || x == 100     // n=2
        || x == 1000    // n=3
        || x == 10000 ) // n=4
      return true;
    
      return false;
    }
    

    This covers the whole int16 range and if that is all you need might be a lot faster. (Depending on the platform.)

    0 讨论(0)
  • 2021-02-18 19:35

    I am afraid you're in for a world of hurt. There is no way to cast down a very large or very small floating point number to a BigInt class because you lost precision when using the small floating point number.

    For example float only has 6 digits of precision. So if you represent 109 as a float chances are it will be converted back as 1 000 000 145 or something like that: nothing guarantees what the last digits will be, they are off the precision.

    You can of course use a much more precise representation, like double which has 15 digits of precision. So normally you should be able to represent integers from 0 to 1014 faithfully.

    Finally some platforms may have a long long type with an ever greater precision.

    But anyway, as soon as your value exceed the number of digits available to be converted back to an integer without loss... you can't test it for being a power of ten.

    If you really need this precision, my suggestion is not to use a floating point number. There are mathematical libraries available with BigInt implementations or you can roll your own (though efficiency is difficult to achieve).

    0 讨论(0)
  • 2021-02-18 19:35
    bool power_of_ten(double x) {
       if(x < 1.0 || x > 10E15) {
          warning("IEEE754 doubles can only precisely represent powers "
                  "of ten between 1 and 10E15, answer will be approximate.");
       }
       double exponent;
       // power of ten if log10 of absolute value has no fractional part
       return !modf(log10(fabs(x)), &exponent);
    }
    
    0 讨论(0)
提交回复
热议问题