доброго времени суток всем. наверное, я совсем заработался, не могу сейчас сообразить. прошу помочь разобраться.
суть проблемы: известно, что вычисления с вещественными числами выполняются не абсолютно точно из-за особенностей машинной арифметики. поэтому, к примеру, результат, на самом деле равный 5-ти, может быть представлен как 5.00000000000000, 5.00000000000001 или 4.99999999999998 - в зависимости от того, как он был получен. мне нужно производить сравнения таких чисел, но корректно, т.е. с учетом этих самых особенностей.
на равенство проверяю так:
Код
const eps=0.0000001
if abs(a-b) < eps then ' равны
а как проверить на больше-меньше? я додумался до такого:
Код
const eps=0.0000001
if a-b > -eps then ' a больше b
if a-b < eps then ' a меньше b
но сомневаюсь.
а с нестрогими условиями (>= и <=) совсем запутался
хелпми.
фрилансер Excel, VBA - контакты в профиле "Совершенствоваться не обязательно. Выживание — дело добровольное." Э.Деминг
Саша, не совсем понял сути вопроса, но я вот набросал вот такой макрос (результаты - в комментариях):
Код
Sub CompareDigits()
Dim num1 As Variant
Dim num2 As Variant
Dim str1 As String
Dim str2 As String
str1 = "4,99999999999998"
str2 = "4,99999999999998"
num1 = CDec(str1)
num2 = CDec(str2)
MsgBox "num1 = num2: " & num1 = num2 ' FALSE
MsgBox "num1 = num2: " & (CStr(num1) = CStr(num2)) ' TRUE
End Sub
По-моему, на больше-меньше надо проверять без eps: сравнение это вычитание, и оно дает вполне однозначный результат: больше нуля или меньше нуля. Если до этого проверили на равенство с точностью до eps.
Код
If Abs(a - b) < eps Then
'a = b
ElseIf a < b Then
'a меньше b
Else
'b меньше a
End If
Александр (ikki), если сравнивать с eps, то можно "пролететь", если числа в экспоненциальном формате. Лучше сравнивать все 15 значащих разряда числа, отбросив остальные незначащие и учесть степенную часть после E . Вот пример, описывающий проблемность использования eps, и в конце - как правильнее (но немного медленнее, конечно)
Код
Sub Test()
Const eps = 0.0000001
Dim a#, b#
' Число Pi
a = 3.14159265358979 ' Большую точность явной константой задать не получится
b = WorksheetFunction.Pi ' А так точнее! Используйте в точных расчетах такой вариант
' здесь выдаст "равно"
If Abs(a - b) < eps Then
Debug.Print "равно, разность =" & CStr(a - b)
Else
Debug.Print "не равно, разность =" & CStr(a - b)
End If
' Добавим степенную часть
a = a * 1E+100
b = b * 1E+100
' и здесь уже "не равно"
If Abs(a - b) < eps Then
Debug.Print "равно, разность = " & CStr(a - b)
Else
Debug.Print "не равно, разность = " & CStr(a - b)
End If
' А вот так правильнее, CStr очищает число от "мусорных" разрядов
a = CDbl(CStr(a))
b = CDbl(CStr(b))
Debug.Print Sgn(a - b) ' 0 равно, 1 больше, -1 меньше
End Sub
недавно столкнулся с этим - решил применением currency формата нужно было в ценах соблюдать точность до копейки.. с ценами все получилось, но перевод суммы на этот формат был ошибочным - так как сумма накапливалась пошагово, то в конце вылезала ошибка округления. так что сумму накапливал в дабл.. ну а так - раунд ее до нужного знака и потом сравнивать