Golang float

Текст "Go" и число 28487 на компьютере с архитектурой x86 представлены одним и тем же набором нулей и единиц — 0110111101000111. Тип устанавливает, что данные биты и байты означают. В первом случае это строка string из двух символов, а во втором случае — 16-битное число integer (2 байта). Тип string используется для многоязычного текста, а 16-битный integer является одним из числовых типов.

Далее будут рассмотрено представление вещественных чисел в Golang. По окончании урока вы сможете:

Премиум 👑 канал по Golang

Рекомендуем вам супер TELEGRAM канал по Golang где собраны все материалы для качественного изучения языка. Удивите всех своими знаниями на собеседовании! 😎

Подписаться на канал

Уроки, статьи и Видео

Мы публикуем в паблике ВК и Telegram качественные обучающие материалы для быстрого изучения Go. Подпишитесь на нас в ВК и в Telegram. Поддержите сообщество Go программистов.

Go в ВК ЧАТ в Telegram


  • Использовать два типа данных для вещественных чисел;
  • Разобраться в компромиссе между памятью и точностью;
  • Избавиться от ошибок округления ваших числовых данных.

Компьютерное хранилище манипулирует вещественными числами вроде 3.14159, используя IEEE-754 стандарт с плавающей запятой. Числа с плавающей запятой могут быть как очень крупными, так и чрезвычайно малыми — для сравнения подумайте о галактиках и атомах. С многогранностью подобного рода языки программирования вроде JavaScript и Lua справляются через исключительное использование чисел с плавающей запятой. Компьютеры также используют integer для целых чисел, о чем мы поговорим в следующем уроке.

Объявление переменных с плавающей запятой в Golang

У каждой переменной есть тип. При объявлении и инициализации переменной с вещественным числом используется тип с плавающей запятой float. Следующие три строки кода эквивалентны, так как компилятор Go отнесет переменную days к типу float64 даже без дополнительного уточнения:

Важно знать, что у переменной days тип float64, излишне уточнять float64. Разработчики и компилятор Go и так поймут тип, просто посмотрев на значение справа. Если рассматривается число с десятичной точкой, его тип всегда будет float64.

При написании кода специальный инструмент golint выдает подсказки для правки. Беспорядочный код будет прокомментирован следующим сообщением:

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

Вопрос для проверки: 

Какого типа будет переменная answer := 42.0?

Числа одинарной точности float32

В Go есть два типа данных для чисел с плавающей запятой. По умолчанию присваивается float64, 64-битный тип с плавающей запятой, что использует восемь байтов памяти. В некоторых языках программирования при описании 64-битного типа с плавающей запятой используется термин двойная точность.

Тип float32 задействует половину используемой float64 памяти, но является менее точным. Данный типа еще называют одинарной точностью. Для использования float32 во время объявления переменной нужно уточнить ее тип. В следующем коде показан пример использования float32:

При работе с большим объемом данных вроде тысяч вершин в 3D-игре будет разумно пожертвовать точностью ради экономии памяти с помощью float32.

На заметку: Функции из пакета math оперируют с типами float64. Если у вас нет четкой причины выбрать иной тип, отдавайте предпочтение float64.

Вопрос для проверки: 

Сколько байт памяти уходит на использование одинарной точности float32?

Нулевое значение в Golang

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

В данном коде объявляется переменная price без значения, поэтому Go инициализирует ее с нулем. Для компьютера код идентичен следующему:

Для программиста разница едва уловима. Объявление price := 0.0 равносильно тому, что товар бесплатен. Отсутствие уточнения значения price является своеобразной подсказкой, что значение будет добавлено в будущем.

Вопрос для проверки:

Что означает нулевое значение для float32?

Отображение типа чисел с плавающей запятой в Golang

При использовании Print и Println для типов с плавающей запятой по умолчанию выводится столько знаков, сколько возможно. Если вам это не нужно, используйте Printf с символом для форматирования %f для уточнения количества чисел после запятой. Код с примером дан ниже:

Специальный символ %f форматирует значение third с шириной (width) и точностью (precision). Схема представлена ниже:

format go

Специальный символ %f для форматирования

Точность, или precision уточняет, сколько знаков вещественного числа должно выводиться после точки. В следующем примере выводится два знака — %.2f:

format go

Результат, отформатированный с шириной (width) 4 и точностью (precision) 2

Ширина уточняет минимальное число выводимых символов, включая точку вместе с числами до и после нее. К примеру, ширина числа 0.33 равна четырем. Если ширина больше количества необходимых символов, Printf заполнит оставшееся место пробелами. Если ширина не уточняется, Printf использует количество символов, необходимое для отображения значения.

Для заполнения пропуском нулями вместо пробелов требуется добавить в префикс ширины ноль. Пример дан ниже:

Задания для проверки:

  1. Самостоятельно наберите код из листинга 3, один из примеров урока, в тело функции main на Go Playground. Попробуйте различные значения для ширины и точности в операторе Printf.
  2. Каковы значения ширины и точности 0015.1021?

Точность чисел с плавающей запятой в Go

В математике некоторые рациональные числа не могут быть точно представлены в форме десятичной дроби. Число 0.33 является лишь приближенным значением дроби 1/3. Неудивительно, что при проведении операций над приближенными значения результат также является приближенным:

1/3 + 1/3 + 1/3 = 1

0.33 + 0.33 + 0.33 = 0.99

Числа с плавающей запятой также страдают от ошибок округления. Разница в том, что машины используют бинарное представление (нули и единицы) вместо десятичного (1-9). В результате компьютеры могут точно передать значение 1/3, но с другими числами могут быть вызваны ошибки округления. Это показано в следующем примере:

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

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

Для уменьшения ошибок округления рекомендуется проводить умножение перед делением. Как правило, при осуществлении вычислений в таком порядке результат более точный. Это показано  в примерах ниже на примере конвертера температуры:

Вопрос для проверки:

Лучший способ избежать ошибок округления?

Сравнение чисел с плавающей запятой

В примере из листинга 5 значение piggyBank 0.30000000000000004, а не описанное 0.30. Имейте это в виду, когда решите сравнить числа с плавающей запятой:

Вместо прямого сравнения чисел с плавающей запятой определите абсолютную разницу между двумя числами, а затем убедитесь, что разница не слишком велика. Для принятия абсолютного значения float64 в пакете math есть функция Abs:

На заметку: Верхняя граница для ошибки с плавающей запятой для одной операции известна как машинный ноль. Его значение равно 2-52 для float64 и 2-23 для float32. К сожалению, ошибки чисел с плавающей запятой можно получить очень быстро. Добавьте 11 монет ($0.10 каждая) к piggyBank, и ошибки округления превысят 2-52 по сравнению с $1.10. Это значит, что лучше выбирать допустимое отклонение, отталкиваясь от особенностей рассматриваемого приложения —  в данном случае это 0.0001.

Вопрос для проверки:

При добавлении 11 монет ($0.10 каждая) к пустой переменной piggyBank типа float64 каким станет финальный результат?

Заключение

  • Go может назначать тип автоматически. В частности, вещественные числа инициализируются переменными типа float64;
  • Числа с плавающей запятой многогранны, но не всегда точны;
  • Мы рассмотрели 2 из 15 числовых типов данных Go: float64 и float32.

Итоговое задание для проверки:

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

5 3 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest
4 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
Аня
Аня
4 месяцев назад

fmt.Println(math.Abs(piggyBank-0.3) < 0.0001) // Выводит: false
Ошибка в примере.
Выводит true, потому что 0.00000000000000004<0.0001

Евгений
Евгений
4 месяцев назад

А я так сделал .
package main

import (
«fmt»
«math/rand»
)

func main() {

numbers := []int{5, 10, 25}
kopilka := 0
for kopilka < 2000 {
index := rand.Intn(len(numbers))
moneta := numbers[index]
kopilka = kopilka + moneta

fmt.Println(«Добавлено», moneta, «Центов. Текущая сумма:», kopilka/100, «долларов»)
}
}

Последний раз редактировалось 4 месяцев назад Евгений ем
Андрей
Андрей
2 месяцев назад

У меня так получилось:

package main

import (
«fmt»
«math/rand»
)

func main() {

var kopilka float64
var add float64

for {
count := rand.Intn(3)
switch count {
case 0:
add = 0.05
case 1:
add = 0.10
case 2:
add = 0.25
}
kopilka += add
fmt.Printf(«%4.2f\n«, kopilka)

if kopilka >= 20.00 {
break
}

}

}

Самуил
Самуил
20 часов назад

Получилось вроде

1000016232