А в мире языке С практика инициализации структур нулем через memset является весьма распространенной и в целом не самой плохой практикой.
Вопрос: а что, если в структуре есть поля типа double или float. Что будет, если поля этих типов будут тупо забиты нулями, каково будет значение этих полей?
Для начала я проверил у себя на Солярисе и в Visual Studio 9 - все вроде нормально. После memset'а нулем и float и double тоже равны нулю.
Хотя в целом правильный ответ такой: если ваш компилятор гарантирует хранение вещественных чисел в форматe IEEE 754, то вы в безопасности. Если нет (стандарт языка не гарантирует, что должен использоваться именно IEEE 754), то могут быть неожиданности.
Я видел платформу, где binary representation для float и double была не в IEEE формате.
ОтветитьУдалить"Нулевое" значение памяти для float'а соответствовало -1.0f
а классы memset-ить можно или нельзя?
ОтветитьУдалитьденьги с плавающей точкой... Поубывалбы
ОтветитьУдалитьbialix: нет, вот тут все четко: в С++ memset-ить можно только POD типы. Если в типе есть хоть минимальная примесь ООП, то нельзя делать никаких предположений о формате хранения типа в памяти, и тем более в эту память лазить руками. Например "struct A { int a; }" это POD-тип, а вот "struct A { public: int a; } - уже нет, хоть по сути одно и тоже.
ОтветитьУдалитьКонечно, во многих компиляторах будет работать memset для класса, но это не по страндарту.
malgarr: А какие проблемы с хранением сумм с плавающей точкой? разве что сравнивать надо не через "==", а через "abs(a-b) < e". Просто float и double - это просто и быстро. Правильнее, конечно, делать свой класс для чисел произвольной длины и точности, но если надо обрабатывать огромное количество сумм (например, цен) в секунду, то тут уже надо идти на компромисс.
ОтветитьУдалитьА как решается проблема невозможности полностью точного представления десятичных дробей? Например, 0.3 это ж 0.2(9) даже в double. Всякие ошибки округления не мучают? Или у вас просто сравнение цен, без дальнейшей обработки их?
ОтветитьУдалить@malgarr: согласен, даже double заставляет меня нервничать.
ОтветитьУдалитьЯ у себя использую тип Currency (хранится в 64-бит целом, фиксированная точка, 4 десятичных знака после запятой). Скорость сравнения для целых, мне кажется, даже пошустрее double будет.
Хранение цены как float дает следующее:
ОтветитьУдалить- поддержка дробности как таковой
- атомарность (float - это 4 байта, что на большинстве современных платформ атомарная единица), можно при многопотоковой обработке не использовать mutex'ы, "взятие" которых съедает все ухищрения по производительности. Атомарность double (8 байт) у нас на Sparc'ах не принимается. В double переводится только после критических по времени участков.
Согласен, тут есть и плюсы и минусы.
Кстати, от ошибок округления можно избавиться разве что хранением в натуральных дробях. Если у вас четко 4 знака после запятой в типе Currency, проблемы с округлением будут точно такие же.
Использоване float и double для финансовых операций неверно! Ни float, ни double не могут представить елементарные 10 сентов (0.1)
ОтветитьУдалитьпример:
float cent = 0.01f;
if (cent < 0.01)
std::cout << "cent < 0.01" << std::endl;
if (cent > 0.01)
std::cout << "cent > 0.01" << std::endl;
if (cent == 0.01)
std::cout << "cent == 0.01" << std::endl;
Для большинства финансовых инструментов достаточно типов int или long long. При этом переменная должна хранить количество центов (или дробную часть центов в зависимости от нужной точности)
Надеятся на атомарность действительных чисел - неправильно в принципе. И размер переменной тут непричём. Это уже оптимизация, а я очень сомневаюсь, что в конкретно вашем случае производительность была критической.
Другой пример
ОтветитьУдалить// we have 1 cent
double cent = 0.01f;
// we can use fantastic multiply machine to
// reproduce it multiple tames
double lot_of_cents = cent * 100000000;
// lets put all big beg of our cents
// to the bank account
double account = lot_of_cents;
// we can estimate that we already have
// 1 million US on our account
double million = 1000000;
// lets try to use them
account -= million;
// now bank will check our account
// to be sure we are even one
double epsilon = 0.01; // too big epsilon !!!
if (account < -epsilon)
std::cout << "You are bankrupt" << std::endl;
// Ups !!!
// Don't use devices you are not sure about!
// double and float are not good
// for financial operations
std::cout << "Account = " << account << std::endl;
Все, сдаюсь! ;-)
ОтветитьУдалитьДля финансовых операций, конечно, надо самому фиксировать точку и понимать, как именно происходит использование дробной части. В банковской сфере так и делают.
Скорее всего интерфейсы через float и double - это наследие Фортрана, на котором написана туча финансовой аналитики.
Этот комментарий был удален автором.
ОтветитьУдалитьУ нас именно аналитика. Там, где происходит исполнение трейдов, часто применяет вообще символьное представление при передаче сумм туда сюда. Например, один из самых распространенных протоколов в мире finance - FIX, вообще текстовый.
ОтветитьУдалитьfloat и double для аналитики вполне подходят. +/- два цента сути не меняют. Аналитика - это прогноз, он изначально неточен.
ОтветитьУдалитьА вот в бухгалтерии все центы надо учитывать точно. В бухгалтерии даже сложный процент считают по "неправильной" формуле.
http://dxdy.ru/topic13064.html