Автоматическое преобразование типов в Visual Basic 6.0 - PullRequest
4 голосов
/ 15 марта 2009

Когда мы конвертируем число с плавающей точкой в ​​integer в Visual Basic 6.0, как оно округляет дробную часть? Я говорю об автоматическом преобразовании типов.

Если мы назначим как

Dim i as Integer
i=5.5
msgbox i

Что это будет печатать? 5 или 6 ??

Я получил "5" пару месяцев назад. Однажды он начал давать мне 6! Есть идеи, что не так? Microsoft выпустила несколько исправлений, чтобы что-то исправить?

Обновление: 5,5 преобразуется в 6, но 8,5 в 8!

Обновление 2: Добавление CInt не имеет значения. CInt (5.5) дает 6, а Cint (8.5) дает 8 !! В некотором роде утомленное поведение. Я должен попробовать что-то вроде пола (х + 0,49);

Ответы [ 5 ]

7 голосов
/ 16 марта 2009

Часть этого находится в справке VB6: тема Функции преобразования типов . К сожалению, это одна из тем, которых нет в документации VB6 на веб-сайте MSDN, но если вы установили справку по VB6, она будет там.

Когда дробная часть равна точно 0,5, CInt и CLng всегда округляют ее до ближайшего четного числа. Например, 0,5 раунда до 0 и 1,5 раунда до 2. CInt и CLng отличаются от функций Fix и Int , которые усечь, а не округлить дробную часть числа. Кроме того, Fix и Int всегда возвращают значение того же типа, что и в.

Приведение неявного типа - aka "Принуждение злого типа (PDF)" - от числа с плавающей запятой до целого числа используются те же правила округления, что и CInt и CLng . Такое поведение нигде не описано в руководстве.

Если вы хотите округлить, когда дробная часть> = 0,5, а в противном случае, простой способ сделать это -

 n = Int(x + 0.5)

И помимо моей головы, вот моя более короткая версия RoundNumber :) Майка Спросса, которая является заменой функции Round VB6.

 'Written off the top of my head, seems to work. 
Public Function RoundNumber(ByVal value As Double, Optional PlacesAfterDecimal As Integer = 0) As Double
  Dim nMultiplier As Long
  nMultiplier = 10 ^ PlacesAfterDecimal
  RoundNumber = Int(0.5 + value / nMultiplier) * CDbl(nMultiplier)
End Function

Пример вывода:

Debug.Print RoundNumber(1.6)       '2'
Debug.Print RoundNumber(-4.8)      '-5'
Debug.Print RoundNumber(101.7)     '102'
Debug.Print RoundNumber(12.535, 2) '12.54'
7 голосов
/ 15 марта 2009

Обновление: После некоторых поисков я наткнулся на следующую статью :

Это не "ошибка", а способ, которым был VB предназначен для работы. Он использует что-то известный как округление банкира, если, если число заканчивается ровно на 5 и вы хочу округлить на позицию впереди из 5, округляет числа вниз, если число перед 5 позиция четная и округляется иначе. Предполагается защитить против повторного расчета с использованием округленные числа, так что ответ не всегда смещен вверх Подробнее об этом вопрос, чем вы, вероятно, хотите знать, см. эту ссылку

http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q196652

Это объясняет (кажущееся) странное поведение:

Cint(5.5) 'Should be 6'
Cint(8.5) 'Should be 8'

Старое обновление: Возможно, вам следует быть более явным: используйте CInt вместо простого присваивания числа с плавающей точкой. Например:

Dim i as Integer
i = CInt(5.5)
MsgBox i
1 голос
/ 16 марта 2009

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

Обновление 2: добавление CInt делает не разница. CInt (5.5) дает 6 и Cint (8.5) дает 8 !!

Это тоже нормально. CInt всегда округляет (снова используя метод округления Банкира) перед выполнением конвертации.

Если у вас есть число с дробной частью и вы просто хотите его обрезать (игнорируйте часть после десятичной точки), вы можете использовать функцию Fix или Int:

Fix(1.5) = 1
Fix(300.4) = 300
Fix(-12.394) = -12

Int работает так же, как и Fix, за исключением того, что округляет отрицательные числа до следующего наименьшего отрицательного числа:

Int(1.5) = 1
Int(300.4) = 300
Int(-12.394) = -13

Если вы действительно хотите округлить число в соответствии с правилами, с которыми знакомо большинство людей, вам придется написать свою собственную функцию, чтобы сделать это. Ниже приведен пример округления, которое округляется в большую сторону, когда дробная часть больше или равна 0,5, и округляется в меньшую сторону в противном случае:


РЕДАКТИРОВАТЬ : См. Ответ MarkJ для более простой (и, вероятно, более быстрой) версии этой функции.


' Rounds value to the specified number of places'
' Probably could be optimized. I just wrote it off the top of my head,'
' but it seems to work.'
Public Function RoundNumber(ByVal value As Double, Optional PlacesAfterDecimal As Integer = 0) As Double

    Dim expandedValue As Double
    Dim returnValue As Double
    Dim bRoundUp As Boolean

    expandedValue = value
    expandedValue = expandedValue * 10 ^ (PlacesAfterDecimal + 1)
    expandedValue = Fix(expandedValue)

    bRoundUp = (Abs(expandedValue) Mod 10) >= 5

    If bRoundUp Then
        expandedValue = (Fix(expandedValue / 10) + Sgn(value)) * 10
    Else
        expandedValue = Fix(expandedValue / 10) * 10
    End If

    returnValue = expandedValue / 10 ^ (PlacesAfterDecimal + 1)
    RoundNumber = returnValue

End Function

Примеры

Debug.Print RoundNumber(1.6)       '2'
Debug.Print RoundNumber(-4.8)      '-5'
Debug.Print RoundNumber(101.7)     '102'
Debug.Print RoundNumber(12.535, 2) '12.54'
1 голос
/ 15 марта 2009

Измененное поведение звучит тревожно, но правильный ответ - 6. Прокрутите вниз до «Метод округления до четности» на Википедия, Округление для объяснения.

0 голосов
/ 15 марта 2009

Функция VB6 Round () использует метод Banker's Rounding . Статья MS KB 225330 (http://support.microsoft.com/kb/225330) говорит об этом косвенно, сравнивая VBA в Office 2000 с собственным поведением Excel, и описывает это так:

Когда число с четным целым числом заканчивается на .5, Visual Basic округляет число (вниз) до ближайшего четного целого числа. [...] Эта разница [между VBA и Excel] составляет только для чисел, заканчивающихся на .5, и такая же, как и для других дробных чисел.

Если вам нужно другое поведение, боюсь, вам придется указать это самостоятельно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...