Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лр2_Go.doc
Скачиваний:
2
Добавлен:
01.07.2025
Размер:
351 Кб
Скачать
☆

If необязательнаяИнструкция1; логическоеВыражение1 {

блок1

} else if необязательнаяИнструкция2; логическоеВыражение2 {

блок2

} else {

блок3

}

Инструкция может иметь нуль или более разделов else if и нуль или один завершающий раздел else. Каждый блок содержит нуль или более инструкций.

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

Необязательная инструкция должна быть простой инструкцией в терминологии Go: это может быть единственное выражение, инструкция передачи данных в канал (с использованием оператора ), инструкция инкремента или декремента, инструкция присваивания или инструкция сокращенного объявления переменной. Если в необязательной инструкции объявляются переменные (например, с помощью оператора :=), их область видимости простирается от точки объявления до конца всей инструкции if, то есть они существуют в блоках if или else if, если те существуют, а также во всех нижележащих разделах и прекращают свое существование в конце инструкции if.

Логическое выражение должно возвращать значение типа bool. В языке Go нелогические значения не преобразуются автоматически в логические, поэтому всегда следует использовать оператор сравнения, например if i == 0.

Рассмотрим пример, который демонстрирует применение необязательной инструкции.

// Канонический вид

if x := vvod(); x < 0 {

fmt.Printf("(%d)\n", - x)

} else {

fmt.Println(x)

}

// Подробный!

{

x := vvod()

if x < 0 {

fmt.Printf("(%d)\n", - x)

} else {

fmt.Println(x)

}

}

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

Задание 2.1 Измените задание 1.11 следующим образом (рисунок 2.1)

Рисунок 2.1  Результат работы приложения

Задание 2.2 Измените задание 2.1 так, чтобы числа были случайными из диапазона от 1 до 99 (рисунок 2.2)

//обновление таблицы случайных чисел (пакет "time")

r := rand.New(rand.NewSource(time.Now().UnixNano()))

a := r.Intn(99) + 1 //генерация случайного числа из диапазона от 1 до 99

b := r.Intn(99) + 1 //пакет "math/rand"

Рисунок 2.2  Результат работы приложения

Инструкция switch

Существуют две разновидности инструкции выбора switch : выбор по значению выражения и выбор по типу. Инструкция switch в Go не выполняет все ветки до первой инструкции break (то есть в Go не требуется завершать инструкцией break каждый раздел case). Однако имеется возможность явно потребовать «проваливаться» в следующий раздел case с помощью инструкции fallthrough .

Инструкция switch выбора по значению выражения в языке Go имеет следующий синтаксис:

switch необязательнаяИнструкция; необязательноеВыражение {

case списокВыражений1: блок1

...

case списокВыраженийN: блокN

default: блокD

}

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

Если в инструкции switch отсутствует необязательное выражение, компилятор предполагает, что в качестве выражения используется значение true. Необязательная инструкция должна быть простой.

Если в необязательной инструкции объявляются переменные (например, с помощью оператора :=), их область видимости простирается от точки объявления до конца всей инструкции switch, то есть они существуют во всех блоках case и в блоке default и прекращают свое существование в конце инструкции switch.

Наибольшая эффективность инструкции switch достигается, когда инструкции case упорядочены сверху вниз от наиболее вероятных вариантов к наименее вероятным.

Раздел default является необязательным, но при его наличии он может находиться в любом месте внутри инструкции switch. Если не будет найдено совпадения ни с одним выражением в инструкциях case, будет выполнен блок default, если имеется. В противном случае управление будет передано инструкции, следующей за инструкцией switch.

В каждой инструкции case должен иметься список из одного или более выражений, разделенных запятыми, типы значений которых совпадают с типом значения необязательного выражения в инструкции switch. Если необязательное выражение отсутствует, компилятор по умолчанию использует значение true, то есть значение типа bool, и в этом случае все выражения во всех инструкциях case должны возвращать значение типа bool.

Если в блоке case или default будет встречена инструкция break, инструкция switch немедленно прервет выполнение и передаст управление следующей за ней инструкции или, если в инструкции break указано имя метки, ближайшей вмещающей инструкции for, switch или select, где определена указанная метка.

Ниже приводится простой пример инструкции switch, не имеющей необязательной инструкции и необязательного выражения.

func BoundedInt(minimum, value, maximum int) int {

switch {

case value < minimum:

return minimum

case value > maximum:

return maximum

}

return value

}

Поскольку здесь нет необязательного выражения, вместо него компилятор будет использовать значение true. То есть все выражения во всех инструкциях case должны возвращать значение типа bool. Здесь оба выражения используют логические операторы сравнения.

switch {

case value < minimum:

return minimum

case value > maximum:

return maximum

default:

return value

}

panic("Недоступно")

Выше приводится альтернативная реализация тела функции BoundedInt(). Инструкция switch теперь охватывает все возможные случаи, поэтому поток выполнения никогда не достигнет конца функции. Тем не менее компилятор Go требует, чтобы функция завершалась инструкцией return или вызовом функции panic() , поэтому здесь использована последняя, чтобы лучше выразить семантику функции.

Задание2.3 Необходимо вывести название времени года по введенному номеру текущего месяца:

switch m {

    case 12:

        fallthrough

    case 1:

        fallthrough

    case 2:

        fmt.Println("Зима")

    case 3:

        fallthrough

    case 4:

        fallthrough

    case 5:

        fmt.Println("Весна")

    case 6:

        fallthrough

    case 7:

        fallthrough

    case 8:

        fmt.Println("Лето")

    case 9:

        fallthrough

    case 10:

        fallthrough

    case 11:

        fmt.Println("Осень")

    default:

        fmt.Println("Неправильный ввод")

    }

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

Задание 2.4 Воспользуемся для получения текущего месяца функцией Now().Month() пакета time, Now() возвращает текущую дату и время, а Month() возвращает значение месяца типа Month:

type Month int

const (

January Month = 1 + iota

February

March

April

May

June

July

August

September

October

November

December

)

Приведем инструкцию switch к канонической форме:

switch mon {

    case 12, 1, 2:

        fmt.Println("Зима")

    case 3, 4, 5:

        fmt.Println("Весна")

    case 6, 7, 8:

        fmt.Println("Лето")

    case 9, 10, 11:

        fmt.Println("Осень")

}

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

Задание 2.5 Разработайте приложение, которое по дню недели определяет какой это день: рабочий или выходной (воспользуйтесь функцией Weekday() пакета time).

Инструкция цикла for

В языке Go имеются две разновидности инструкции for, простая инструкция for и for ... range. Синтаксис простой инструкции:

for необязатПредИнструкция;логичВыражение; необязатПостИнструкция {

блок

}

Фигурные скобки являются обязательными, а точки с запятой необходимы только в случае использования пред- и постинструкций, которые должны быть простыми инструкциями. Если в необязательной инструкции объявляются переменные или сохраняются значения, возвращаемые ключевым словом range (например, с помощью оператора :=), их область видимости простирается от точки объявления до конца всей инструкции for.

Логическое выражение в простой инструкции for должно возвращать значение типа bool, потому что в языке Go не выполняется автоматическое преобразование нелогических значений. Частные случаи инструкции for:

for { // Бесконечный цикл

блок

}

for логическоеВыражение { // Цикл while

блок

}

Вторая разновидность инструкции for ...range итераций по строкам возвращает индексы байтов.

for индекс, символ := range Строка { // Итерации по символам в Строке

блок

}

Вторая разновидность инструкции for ...range итераций по массивам или срезам для непустых срезов или массивов возвращает индексы элементов от 0 до len(срез) - 1.

for index := range массивИлиСрез { // Итерации по массиву или срезу

блок // item := массивИлиСрез[index]

}

Еще одна разновидность инструкции for range итераций по массивам и срезам

for индекс, элемент := range массивИлиСрез { // Итерации по массиву или срезу

блок

}

Инструкции for ...range итераций по элементам ключ/значение и по ключам отображений возвращают элементы или ключи в произвольном порядке.

for ключ, значение := range Отображение { // Итерации по элементам отображения

блок

}

for ключ := range Отображение { // Итерации по элементам отображения

блок // значение := Отображение[ключ]

}

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

Если какая-либо из форм будет применена к пустой строке, массиву, срезу или отображению, тело цикла for просто не будет выполнено ни разу, и управление сразу перейдет к следующей инструкции.

Выполнение цикла for можно прервать в любой момент с помощью инструкции break , передающей управление инструкции, следующей за инструкцией for, или, если в инструкции break указана метка, ближайшей вмещающей инструкции for, switch или select, где определена эта метка. Имеется также возможность с помощью инструкции continue передать управление в начало инструкции for, условному выражению или ключевому слову range , чтобы принудительно запустить следующую итерацию (или завершить цикл).

Задание 2.6 Определить, количество простых чисел в одномерном массиве.

var a [10] int //описываем массив из 10 целых чисел

for i := range a { //заполнение массива случайными значениями от 1 до 99

a[i] = r.Intn(99) + 1

fmt.Printf("%d ", a[i])

}

fmt.Print("\n")

count := 0 // количество составных чисел в массиве

for i := range a {

METKA:

for j := 2; j < a[i]; j++ {

if a[i]%j == 0 {

count++

break METKA

}

}

}

fmt.Printf("Количество простых чисел в массиве: %d ", 10-count)

Метка – это идентификатор, за которым следует двоеточие. При обнаружении искомого значения (делителя) выполняется прерывание внутреннего цикла с переходом в начало внешнего цикла за счет использования инструкции break с меткой. Преимущества использования приема прерывания цикла с переходом по метке возрастают многократно, когда он применяется в серии глубоко вложенных циклов.

Метки могут применяться к циклам for, инструкциям switch и select. Обе инструкции, break и continue , позволяют указывать метки и могут использоваться внутри циклов for. Инструкции break, с метками или без них, можно также использовать внутри инструкций switch и select.

Метки могут играть роль самостоятельных инструкций, и в этом случае их можно использовать в инструкциях безусловного перехода goto (например: goto label). Один из случаев применения инструкции goto – автоматическая генерация программного кода.

Задание 2.7 Разработать приложение, которое позволяет подсчитать количество повторяющихся строк в файле (файлах), имена файлов передаются как аргументы командой строки. Программа должна выводить строку и количество ее повторений.

counts := make(map[string]int) /*Отображение (map) содержит набор пар «ключ-значение» и обеспечивает константное время выполнения операций хранения, извлечения или проверки наличия элемента в множестве. Ключ может быть такого типа, значения которого можно сравнить с помощью оператора = =; распространенным примером ключа являются строки. Значение может быть любого типа. В нашем примере ключи представляют собой строки, а значения представлены типом int . Встроенная функция make создает новое пустое отображение*/

for _, fname := range os.Args[1:] {

data, err := ioutil.ReadFile(fname) /* Функция ReadFile (пакет io/ioutil) возвращает байтовый срез, который должен быть преобразован в string так, чтобы его можно было разбить с помощью функции strings.Split (пакет strings)*/

if err != nil { //вывод возможной ошибки при чтении данных из файла

fmt.Fprintf(os.Stderr, "dup2: %v\n", err)

continue

}

/*Данные, прочитанные из файла, разбиваем на строки и считаем повторения. Когда новая строка встречается впервые, выражение counts [line] присваивает нулевое значение новому элементу, которое для типа int равно 0*/

for _, line := range strings.Split(string(data), "\n") {

counts[line]++

}

}

/* Для вывода результатов используем цикл по отображению counts. Каждая итерация дает две величины  ключ и значение элемента отображения для этого ключа. Порядок обхода отображения не определен, на практике этот порядок случаен и варьируется от одного выполнения программы к другому*/

for line, n := range counts {

if n > 1 {

fmt.Printf("%s\t%d\n", line, n)

}

}

Функция fmt.Printf выполняет форматированный вывод на основе списка выражений. Первым ее аргументом является строка формата, которая указывает, как должны быть отформатированы последующие аргументы. Формат каждого аргумента определяется символом преобразования, буквой, следующей за знаком процента. Например, %d форматирует целочисленный операнд в десятичной записи, a %s выводит значение строкового операнда.

Функция Printf имеет больше десятка таких преобразований, которые программисты на Go называют глаголами (verbs), часть из них представлена в таблице 2.1.

Таблица 2.1  Некоторые преобразования функции Printf

Глагол

Описание

%d

Десятичное целое

%х, %о, %b

Целое в шестнадцатеричном, восьмеричном и двоичном представлениях

%f, %g, %е

Числа с плавающей точкой: 3.141593 3.141592653589793 3.141593e+00

%t

Булево значение: true или false

%с

Руна (символ Unicode)

%s

Строка

%q

Выводит в кавычках строку типа "abc" или символ типа ' с '

%v

Любое значение в естественном формате

%T

Тип любого значения

%%

Символ процента

Рассмотрим пример создания простого HTTP-сервера.

Задание 2.8 Создайте веб-приложение, предлагающее пользователю вводить числа и выполнять простейшие вычисления.

Для реализации простого HTTP-сервера необходимо сделать следующее:

1 Определить строковые константы:

pageTop = `<!DOCTYPE HTML><html><head>

<style>.error{color:#FF0000;}</style></head><title>Калькулятор</title>

<body><h3>Арифметические операции</h3>

<p>Выполнение некоторых арифметических операций</p>`

form = `<form action="/" method="POST">

<label for="number1">Введите первое число:</label><br />

<input type="text" name="a" size="10"><br />

<label for="number2">Введите второе число:</label><br />

<input type="text" name="b" size="10"><br />

<input type="submit" value="Выполнить">

</form>`

pageBottom = `</body></html>`

error = `<p class="error">%s</p>`

2 В функцию main добавить строки:

func main() {

http.HandleFunc("/", homePage) /*Функция http.HandleFunc() принимает два аргумента: путь и ссылку на функцию, которую следует вызвать при поступлении запроса по указанному пути. Функция должна иметь сигнатуру func(http.ResponseWriter, *http.Request). Приложение может зарегистрировать неограниченное количество пар путь/функция. Здесь регистрируются путь / (то есть домашняя страница веб-приложения) и пользовательская функция homePage()*/

if err := http.ListenAndServe(":9001", nil); err != nil { /*Функция http.ListenAndServe() запускает веб-сервер, принимающий запросы на указанном сетевом TCP-адресе, – здесь используется локальный адрес компьютера и порт с номером 9001. Когда указывается только номер порта, автоматически предполагается, что адрес соответствует локальному компьютеру, можно было использовать адрес "localhost:9001" или "127.0.0.1:9001". Номер порта для данного приложения был выбран совершенно произвольно, вместо него можно указать другой, если использование этого номера вызывает конфликты с существующим сервером. Второй аргумент определяет тип сервера. Обычно в нем передается nil, чтобы выбрать тип по умолчанию*/

log.Fatal("Не удалось запустить сервер", err)

}

}

3 Написать функцию homePage():

/*Эта функция вызывается при каждом посещении веб-сайта приложения. В аргументе writer передается значение, куда должен записываться ответ (в формате HTML), а в аргументе request – подробная информация о запросе*/

func homePage(writer http.ResponseWriter, request *http.Request) {

err := request.ParseForm()// Должна вызываться перед записью в ответ

/*Функция начинается с анализа формы (которая изначально имеет пустые текстовые элементы <input>). Текстовым элементам <input> присвоены имена «a» и «b», чтобы на них можно было ссылаться позднее, при обработке формы. Атрибуту action формы присвоено значение /, чтобы после щелчка на кнопке Выполнить браузер запрашивал ту же самую страницу. Это означает, что функция homePage() будет вызываться для обработки всех запросов, поэтому она должна уметь обрабатывать первичный вызов, когда еще не было введено ни одного числа, и последующие вызовы, когда числа были введены или когда возникла ошибка. Фактически вся работа выполняется функцией processRequest(), поэтому разные случаи обрабатываются этой функцией.

После анализа формы выводятся строковые константы pageTop и form. Если в ходе анализа обнаружится ошибка, также будет выведено сообщение об ошибке; anError – это строка формата, а err – значение ошибки для форматирования*/

fmt.Fprint(writer, pageTop, form)

if err != nil {

fmt.Fprintf(writer, error, err)

} else {

/*В случае успешного выполнения анализа вызывается функция processRequest(), извлекающая числа, введенные пользователем*/

if nums, message, ok := processRequest(request); ok {

/*Если все числа окажутся допустимыми, вызовом функций вычисляются и выводятся в форматированном виде арифметические операции; иначе будет выведено сообщение об ошибке, если оно имеется*/

add := addition(nums) //сумма чисел

sub := subtraction(nums) //разность чисел

mul := multiplication(nums) //произведение чисел

div, str := division(nums) //деление чисел (или сообщение, что на

//0 делить нельзя)

//формирование ответа (таблица с результатами)

answer := formatSolutions(nums, add, sub, mul, div, str)

fmt.Fprintf(writer, answer) //вывод ответа

} else if message != "" {//если возникла ошибка

fmt.Fprintf(writer, error, message)

}

}

fmt.Fprint(writer, pageBottom)

}

4 Функция processRequest выглядит следующим образом:

/*Функция возвращает введенные числа (массив), строку, если возникает ошибка и логическое значение. Эта функция читает данные формы из значения request*/

func processRequest(request *http.Request) ([2]float64, string, bool) {

    var floats [2]float64 //массив с вещественными числами

    count := 0 //количество прочитанных чисел

    for index, key := range []string{"a", "b"} {

/*Значение request имеет поле Form типа map[string][]string. Это означает, что ключи отображения являются строками, а значения – срезами со строками. То есть одному ключу соответствует значение, содержащее произвольное количество строк.

Функция проверяет наличие ключа "key" (значения определены во внешнем цикле) и, если он присутствует и его значение содержит хотя бы одну строку, можно быть уверенными, что в форме имеются числа для чтения*/

        if slice, found := request.Form[key]; found && len(slice) > 0 {

            if slice[0] != "" {

/*Для каждой строки предпринимается попытка преобразовать строку в значение типа float64 с помощью функции strconv.ParseFloat(), принимающей строку и размер результата в битах, 32 или 64. Если в процессе преобразования возникнет ошибка, вызывающей программе немедленно возвращаются все числа типа float64, которые удалось получить, непустое сообщение об ошибке и значение false*/

                if x, err := strconv.ParseFloat(slice[0], 64); err != nil {

                    return floats, "'" + slice[0] + "' ошибка", false

                } else {

/*В случае успешного преобразования полученное число типа float64 добавляется в массив floats*/

                    floats[index] = x

                }

            } else {

/*Если поля для ввода чисел были пусты при очередном нажатии кнопки Выполнить, то числам будут присвоены нулевые значения*/

                request.Form[key][0] = "0"

                floats[index] = 0

            }

            count++

        }

    }

/*Если форма отображается первый раз, элементы <input> с именами «a» и «b» еще пусты. Это не является ошибкой, поэтому возвращается пустой срез со значениями типа float64, пустое сообщение об ошибке и false, чтобы показать, что статистические характеристики не были вычислены, – в результате этого будет отображена пустая форма*/

    if count != 2 { // при первом запуске поля пустые

        return floats, "", false //это не ошибка

    } else { // но вычислять нечего

/*Если пользователь ввел некоторые данные, возвращается срез со значениями типа float64, пустое сообщение об ошибке и true*/

        return floats, "", true

    }

}

5 Функции для расчета результата выполнения арифметических операций практически одинаковы, поэтому рассмотрим только функцию для операции деления:

/*Функция принимает в качестве аргумента массив из введенных чисел и возвращает результат в формате float64 и строку, которая пуста, когда операция деления допустима, иначе, принимает значение «Деление на 0»*/

func division(floats [2]float64) (float64, string) {

    a, b := floats[0], floats[1] /*переменные принимают значения первого и второго числа соответственно*/

    if b == 0 {

        return 0, "Деление на 0"

    } else {

        return a / b, ""

    }

}

Остальные функции оформите самостоятельно.

6 Функция для вывода результатов вычислений может быть следующей (оформляется таблица с результатами выполнения арифметических операций):

func formatSolutions(x [2]float64, a, b, c, d float64, str string) string {

    if str == "" {

        return fmt.Sprintf(`<table border="1">

<tr><th colspan="2">Результат</th></tr>

<tr><td>Число a</td><td>%f</td></tr>

<tr><td>Число b</td><td>%f</td></tr>

<tr><td>Сложение (a+b)</td><td>%f</td></tr>

<tr><td>Вычитание (a-b)</td><td>%f</td></tr>

<tr><td>Умножение (a*b)</td><td>%f</td></tr>

<tr><td>Деление (a/b)</td><td>%f</td></tr>

</table>`, x[0], x[1], a, b, c, d)

    } else {

        return fmt.Sprintf(`<table border="1">

        <tr><th colspan="2">Результат</th></tr>

        <tr><td>Число a</td><td>%f</td></tr>

<tr><td>Число b</td><td>%f</td></tr>

        <tr><td>Сложение (a+b)</td><td>%f</td></tr>

        <tr><td>Вычитание (a-b)</td><td>%f</td></tr>

        <tr><td>Умножение (a*b)</td><td>%f</td></tr>

        <tr><td>Деление (a/b)</td><td>%s</td></tr>

        </table>`, x[0], x[1], a, b, c, str)

    }

}

Результат работы приложения представлен на рисунке 2.3:

Рисунок 2.3  Результат работы веб-приложения

Задание 2.9 Дополните приложение новыми возможностями (используйте функции из таблицы 1.8).

Задание 2.10 Выполните задания по вариантам.

Задача 1 Требуется вывести «Истина», если приведенное высказывание для предложенных исходных данных является истинным, и «Ложь» ‑ в противном случае. Все числа, для которых указано количество цифр (двузначное число, трехзначное число и т.д.), считаются целыми.

Вариант 1

Квадратное уравнение A·x2 + B·x + C = 0 с данными коэффициентами A, B, C имеет вещественные корни

Вариант 2

Данные числа x, y являются координатами точки, лежащей во второй координатной четверти

Вариант 3

Данные числа x, y являются координатами точки, лежащей в первой или третьей координатной четверти

Вариант 4

Точка с координатами (x, y) лежит внутри прямоугольника, левая верхняя вершина которого имеет координаты (x1, y1), правая нижняя — (x2, y2), а стороны параллельны координатным осям

Вариант 5

Данное целое число является четным двузначным числом

Вариант 6

Данное целое число является нечетным трехзначным числом

Вариант 7

Среди трех данных целых чисел есть хотя бы одна пара совпадающих

Вариант 8

Среди трех данных целых чисел есть хотя бы одна пара взаимно противоположных

Вариант 9

Сумма цифр данного трехзначного числа является четным числом

Вариант 10

Сумма двух первых цифр данного четырехзначного числа равна сумме двух его последних цифр

Вариант 11

Данное четырехзначное число читается одинаково слева направо и справа налево

Вариант 12

Все цифры данного трехзначного числа различны

Вариант 13

Цифры данного трехзначного числа образуют возрастающую последовательность

Вариант 14

Цифры данного трехзначного числа образуют возрастающую или убывающую последовательность

Вариант 15

Цифры данного трехзначного числа образуют арифметическую прогрессию

Вариант 16

Цифры данного трехзначного числа образуют геометрическую прогрессию

Задачи 2 и 3 выполнить в виде веб-приложения:

Вариант 1

Задача 2 Заменить наименьшее из трех чисел суммой двух других чисел.

Задача 3 Дано целое число в диапазоне 100 – 999. Вывести строку — словесное описание данного числа, например: 256 — «двести пятьдесят шесть», 814 — «восемьсот четырнадцать»

Вариант 2

Задача 2 Дано целое число, лежащее в диапазоне от –999 до 999. Вывести строку — словесное описание данного числа вида «отрицательное двузначное число», «нулевое число», «положительное однозначное число» и т.д. 

Задача 3 В восточном календаре принят 60-летний цикл, состоящий из 12-летних подциклов, обозначаемых названиями цвета: зеленый, красный, желтый, белый и черный. В каждом подцикле годы носят названия животных: крысы, коровы, тигра, зайца, дракона, змеи, лошади, овцы, обезьяны, курицы, собаки и свиньи. По номеру года вывести его название, если 1984 год был началом цикла — годом зеленой крысы