2015-09-06 3 views
3

Учитывая целое число (2^n), которое является степенью 2, я хочу узнать значение n, значение индекса, используя логарифм. Формула для поиска индекса: log (число)/log (2). Ниже приведен фрагмент кода:Учитывая 2^n, найдите n, используя логарифм

unsigned long int a; 
    double apower; 
    apower = log((double)a)/log((double)2); 

Я обнаружил, что значение «apower» неправильно на каком-то большом значении а, я не знаю значение, так как мой код не удается, после отправки его. Почему это так? Есть ли какая-то проблема с кастингами?

Ниже весь фрагмент кода:

int count = 0; 
    unsigned long int a,b; 
    double apower,bpower; 
    apower = log((double)a)/log((double)2); 
    bpower = log((double)b)/log((double)2); 
    count = abs(apower - bpower); 
    printf("%d\n",count); 

Значения а и Ь всегда будет сила 2. Так apower и bpower должны иметь 00 в знаков после запятой. Поэтому значение count будет равно int (% d). Я просто хочу знать поведение Логарифма.

+1

почему вы используете 'неподписанных долгое INT 'for' a', если вы производите его «двойным»? Это не имеет никакого смысла ... – Nidhoegger

+0

Что такое sizeof (long) на вашей платформе? –

+0

ive написал небольшую пробную программу, используя ваш код. он работает до тех пор, пока 'n' не станет большим для' unsigned long int', когда слишком велико, результатом будет '-inf', что является правильным поведением. Поэтому, пожалуйста, предоставьте дополнительную информацию о своей домашней работе ... извините ... ваша проблема ... – Nidhoegger

ответ

1

При использовании double математики, результат журнала или quotient не может быть точно математическим результатом, но 1 (или 2) следующим представимым double.

Расчет log() возвращает только точный математический результат для log(0), все остальные математические результаты являются иррациональными. Все double рациональны.

Это может привести к ответу, как 29.999999 ..., которые сохраняются как int является 29.

Рекомендуется использовать целочисленную арифметику вместо


int mylog2(unsigned long x) { 
    int y = 0; 
    #if (ULONG_MAX>>16 > 1lu<<16) 
    if (x >= 1lu<<32) { x >>= 32; y += 32; 
    #endif 
    if (x >= 1lu<<16) { x >>= 16; y += 16; } 
    if (x >= 1lu<<8) { x >>= 8; y += 8; } 
    if (x >= 1lu<<4) { x >>= 4; y += 4; } 
    if (x >= 1lu<<2) { x >>= 2; y += 2; } 
    if (x >= 1lu<<1) { x >>= 1; y += 1; } 
    return y; 
} 
4

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

unsigned long long a = 0x8000000000000000ULL; 
int n = 0; 
while (a >>= 1) n++; 
printf("%d\n", n); 

Выход:

63 

Преобразование журналов и divding может привести к потере значимости, в этом случае вы должны использовать round. Вы используете слово «submit», так что это был вызов онлайн, который не удался? Что именно вы напечатали? (в данном случае) 63.000000? Это будет получено из формата по умолчанию %f.

+0

[более быстрый способ вычисления журнала целого числа] (https://graphics.stanford.edu/~seander/bithacks.html #IntegerLog) –

+0

Я хотел избежать циклов, так что результат приходит в O (1). – user2737359

4

Почему бы не воспользоваться тем фактом, что log2 хранится в поле экспоненты двойника? :)

unsigned long long a = 0x8000000000000000ULL; 
union { 
    double d; 
    unsigned long long l; 
} u; 
u.d = a; 
int apower = (u.l >> 52) - 1023; 
printf("%d\n", apower); 

Выход:

63 

Это предполагает, что неподписанные длинные длинные позиции и двойники являются 64 битами и что вход> 0.

+0

@EOF: Это не значит, что это слишком серьезно, но не видели этого в gazillion других вопросов log2 здесь, когда переполнение стека, и я всегда хотел попробовать это :) –

+0

@EOF ok, лучше? O :) –

+0

Адресовано в мелкой печати O :) –

Смежные вопросы