Вариант this один:
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
целое.
EDIT: В связи с этим возникла разногласия из-за того, что log10
может быть неточным и общее понимание того, что вы не должны сравнивать двойники без эпсилона, а вот более точный способ определить, является ли двойное значение мощностью 10, используя только свойства степеней 10 и IEEE 754 удваиваются.
Во-первых, пояснение: двойной может представлять до 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
, что добавляет дополнительный бит значения, что мы должны извлечь из возможной мощности of 5.
@Yacoby Сила десяти - это номер формы '10^n', где' n' является целым числом, поэтому это, безусловно, будет работать. –
Обратите внимание, что удвоения IEEE754 имеют только 52 бит точности. В результате 10^15 можно представить точно, но «double (10^16) == double (10^16 + 1)». В результате у вас будут либо ложные срабатывания, либо ложные негативы. Использование 'long long' (если доступно) может быть лучше. – MSalters
Таким образом, 10E15 - это максимальная мощность 10, которая может быть представлена точно. Ради любопытства, что является минимальным, 10Е-15? –