вторник, 27 сентября 2016 г.

Фиаско №1

Почему №1? Потому что уверен, что их будет ещё очень много. ))

Вчера вечером занялся решением первой тестовой задачи на продвинутых (углублённых) курсах программирования на C. Задание было такое: написать программу, которая находит номер введенного целого положительного треугольного числа в диапазоне от 1 до 9'223'372'036'854'775'807.

Написал целых три программы.
Как решал:
1. Определил, что числа в диапазоне от 1 в 9'223'372'036'854'775'807 входят в множество long long int чисел.
2. Поверхностно изучил функции scanf() и sqrt().
3. Поверхностно изучил операторы цикла for, while и ветвления if - else.
4. Почитал, что такое треугольные числа и как они рассчитываются.
5. Написал первую программу, которая в цикле while требовала ввести правильное треугольное число, проверяла его на соответствие диапазону исходных данных и вычисляло его номер.
6. Подумав, решил от цикла while отказаться - его, ведь, не было в условиях задачи. Написал программу без цикла, с диалогами на английском:

#include <stdio.h>
#include <math.h>

void checkNumber (const long long int * const ptr)
{
     int n = (sqrt(1+8* (*ptr))-1)/2;

     if (*ptr > 0 && *ptr <= 9223372036854775807 && (n%1) == 0 && (n*(n+1)/2) == *ptr)
        {
          printf ("The number of this triangular number is: %d\n", n);
        }  else
        {
          printf ("It's not valid number.\n");
        }

      return;
}

int main (void)
{
     long long int triangularNumber;
     long long int *triangularNumberPtr = &triangularNumber;
     printf ("Input positive triangular number: ");
     scanf ("%lli", &triangularNumber);
     checkNumber (triangularNumberPtr);

     return 0;
}

Использовал в программе указатели, чтоб было вроде как "правильнее".
7. Отправил программу на проверку и дальше третьего теста она не прошла.
Уж не помню, какие там ошибки автотест выдавал, но смысл был в том, что диалоги в программе не нужны.
8. Убрал диалоги, указатели и прочие "красивости":

#include <stdio.h>
#include <math.h>

int main (void)
{
     long long int tn;

     scanf ("%lli", &tn);
     long double n = (sqrt(1+8*tn)-1)/2;

     if (tn > 0 && tn <= 9223372036854775807 && (n*(n+1)/2) == tn) 
    {
         printf ("%Lg\n", n);
    }

      return 0;

}

Для переменной n использовал тип long double, так как дальше 5 теста пройти не смог, а в комментариях к задаче другие программисты написали, что тесты не проходит в том числе если тип этой переменной будет не long double. Короче, сделал сам точно не знаю, что и программа всё равно в тестах далеко не ушла.

В консоли работает нормально, если вводить в неё более-менее нормальные данные. Такие "числа" как 1.5,  21/5, 41,5, 23a программа принимает как валидные и первые цифры таких чисел (1, 21, 41, 23) определяет для себя как введенное число, которое нужно проверить на "треугольность" и вычислить его номер.

Погуглил на тему проверки валидности вводимых данных, но все решения были или на непонятном мне C++ или представляли собой тупой посимвольный перебор по алфавиту.

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

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

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

Ну, что ж, изучать мне ещё "методички" и изучать.))

Развлекусь пока созерцанием скриншота своего рабочего стола:



До        После