PageRenderTime 64ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/ws12/get-bit/src/get-bit.c

https://gitlab.com/dedstroyer/mai-workshops-2013
C | 214 lines | 46 code | 13 blank | 155 comment | 8 complexity | 38794205787733ec0727371b58c3e459 MD5 | raw file
  1. /**
  2. * @section Описание
  3. *
  4. * Программа выводит значения бита заданного числа.
  5. * Со стандартного потока ввода (stdin) считывается входное число
  6. * и номер бита, который нужно вывести. Отсчет ведется от нуля.
  7. * На стандартный поток вывода (stdout) выводится значение искомого бита.
  8. * На стандартный поток ошибок выводится отладочная информация:
  9. * * входное число в двоичном представлении;
  10. * * входное число после двоичного сдвига на номер бита
  11. * (тоже в двоичном представлении).
  12. * Размер входного числа должен быть не более размера типа `unsigned long`,
  13. * вашего компилятора. Программа проверялась на gcc x86_64.
  14. * Размер `unsigned long int` составлял восемь байт (64 бита).
  15. *
  16. * @subsection Пример
  17. *
  18. * $> gcc get-bit.c -Wall -pedantic -std=c89
  19. * $> ./a.out
  20. * 100 2
  21. * 0000000000000000000000000000000000000000000000000000000001100100
  22. * 0000000000000000000000000000000000000000000000000000000000011001
  23. * 1
  24. * $> ./a.out 2> /dev/null
  25. * 100 2
  26. * 1
  27. * $> ./a.out
  28. * 4294967295 31
  29. * 0000000000000000000000000000000011111111111111111111111111111111
  30. * 0000000000000000000000000000000000000000000000000000000000000001
  31. * 1
  32. * $> ./a.out 2> /dev/null
  33. * 9223372036854775807 63
  34. * 0
  35. * $> ./a.out 1> /dev/null
  36. * 9223372036854775807 63
  37. * 0111111111111111111111111111111111111111111111111111111111111111
  38. * 0000000000000000000000000000000000000000000000000000000000000000
  39. * $> ./a.out
  40. * -10 1
  41. * 1111111111111111111111111111111111111111111111111111111111110110
  42. * 0111111111111111111111111111111111111111111111111111111111111011
  43. * 1
  44. *
  45. *
  46. * @authors Никитин Илья Константинович (преп. каф. 806 МАИ) <w@w-495.ru>
  47. * @version 1.0
  48. **/
  49. /*
  50. * Подключаем заголовочный файл стандартного ввода-вывода
  51. * (STanDart Input-Output) для использования getchar, putchar, scanf, printf.
  52. */
  53. #include <stdio.h>
  54. /**
  55. * @fn Возвращает бит числа `input` под номером `numbit`.
  56. * Отсчет ведется от нуля.
  57. *
  58. * @param input входное число;
  59. * @param numbit номер бита;
  60. **/
  61. int get_bit(unsigned long input_number, unsigned short numbit);
  62. /**
  63. * @fn Выводит на поток ошибок число `input` в двоичном представлении.
  64. * В этой программе нужна исключительно для отладки.
  65. *
  66. * @param input входное число;
  67. **/
  68. void debug_print_binary(unsigned long input);
  69. int main(){
  70. /**
  71. * @var Входное число, для которого надо вывести бит.
  72. */
  73. unsigned long input_number = 0;
  74. /**
  75. * @var Номер бита, который нужно вывести. Отсчет от нуля.
  76. */
  77. unsigned short numbit = 0;
  78. /**
  79. * @var Бит, который мы будем выводить.
  80. * Изначально присваиваем невозможное значение,
  81. * Чтобы быстро выловить ошибку, если у нас такая случится.
  82. */
  83. unsigned short bit = 2;
  84. if(scanf("%lu", &input_number) != 1){
  85. /*
  86. * Защита от дурака.
  87. * Если на вход подается что-то неприличное,
  88. * то на стандартный поток (файл) ошибок выводим сообщения об ошибке.
  89. */
  90. fprintf(stderr, "error: %lu is not integer number.", input_number);
  91. return 1;
  92. }
  93. if(scanf("%hu", &numbit) != 1){
  94. /*
  95. * Защита от дурака.
  96. * Если на вход подается что-то неприличное,
  97. * то на стандартный поток (файл) ошибок выводим сообщения об ошибке.
  98. */
  99. fprintf(stderr, "error: %hu is not number of bit.", numbit);
  100. return 1;
  101. }
  102. /*
  103. * Определяем бит. Обратите внимение,
  104. * что отсчет битов идет не от единицы, а от нуля.
  105. */
  106. bit = get_bit(input_number, numbit);
  107. printf("%hu\n", bit);
  108. return 0;
  109. }
  110. /**
  111. * @fn Возвращает бит числа `input` под номером `numbit`.
  112. * Отсчет ведется от нуля.
  113. *
  114. * @param input входное число;
  115. * @param numbit номер бита;
  116. **/
  117. int get_bit(unsigned long input_number, unsigned short numbit){
  118. unsigned long tmp = 0;
  119. /*
  120. * Посмотрим, как выглядит наше число в двоичном представлении.
  121. * Это нужно только для отладки
  122. */
  123. debug_print_binary(input_number);
  124. /*
  125. * Двоичный сдвиг числа `input_number` на `numbit` бит влево
  126. * (по сути, `numbit` раз разделили на `2`).
  127. */
  128. tmp = (input_number >> numbit);
  129. /*
  130. * Посмотрим в двоичном представлении это же число после сдвига.
  131. * Это нужно только для отладки.
  132. */
  133. debug_print_binary(tmp);
  134. /**
  135. * Применяем побитовое умножение `битовое И` для исходного числа
  136. * и единицы. Таким образом выделяем нужные бит.
  137. * Суффикс `L` у числа говорит компилятору,
  138. * что мы работаем с типом `unsigned long`.
  139. */
  140. if(1L == (tmp & 1L)){
  141. return 1;
  142. }
  143. return 0;
  144. }
  145. /**
  146. * @fn Выводит на поток ошибок число `input` в двоичном представлении.
  147. * В этой программе нужна исключительно для отладки.
  148. *
  149. * @param input входное число;
  150. * @param width ширина выводимого числа;
  151. * Этот аргумент нужен, чтобы дополнять выходное число
  152. * ведущими нулями, до нужного размера.
  153. * Например `debug_print_binaryw(2, 4)` напечатает `0010`.
  154. **/
  155. void debug_print_binaryw(unsigned long input, unsigned short width){
  156. /*
  157. * Получаем разряд числа `input` в системе счисления `2`.
  158. */
  159. unsigned short digit = input % 2;
  160. /*
  161. * Условие остановки рекурсии.
  162. */
  163. if(!input){
  164. unsigned short i;
  165. /*
  166. * Печатаем ведущие нули.
  167. * Каждый предыдущий шаг рекурсии уменьшал `width` на единицу,
  168. * т.к. к выходному числу добавлялось по разряду.
  169. * Теперь мы выводим столько нулей, сколько необходимо,
  170. * до дополнения до ширины `width`.
  171. */
  172. for(i = 0; i < width; ++i)
  173. fprintf(stderr, "0");
  174. }
  175. else{
  176. /*
  177. * Рекурсивно вызываем эту же функцию,
  178. * Параметр `input` становится в `2` раза меньше,
  179. * а параметр `width` уменьшаем на 1,
  180. * если он был положительным (тут используется тренарный оператор).
  181. * Как результат возвращает предыдущие разряды числа.
  182. */
  183. debug_print_binaryw(input / 2, (width) ? (width - 1) : 0);
  184. fprintf(stderr, "%hu", digit);
  185. }
  186. }
  187. /**
  188. * @fn Выводит на поток ошибок число `input` в двоичном представлении.
  189. * В этой программе нужна исключительно для отладки.
  190. *
  191. * @param input входное число;
  192. **/
  193. void debug_print_binary(unsigned long input){
  194. /**
  195. * @var Ширина выводимого числа.
  196. * Нужна для дополнения его ведущими нулями.
  197. */
  198. unsigned short width = sizeof(input) * 8;
  199. debug_print_binaryw(input, width);
  200. fprintf(stderr, "\n");
  201. }