Проблема округления VBA

у меня есть эта неясная проблема округления в VBA.

a = 61048.4599674847
b = 154553063.208822
c = a + b   
debug.print c
Result: 
154614111.66879 

вот вопрос, почему VBA округлил переменную c? Я не выдал никакой функции округления. Стоимость я ожидал был 154614111.6687894847. Даже если я округляю или форматирую переменную c до 15 знаков после запятой, я все равно не получаю ожидаемого результата.

любое объяснение было бы оценено.

Edit:

получил ожидаемые результаты с помощью cDec. Я читал это у Джонатана. Ответ Аллена в почему CLng дает разные результаты?

результат теста:

a = cDec(61048.4599674847)
b = cDec(154553063.208822)
c = a + b
?c
154614111.6687894847 

2 ответов


причиной является ограниченная точность, которая может храниться в переменной с плавающей точкой.
Для полного объяснения вы должны читать газеты Что Каждый Компьютерщик Должен Знать Об Арифметике С Плавающей Запятой, Дэвид Голдберг, опубликованный в марте 1991 года в номере Computing Surveys.

ссылка на документ

в VBA тип с плавающей запятой по умолчанию -Double который является 64-разрядной (8-байтовой) плавающей точкой IEEE число.

есть еще один тип доступный: Decimal который представляет собой 96-битные (12-байтовые) целые числа со знаком, масштабируемые переменной мощностью 10
Проще говоря, это обеспечивает числа с плавающей запятой до 28-значной точности.

использовать в вашем примере:

a = CDec(61048.4599674847)
b = CDec(154553063.208822)
c = a + b   
debug.print c
Result: 
154614111.6687894847 

Это не неясно, но это не обязательно очевидно.

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

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

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

выполняя cDec, вы конвертируете в другой тип переменной (decimal), которая способна к большей точности