Сравнение с плавающей запятой в VB6

Как лучше всего проверить два сингла на равенство в VB6?

Я хочу проверить два значения Single на равенство 7 значащим цифрам.

В этой статье MSDN рекомендуется использовать что-то вроде

If Abs(a - b) <= Abs(a / 10 ^ 7) Then
    valuesEqual = True
End If

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

Public Sub Main()

    Dim a As Single
    Dim b As Single

    a = 0.50000005
    b = 0.50000014

    Debug.Print "a = " & a
    Debug.Print "b = " & b
    Debug.Print "a = b: " & (a = b)
    Debug.Print "SinglesAreEqual(a, b): " & SinglesAreEqual(a, b)

    // Output:
    // a = 0.5000001
    // b = 0.5000001
    // b = b: False
    // SinglesAreEqual(a, b): False

End Sub

Private Function SinglesAreEqual(a As Single, b As Single) As Boolean

    If Abs(a - b) <= Abs(a / 10 ^ 7) Then
        SinglesAreEqual = True
    Else
        SinglesAreEqual = False
    End If

End Function

Самый простой способ, который я нашел для получения нужного мне результата, - преобразовать значения в строки, но кажется ужасно уродливым:

Private Function SinglesAreEqual(a As Single, b As Single) As Boolean

    SinglesAreEqual = (Str$(a) = Str$(b))

End Function

Есть ли лучшие способы?


person roomaroo    schedule 07.09.2010    source источник
comment
Я думаю, что основная проблема здесь заключается в том, чтобы думать, что Single содержит десятичные данные. Это делает понятие, такое как 7 значащих цифр, подверженным ошибкам преобразования и аппроксимации. Вы можете попробовать преобразовать их в двойные значения, прежде чем выполнять сравнительный расчет, который вы указали.   -  person Bob77    schedule 07.09.2010
comment
Bob — a Single — это 4-байтовое значение с плавающей запятой, Double — 8-байтовое значение с плавающей запятой, поэтому важны значащие цифры. Десятичные данные хранятся в типе данных Decimal.   -  person roomaroo    schedule 08.09.2010
comment
Нет, подтип Decimal Variant представляет собой масштабированное двоичное целое число, как и Currency. Ваши 7 цифр — это 7 десятичных цифр, и, поскольку Single содержит двоичные данные, именно здесь закрадываются ошибки. 10).aspx" rel="nofollow noreferrer">msdn.microsoft.com/en-us/library/aa164504(office.10).aspx для большей ясности? 7 цифр раздвигают границы точности сингла.   -  person Bob77    schedule 10.09.2010


Ответы (3)


Я поддерживаю приложение CAD/CAM, и мне постоянно приходится иметь дело с числами с плавающей запятой. У меня есть функция, которую я называю fComp и передаю значение с плавающей запятой, когда мне нужно проверить равенство. fComp вызвать функцию округления с заданным уровнем точности. Для нашей системы я округляю до 6 знаков после запятой. Вашему может потребоваться больше или меньше, это зависит от приложения.

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

Public Function pRound(ByVal Value As Double, ByVal Power As Double) As Double
    Dim TempValue As Double
    Dim tSign As Double
    TempValue = Value
    tSign = TempValue
    TempValue = Abs(TempValue)
    TempValue = TempValue * 10 ^ (Power * -1)
    TempValue = Fix(TempValue + 0.5)
    TempValue = TempValue / 10 ^ (Power * -1)
    pRound = TempValue * Sign(tSign)
End Function

Чтобы округлить до 6-го знака после запятой, вы идете

RoundedNumber = pRound(MyValue, -6)

Отрицательное находится справа от десятичной точки, положительное слева.

person RS Conley    schedule 07.09.2010
comment
Спасибо, но мне нужно округлить до определенного количества значащих цифр, а не знаков после запятой - 123,456789 следует округлить до 123,4568, а 1,23456789 - до 1,234568. - person roomaroo; 07.09.2010

Вместо этого при округлении и проверке на равенство вы можете взять разницу двух чисел и сравнить ее с коэффициентом

If Abs(a - b) < 0.000001 Then

Вы можете настроить 0.000001 на любое разрешение, которое вам нужно.

person bugtussle    schedule 08.09.2010

Я не верю, что вы можете использовать тип данных single для такого количества значащих цифр. Вместо этого вам нужно будет использовать double:

Dim a As Single
Dim s As String

s = "0.50000005"
a =  0.50000005

Debug.Print s & " " & a

Вышеуказанные результаты:

0.50000005
0.5000001
person jbobbins    schedule 08.09.2010
comment
Попробуйте это в ближайшем окне 4.2 - 0.1 = 4.1. Он вернет false из-за того, как компьютеры обрабатывают повторяющиеся числа. Вы можете попробовать 4.2 - 0.1 в режиме ожидания python или непосредственном окне vb.net, чтобы увидеть, что возвращается. См. также docs.sun.com/source/806-3568/ncg_goldberg.html< /а> - person bugtussle; 09.09.2010