Ваше утверждение неверно: 369.1368
не может быть точно представлено либо float32
или float64
.
Ближайшее значение float32
(приблизительно) 369.136810302734375
, округляя до 369.13681
, откуда берется ваша дополнительная цифра. Ближайшее значение float64
(приблизительно) 369.13679999999999382
, которое лучше подходит для ваших целей.
(Конечно, если вы округлите одно из этих значений до четырех цифр после десятичной точки, вы получитеожидаемое число.)
Представление Decimal
является точным: ошибки округления нет.
JSON передает и получает значения с плавающей запятой, выраженные в десятичном виде, но фактические реализации , на разных языках, тогда кодируют эти числа по-разному. В зависимости от того, с какой сущностью вы разговариваете с помощью JSON, кодирование и декодирование с помощью Decimal
может сохранить число в точности так, как вы хотите, но помните, что программы, написанные, например, на C ++ или Python, могут декодировать ваш номер вдругая точность с плавающей точкой и вводит различные ошибки округления.
Этот пример Go Playground использует недавно добавленный формат %x
и показывает, как числа хранятся внутри:
как float32 = 369.13681030273437500 (float32), что в действительности составляет 12095875p-15 или 0x1.712306p + 08
и:
как float64 =369.13679999999999382 (float64), который на самом деле 6493923261440380p-44 или 0x1.712305532617cp + 08
То есть число 369. независимо от внутренне представлено в двоичном виде. Это между 2 8 = 256 и 2 9 = 512. В двоичном виде это 1 256, нет 128, 1 64, 1 32, 1 16, нет 8, нет 4,нет 2, а 1 1: 1.01110001 что-то x 2 8 . Формат %b
выражает это в одном направлении, а формат %x
- в другом, с %x
, начинающимся с 1.72
(1. 0111 0010).
См. Не нарушена ли математика с плавающей запятой? (как jub0bs связаны в комментарии) для более.