JavaRush /Курси /Go SELF /Цілі числа в Go: int, арифметика та пріоритет

Цілі числа в Go: int, арифметика та пріоритет

Go SELF
Рівень 2 , Лекція 1
Відкрита

1. Тип int: базовий тип цілих чисел

Коли ви тільки починаєте програмувати, найчастіше потрібно щось порахувати: суму, різницю, кількість, остачу, розмір або індекс. І тут з’являється тип int: він зберігає цілі числа без дробової частини. У Go це базовий і найпопулярніший тип для лічильників і «звичайних» чисел, тож сьогодні ми потренуємося саме на ньому.

Важлива думка: int — це про числа, які можна уявити як «…, -2, -1, 0, 1, 2, …». Від’ємні значення теж допустимі. Наприклад, температура може бути -5, баланс може бути -200, а настрій після трьох годин налагодження — ну, ви й самі знаєте.

Технічна ремарка без заглиблення: розмір int залежить від платформи — зазвичай це 32 або 64 біти. Для навчальних задач вам досить знати, що int підходить для більшості звичайних обчислень.

Мініприклад: оголошуємо int і виводимо

package main

import "fmt"

func main() {
	var tasks int = 12
	fmt.Println(tasks) // 12
}

Зверніть увагу: ми явно вказали int, але могли б і коротше — через := (ми це вже проходили раніше).

package main

import "fmt"

func main() {
	tasks := 12
	fmt.Println(tasks) // 12
}

2. Оператори +, -, *: додавання, віднімання, множення

Тепер, коли у нас є числа, хочеться робити з ними саме те, заради чого люди зазвичай терплять математику в школі: рахувати. У Go для int доступні звичні арифметичні оператори: + (додавання), - (віднімання) і * (множення). Вони виглядають саме так, як ви очікуєте, і поводяться теж передбачувано — це одна з приємних рис мови.

Важливий нюанс для новачків: у Go немає прихованої магії на кшталт автоматичних перетворень типів під час арифметики. Якщо у вас числа — ви працюєте з числами. Якщо рядки — це окрема історія, і склеювання рядків через + ми розбиратимемо окремо. Сьогодні тримаємо фокус саме на цілих числах.

Приклад: «мініпланувальник завдань»

Уявімо, що в нас є план на день і вже виконані завдання. Порахуємо, скільки залишилося.

package main

import "fmt"

func main() {
	planned := 10
	done := 3

	remaining := planned - done
	fmt.Println(remaining) // 7
}

А тепер додамо «очки продуктивності»: припустімо, за кожну виконану задачу ви отримуєте 5 очок. Порахуємо.

package main

import "fmt"

func main() {
	done := 3
	pointsPerTask := 5

	points := done * pointsPerTask
	fmt.Println(points) // 15
}

Так, це трохи схоже на RPG. Певною мірою програмування й справді так працює: прокачуємо рівень, збираємо артефакти, перемагаємо баги.

3. Оператор /: цілочисельне ділення

Ділення — найчастіша пастка для новачка, бо мозок пам’ятає шкільну математику, а комп’ютер — типи даних. Якщо ви ділите два значення типу int, результат теж буде int. А це означає, що дробова частина просто відкидається. Не округлюється, не «зберігається десь поруч», не ховається в темному кутку програми — її просто немає.

Ця поведінка називається цілочисельним діленням. Воно не «погане» і не «хороше» — воно корисне, якщо ви ділите цукерки між дітьми або розподіляєте сторінки між розділами. Але воно може бути несподіваним, якщо ви розраховували на дріб.

Приклад: «порівну» і «без решти»

package main

import "fmt"

func main() {
	a := 7
	b := 2

	fmt.Println(a / b) // 3
}

Чому так? Тому що 7 / 2 у цілих числах — це «скільки разів двійка повністю вміщується в сімці». Три рази. Остача буде окремо, і для неї в нас є оператор % (трохи пізніше).

Практичний приклад: «відсоток виконання» без дробів

Не плутайте цей оператор із відсотками. Символ схожий, але зміст інший. У програмуванні % — це остача.

package main

import "fmt"

func main() {
	planned := 10
	done := 3

	percent := (done * 100) / planned
	fmt.Println(percent) // 30
}

Тут важливо, що ми спочатку помножили done на 100, а вже потім поділили на planned. Якби ми обчислювали done / planned напряму, вийшло б 0, і далі все було б сумно та неправдоподібно.

4. Оператор %: остача від ділення

Оператор % у Go — це остача від ділення. Він відповідає на запитання: «Що залишиться, якщо ми поділимо максимально рівно, без дробів?» Якщо / дає нам «цілу частину», то % дає «хвостик». І цей хвостик надзвичайно корисний: для перевірки парності, розкладу хвилин на години, розподілу чогось порівну та розуміння, скільки залишилося.

Не плутайте цей оператор із відсотками. Знак схожий на символ відсотка, але зміст інший. У програмуванні % — це остача.

Приклад: цукерки і діти

package main

import "fmt"

func main() {
	candies := 17
	kids := 5

	each := candies / kids
	left := candies % kids

	fmt.Println(each) // 3
	fmt.Println(left) // 2
}

Читається по-людськи: «кожному по 3, ще 2 залишаться». І так, саме так ви раптово стаєте головним із чесного поділу в компанії.

Приклад: хвилини в години та хвилини

Класична задача: є кількість хвилин, хочемо отримати «скільки годин» і «скільки хвилин залишилося».

package main

import "fmt"

func main() {
	totalMinutes := 135

	hours := totalMinutes / 60
	minutes := totalMinutes % 60

	fmt.Println(hours, minutes) // 2 15
}

Зверніть увагу: ми поки не збираємо рядок виду 2:15, бо це вже тема про рядки. Зараз нам важлива математика: / дає «скільки цілих годин», % — «скільки хвилин залишилося».

5. Пріоритет операторів: як читаються вирази

Коли вирази стають довшими, виникає питання: «Що виконається першим?» Оператори мають пріоритет. У Go, як і в звичайній математиці, множення й ділення виконуються раніше, ніж додавання та віднімання. А остача % за пріоритетом стоїть поруч із * і /. Це означає, що вираз 2 + 3*4 обчислиться як 2 + (3*4).

Новачок часто отримує «не ту відповідь» саме через пріоритет, а потім підозрює Go у змові. Насправді змова проста: математика.

Таблиця пріоритету

Оператори Приклад Виконуються першими?
*, /, %
a*b
a/b
a%b
Так
+, -
a+b
a-b
Ні

Приклад: один вираз — два результати

package main

import "fmt"

func main() {
	fmt.Println(2 + 3*4)     // 14
	fmt.Println((2 + 3) * 4) // 20
}

Дужки — це ваш спосіб сказати: «Я точно знаю, чого хочу, і прошу комп’ютер не здогадуватися замість мене». Навіть якщо ви пам’ятаєте про пріоритет, дужки роблять код читабельнішим. У промисловій розробці це часто важливіше, ніж економія двох символів.

6. Мініпроєкт: ділимо піцу і рахуємо прогрес

Зараз у нас уже достатньо інструментів, щоб написати маленьку програму, яка виглядає як справжній застосунок, а не просто набір розрізнених обчислень. Ми поки не читаємо дані зі вводу; це буде окрема тема, тому значення задамо прямо в коді. Зате потренуємося одразу на + - * / %, у пріоритеті та в цілочисельному діленні.

Ідея така: у нас є піца, нарізана на шматочки, є компанія людей і є план — скільки шматочків можна з’їсти сьогодні, щоб совість не дзвонила мамі. Порахуємо порції, остачу та відсоток виконання плану.

Версія 1: ділимо порівну і рахуємо остачу

package main

import "fmt"

func main() {
	slices := 14
	people := 5

	each := slices / people
	left := slices % people

	fmt.Println(each, left) // 2 4
}

Результат 2 4 означає: «кожному по 2 шматочки, 4 залишиться».

Версія 2: додаємо «план» і відсоток виконання

Припустімо, наш план — з’їсти не більше 10 шматочків усією компанією (піца в небезпеці, але ми тримаємося).

package main

import "fmt"

func main() {
	plan := 10
	alreadyEaten := 3

	remaining := plan - alreadyEaten
	percent := (alreadyEaten * 100) / plan

	fmt.Println(remaining) // 7
	fmt.Println(percent)   // 30
}

Тут ми використали одразу кілька речей: віднімання для остачі за планом, множення й ділення для цілого відсотка, а також дужки. У цьому випадку дужки не обов’язкові, але вони допомагають читати код.

Версія 3: скільки піц потрібно за значенням pizzaSize

Уявімо, що ми заздалегідь знаємо, скільки всього шматочків потрібно на всіх, наприклад по 3 на людину. Тепер хочемо зрозуміти, скільки цілих піц купити та скільки шматочків залишиться «на ранок» (ранок, звісно, настане не в усіх).

package main

import "fmt"

func main() {
	people := 5
	slicesPerPerson := 3
	pizzaSize := 8

	totalSlices := people * slicesPerPerson
	pizzas := totalSlices / pizzaSize
	left := totalSlices % pizzaSize

	fmt.Println(pizzas, left) // 1 7
}

Вийшло 1 7: одна ціла піца і ще 7 шматочків зверху. Тобто фактично потрібно 2 піци, але тут ми впираємося в те, що в нас поки немає умов if. Тому зараз ми чесно показуємо результат ділення та остачу. Трохи пізніше, коли з’являться умови, ми навчимося коректно й автоматично округляти вгору в таких задачах.

7. Типові помилки під час роботи з int і арифметикою

Помилка №1: очікувати дробовий результат від int / int.
Дуже легко за звичкою думати, що 7 / 2 має дати 3.5. Але якщо обидва числа — int, результат теж int, а дробова частина відкидається. Якщо вам потрібні «справжні дроби», це окрема тема, і там будуть інші типи чисел та інші звички.

Помилка №2: забувати про пріоритет операторів і отримувати «дивні» відповіді.
Вираз a + b*c рахується як a + (b*c), а не як (a+b)*c. Якщо порядок важливий, дужки — ваш найкращий друг. Навіть коли дужки не обов’язкові, вони часто роблять намір коду очевидним і рятують від помилок під час читання.

Помилка №3: плутати % з відсотками.
Символ схожий на знак відсотка, але це остача. 17 % 5 — це не 17 відсотків від 5 і не 5 відсотків від 17. Це те, що залишилося, коли ми поділили 17 на 5 порівну. Дуже корисна операція, особливо в задачах на парність, час і поділ.

Помилка №4: випадково ділити на нуль (/ 0 або % 0).
Ділення на нуль для int — це не «помилка компіляції», а помилка виконання: програма впаде. Зараз у нас ще немає умовних операторів, щоб акуратно перевіряти дільник, тому запам’ятайте просте правило: дільник має бути ненульовим, і про це треба подбати заздалегідь.

Помилка №5: обчислювати відсоток як done / total * 100.
За цілочисельного ділення done / total часто перетворюється на 0, і далі все теж стає 0. У цілочисельній арифметиці зазвичай роблять навпаки: (done * 100) / total. Це не «хак», а нормальний прийом роботи з int, коли вам потрібен цілий відсоток без дробів.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ