Неожиданная Runtime error в системе автотестов
Решаю небольшую задачу:
Составить программу для работы с целыми числами в троичной системе счисления. Для хранения таких чисел использовать стандартный тип long int, но ограничиться только цифрами 0,1,2. Учесть, что при таком представлении можно работать только с числами, ограниченными диапазоном типа long int. В качестве диапазона чисел в троичной системе счисления можно взять значения от –2 122 222 222 до 2 122 222 222. Составить функции для выполнения простейших арифметических операций и вычислить значение выражения
(числа a, b вводятся с консоли в троичной системе счисления).
В случаях возникновения переполнения, вместо значения результата выводить символ «!» и код той операции, при которой произошло переполнение:
1 – при сложении,
2 – при вычитании,
3 – при умножении,
4 – при возведении в степень.
Собственно реализовал я ее, можно сказать, "в лоб". Все функции просто переводят число из троичной системы в десятичную, вычисляют, переводят обратно. Добавил коды возврата, сигнализирующие об ошибках. Собственно, вот:
#include <stdio.h>
#define INT32_MAX 2147483647
#define NO_ERROR 0b0
#define OVERFLOW 0b1
#define ZERO_DIVISION 0b10
int toBase3(int k, int* res) {
if (k < -52487 || k > 52487) return OVERFLOW;
int p = 1;
while (k) {
*res += p * (k % 3);
p *= 10;
k /= 3;
}
return NO_ERROR;
}
int fromBase3(int k) {
int res = 0;
int p = 1;
while (k) {
res += p * (k % 10);
p *= 3;
k /= 10;
}
return res;
}
int sum3(int a, int b, int* exitCode) {
int a10 = fromBase3(a);
int b10 = fromBase3(b);
int res10 = a10 + b10;
int res3 = 0;
*exitCode = toBase3(res10, &res3);
return res3;
}
int sub3(int a, int b, int* exitCode) {
int a10 = fromBase3(a);
int b10 = fromBase3(b);
int res10 = a10 - b10;
int res3 = 0;
*exitCode = toBase3(res10, &res3);
return res3;
}
int mul3(int a, int b, int* exitCode) {
if (a == 0 || b == 0) {
*exitCode = NO_ERROR;
return 0;
}
int a10 = fromBase3(a);
int b10 = fromBase3(b);
if (a10 > INT32_MAX / b10) {
*exitCode = OVERFLOW;
return 0;
}
int res10 = a10 * b10;
int res3 = 0;
*exitCode = toBase3(res10, &res3);
return res3;
}
int div3(int a, int b, int* exitCode) {
if (b == 0) {
*exitCode = ZERO_DIVISION;
return 0;
}
int a10 = fromBase3(a);
int b10 = fromBase3(b);
int res10 = a10 / b10;
int res3 = 0;
*exitCode = toBase3(res10, &res3);
return res3;
}
int pow3(int a, unsigned short p, int* exitCode) {
*exitCode = NO_ERROR;
if (a == 0) return 0;
if (p == 0) return 1;
int a10 = fromBase3(a);
int res10 = a10;
unsigned short curPow = 1;
while (curPow < p) {
if (res10 > INT32_MAX / a10) {
*exitCode = OVERFLOW;
return 0;
}
res10 *= a10;
++curPow;
}
int res3 = 0;
*exitCode = toBase3(res10, &res3);
return res3;
}
int main() {
int a;
int b;
scanf("%d %d", &a, &b);
//ab^2 - a(b - a) + b
int res = 0;
int exitCode;
res = pow3(b, 2, &exitCode);
if (exitCode & OVERFLOW) {
printf("!4\n");
return OVERFLOW;
}
res = mul3(res, a, &exitCode);
if (exitCode & OVERFLOW) {
printf("!3\n");
return OVERFLOW;
}
int temp = sub3(b, a, &exitCode);
if (exitCode & OVERFLOW) {
printf("!2\n");
return OVERFLOW;
}
temp = mul3(temp, a, &exitCode);
if (exitCode & OVERFLOW) {
printf("!3\n");
return OVERFLOW;
}
res = sub3(res, temp, &exitCode);
if (exitCode & OVERFLOW) {
printf("!2\n");
return OVERFLOW;
}
res = sum3(res, b, &exitCode);
if (exitCode & OVERFLOW) {
printf("!1\n");
return OVERFLOW;
}
printf("%d\n", res);
return NO_ERROR;
}
При загрузке его в тестовую систему, получаю половину правильно пройденных тестов и половину Runtime error. Честно говоря, не вижу, где она может происходить. Компилятор предупреждений не дает, отладчик тоже. Я так и не смог подобрать тесты, чтобы сломать программу. Буду рад, если поможете найти такие.
PS: есть небольшой шанс ошибок в тестовой системе, так как подобные случаи уже встречались: при загрузке программы от имени другого пользователя пропадала Runtime error.
Ответы (1 шт):
Итак, оказалось, что код выше содержал две проблемы:
- Первая, как указал @wololo, действительно заключалась в неверной проверке на переполнение типа данных при отрицательных входных значениях. Исправил добавлением модуля.
- Вторая же была связана с тестирующей системой: оказалось, что каждый раз, когда
main()возвращает ненулевой код, тест считается проваленным независимо от вывода программы в консоль. Замена всехreturn code; наreturn 0;исправила проблему.
Спасибо за помощь)