Страницы: 1
RSS
Цикл с шагом 0.01 прибавляет неверное значение и переменная отображается неправильно
 
Добрый вечер.
Вопрос простой, но поставил в ступор. Имеется простой цикл с шагом в 0.01.
Код
Sub Диаграмма()
Dim a As Single
Dim i As Long
i = 0
Application.Calculation = xlCalculationManual
For a = 1.06 To 9.25 Step 0.01
i = i + 1
    Cells(1, 1) = a
    Calculate
    Cells(i, 2) = Cells(1, 1)
Application.StatusBar = a
Next a
Application.Calculation = xlCalculationAutomatic
Application.StatusBar = False
MsgBox "всё"
End Sub
Вопрос в том, что при прибавлении к переменной очередной шаг 0.01, по факту переменная имеет другое значение.
Например, при прибавлении к 1.06 получается 1,06999993324279. и т.д. А по факту должно быть 1,07.
В ячейку также записывается число с длинным хвостом.
Что не так в данном макросе?
Мастерство программиста не в том, чтобы писать программы, работающие без ошибок.
А в том, чтобы писать программы, работающие при любом количестве ошибок.
 
Может, Dim a As Double ?
 
_Igor_61, тоже самое на выходе
Мастерство программиста не в том, чтобы писать программы, работающие без ошибок.
А в том, чтобы писать программы, работающие при любом количестве ошибок.
 
В общем-то вопрос откуда эти хвосты берутся?
Мастерство программиста не в том, чтобы писать программы, работающие без ошибок.
А в том, чтобы писать программы, работающие при любом количестве ошибок.
 
Интересно, у меня в столбце "В" с "Double" все нормально получается, без хвостов, но в "А1" - с хвостом...    
 
а  Dim a As Currency
 
Doober, вот это правильно работает. С этим вроде разобрались.
Но теперь надо докопаться до истины откуда Single хвост берёт?
Мастерство программиста не в том, чтобы писать программы, работающие без ошибок.
А в том, чтобы писать программы, работающие при любом количестве ошибок.
 
Все дробные числа, знаменатель которых отличен от степени двойки, хранятся в Excel (и в VBA) приближенно. При суммировании погрешность накапливается, причем в Single намного быстрее, чем в Double.
Если параметр цикла сделать целым (а потом при вычислениях делить на 100), то погрешность накапливаться не будет.
Владимир
 
sokol92, со значением Double я тоже заметил, что хвост вырастает чуть позже. Но почему так? Почему нельзя элементарную математику без погрешности сделать, где подвох?
Мастерство программиста не в том, чтобы писать программы, работающие без ошибок.
А в том, чтобы писать программы, работающие при любом количестве ошибок.
 
Если бы мы пользовались двоичной системой счисления (как компьютер), то проблем бы не было. А нам подавай дроби со знаменателем степени десятки. :)

Не думаю, что пользователям эта погрешность сильно вредит (даже Вы ведь ее только сейчас обнаружили). Не везде так. В Oracle тип Number имеет в основе десятичную систему счисления и позволяет оперировать с числами вплоть до 33 значащих десятичных цифр. Однако нужна еще и эффективность. Интересно, что в последних версиях и в Oracle появился тип Double, предназначенный для интенсивных вычислений. Так что, авторы Excel пошли по проторенному ранее (FORTRAN, C, ...) пути.
Изменено: sokol92 - 20.05.2018 21:52:59
Владимир
 
Цитата
Alemox написал:
Почему нельзя элементарную математику без погрешности сделать, где подвох?
Это одна из наиболее избитых тем на всех форумах по Excel :)
https://www.google.ru/search?q=ieee+754+site%3Aplanetaexcel.ru
 
Цитата
Alemox написал:
Почему нельзя элементарную математику без погрешности сделать, где подвох?
какая математика используется обьяснено в стандарте
строго использовать особенности или рассчитывать на удачу - это Ваш личный выбор. все необходимые инструменты у программиста есть, и только Ваша вина если Вы игнорируете необходимость их использования
забудьте о правилах абсолютной математики. Вы не территории компьютера, учитывайте правила (особенности), по которым он работает
 
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
Большое спасибо коллеги за разъяснение. Придётся переделывать макрос. Мне в данный момент нужны операции именно с сотыми и тысячными. Вот ЭТА статья меня удовлетворила. Но я не согласен с такими расчётами. Я же не делю и не умножаю дроби, а просто решил сложить.
Мастерство программиста не в том, чтобы писать программы, работающие без ошибок.
А в том, чтобы писать программы, работающие при любом количестве ошибок.
 
Цитата
Alemox написал:
Я же не делю и не умножаю дроби, а просто решил сложить.
Но Вы выполняете операцию сложения не один раз, а 919 (в #1). Соответственно, погрешность может расти. Если действовать, как написано в #8, погрешность будет возникать только при делении на 100 (одна операция).
Владимир
 
Совсем забыл про "недоделанный" (под)тип в VBA. Может быть, устроит запись цикла в таком виде:


Код
Dim a as Variant
' ---
For a = CDec(1.06) To CDec(9.25) Step CDec(0.01)
Изменено: sokol92 - 21.05.2018 10:40:20
Владимир
 
sokol92, Нет такой вариант не подходит.
На данный момент подходит вариант Doober-a. Им пока буду пользоваться.
Мастерство программиста не в том, чтобы писать программы, работающие без ошибок.
А в том, чтобы писать программы, работающие при любом количестве ошибок.
Страницы: 1
Наверх