Мне интересно такое поведение, которое я вижу в VBA. Я использую консоль Immediate для отладки своего кода и получил следующий результат:
Debug.Print(Int(0.00024575*10000000+0.5))
2457
Я ожидал, что этот результат будет 2458. Кто-нибудь знает, почему это происходит? Как и ожидалось, перед вызовом функции Int вычисления производятся с двойной точностью.
Debug.Print(VarType(0.00024575*10000000+0.5))
5
Любая помощь очень ценится!
Но разве не следует Int правильно обращаться с двойниками? Это плохое поведение для такого широко используемого языка, как VBA.
Вместо этого попробуйте использовать CInt. Он будет округлять, а не усекать результат. Согласно файлу справки: «Когда дробная часть равна ровно 0,5, CInt и CLng всегда округляют ее до ближайшего четного числа. Например, 0,5 округляет до 0, а 1,5 округляет до 2. CInt и CLng отличаются от функций Fix и Int, которые усекают, а не округляют дробную часть числа. Кроме того, Fix и Int всегда возвращают значение того же типа, что и передано.
@BigBen Извините, я просто имел в виду, что это удивительное поведение, даже для функции, которая просто усекает. Я бы подумал, что это даст более надежный результат, но он кажется не очень надежным... Я ожидаю ошибок с плавающей запятой при более высокой точности ввода.





Если вы запустите следующий тест:
Sub Test()
Dim d As Double: d = 0.5 + 0.00024575 * 10000000
Debug.Assert d = Int(d)
Debug.Assert 0.5 + 2457.5 = Int(0.5 + 2457.5)
Debug.Assert 0.5 + 0.00024575 * 10000000 = Int(CDbl(0.5 + 0.00024575 * 10000000))
Debug.Assert 0.5 + 0.00024575 * 10000000 = CDbl(0.5 + 0.00024575 * 10000000)
Debug.Assert 0.5 + 0.00024575 * 10000000 = VBA.Int(0.5 + 0.00024575 * 10000000)
Debug.Assert 0.5 + 0.00024575 * 10000000 = Int(0.5 + 0.00024575 * 10000000)
End Sub
Вы увидите, что только последний Assert не работает. Вероятно, это ошибка компилятора.
Обратите внимание, что Int — это не то же самое, что VBA.Int.
Как было предложено в комментариях @GSerg, похоже, что метод Int (не VBA.Int) действительно выполняет вычисления во время компиляции и, вероятно, использует другую точность с плавающей запятой. Например:
Option Explicit
#Const Test = Int(12.5)
Sub TestPrecompiler()
#If Test = 12 Then
Debug.Print "Int method calculates at compile time"
#End If
End Sub
Очень интересно, хорошая находка.
Значит, Int тоже забавная функция , как у Лена ? Но это не ключевое слово , и я не вижу для этого причин. Это как если бы весь Int(0.5 + 0.00024575 * 10000000) вычислялся во время компиляции (что может быть и в случае забавных функций), и в этот момент компилятор использовал различную точность с плавающей запятой (что не является чем-то необычным), в то время как все остальное обрабатывается во время выполнения.
@GSerg Действительно. Если я правильно помню, Int можно использовать в константах компилятора, но я не могу проверить это.
Нет, говорит: Требуется постоянное выражение.
@GSerg хорошие рефералы, спасибо!
@GSerg #Const Test = Int(12.5) у меня компилируется нормально. Я использую Office 365 Excel на Win x64 VBA7.
Так что это работает в константе компиляции. Однако в обычных константах этого нет. И потом Int не является чем-то особенным, многие другие тоже работают в константах компиляции, но не в обычных.
Я предполагаю ошибку с плавающей запятой.