255 lines
9.7 KiB
Typst
255 lines
9.7 KiB
Typst
#set text(size: 1.3em)
|
||
|
||
#show raw.where(block: false): box.with(
|
||
fill: luma(240),
|
||
inset: (x: 3pt, y: 0pt),
|
||
outset: (y: 3pt),
|
||
radius: 2pt,
|
||
)
|
||
|
||
#show raw.where(block: true): block.with(
|
||
fill: luma(240),
|
||
inset: 10pt,
|
||
radius: 4pt,
|
||
)
|
||
|
||
// title
|
||
|
||
#align(center)[Санкт-Петербургский национальный исследовательский университет информационных технологий, механики и оптики]
|
||
\
|
||
\
|
||
\
|
||
#align(center)[Факультет инфокоммуникационных технологий]
|
||
#align(center)[Направление подготовки 11.03.02]
|
||
\
|
||
\
|
||
#align(center)[Лабораторная работа №2]
|
||
#align(center)[Создание и использование размерных типов данных]
|
||
\
|
||
\
|
||
\ //#align(center)[Вариант 19]
|
||
\
|
||
\
|
||
\
|
||
\
|
||
\
|
||
\
|
||
\
|
||
#align(right)[Выполнил:]
|
||
#align(right)[Дощенников Никита Андреевич]
|
||
#align(right)[Группа: К3221]
|
||
#align(right)[Проверил:]
|
||
#align(right)[Береснев Артем Дмитриевич]
|
||
\
|
||
\
|
||
#align(center)[Санкт-Петербург]
|
||
#align(center)[2025]
|
||
|
||
#pagebreak()
|
||
|
||
=== Цель работы:
|
||
|
||
Получить практические навыки программирования на bash, освоить практические приемы работы с командной оболочкой bash.
|
||
|
||
=== Часть 1. Работа в среде bash.
|
||
|
||
Для изменения приглашения командной строки я отредактировал файл `~/.bashrc`, добавив туда строку:
|
||
|
||
```bash
|
||
PS1='\t \u \w \$ '
|
||
```
|
||
|
||
Теперь приглашение отображает текущее время, имя пользователя, текущий каталог и символ `$`.
|
||
|
||
#align(center)[#image("assets/1.png")]
|
||
|
||
Создал алиас для вывода приветствия:
|
||
|
||
```bash
|
||
alias hi='echo "Have a nice day, $(whoami)!"'
|
||
```
|
||
|
||
После этого при вводе команды `hi` в терминале появляется строка с приветствием и именем текущего пользователя.
|
||
|
||
#align(center)[#image("assets/2.png")]
|
||
|
||
Чтобы изменения сохранились при перезапуске, эти строки были добавлены в файл `~/.bashrc`. Применил изменения без выхода из системы командой:
|
||
|
||
```bash
|
||
source ~/.bashrc
|
||
```
|
||
|
||
=== Часть 2. Простые задачи на bash.
|
||
|
||
1. Принимает две строки как параметры и сравнивает их.
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
[ "$#" -ne 2 ] && echo "usage: $0 str1 str2" && exit 1
|
||
[ "$1" = "$2" ] && echo "equal" || echo "not equal"
|
||
```
|
||
|
||
#align(center)[#image("assets/3.png")]
|
||
|
||
2. Принимает три целых числа и находит максимальное из них.
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
[ "$#" -ne 3 ] && echo "usage: $0 a b c" && exit 1
|
||
a=$1
|
||
b=$2
|
||
c=$3
|
||
max=$a
|
||
(( b > max )) && max=$b
|
||
(( c > max )) && max=$c
|
||
echo "$max"
|
||
```
|
||
|
||
#align(center)[#image("assets/4.png")]
|
||
|
||
3. Считывает строки до тех пор, пока не встретится строка `q`. После завершения цикла все введённые строки объединяются и выводятся в одну строку.
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
arr=()
|
||
while IFS= read -r line; do
|
||
[ "$line" = "q" ] && break
|
||
arr+=("$line")
|
||
done
|
||
printf "%s" "${arr[*]}"
|
||
```
|
||
|
||
#align(center)[#image("assets/5.png")]
|
||
|
||
4. Считывает последовательность целых чисел. Чтение продолжается, пока не встретится чётное число. После этого выводится количество введённых чисел до него.
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
count=0
|
||
while IFS= read -r n; do
|
||
r=$(( n % 2 ))
|
||
[ "$r" -eq 0 ] && break
|
||
count=$(( count + 1 ))
|
||
done
|
||
echo "$count"
|
||
```
|
||
|
||
#align(center)[#image("assets/6.png")]
|
||
|
||
5. Создано текстовое меню с четырьмя пунктами: запуск редактора `nano`, редактора `vi`, браузера `links`, или выход. Перед выполнением команда `command -v` проверяет наличие программ. Если программа не установлена — выводится сообщение и скрипт завершается.
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
for cmd in nano vi links; do
|
||
command -v "$cmd" >/dev/null 2>&1 || { echo "$cmd is not installed"; exit 1; }
|
||
done
|
||
echo "1) nano"
|
||
echo "2) vi"
|
||
echo "3) links"
|
||
echo "4) exit"
|
||
read -r -p "choose 1-4: " choice
|
||
case "$choice" in
|
||
1) exec nano ;;
|
||
2) exec vi ;;
|
||
3) exec links ;;
|
||
4) exit 0 ;;
|
||
*) echo "invalid choice" ; exit 1 ;;
|
||
esac
|
||
```
|
||
|
||
#align(center)[#image("assets/7.png")]
|
||
#align(center)[#image("assets/8.png")]
|
||
|
||
6. Принимает три параметра: имя файла, режим (`h` или `t`), и число строк. В режиме `h` печатаются первые N строк файла (`head -n`). В режиме `t` — последние N строк (`tail -n`). Ошибки при отсутствии файла подавляются перенаправлением `2>/dev/null`.
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
[ "$#" -ne 3 ] && echo "usage: $0 file h|t N" && exit 1
|
||
file=$1
|
||
mode=$2
|
||
num=$3
|
||
case "$mode" in
|
||
h) head -n "$num" -- "$file" 2>/dev/null ;;
|
||
t) tail -n "$num" -- "$file" 2>/dev/null ;;
|
||
*) echo "mode must be h or t" ; exit 1 ;;
|
||
esac
|
||
```
|
||
|
||
#align(center)[#image("assets/6.png")]
|
||
|
||
=== Часть 3. Разработка скрипта расчета производительности.
|
||
|
||
1. В этой части требовалось написать скрипт `script23`, который измеряет производительность CPU в FLOPS (Floating Point Operations Per Second). Для этого необходимо было реализовать большое количество операций с плавающей запятой и зафиксировать время их выполнения.
|
||
|
||
2. Для вычислений использовалась утилита `bc`, так как она позволяет работать с произвольной точностью. В скрипте выставлена точность `scale=10`.
|
||
|
||
3. В скрипте организована функция `bench`, в которой выполняется $N$ умножений двух одинаковых чисел. Параметр $N$ можно передать в скрипт, по умолчанию используется 1 000 000.
|
||
|
||
4. С помощью команды `date +%s.%N` время сохраняется до и после выполнения функции. Далее определяется разница во времени и вычисляется показатель FLOPS по формуле:
|
||
|
||
$
|
||
F L O P S = frac(N, Delta t)
|
||
$
|
||
|
||
5. В завершении программа выводит три значения: количество итераций, время выполнения в секундах, и рассчитанный FLOPS.
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
n=${1:-1000000}
|
||
command -v bc >/dev/null 2>&1 || { echo "bc is required"; exit 1; }
|
||
|
||
bench() {
|
||
printf 'scale=10\na=1.2345678901\nb=1.2345678901\nfor(i=0;i<%s;i++) x=a*b\n' "$n" | bc >/dev/null
|
||
}
|
||
|
||
start=$(date +%s.%N)
|
||
bench
|
||
end=$(date +%s.%N)
|
||
|
||
dur=$(echo "$end - $start" | bc -l)
|
||
flops=$(echo "$n / $dur" | bc -l)
|
||
|
||
printf "iterations=%s\ntime_s=%s\nFLOPS=%s\n" "$n" "$dur" "$flops"
|
||
```
|
||
|
||
#align(center)[#image("assets/10.png")]
|
||
|
||
=== Вопросы.
|
||
|
||
==== 1. Как определить сколько параметров пользователь передал в скрипт при запуске?
|
||
|
||
В bash для этого используется специальная переменная `$#`.
|
||
Она хранит количество аргументов, переданных скрипту.
|
||
Пример:
|
||
|
||
```bash
|
||
echo "amount of params: $#"
|
||
```
|
||
|
||
==== 2. Что выведет простой скрипт с постдекрементом?
|
||
|
||
Код:
|
||
|
||
```bash
|
||
count=10
|
||
echo $(( count-- ))
|
||
echo $(( count-- ))
|
||
```
|
||
|
||
#align(center)[#image("assets/11.png")]
|
||
|
||
Первая строка напечатает `10`, потому что оператор постдекремента возвращает старое значение, а потом уменьшает переменную. После этой операции `count=9`. Вторая строка напечатает `9` — аналогично.
|
||
|
||
==== 3. Недостатки подхода к определению FLOPS в нашем скрипте
|
||
|
||
- Измеряется не только операция умножения, но и работа интерпретатора bash и программы `bc`.
|
||
- Не используется SIMD (векторные инструкции) и многопоточность, поэтому результат сильно занижен.
|
||
- Выполняется только умножение одинаковых чисел, что не отражает реальную работу CPU.
|
||
- На результат влияют другие процессы в системе, частота процессора, троттлинг, кэш.
|
||
- Такой метод больше демонстрационный и не сопоставим с эталонными тестами на C/Fortran.
|
||
|
||
=== Вывод.
|
||
|
||
В ходе проделанной работы я получил практические навыки программирования на bash, освоил практические приемы работы с командной оболочкой bash.
|
||
|