Гость
Форумы / Microsoft Access [игнор отключен] [закрыт для гостей] / VBA - Остерегайтесь ошибок в вычислениях (функция int()) / 9 сообщений из 9, страница 1 из 1
16.07.2019, 10:58
    #39837760
Joss
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
VBA - Остерегайтесь ошибок в вычислениях (функция int())
Статья Даниеля Пино - VBA - Остерегайтесь ошибок в вычислениях (функция int())

https://www.devhut.net/2019/04/11/vba-beware-of-flawed-math/

Я решил, что расскажу об ошибке, доведенной до моего сведения Джейсоном , касающуюся проблемы с использованием функции Int() .

Всегда были проблемы с вычислениями из-за проблем с плавающей запятой, о которых я даже не собираюсь рассказывать в этом посте. Есть гораздо большие умы, которые разрабатывали эту тему в прошлом. Тем не менее, всякий раз, когда вам нужно выполнить какой-либо расчет, лучше всего всегда использовать денежные или десятичные типы данных.

Возвращаясь к сегодняшнему сообщению, проблема с функцией Int(). Int () используется для возврата целой части числа из числа. Так,

Код: plaintext
1.
2.
3.
4.
5.
? Int (1)
 1 
? Int (5.25)
 5 
? Int (13.65)
 13

Недостаток!

В Access Query
В запросе
Код: sql
1.
SELECT 40*0.3 AS Expr1, Int(12) AS Expr2, Int(40*0.3) AS Expr3;


Результаты в
Код: plaintext
12 | 12 | 12

В рабочем листе Excel
Код: plaintext
= INT(40 * 0,3) 
Результаты в
Код: plaintext
12

НО В VBA (ошибка)

Код: plaintext
1.
2.
3.
? 40 * 0,3
12 
? INT(12)
12

но возникает проблема с

Код: plaintext
1.
? int(40 * .3)
 11

или в простой функции, как

Код: vbnet
1.
2.
3.
Function dd(a As Integer, b As Double)
    dd = Int(a * b)
End Function


Код: plaintext
1.
? dd(40, 0.3)
11

Теперь, поскольку в VBA существует такая проблема, это означает, что это общая ошибка Office VBA, а не только Access! Так что будьте предупреждены, та же проблема будет существовать в Excel, Word, ...

Где это зацепит нас точно

Теперь, когда, очевидно, на базовую математическую функцию, такую, как Int() , нельзя положиться, что делать ?!

Что ж, я опубликовал эту проблему в Access Dev Team и пока не получил ответа, но, как обычно, мои коллеги из MVP готовы предложить свою помощь! Густав Брок указал, что использование функции преобразования заставит Int() вести себя правильно. Таким образом, обходной путь становится

Код: plaintext
1.
? Int(CDec(40) * 0,3)
12

или же

Код: plaintext
1.
? Int(40 * CCur(0,3))
12

Итак, да, вам нужно применять преобразование везде, где вы используете Int(), чтобы убедиться, что оно работает правильно!

В случае функции переключение типа данных с Double на Currency устранит проблему

Код: vbnet
1.
2.
3.
Function dd(a As Integer, b As Currency)
    dd = Int (a * b)
End Function


Код: plaintext
1.
? dd (40, 0,3)
12
или применить преобразование в самой функции, такой как

Код: vbnet
1.
2.
3.
Function dd(a As Integer, b As Currency)
    dd = Int(a * b)
End Function


Код: plaintext
1.
? dd(40, 0.3)
12

Как всегда, когда я получу ответ от команды Access Dev, я опубликую любую дополнительную информацию, которой они смогут поделиться с нами.

Обновление 2019-04-18, 2019-05-01
Что ж, прошло всего 3 недели, и от команды разработчиков не было никаких комментариев/ответов по поводу моего электронного письма на эту тему, поэтому я полагаю, что не получу от них никаких отзывов по этому вопросу. Так что просто убедитесь, что ВСЕГДА используйте преобразования везде, где вы используете функцию Int(), чтобы избежать каких-либо ошибочных результатов !!!

... и если эта проблема существует в Int(), должны ли мы беспокоиться о других математических функциях? Это настоящий вопрос!

Обновление 2019-04-24
Просто добавлена информация, касающаяся тестирования выше.

Когда я писал статью, я работал под управлением Access 2013 x32 на Windows 7, с тех пор я тестировал (с такими же результатами)

Access 2003 в Windows XP
Access 2007 SP3 (x32) в Windows 7
Access 2010 SP2 (x32) в Windows 7
Access 2013 (x32) в Windows 10 (версия 1803, сборка ОС 17134.706)
Access 2016 (x32) в Windows 7

Дальнейшие ресурсы по теме
В комментариях ниже Люк Чунг , президент FMS Inc. , только что поделился со мной техническим документом, который он выпустил более 20 лет назад, в котором подробно об этом и многом другом! Поэтому не забудьте проверить, When Microsoft Access Math Doesn’t Add Up , чтобы убедиться, что вы знаете о множестве математических проблем и о том, как наилучшим образом обеспечить надежность ваших расчетов.


-------------------------------------------------------------
А ты вложил уже свой кровный рубль в 50-ти миллиардное состояние Билла Гейтса?
...
Рейтинг: 0 / 0
16.07.2019, 11:24
    #39837787
Панург
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
VBA - Остерегайтесь ошибок в вычислениях (функция int())
Joss, я так понимаю, что этот Даниель Пино вчера вылупился?
...
Рейтинг: 0 / 0
16.07.2019, 11:41
    #39837795
VBA - Остерегайтесь ошибок в вычислениях (функция int())
Это именно "из-за проблем с плавающей запятой". Некоторые десятичные числа невозможно представить в двоичной системе со 100% точностью. Например 0.3 может выглядеть как 0.299999999999, поэтому:
Код: vbnet
1.
2.
?40*0.299999999999
 11.99999999996

А Int() честно отбрасывает дробную часть и возвращает 11.
Для наглядности?
Код: vbnet
1.
2.
3.
4.
?Int(40000000000*0.3)
 11999999999 
?Int(40000000000*0.6)
 23999999999


В данном случае 0.3 имеет тип Double (в VBA по умолчанию для дробных чисел).

Что интересно, есть тип Single, который еще грубее но здесь:
Код: vbnet
1.
2.
?Int(40000000000*CSng(0.3))
 12000000476
...
Рейтинг: 0 / 0
16.07.2019, 12:05
    #39837813
sdku
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
VBA - Остерегайтесь ошибок в вычислениях (функция int())
прежде чем искать ошибку в стандартной функции VBA ("проверенной веками") надо спросить себя:"а все-ли я правильно делаю?" -тип Double,в принципе,не может дать точный результат
...
Рейтинг: 0 / 0
16.07.2019, 12:13
    #39837822
sdku
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
VBA - Остерегайтесь ошибок в вычислениях (функция int())
вдогонку:безумно "нравится" когда бестолочь искренне считает себя умней других и пытается оспорить что-то устоявшееся(существует куча доказательств что 2*2=5-кроме смеха и убежденности в том,что автор полный идиёт это не вызывает)
...
Рейтинг: 0 / 0
16.07.2019, 12:14
    #39837823
Joss
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
VBA - Остерегайтесь ошибок в вычислениях (функция int())
Вчера-не вчера. И о точности то же известно. Но вот можешь нечаянно вляпаться.
...
Рейтинг: 0 / 0
16.07.2019, 12:22
    #39837830
ROI
ROI
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
VBA - Остерегайтесь ошибок в вычислениях (функция int())
sdkuпрежде чем искать ошибку в стандартной функции VBA ("проверенной веками") надо спросить себя:"а все-ли я правильно делаю?" -тип Double,в принципе,не может дать точный результат
100500
Я ужо думал, что не дождусь этой (правильной реакции)
...
Рейтинг: 0 / 0
16.07.2019, 12:23
    #39837831
Панург
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
VBA - Остерегайтесь ошибок в вычислениях (функция int())
JossВчера-не вчера. И о точности то же известно. Но вот можешь нечаянно вляпаться.И что даст это обсуждение? Это описано на сто раз в учебниках по VBA. А уж если придётся встрять, то и сто первый раз не поможет.
...
Рейтинг: 0 / 0
16.07.2019, 13:25
    #39837870
sdku
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
VBA - Остерегайтесь ошибок в вычислениях (функция int())
ПанургJossВчера-не вчера. И о точности то же известно. Но вот можешь нечаянно вляпаться.И что даст это обсуждение? Это описано на сто раз в учебниках по VBA. А уж если придётся встрять, то и сто первый раз не поможет.
+100500
В принципе ничего...
...
Рейтинг: 0 / 0
Форумы / Microsoft Access [игнор отключен] [закрыт для гостей] / VBA - Остерегайтесь ошибок в вычислениях (функция int()) / 9 сообщений из 9, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]