В чем разница между типами double и decimal в C#?

Ответ

Типы double и decimal предназначены для чисел с плавающей запятой, но имеют фундаментальные различия в представлении, точности и применении.

Критерий double (System.Double) decimal (System.Decimal)
Стандарт IEEE 754 (двоичный) Десятичный (base-10)
Размер 64 бита (8 байт) 128 бит (16 байт)
Точность ~15-16 десятичных знаков ~28-29 десятичных знаков
Диапазон Огромный (±5.0 × 10^−324 до ±1.7 × 10^308) Меньший (±1.0 × 10^−28 до ±7.9 × 10^28)
Основная проблема Ошибки двоичного представления (например, 0.1) Нет ошибок представления для десятичных чисел
Производительность Высокая (аппаратная поддержка FPU) Ниже (программная эмуляция)
Сфера применения Научные вычисления, 3D-графика, симуляции Финансовые расчеты, денежные суммы, бухгалтерия

Ключевой пример ошибки округления double:

double d = 0.1 + 0.2;
Console.WriteLine(d == 0.3); // False!
Console.WriteLine(d); // 0.30000000000000004

// Для decimal используется суффикс 'm'
decimal m = 0.1m + 0.2m;
Console.WriteLine(m == 0.3m); // True
Console.WriteLine(m); // 0.3

Рекомендация:

  • Используйте decimal для всех финансовых операций, где важна точность десятичных расчетов (цена, налог, процент).
  • Используйте double для вычислений, где важна скорость и диапазон, а небольшая погрешность допустима (физика, координаты, статистика).

Ответ 18+ 🔞

Ну слушай, смотри, есть два типа для чисел с плавающей точкой — double и decimal. И они, блядь, как небо и земля, хотя на первый взгляд одно и то же. Просто один для учёных, а другой для бухгалтеров, которые с каждой копейкой считаются.

Вот смотри, табличка, чтобы не запутаться:

Критерий double (System.Double) decimal (System.Decimal)
Как внутри устроен По стандарту IEEE 754 (двоичный) По-человечески, десятичный (base-10)
Сколько жрёт памяти 64 бита (8 байт) 128 бит (16 байт) — в два раза больше!
Точность Примерно 15-16 знаков после запятой Целых 28-29 знаков, представляешь?
Диапазон значений Охуенно огромный (±5.0 × 10^−324 до ±1.7 × 10^308) Поменьше, но всё равно дохуя (±1.0 × 10^−28 до ±7.9 × 10^28)
Главная засада Ошибки из-за двоичного представления (например, 0.1) Для десятичных дробей ошибок нет, красота
Скорость Высокая, железо его напрямую поддерживает Ниже, потому что софтовые вычисления
Где юзать Наука, графика, игры — где скорость важнее Финансы, деньги, бухгалтерия — где каждая копейка на счету

А теперь самый сок, пример, от которого мозг вытекает. Берём double:

double d = 0.1 + 0.2;
Console.WriteLine(d == 0.3); // False, блядь!
Console.WriteLine(d); // 0.30000000000000004 — вот же ж ёбаный насос!

Видишь? Сложил 0.1 и 0.2, а получил какую-то хуйню. Это потому что внутри он двоичный, и для него 0.1 — это бесконечная дробь, как пилить сук, на котором сидишь.

А теперь decimal (не забудь суффикс 'm', а то опять обосрёшься):

decimal m = 0.1m + 0.2m;
Console.WriteLine(m == 0.3m); // True, ура!
Console.WriteLine(m); // 0.3 — всё чисто, как слёзы младенца.

Вот и весь сказ. Итог простой, как три копейки:

  • Если делаешь что-то с деньгами — цена, налог, зарплата — только decimal. Иначе потом бухгалтер придёт и ебальник набьёт за потерянную копейку.
  • Если гоняешь полигоны, считаешь траектории или делаешь научные расчёты — бери double. Он быстрый, и погрешность в десятом знаке тебя волновать не должна.