Ответ
Для работы с деньгами следует избегать типов с плавающей запятой (float32, float64) из-за их неточности в представлении десятичных дробей. Лучшими практиками являются:
1. int (в минимальных единицах)
Хранить сумму в минимальных денежных единицах (копейках, центах). Это самый простой, быстрый и распространенный подход.
- Преимущества: Высокая производительность, простота, отсутствие проблем с точностью, возможность использовать в качестве ключа
map. - Недостатки: Требуется ручное преобразование при отображении пользователю (деление на 100).
// 123 рубля 45 копеек хранятся как 12345
priceInKopecks := 12345
// Для отображения
fmt.Printf("Цена: %.2f руб.n", float64(priceInKopecks)/100.0)
2. Специализированные пакеты (decimal)
Использовать библиотеки для работы с десятичной арифметикой с фиксированной точностью. Самая популярная — github.com/shopspring/decimal.
- Преимущества: Гарантированная точность, удобные методы для арифметических операций (сложение, вычитание, округление).
- Недостатки: Ниже производительность по сравнению с
int, добавляет внешнюю зависимость, экземплярыdecimal.Decimalне являются сравниваемыми и не могут быть ключами вmap.
import "github.com/shopspring/decimal"
price1, _ := decimal.NewFromString("100.50")
price2 := decimal.NewFromFloat(0.2)
// Точное сложение
total := price1.Add(price2) // "100.7"
Почему float — плохой выбор?
Типы float хранят числа в двоичном формате, который не может точно представить большинство десятичных дробей. Это приводит к ошибкам округления.
// Классический пример
fmt.Println(0.1 + 0.2) // Выведет: 0.30000000000000004
// При работе с деньгами это недопустимо
var price float64 = 100.50
var tax float64 = 0.21
fmt.Println(price * tax) // Выведет: 21.105000000000004 Ответ 18+ 🔞
А, ну ты глянь, какие тут советы по деньгам раздают! Слушай, это же просто пиздец, как люди умудряются накосячить с баблом в коде. Ну ладно, сейчас разложу по полочкам, как не облажаться.
Во-первых, забудь нахуй про эти float'ы, когда речь про деньги. Это как пытаться измерить граммы на весах для грузовиков — нихуя точности не будет. Вот смотри, классика жанра:
fmt.Println(0.1 + 0.2) // Выведет: 0.30000000000000004
Ёпта, ну что это за пиздец? Ты представляешь, если бы в магазине тебе сдачу так считали? "С вас 0.30000000000000004 рубля, гражданин". Да я бы кассу разнёс, блядь!
1. Самый простой и надёжный способ — int в копейках
Это как работать голыми руками, зато точно и быстро. Всё хранишь в минимальных единицах — копейках, центах, сатоши, чёрт знает в чём ещё.
- Что хорошего: Быстрее некуда, никаких проблем с точностью, можно хоть в
mapключом пихать. - Что не очень: Надо постоянно делить на 100, когда показываешь людям. Ну, терпимо, блядь.
// 123 рубля 45 копеек — это просто 12345
priceInKopecks := 12345
// А чтобы показать — подели на сотку
fmt.Printf("Цена: %.2f руб.n", float64(priceInKopecks)/100.0)
Вот и вся магия. Никаких сюрпризов, всё прозрачно, как слёзы ребёнка. Хочешь прибавить 50 копеек? priceInKopecks += 50. И нехуй мудохаться.
2. Для сложных расчётов — пакеты вроде decimal
Если у тебя там проценты, сложные проценты, налоги на налоги — тогда уже можно прикрутить что-то серьёзное. github.com/shopspring/decimal — народный выбор.
- Что хорошего: Точность гарантирована, как у швейцарских часов. Сложение, умножение, округление — всё из коробки.
- Что не очень: Тормознее, чем
int, ещё и зависимость подтягивать. И вот это вот — вmapих не засунешь, они не сравниваемые. Ну, ебать, не судьба.
import "github.com/shopspring/decimal"
price1, _ := decimal.NewFromString("100.50")
price2 := decimal.NewFromFloat(0.2)
// Складываешь — и спишь спокойно
total := price1.Add(price2) // "100.7"
Итог, блядь
Не выёбывайся. Для 99% случаев — int в копейках, и все довольны. Если реально сложная финансовая хуйня с кучей расчётов — тогда decimal. А float для денег — это как ебать гвоздями: и больно, и бесполезно, и результат предсказуемо пиздецовый.
Вот так-то, а то некоторые думают, что они умные, с этими своими числами с плавающей запятой. Плавать они будут, только не в деньгах, а в говне, когда клиенты начнут жаловаться на копейку в расчётах.