Является ли приведение узких типов к более широким типам для экономии памяти и сохранения высокоточных вычислений - ужасная идея? - PullRequest
5 голосов
/ 28 мая 2009

Я имею дело с финансовыми данными, поэтому их много, и они должны быть относительно высокоточными (с 64-битной плавающей точкой или шире).

Стандартная практика на моем рабочем месте, как представляется, представляет все это как десятичный тип c #, представляющий собой 128-битную плавающую точку, специально созданную для поддержки операций округления, свободных от base10.

Поскольку 64-битная система достаточно широка, чтобы поддерживать репрезентативную точность, смешно ли приводить данные к более широкому типу для всех вычислений (mult, div, add и т. Д.), А затем возвращаться к 64-битной версии для хранения в памяти (где это тратит большинство, если его время)?

Для справки: память определенно является ограничивающим ресурсом.

Ответы [ 10 ]

16 голосов
/ 28 мая 2009

Смысл использования десятичного (128 бит) над двойным (64 бит) и с плавающей точкой (32 бит) обычно не связан с размером. Это связано с базой. В то время как double и float являются плавающими двоичными точечными типами, decimal - это плавающий десятичный точечный тип - и это та функция, которая позволяет ему представлять числа, подобные 0.1, в точности там, где float / double нельзя.

Нет концептуальной причины, по которой у нас не могло бы быть 64-битного десятичного типа, и во многих случаях этого действительно было бы достаточно - но пока такой тип не появится или вы не напишите его самостоятельно, пожалуйста не используйте «более короткие» (и двоичные числа с плавающей точкой) типы float / double для финансовых расчетов. Если да, то ты напрашиваешься на неприятности.

Если вы предлагаете записать тип хранилища, который может преобразовывать в / из десятичного числа и все еще является плавающим десятичным типом, это звучит как потенциально хорошая идея, даже если она не может выполнять какие-либо вычисления. Вам нужно быть очень осторожным, когда вы думаете о том, что делать, если вас когда-либо просят преобразовать десятичное значение, которое вы не можете точно представить. Мне было бы интересно увидеть такой тип, если честно. Хм ...

(Как указывали другие ответы, я действительно должен убедиться, что это числа, которые занимают память, прежде чем делать это, однако. Если вам не нужно , чтобы сделать это, мало Точка введения дополнительной сложности умозрительно.)

5 голосов
/ 28 мая 2009

64-битная плавающая точка не может поддерживать точность финансовых данных. Это не вопрос пространства, это вопрос о том, какую систему счисления используют типы данных; double использует base-2, decimal - это base-10, а base-2 не может представлять точные десятичные числа base-10, даже если он имеет 1000 бит точности.

Не верите мне? Запустите это:

double d = 0.0;
for (int i = 0; i < 100; i++)
    d += 0.1;
Console.WriteLine(d);

> 9.99999999999998

Если вам нужны вычисления с основанием 10, вам нужен десятичный тип.

(Правка: черт побери, Джон Скит снова ...)

Если десятичный тип действительно является узким местом, вы можете использовать большое количество копеек (или 1/8 цента, или что бы то ни было из вашей единицы) вместо десятичных долларов.

3 голосов
/ 28 мая 2009

Вполне разумно хранить ваши числа в 64-битном формате, приводить их к десятичному типу для вычислений и приводить результат обратно к 64-битному, если вы не возражаете против снижения производительности.

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

Подробнее об арифметике с плавающей запятой и причинах появления ошибок в ваших вычислениях см. «Что должен знать каждый компьютерный специалист об арифметике с плавающей запятой» по адресу http://docs.sun.com/source/806-3568/ncg_goldberg.html

3 голосов
/ 28 мая 2009

Вы должны использовать профилировщик, чтобы увидеть, какие объекты занимают много памяти. Если ваши десятичные объекты являются виновником, то я бы сказал, да идти за ними. В противном случае вы просто делаете предположения. Профилировщик скажет вам точно.

2 голосов
/ 28 мая 2009

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

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

Другой подход может заключаться в улучшении алгоритмической эффективности вашей системы, а не в «сжатии» типа хранилища. Вам действительно нужны все эти данные в памяти сразу? Можете ли вы виртуализировать это как-нибудь?

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

2 голосов
/ 28 мая 2009

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

0 голосов
/ 14 января 2015

То же значение удваивается, преобразуется в десятичные дроби, затем преобразуется в байты [], а затем сжимается, занимает в 2 раза меньше места (я только что проверил это с несколькими библиотеками сжатия: Blosc по умолчанию, lz4, zlib с или без случайного числа, с десятичным числом случайного числа) лучшие).

Один из вариантов - хранить сжатые десятичные дроби в памяти или на диске, поскольку процессоры сегодня голодают. Смотрите ряд презентаций здесь: http://blosc.org/docs/

0 голосов
/ 28 мая 2009

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

Похоже, ТРЕБУЕТСЯ выполнить приведение в том случае, если вы используете.

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

Вы можете рассмотреть возможность создания / поиска 64-битной реализации BCD (Binary Coded Decimal), которую можно использовать для вашей системы.

0 голосов
/ 28 мая 2009

Является ли "просто добавить больше памяти" приемлемым ответом?

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

0 голосов
/ 28 мая 2009

Вам нужно провести численный анализ, чтобы увидеть, является ли практика (хранения 128 битов) нелепой, или просто ленивой, или действительно необходимой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...