#scala #csv #apache-spark
#scala #csv #apache-spark
Вопрос:
Я считываю некоторые данные из файла CSV, и у меня есть пользовательский код для разбора строковых значений на разные типы данных. Для чисел я использую:
val format = NumberFormat.getNumberInstance()
который возвращает a DecimalFormat
, и я вызываю parse
функцию для этого, чтобы получить мое числовое значение. DecimalFormat
имеет произвольную точность, поэтому я не теряю никакой точности. Однако, когда данные помещаются в Spark DataFrame, они сохраняются с использованием DoubleType
. На данный момент я ожидаю увидеть некоторые проблемы с точностью, однако я этого не делаю. Я попытался ввести значения из 0.1, 0.01, 0.001, …, 1e-11 в свой CSV-файл, и когда я смотрю на значения, хранящиеся в Spark DataFrame, все они точно представлены (т. Е. Не похожи на 0.0999999999). Я удивлен таким поведением, поскольку я не ожидаю, что двойное значение сохранит произвольную точность. Кто-нибудь может помочь мне понять магию здесь?
Приветствия!
Комментарии:
1. Я думаю, это просто представление. Попробуйте что-нибудь ближе к пределам того, что может обрабатывать double.
2. Также …
Double
s хороши для представления значений, если они находятся в их диапазоне. Проблема возникает, когда вы выполняете операции с произвольными числами точности, представленными с использованием удвоений.3. Я думал, что удвоения будут точно представлять целые числа в пределах поддерживаемого диапазона, но не все десятичные значения между целыми числами. Это то, что меня смутило.
Ответ №1:
Вероятно, здесь есть две проблемы: количество значащих цифр, которые Double может представлять в своей мантиссе; и диапазон его экспоненты.
Грубо говоря, Double имеет точность около 16 (десятичных) цифр, а показатель степени может охватывать диапазон от примерно 10 ^ -308 до 10 ^ 308. (Очевидно, что фактические ограничения устанавливаются двоичным представлением, используемым форматом ieee754.)
Когда вы пытаетесь сохранить число, подобное 1e-11, его можно точно аппроксимировать в пределах 56 бит, доступных в мантиссе. Проблемы с точностью возникают, когда вы хотите вычесть два числа, которые настолько близки друг к другу, что они отличаются только небольшим количеством младших значащих битов (при условии, что их мантиссы были выровнены, сдвинуты так, чтобы их показатели были одинаковыми).
Например, если вы попробуете (1e20 2) — (1e20 1), вы надеетесь получить 1, но на самом деле вы получите ноль. Это связано с тем, что у Double недостаточно точности для представления необходимых 20 (десятичных) цифр. Однако (1e100 2e90) — (1e100 1e90) вычисляется как почти точно 1e90, как и должно быть.
Комментарии:
1. Кроме того, если вы многократно умножаете очень маленькие числа, которые будут происходить во многих случаях, например, проценты на небольшие центы.
2. Итак, какой тип данных использовать для получения точности, превышающей 16 (десятичных) цифр