Подтвердить что ты не робот

С++: как я могу проверить, имеет ли число десять?

Я хочу проверить, является ли число double x целочисленной степенью 10. Я мог бы использовать cmath log10, а затем проверить, если x == (int) x?

edit: На самом деле, мое решение не работает, потому что удваивается может быть очень большим, намного больше, чем int, а также очень маленькими, как фракции.

4b9b3361

Ответ 1

Таблица поиска будет на сегодняшний день самым быстрым и точным способом сделать это; только около 600 степеней 10 представлены в виде двойников. Вы можете использовать хеш-таблицу, или если таблица упорядочена от наименьшей до самой крупной, вы можете быстро ее искать с помощью бинарной отбивной.

Это имеет то преимущество, что вы получите "хит" тогда и только тогда, когда ваш номер будет максимально близким к IEEE, до некоторой степени 10. Если это не то, что вы хотите, вам нужно уточнить точно, как вы хотели бы, чтобы ваше решение справлялось с тем фактом, что многие полномочия 10 не могут быть точно представлены как двойные.

Лучшим способом построения таблицы является, вероятно, использование преобразования string → float; таким образом, мы надеемся, что ваши авторы библиотеки уже решат проблему того, как сделать преобразование таким образом, чтобы дать наиболее точный ответ.

Ответ 2

Ваше решение звучит неплохо, но я бы заменил точное сравнение с допуском.

double exponent = log10(value);
double rounded = floor(exponent + 0.5);
if (fabs(exponent - rounded) < some_tolerance) {
    //Power of ten
}

Ответ 3

Я боюсь, что вы попали в мир боли. Невозможно отличить очень большое или очень маленькое число с плавающей запятой до класса BigInt, потому что вы потеряли точность при использовании небольшого числа с плавающей запятой.

Например, float имеет только 6 цифр точности. Поэтому, если вы представляете 10 9 как вероятность float, он будет преобразован обратно как 1 000 000 145 или что-то вроде этого: ничто не гарантирует, что будут последние цифры, они не соответствуют точности.

Конечно, вы можете использовать гораздо более точное представление, например double, которое имеет 15 цифр точности. Поэтому обычно вы должны иметь возможность представлять целые числа от 0 до 10 14 добросовестно.

Наконец, некоторые платформы могут иметь тип long long с еще большей точностью.

Но в любом случае, как только ваше значение превысит количество цифр, доступных для преобразования обратно в целое число без потерь... вы не можете проверить его на десять.

Если вам действительно нужна эта точность, мое предложение состоит в том, чтобы не использовать число с плавающей запятой. Существуют математические библиотеки, доступные с реализациями BigInt, или вы можете сворачивать свои собственные (хотя эффективность трудно достичь).

Ответ 4

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);
}

Ответ 5

В зависимости от платформы, которую ваш код должен запускаться в журнале, может быть очень дорого.

Так как количество чисел, равных 10 ^ n (где n естественно), очень мало, скорее всего, будет просто использовать жестко скопированную таблицу поиска.

(Ugly псевдокод следует:)

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;
}

Это охватывает весь диапазон int16, и если это все, что вам нужно, это может быть намного быстрее. (В зависимости от платформы.)

Ответ 6

Как насчет кода вроде этого:


#include <stdio.h>
#define MAX 20
bool check_pow10(double num)
{
   char arr[MAX];
   sprintf(arr,"%lf",num);
   char* ptr = arr;
   bool isFirstOne = true;

   while (*ptr)
   {
     switch (*ptr++)
     {
       case '1':
                if (isFirstOne)
                   isFirstOne = false;
                else
                   return false;
                break;
       case '0':
                break;
       case '.':
                break;
       default:
                return false;
     }
   }

 return true;
}

int main()
{
  double number;
  scanf("%lf",&number);
  printf("isPower10: %s\n",check_pow10(number)?"yes":"no");
}

Это не сработало бы для отрицательных полномочий 10. EDIT: также работает и с отрицательными полномочиями.

Ответ 7

если вам не нужно быстро, используйте рекурсию. Псевдокод:

bool checkifpoweroften(double Candidadte)
     if Candidate>=10
         return (checkifpoweroften(Candidadte/10) 
     elsif Candidate<=0.1
         return (checkifpoweroften(Candidadte*10)
     elsif Candidate == 1
         return 1
     else 
         return 0

Вам все равно нужно выбирать между ложными срабатываниями и ложными негативами и соответственно добавлять допуски, как указывали другие ответы. Допуски должны применяться ко всем сравнениям, иначе, например, 9,99999999 завершится с ошибкой >= 10.

Ответ 8

как насчет этого:

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;
}

Я думаю, если производительность является проблемой, несколько значений могут быть предварительно вычислены с использованием или без epsilon в соответствии с потребностями.

Ответ 9

Вариант this:

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

return fractional_value==0.0;

Обратите внимание, что сравнение с 0.0 является точным, а не конкретным epsilon, поскольку вы хотите, чтобы log10_value было целым числом.

EDIT: поскольку это вызвало несколько разногласий из-за log10, возможно, неточных и общее понимание того, что вы не должны сравнивать удвоения без эпсилона, здесь более точный способ определить, является ли двойное значение мощностью 10 используя только свойства степеней 10 и IEEE 754.

Во-первых, пояснение: double может представлять до 1E22, так как 1e22 имеет только 52 значащих бита. К счастью, 5 ^ 22 также имеет только 52 значащих бита, поэтому мы можем определить, является ли double (2*5)^n для 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;
    }
}

Так как 2^10==1024, это добавляет дополнительный бит значимости, который мы должны удалить из возможной мощности 5.