Что не так с моим синтаксисом, и я делаю это эффективно? - PullRequest
3 голосов
/ 10 марта 2010

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

class prime
{

    public static boolean prime (int a, int b) 
    { 
        if (a == 0) 
        {
            return false; 
        }
        else if (a%(b-1) == 0) 
        {
            return false; 
        }
        else if (b>1) 
        {
            prime (a, b-1) ;
        }
        else
        {
            return true; 
        }

    }

    public static void main (String[] arg) 
    {
        System.out.println (prime (45, 45)) ; 
    }
}

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

prime.java:23: missing return statement
    }
    ^
1 error

Возможно, я неверно истолковал то, что говорится в сообщении об ошибке, но мне кажется, что нет пропущенного оператора return, поскольку у меня есть оператор return для каждого возможного набора условий. если a равно 0, то он возвращает false, если нет, то проверяет, делится ли a на b, если это так, то возвращается, если нет, то, если b больше 1, он начинается снова. если b не больше 1, он также возвращается.

  • Также, кажется, немного грязно сделать этот метод взять две целые являются одинаковыми Int.

  • Что не так с моим синтаксисом / почему я получаю сообщение об ошибке? Есть ли способ сделать так, чтобы метод, который я использую в main, занимал только одно целое (возможно, другой метод разбивает это int на два клона, которые затем передаются в public static boolean prime собственно?

  • или есть более эффективный способ собирается об этом, что я скучаю полностью

Ответы [ 8 ]

6 голосов
/ 10 марта 2010

В вашей функции prime есть четыре возможных пути кода, один из которых не возвращает что-либо . Вот на что жалуется сообщение об ошибке. Вам необходимо заменить:

prime (a, b-1) ;

с:

return prime (a, b-1) ;

в случае else if (b>1).

Сказав это, на самом деле это не очень хороший способ вычислить, является ли число простым числом. Проблема в том, что каждый рекурсивный вызов выделяет кадр стека, и вы столкнетесь с серьезными проблемами переполнения стека, если попытаетесь определить, является ли 99 999 999 простым числом?

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

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

И некоторые, возможно, хитрые трюки в духе:

  • каждое число, кроме 2, оканчивающееся на 2, 4, 6, 8 или 0, не является простым числом.
  • каждое число, кроме 5, оканчивающееся на 5, не простое. Эти два правила уменьшат ваше пространство поиска на 60%. Предполагая, что вы получите свой тестовый номер в виде строки, просто проверить последнюю цифру этой строки даже перед преобразованием в целочисленный тип.

Есть несколько более сложных правил проверки делимости. Если вы возьмете число, кратное 9, и сложите все цифры, чтобы получить новое число, затем сделаете это снова для этого числа, а затем продолжите, пока не получите одну цифру, вы обнаружите, что она всегда равна 9.

Это даст вам еще 10% -ное сокращение пространства поиска, хотя и с более дорогостоящей проверкой. Имейте в виду, что эти проверки выгодны только для действительно больших количеств Преимущества не так велики, скажем, для 32-разрядных целых чисел, поскольку предварительно вычисленное растровое изображение будет гораздо более эффективным (см. Ниже).

Для упрощенного начала я бы использовал следующее итерационное решение:

public static boolean prime (int num) {
    int t = 2;
    while (t * t <= num) {
        if ((num % t) == 0) {
            return false;
        }
        t++;
    }
    return true;
}

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

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

На самом деле у меня есть список первых 100 миллионов простых чисел в файле, и мне проще и быстрее использовать grep, чтобы определить, является ли число простым, чем запустить некоторый код для его вычисления: -)


Что касается того, почему ваш алгоритм (исправленный с помощью оператора return) настаивает на том, что 7 не является простым, он будет настаивать на том, что каждое число не является простым (не проверялось с отрицательными числами, я Я уверен, что они вызовут серьезные проблемы - ваша первая проверка, вероятно, должна быть if (a < 1) ...).

Давайте рассмотрим, что происходит, когда вы звоните prime(3,3).

Впервые он достигает третьего условия, поэтому вызывает prime(3,2).

Затем выполняется условие секунда , поскольку 3 % (2-1) == 0 имеет значение true (N % 1 равно всегда 0).

Так что возвращается false. Вероятно, это можно исправить, изменив третье условие на else if (b>2), хотя я не проверил это тщательно, так как не думаю, что рекурсивное решение в любом случае является хорошей идеей.


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

public class prime
{
    public static boolean isPrime (int num) {
        int t = 2;
        while (t * t <= num) {
            if ((num % t) == 0) {
                return false;
            }
            t++;
        }
        return true;
    }


    public static void main (String[] arg) 
    {
        System.out.println (isPrime (7)) ; 
    }
}
5 голосов
/ 10 марта 2010

Похоже, у вас сложилось впечатление, что, поскольку рекурсия в конечном итоге найдет базовый случай, который попадет в оператор return, этот возврат будет возникать во всех рекурсивных вызовах. Это не правда. Каждый рекурсивный вызов должен передавать результат следующим образом:

return prime(a, b - 1);
4 голосов
/ 10 марта 2010

Если b больше 1, ваша функция ничего не вернет.

Может быть return prime (a, b-1) ;?

3 голосов
/ 10 марта 2010

Чтобы повысить эффективность, подумайте больше о своих условиях. Вам действительно нужно проверить каждый фактор от 2 до N? Есть ли другая точка остановки, которая поможет быстрее выполнить тесты простых чисел?

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

public static boolean prime(int n) {
  return recurse(n, n);
}

private static boolean recurse(int a, int b) {
 ...
}

Создание метода private означает, что его нельзя вызвать из другого класса. Это эффективно невидимо для пользователей класса. Намерение здесь состоит в том, чтобы скрыть «некрасивый» дополнительный параметр, предоставив публичный вспомогательный метод.

Подумайте о факторах некоторых составных чисел. 10 факторов в 5 раз; 2. 12 факторов в 6 раз; 2. 14 факторов в 7 раз; 2. Теперь подумайте о 25. 25 факторов в 5 раз; 5. А как насчет 9? Вы видите образец? Кстати, если это не домашнее задание, пожалуйста, дайте мне знать. Мне трудно быть дидактиком.

2 голосов
/ 10 марта 2010

В ответ на вопрос, почему 7 не работает, представьте, что вы компьютер, и проработайте свою логику. Вот что ты написал.

class prime
{

    public static boolean prime (int a, int b) 
    { 
        if (a == 0) 
        {
            return false; 
        }
        else if (a%(b-1) == 0) 
        {
            return false; 
        }
        else if (b>1) 
        {
            // Have to add the return statement
            // here as others have pointed out!
            return prime(a, b-1);
        }
        else
        {
            return true; 
        }

    }

    public static void main (String[] arg) 
    {
        System.out.println (prime (45, 45)) ; 
    }
}

Итак, начнем с 7.

if(7 == 0) // not true, don't enter this block
else if(7 % 6 == 0) // not true
else if(7 > 1) // true, call prime(7, 6)

if(7 == 0) // not true, don't enter this block
else if(7 % 5 == 0) // not true
else if(6 > 1) // true, call prime(7, 5)

if(7 == 0) // not true, don't enter this block
else if(7 % 4 == 0) // not true
else if(5 > 1) // true, call prime(7, 4)

... продолжайте называть простое число (7, 2)

if(7 == 0) // not true, don't enter this block

else if(7 % 1 == 0) true, return false

Когда вы приступаете к вызову prime(n, 2), он всегда будет возвращать false, потому что у вас есть логическая ошибка.

0 голосов
/ 27 июня 2010

Аналогично ответу @ paxdiblo, но чуть более эффективно.

public static boolean isPrime(int num) {
    if (num <= 1 || (num & 1) == 0) return false;
    for (int t = 3; t * t <= num; t += 2)
        if (num % t == 0)
            return false;
    return true;
}

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

0 голосов
/ 10 марта 2010

Я думаю, что на первоначальный вопрос уже был дан ответ - вам нужно вставить return в теле else if (b>1) - Я просто хотел указать, что ваш код все равно будет аварийно завершать работу, когда ему дается 1 в качестве значения для b, бросая ArithmeticException, поскольку a%(b-1) будет оценено как a%0, что приведет к делению на ноль.

Вы можете избежать этого, сделав первое выражение if if (a == 0 || b == 1) {} Это не улучшит способ, которым программа находит простые числа, просто гарантирует, что есть еще один способ ее сбить.

0 голосов
/ 10 марта 2010

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

    public static boolean prime (int a, int b) 
{
    if (a == 0) 
    {
        return false; 
    }
    else if (a%(b-1) == 0) 
    {
        return false; 
    }
    else if (b>1) 
    {
        return prime (a, b-1) ;
    }
    else
    {
        return true; 
    }

}

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

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