Ошибка получения логарифмов базы 2 в с - PullRequest
0 голосов
/ 22 апреля 2019

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

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

for(unsigned int numero=1;numero<=2048;numero*=2)
{
    int x=log10(numero)/log10(2);
    printf("%d\n",x);
}

return 0;

Он печатает:

0 1 2 2 4 5 5 6 8 9 10 11

Должно быть:

0 1 2 3 4 5 6 7 8 9 10 11

Похоже, он работает для некоторых чисел, но я не понимаю, почему он не работает для всех чисел.

1 Ответ

2 голосов
/ 22 апреля 2019

log10 возвращает число с плавающей запятой (double). Значение log10 не является точно представимым в плавающей точке для большинства передаваемых вами чисел, поэтому вы можете получить что-то вроде log10(8)/log10(2) == 2.9999999 вместо точного 3. Преобразование в int усекает его до 2. Чтобы исправить это, вы должны правильно округлить:

int x = lrint(log10(numero)/log10(2));

Или, если у вашего компилятора нет функции lrint, которую вы можете использовать:

int x = log10(numero)/log10(2) + 0.5;

, который будет работать для этого случая.

Обратите внимание, что существуют альтернативные способы расчета желаемого результата. Поскольку числа с плавающей запятой уже хранят показатель степени в базе 2, вы можете получить его с помощью вызова frexp:

int x;
frexp(numero, &x);

Другим способом было бы вообще избежать математики с плавающей запятой и использовать внутреннюю для получения индекса последнего бита, установленного в numero. К сожалению, нет кроссплатформенного способа сделать это.

...