Привет ! Меня зовут Ксавье Жувено, и это четвертая часть длинной серии статей The Modern C++ Challenge. В этой статье я собираюсь объяснить, как я решил четвертую задачу на C++ и как интегрировал это решение в проект Android.

Цель этой четвертой проблемы проста.

Мы должны вычислить наибольшее простое число, которое меньше числа, предоставленного пользователем, а затем распечатать его пользователю. Решение будет вычислено на C++, а интерфейс для получения пользовательского ввода и отображения результата будет обрабатываться с помощью Android Studio Framework.

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

Решение на С++

Чтобы получить наибольшее простое число, меньшее, чем число, предоставленное пользователем, мы сначала должны уметь распознавать, что такое простое число. 😉

Простое число — это натуральное число больше 1, которое делится только на 2 числа: 1 и само себя.

Функция, реализующая такое определение, выглядит так:

static constexpr bool isPrime(unsigned int number) {
  if(number < 2) { return false; }
  for(auto divisor = (number / 2); divisor > 1; --divisor) {
    if(number % divisor == 0) {
      return false;
    }
  }
  return true;
}

Первое условие подтверждает, что число должно быть больше 1, чтобы быть простым. Затем мы повторяем половину пользовательского ввода, потому что мы имеем дело с натуральным числом, поэтому нет необходимости проверять числа, превышающие половину пользовательского ввода, поскольку любое из этих чисел, умноженное как минимум на 2, будет больше, чем наше число , что сэкономит нам некоторое время вычислений. Мы итерируем до 2, но останавливаемся, если одно из чисел может разделить пользовательский ввод. В этом случае мы возвращаем false, так как пользовательский ввод может быть разделен на число, отличное от 1 и самого себя, поэтому пользовательский ввод не является простым. Но если мы можем найти число, соответствующее этому условию, мы возвращаем true, так как мы выяснили, что этот пользовательский ввод является простым. 🙂👍

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

unsigned int largestPrimeSmallerThan (const unsigned int upperLimit){
  for(auto number = upperLimit; number > 1; --number) {
    if(isPrime(number)) {
      return number;
    }
  }
  assert(false);
  return 1;
}

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

Интерфейс пользовательского интерфейса в Android Studio

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

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

Для этого мы создали файл макета с именем problem.xml, в который мы поместили все элементы, которые будут отображаться в интерфейсе всех задач, такие как заголовок, текст задачи и кнопки NEXT и PREVIOUS. Затем в макет каждой задачи мы включаем общий макет problem следующим образом:

<LinearLayout  
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical" android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:gravity="center_horizontal"> <include
  layout="@layout/problem"/>
</LinearLayout>

Теперь, когда у нас есть некоторые элементы, включенные во всю задачу, мы должны указать, что они содержат в Java-коде Activity, а не в xml-файле их макета. Например, вот как задается текст задачи 4:

protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_problem_4);
  // some code TextView
  problemText = findViewById(R.id.problemText);
  problemText.setText(getString(R.string.problem_4_text));
  // some other code
}

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

public abstract class ProblemInterface extends AppCompatActivity {
  public abstract void goToNextProblem(View v);
  public abstract void goToPreviousProblem(View v);
}

И только реализует обратный вызов в соответствии с проблемой.

public class Problem_4 extends ProblemInterface {
  @Override public void goToNextProblem(View v) {
    // empty on purpose
  }
  public void goToPreviousProblem(View v) {
    Intent intent = new Intent(this, Problem_3.class);
    startActivity(intent);
  }
}

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

Использование собственного кода C++

Связывание пользовательского интерфейса и кода C++ будет похоже на предыдущую задачу. 😉 В Java-файле активности объявляем нативный метод:

public class Problem_4 extends ProblemInterface {
  public native String LargestPrimeSmallerThan(int userInput);
}

А в нативном методе мы вызываем нашу функцию C++ для решения проблемы и возвращаем решение.

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_themoderncppchallenge_Problem_14_LargestPrimeSmallerThan(JNIEnv *env, jobject thiz, jint user_input) {
  auto result = largestPrimeSmallerThan(user_input);
  return env->NewStringUTF(std::to_string(result).c_str());
}

Вывод

Вуаля! Теперь у нас есть приложение, которое может решить первые четыре задачи The Modern C++ Challenge.

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

Спасибо всем за прочтение этой статьи, и до моей следующей статьи, хорошего дня 😉

Интересные ссылки

Первоначально опубликовано на http://10xlearner.com 15 апреля 2020 г.