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

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

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

18
задан James Reinstate Monica Polk 31 March 2010 в 23:27
поделиться

9 ответов

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

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

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

23
ответ дан 30 November 2019 в 07:08
поделиться

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

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

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

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

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

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

5
ответ дан 30 November 2019 в 07:08
поделиться

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

double exponent = log10(value);
double rounded = floor(exponent + 0.5);
if (fabs(exponent - rounded) < some_tolerance) {
    //Power of ten
}
10
ответ дан 30 November 2019 в 07:08
поделиться
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);
}
2
ответ дан 30 November 2019 в 07:08
поделиться

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


#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: работает и для отрицательных сил.

0
ответ дан 30 November 2019 в 07:08
поделиться

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

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

(Далее следует уродливый псевдокод:)

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 и, если это все, что вам нужно, может быть намного быстрее. (В зависимости от платформы)

.
1
ответ дан 30 November 2019 в 07:08
поделиться

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

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.

0
ответ дан 30 November 2019 в 07:08
поделиться

Вариант этого :

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

return fractional_value==0.0;

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

РЕДАКТИРОВАТЬ: так как это вызвало споры из-за того, что log10 , возможно, неточен, и общее понимание того, что вам не следует сравнивать двойники без эпсилона, вот более точный способ определения того, является ли двойной степень 10, используя только свойства степеней 10, и IEEE 754 удваивается.

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

-1
ответ дан 30 November 2019 в 07:08
поделиться

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

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

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

0
ответ дан 30 November 2019 в 07:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: