С++: как я могу проверить, имеет ли число десять?
Я хочу проверить, является ли число double x
целочисленной степенью 10. Я мог бы использовать cmath log10
, а затем проверить, если x == (int) x
?
edit: На самом деле, мое решение не работает, потому что удваивается может быть очень большим, намного больше, чем int, а также очень маленькими, как фракции.
Ответы
Ответ 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.