Дробные числа и преобразования
Целых чисел не хватает, когда нужна средняя цена, вес в килограммах или доля: для этого есть float64. Главное на странице: целые и дробные числа в Go не смешиваются сами, их переводят друг в друга явно.
Дробное деление
Ситуация. Семь килограммов разложить на два пакета поровну: целое деление даст 3, килограмм потерялся.
package main
import "fmt"
func main() {
fmt.Println(7/2, 7.0/2, 7/2.0)
}Что увидите.
stagiaire@lab:~/gocourse/day03/scratch$ go run .
3 3.5 3.5Как это читать. 7/2 — два целых, деление целое. В 7.0/2 и 7/2.0 одно число записано с точкой, оно дробное — и деление дробное. Числа из кода Go подгоняет друг под друга сам: целое 2 рядом с дробным 7.0 становится дробным без потерь. С переменными так не получится.
int и float64 не смешиваются
a := 7
b := 2.5
fmt.Println(a + b)stagiaire@lab:~/gocourse/day03/scratch$ go run .
# day03/scratch
./main.go:8:14: invalid operation: a + b (mismatched types int and float64)Как это читать. invalid operation: a + b — «действие недопустимо», дальше причина: mismatched types int and float64 — типы не совпадают. Go не решает за вас, каким быть результату: дробным (9.5) или целым (9), — это говорят явно.
Преобразование типа
Запись float64(x) даёт новое значение типа float64, а сама переменная x остаётся int. Так же int(f) даёт целое из дробного.
Ситуация. Сумма 10, позиций 3, нужна средняя.
sum := 10
count := 3
avg := float64(sum) / float64(count)
fmt.Println(avg)3.3333333333333335Оба значения переведены в float64 до деления — деление дробное. Пятёрка в конце не опечатка: дробные числа хранятся неточно, подробно на пятой странице.
Преобразовать после деления — поздно:
avg := float64(sum / count)
fmt.Println(avg)3Сначала выполнилось sum / count — деление двух int, вышло 3, потом 3 превратилось в 3.0: потерянная дробь не вернулась. А запись float64(sum) / count не соберётся вовсе — float64 и int снова рядом.
Попробуйте сейчас: что выведет?
Цель: предсказать вывод с преобразованием до и после деления и отправить ответ.
Код для чтения · разбираем, набирать не нужноpackage main import "fmt" func main() { boxes := 9 fmt.Println(float64(boxes)/2, float64(boxes/2)) }▶ Выполните · выделенное замените своимcourse answer day03.q3 ВАШ_ОТВЕТВместо
ВАШ_ОТВЕТ— строка вывода целиком.После ответа проверьте себя запуском — программу нужно набрать в
scratch/main.go:✎ Наберите в файлscratch/main.gopackage main import "fmt" func main() { boxes := 9 fmt.Println(float64(boxes)/2, float64(boxes/2)) }▶ Выполнитеcd ~/gocourse/day03/scratch go run .Разошлось — отправьте ответ заново, засчитывается последний.
Готово, когда: ответ отправлен — пункт проверки
q3.
int(f) отбрасывает дробь
w := 3.99
n := -3.99
fmt.Println(int(w), int(n))3 -3int от дробного отбрасывает дробную часть — к нулю, как целое деление, а не округляет: 3.99 стало 3, а не 4. Округление — в день 04.
Константа или переменная
С переменной int(w) работает. С тем же числом, записанным прямо в коде, — нет:
fmt.Println(int(3.99))stagiaire@lab:~/gocourse/day03/scratch$ go run .
# day03/scratch
./main.go:6:18: cannot convert 3.99 (untyped float constant) to type intПри этом int(4.0) компилируется и даёт 4.
Почему так. Число в коде — константа, её значение компилятор знает заранее: 4.0 станет целым без потерь, 3.99 — с потерей, и это ошибка сборки. Значение переменной известно только при работе, поэтому int(w) — явное разрешение отбросить дробь (подробнее — в course extra 03). Та же логика даёт ловушку: число без типа подгоняется под тип соседа.
x := 7
fmt.Println(x * 2.5)stagiaire@lab:~/gocourse/day03/scratch$ go run .
# day03/scratch
./main.go:7:18: 2.5 (untyped float constant) truncated to intx — целое, и 2.5 пытается стать целым: с потерей, ошибка. А 2.0 станет целым без потерь, и fmt.Println(x*2.0, x/2.0) печатает 14 3: x/2.0 выглядит дробным делением, но 2.0 превратилось в целое 2. Точка у числа не делает деление дробным, если рядом переменная int; надёжно — float64(x) / 2.
Что может пойти не так
| Что видите | Что это значит | Что делать |
|---|---|---|
invalid operation: a + b (mismatched types int and float64) |
действие между int и float64 |
перевести одно значение: float64(a) + b или a + int(b) |
cannot convert 3.99 (untyped float constant) to type int |
константа с дробью, дробь потерялась бы | целое число или переменная float64 |
2.5 (untyped float constant) truncated to int |
дробное число рядом с переменной int |
float64(x) * 2.5 |
float64(sum / count) печатает целое |
деление выполнилось до преобразования | переводить до деления: float64(sum) / float64(count) |
| средняя на копейку меньше | делили в int, float64 взяли после деления |
переводить до деления; о средней — пятая страница |
Попробуйте сейчас: почините программу
fix1.Цель:
fix1собирается и печатает то, что обещано в первых строках файла, а правка — точечная.
- Программа в
fix1не собирается — запустите её:▶ Выполнитеcd ~/gocourse/day03/fix1 go run .
- В первых строках файла — что она должна напечатать. Прочитайте сообщение: какие два типа не сошлись? Почините так, чтобы программа печатала обещанное. Хватает одной строки, принимается не больше двух: переписанную заново программу проверка не засчитает, а копию запустит с другим числом коробок — вписать готовый вес не выйдет.
- Сообщение компилятора — в
~/errors.md: текст ошибки, тире, что значило.Готово, когда:
go run .печатает обещанную в начале файла строку и изменено не больше двух строк — пунктfix1; в~/errors.mdновая строка с тире.
Дальше: строки и форматированный вывод — course next