Точность с использованием VariantCopyInd

Я использую VariantCopyInd. Источник содержит 1111.199999999. Однако после VariantCopyInd значение округляется в месте назначения до 1111.200000. Я хотел бы сохранить исходное значение. как этого можно добиться?


person sameer karjatkar    schedule 30.11.2011    source источник
comment
Почтовый индекс, который воспроизводит эту проблему.   -  person Hans Passant    schedule 30.11.2011


Ответы (2)


Это не имеет никакого отношения к VariantCopyInd, а просто к тому факту, что литерал в том виде, в каком он существует в коде, не имеет точного представления в формате с плавающей запятой, используемом внутри COM Variants.

Следовательно, нет никакого способа добиться того, чего вы хотите, кроме как использовать вариант типа CURRENCY. Он будет иметь ограниченную точность, см. MSDN:

Типы CURRENCY используют внутри себя десятичное представление, как и кодовый литерал. Вам все равно придется обеспечить косвенную инициализацию (из строки, а не литерала с плавающей запятой/двойного числа) в коде, чтобы предотвратить любые нежелательные эффекты представления.

Число валюты, хранящееся как 8-байтовое целое число с дополнением до двух, масштабированное на 10 000, чтобы получить число с фиксированной запятой с 15 цифрами слева от десятичной точки и 4 цифрами справа. Этот IDispatch::GetTypeInforesentation предоставляет диапазон от 922337203685477,5807 до -922337203685477,5808.

Тип данных CURRENCY полезен для вычислений, связанных с деньгами, или для любых вычислений с фиксированной точкой, где особенно важна точность.

person sehe    schedule 30.11.2011
comment
@sameerkarjatkar: я понимаю. CComVariant также является просто (оболочкой) VARIANT. Обновлен мой ответ с моей лучшей подсказкой: используйте валюту (которая использует десятичное представление внутри) - person sehe; 30.11.2011
comment
можно ли преобразовать VARIANT в CURRENCY? - person sameer karjatkar; 30.11.2011
comment
@sameerkarjatkar: По определению, VARIANT — это размеченный союз. Если вы сохраняете значение CURRENCY в VARIANT, приведение не происходит. Чтобы использовать значение в двойной арифметике, вы можете использовать (double) dblVariant.cyVal.int64 / 10000.0. Несомненно, у CComVariant есть геттеры для этого, но и MSDN в вашем распоряжении. - person sehe; 30.11.2011

Я нашел очень хорошую ссылку из msdn

введите здесь описание ссылки Ссылка четко указывает любое число, длина которого больше 15 будет оцениваться как неправильный результат.

Возьмите 2 случая

1) 101126.199999999 будет хранить правильное значение, так как длина равна 15. Без преобразования или потери точности 2) 111.12345678912345 будет хранить неверное значение, поскольку длина равна 17 . Преобразование будет выполнено

person sameer karjatkar    schedule 30.11.2011
comment
К сожалению, вы упустили главное: на странице также упоминаются might not exactly approximate the decimal number и A value might not roundtrip if a floating-point number is involved. Это не имеет ничего общего с десятичными значащими цифрами (на самом деле выборка из OP меньше 15 цифр). - person sehe; 30.11.2011
comment
Ой. Кроме того, связанная статья даже не применима, потому что она не посвящена .NET или даже CLR. (Вы можете ожидать, что внутреннее представление будет тем же стандартом IEEE с плавающей запятой, но это явно не упоминается) - person sehe; 30.11.2011
comment
@sehe, наверное, мой вопрос неверен. Вы говорите, что число с плавающей запятой длиной 15 также может потерять свою точность или будет преобразовано? - person sameer karjatkar; 01.12.2011
comment
хорошо... У меня очень простой сценарий: пользователь вводит число вроде 101126.199999999, которое я сохраняю в базе данных в столбце, тип данных которого равен NUMBER. Я не выполняю никаких арифметических операций. Это работает хорошо, пока длина равна 15, в тот момент, когда я увеличиваю длину за пределы 15, значение округляется. Я просто хочу быть уверен, что это округление произойдет только после длины 15 - person sameer karjatkar; 01.12.2011
comment
Рецепт прост: либо 1. Обеспечьте достаточную точность хранения и используйте исключительно десятичные представления (ищите: десятичные, валютные или денежные типы) 2. Обеспечьте избыточную точность и округлите до требуемой точности. Обратите внимание, что в последнем случае кумулятивный эффект ошибки округления могут привести к потере точности - person sehe; 01.12.2011