2016-10-19 5 views
0

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

Первое:

public int calcPow(long num) { 
    int count = 0; 
    while(num/2!=0) { 
     num = num/2; 
     count++; 
    } 
    return count; 
} 

Второй:

private long findParentNumber(long value) { 
    for(int bitNum = 0; bitNum < Long.SIZE; bitNum++) { 
     if((value & (1L << bitNum)) != 0) { 
      return value^(1L << bitNum); 
     } 
    } 
    throw new RuntimeException("No parent number found"); 
} 

Я считаю, есть способы, чтобы сделать то же самое без петель. Вы можете помочь?

Cheers!

+0

Что случилось с петлями? Вы можете попытаться заменить циклы рекурсивными методами. – Eran

+0

@Eran, но это более опасно и занимает немного больше места –

+0

Не могли бы вы объяснить, что выполняет вторая функция? –

ответ

2

Для первого, вы можете использовать Math.log метод, который уже существует:

public static int log2(long number) { 
    return (int) Math.floor(Math.log(number)/Math.log(2)); 
} 

или это быстрее функции suggested by saka1029:

public static int log2(long number) { 
    return number == 0? 0: Long.numberOfTrailingZeros(Long.highestOneBit((number < 0)? number * -1: number)); 
} 

Как вы можете видеть, что я также изменил метод статического , поскольку я не вижу смысла использовать объект для получения журнала, когда объект не задействован. И во-вторых, я изменил имена на что-то более подходящее.

Для второго вы можете использовать побитовую проверку оператор &:

public static long removeSmallBit(long value) { 
    return value & (value - 1); 
} 

По существу вы удаляете наималейший бит из переменных и возвращаете этот номер после того как вы измените этот бит на 0. как вы можете видеть снова, я сделал метод статическим и изменил имя. 2-й ответ на этот вопрос вызван this answer submitted by harold

+0

Я * думаю * это потолок из-за того, как работает целочисленное деление. – Bathsheba

+0

На самом деле вы были первыми, кто понял это правильно; имейте upvote! – Bathsheba

+0

Да, это работает! Большое спасибо –

4

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

Во всяком случае, это

return x & (x - 1); 

Логика здесь в том, что в x - 1, есть заимствуют работает через низшие нули, пока не достигнет самого низкого 1 бит, который он сбрасывает. Самые низкие нули оставлены, они затем удаляются с помощью ANDing с исходным номером.

Вы можете написать первую в терминах numberOfLeadingZeros, что было бы более корректно, чем взломы с плавающей запятой, которые всегда заставляют вас думать о том, насколько точны они могут быть (и в любом случае они медленны, выкл с петлей).

Редактировать: для полноты, которая была бы 63 - numberOfLeadingZeros(x), она отличается от вашего определения на x = 0, но это плохой вход в любом случае.

+0

Упрощенный, это хорошо, и переносится на C и C++ тоже. – Bathsheba

+0

Спасибо, испытал это, и все в порядке. Очень хорошее решение. –

3

Попробуйте это для первого.

public int calcPow(long num) { 
    if (num == 0) return 0; 
    if (num < 0) num = -num; 
    return Long.numberOfTrailingZeros(Long.highestOneBit(num)); 
} 

Или это suggested by harold

public int calcPow(long num) { 
    return num == 0 ? 0 
     : 63 - Long.numberOfLeadingZeros(Math.abs(num)); 
} 
+0

Это короткое и быстрое решение. Благодарю. –

+0

@CD Я согласен, хотя я бы предпочел, чтобы трояны использовались для первых двух строк. Я думаю, это будет выглядеть лучше. Как 'return num == 0? 0: Long.numberOfTrailingZeros (Long.highestOneBit (num <0)? Num * -1: num); 'или использовать' Math.abs() ' –

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