Создание четных случайных чисел

У меня есть этот класс, который используется как часть игры. Он должен генерировать значения Random Even, которые производятся путем генерации случайных чисел, пока результат не станет четным.

Есть ли лучший способ сделать это?

Кроме того, в настоящее время у меня есть методы, реализованные как частные методы экземпляра, но я должен объявить generateRandomNumber() и evenNumber(number) как статические методы? Будет ли это иметь какие-либо преимущества?

public class Game {
    //...

    public void opponentSaysEvenNumber() {
        int number = generateRandomEvenNumber();
        System.out.println("Opponent: " + number);
    }

    private int generateRandomEvenNumber() {
        Random random = new Random();
        int number = random.nextInt();
        while (!evenNumber(number)) {
            number = random.nextInt();
        }
        return number;
    }

    private boolean evenNumber(int number) {
        return (number % 2) == 0;
    }
}
30 голосов | спросил leonideveloper 16 Jam1000000amThu, 16 Jan 2014 11:34:23 +040014 2014, 11:34:23

10 ответов


42

Да. Я бы пошел дальше и объявлял ваши функции как private static final , если это возможно. Комбинация этих three ключевых слов означает, что код не будет зависеть от какой-либо переменной экземпляра, любого суперкласса или любого подкласса и также не может быть вызван каким-либо кодом, внешним по отношению к классу. Поэтому у компилятора достаточно намека на то, что он может решить встроить всю функцию.

Я бы также переименовал evenNumber(int number) в isEven(int number). В Java существует соглашение, в котором функции с именем isSomething() возвращают boolean и не имеют побочных эффектов. Ваша функция соответствует этим критериям.

Чтобы создать случайное четное число, вы можете просто взять random.nextInt() & -2 для маскировки наименьшей значащей цифры. Это было бы более эффективно, чем цикл, тестирование и отбрасывание. В этом случае весь вопрос о вспомогательных функциях не имеет значения.

Неправильная практика создавать новый экземпляр Random каждый раз, когда вы хотите создать одно случайное число. Генератор псевдослучайных чисел фактически несет некоторое состояние, даже если вы не думаете об этом таким образом. Поэтому вы должны использовать переменную private static для хранения объекта Random.

ответил 200_success 16 Jpm1000000pmThu, 16 Jan 2014 14:06:39 +040014 2014, 14:06:39
21

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

ответил Andris 16 Jam1000000amThu, 16 Jan 2014 11:53:10 +040014 2014, 11:53:10
14

Ваша техника неэффективна. Чтобы генерировать четные числа, выполните одно из следующих действий:

  • Маска от младшего значащего бита (-2 является 0xFFFFFFFE) или битовой маской со всеми, кроме последнего)

    random.nextInt() & -2;
    
  • Сдвиг влево на один бит с помощью оператора бит-сдвига

    random.nextInt() << 1;
    
  • Сдвиг влево на один бит с использованием умножения

    random.nextInt() * 2;
    
ответил wizzy poo 17 Jam1000000amFri, 17 Jan 2014 01:46:13 +040014 2014, 01:46:13
8

Если вы не используете какие-либо атрибуты класса, это значит, что вы должны, вероятно, поместить этот метод в другое место. Возможно, в другом классе RandomEvenNumberGenerator.

Я всегда считал статическую плохую практику. Это открывает путь к множеству проблем, семантических проблем и синдрому «Я знаю, где вы живете», который по очереди усложняет тестирование и т. Д.

ответил Antoine_935 16 Jpm1000000pmThu, 16 Jan 2014 14:39:01 +040014 2014, 14:39:01
8

Почему бы просто не удвоить первое генерируемое случайное число и не вернуть его? У вас все еще будут случайные числа, их распространение не будет повреждено и быстрее.

public class Game {
    //...

    public void opponentSaysEvenNumber() {
        int number = generateRandomEvenNumber();
        System.out.println("Opponent: " + number);
    }

    private int generateRandomEvenNumber() {
        Random random = new Random();
        int number = random.nextInt();
        return number * 2;
    }
}
ответил Carl 17 Jam1000000amFri, 17 Jan 2014 07:46:49 +040014 2014, 07:46:49
5

Рассмотрите возможность использования ThreadLocalRandom

private int generateRandomEvenNumber() {
    return ThreadLocalRandom.current().nextInt() & -2;
}

ThreadLocalRandom был добавлен в Java 7 и решает несколько проблем с функциями Random, особенно в многопоточных средах. Даже если вы не находитесь в среде с несколькими ступеньками, я думаю, что это хорошая идея использовать ее каждый раз. Кроме того, Api лучше, чем старый случайный (вам не нужно создавать объект, просто используйте статический метод).

Использование & -2 (или любой другой метод, предложенный @wizzi poo ), гарантирует, что сгенерированное число всегда даже если установить последний бит сгенерированного числа равным 0. Это лучше, чем делать какое-то время, поскольку всегда существует вероятность, что Random не сможет генерировать четное число (маловероятно).

ответил Fredszaq 18 J000000Friday14 2014, 14:11:32
2

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

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

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

private static final Random rand = new Random(); 

public static int randomEvenNumber(int min, int max) {
    if(min % 2 != 0) throw new IllegalArgumentException("Minimum value must be even");
    if(max % 2 != 0) throw new IllegalArgumentException("Maximum value must be even");
    int range = max - min;
    int rangeHalf = range >> 1; // divided by 2
    int randomValue = rand.nextInt(rangeHalf);
    randomValue = randomValue << 1; // multiplied by 2 to make it even
    return min + randomValue;
}

public static final int randomEvenNumber(int max) {
    return randomEvenNumber(0,max);
}
ответил corsiKa 17 Jam1000000amFri, 17 Jan 2014 05:00:13 +040014 2014, 05:00:13
2

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

Случайные методы генератора (generateRandomEvenNumber () и evenNumber ()) носят математический характер и действительно не специфичны для игры. Они не имеют зависимости от игрового класса (например, они не используют поля), и у них нет побочных эффектов.

Мой подход состоял бы в том, чтобы сделать что-то подобное. Создайте класс RandomService с этими методами и введите экземпляр службы в игру. Используя Spring или какой-либо другой интерфейс DI (зависимость), служба может быть создана как одноэлементная. Методы RandomService могут быть общедоступными, потому что у них нет зависимостей или побочных эффектов, и они легко проверяются отдельно от игры.

ответил Patrick 17 Jpm1000000pmFri, 17 Jan 2014 20:26:38 +040014 2014, 20:26:38
1

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

Вы также должны объявить экземпляр Random как private final static.

Наконец, поскольку метод evenNumber состоит из одного теста, вы можете перенести этот тест на свой метод generateRandomEvenNumber и создать свой класс только двумя способами.

Другая возможность, если вы хотите централизовать генерацию этих случайных чисел, заключается в создании Singleton генератор случайных чисел.

ответил user3067411 16 Jpm1000000pmThu, 16 Jan 2014 18:21:25 +040014 2014, 18:21:25
0

Другой вариант - добавить или вычесть 1 в случае нечетного случайного числа.

...
number = random.nextInt();
if (number % 2 == 1) {
    number++;
    number %= MAX_NUMBER;   // assuming upper limit is required
}
...
ответил Andrej 20 42014vEurope/Moscow11bEurope/MoscowThu, 20 Nov 2014 01:59:55 +0300 2014, 01:59:55

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132