Что делать, если код не работает?

Опубликовано: 4 Сентября, 2022

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

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

  • Неправильный ответ
  • Превышен предел времени/памяти
  • Сбой (ошибка выполнения)

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

  • Проверьте пограничные случаи: например, если N = 1 или n — максимально возможное число, удовлетворяющее ограничениям. Проверьте, правильно ли ведет себя программа при входных данных, которые соответствуют ограничениям во всех возможных смыслах.
  • Создайте несколько общих тестовых случаев: для которых вы знаете правильный ответ. Не смотрите на ответ кода для этих тестов, пока не выясните, каким должен быть ответ с ручкой и бумагой. Иначе легко убедить себя в правильности и не увидеть какой-нибудь глупой ошибки.
  • Ограничение по времени превысило ошибку , измеряя, как долго программа работает для больших входных данных. Следующие функции помогают измерить процессорное время с момента запуска программы:
    • C++ (двойные) часы () / ЧАСЫ В СЕК с включенным временем.
    • python time.clock() возвращает значение с плавающей запятой в секундах.
    • Java System.nanoTime() возвращает длинные значения в наносекундах.

Измеряйте время для небольших тестов, средних тестов и больших тестов. Можно столкнуться с одним из следующих возможных результатов:

  • Программа работает на малых и средних тестах по времени, но более чем в 10 раз медленнее, чем нужно (или зависает на больших тестах). В этом случае программа, вероятно, имеет проблемы со сложностью, и мы могли бы попытаться выяснить проблему, используя следующие параметры:
    • Измерьте время, которое части программы занимают отдельно. Например, сколько времени занимает чтение ввода/печать вывода).
    • Вычислите фактическое количество операций, выполняемых вашим алгоритмом и его частями, и посмотрите, ожидается ли это.
    • Проверьте, были ли переданы ссылки на функции, применимые только к C++, Java и Python. Всегда упоминается).
  • Программа зависает на маленьком или среднем тесте. Проверьте наличие бесконечного цикла/рекурсии. Добавьте утверждения (утверждения в c++, python и java) для предусловий и постусловий циклов и функций и посмотрите, не сработают ли они. Используйте отладочный вывод/отладчик, чтобы увидеть, какой путь кода приводит к зависанию.
  • Если это ошибка времени выполнения, сообщение может быть неизвестным сигналом, то это может быть хорошим знаком. Это одна из наиболее информативных причин, означающая, что программа может аварийно завершить работу из-за одного из следующих факторов:
    • Доступ к ячейке памяти, которая не принадлежит программе. В C++ это может принимать две формы: попытка доступа к несуществующему элементу массива, попытка оценить нулевой указатель или указатель, указывающий на место, не принадлежащее программе.
    • Допустить арифметическую ошибку: деление на ноль, переполнение числа с плавающей запятой и т. д.
    • (Специфично для C++) Превышен размер стека, что может быть вызвано бесконечной рекурсией или созданием большого объекта (например, массива) внутри функции.

Создавайте разные тесты и запускайте против них свою программу, пока она не рухнет:

  • Причина «неправильного ответа», вероятно, самая сложная; многое может привести к этому. Чтобы найти неудачный тест, можно выполнить одно из следующих действий:
    • Найдите альтернативное решение, которое может быть неправильным с точки зрения эффективности (а в некоторых случаях даже не работает для некоторых типов тестов), но может быть использовано для проверки правильности ответа основного решения.
    • Сделайте сбой программы, если что-то несовместимо. Это означает добавление утверждений для постусловий и предусловий ваших функций и циклов.

Как создавать тесты. Самый простой способ создать тест — написать программу, которая печатает тест в текстовый файл. Ниже приведен пример, иллюстрирующий то же самое:

Программа 1: Генерация теста на максимальное попарно различное:

Python3




import sys
n = int(sys.argv[1])
print(n)
print(" ".join([str(i∗2)for i in range(n)])

Пожалуй, самое загадочное здесь — это sys.argv[1]. Это геттер для первого аргумента командной строки. Теперь, как использовать это для запуска программы? Скопируйте исполняемый файл или скрипт Python в тот же каталог, что и генерирующий скрипт, и выполните следующие команды:

python script.py 17 > input.txt
./your_program_name < input.txt

Вместо Python рекомендуется использовать Python3. В некоторых случаях это может помочь решить проблемы. Таким образом, некоторые тесты могут быть сгенерированы автоматически и программа может работать с ними, но следующие вопросы остаются без ответа:

  • Как рандомизировать тесты?
  • Как сгенерировать их много?
  • Как проверить ответы?

Генерация случайных тестов и запуск на них вашей программы: Можно использовать следующую технику, состоящую из 3 частей:

  • Генератор тестов, который принимает начальное значение в качестве параметра командной строки, как обсуждалось в программе 2.
  • Альтернативное решение.
  • Скрипт, многократно генерирующий тест с генератором из (1), запускает как основное решение, так и модельное решение на сгенерированном тесте и проверяет, совпадают ли ответы в программе 2 или нет.

Программа 2: Генератор, который принимает начальное значение из командной строки:

Python3




import random
import sys
  
# Input the number N
n = int(sys.argv[1])
myseed = int(sys.argv[2])
random.seed(myseed)
  
print(n)
  
# 1000 could also be moved to
# parameters instead of making it
# a hard constant in the code
print(" ".join([str(random.randint(1, 1000)) for i in range(n)])

Программа 3: Собственно скрипт:

Python3




import random
import sys
import os
  
# Accept the number of tests as a
# command line parameter
  
tests = int(sys.argv[1])
  
# Accept the parameter for the
# tests as a command line parameter
  
n = int(sys.argv[2])
for i in range(tests):
    print("Test #" + str(i))
  
    # Run the generator gen.py with
    # parameter n and the seed i
os.system("python3 gen.py " + str(n) + " " + str(i) + " > input.txt")
  
# Run the model solution model.py
# Notice that it is not necessary
# that solution is implemented in
# python, you can as well run
# ./model < input.txt > model.txt
# for a C++ solution.
  
os.system("python3 model.py < input.txt > model.txt")
  
# Run the main solution
  
os.system("python3 main.py < input.txt > main.txt")
  
# Read the output of the
# model solution
  
with open("model.txt") as f:
    model = f.read()
print("Model: ", model)
  
# Read the output of the
# main solution :
  
with open("main.txt") as f:
    main = f.read()
print("Main: ", main)
if model != main:
    break

Как добавить утверждения: в Java, Python и C++ выражение утверждения, выражение утверждения и утверждение (выражение); соответственно, вызовет ошибку времени выполнения, если логическое выражение будет ложным. Одним из возможных вариантов использования утверждений является проверка согласованности ответа на программу. Другим распространенным вариантом использования является проверка согласованности промежуточных шагов программы.