Библиотека Generic классов - ошибки, описание, вопросы, особенности использования и предложения - страница 19
Вы упускаете торговые возможности:
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Регистрация
Вход
Вы принимаете политику сайта и условия использования
Если у вас нет учетной записи, зарегистрируйтесь
можно ведь написать свою специализацию функции для класса.
Без интерфейса нельзя.
Без интерфейса нельзя.
Что без интерфейса нельзя? )
Ну а ты подумай. Короче, не захломляй ветку плиз.
Проблема
Очевидно, что GetHashCode невозможно реализовать в пользовательском окружении MQL5 должным образом. Это так, потому что не ко всем объектам есть доступ. И если на примитивных членах вроде double int и т.п. реализация работает нормально, то для сложных объектов (классы, структуры и даже перечисления) хеш расчитывается по имени. Очевидно, что если у нас тысяча объектов типа CObject или даже ENUM_что-то_там, то и CHashMap и CHashSet вырождаются в обычный LinkedList:
избежать этого не получиться, потому что все что у нас есть на пользовательском уровне это имя объекта:
Следовательно, хеши у всех объектов сложных типов равны между собой и вот этот код для поиска задействует полный перебор массива:
На самом деле это настолько критично, что перечеркивает смысл использования всего Generic на корню. Дело в том, что в большинстве случаев, требуется ассоциация или хранения сложных объектов: перечислений, структур или классов. Если бы требовалось оперирование только простыми типами, можно было бы обойтись чем-нибудь по проще.
Для того что бы коллекции Generic работали корректно с объектами классов, эти классы должны реализовывать интерфейс IEqualityComparable, в котором определены методы Equals и HashCode. Т.е. пользователю самому необходимо задавать методы вычисления хэш кодов, и это пока единственный вариант, так как реализовать эти методы автоматически, как это сделано например в .Net, средствами MQL5 не получиться.
Для того что бы коллекции Generic работали корректно с объектами классов, эти классы должны реализовывать интерфейс IEqualityComparable, в котором определены методы Equals и HashCode. Т.е. пользователю самому необходимо задавать методы вычисления хэш кодов, и это пока единственный вариант, так как реализовать эти методы автоматически, как это сделано например в .Net, средствами MQL5 не получиться.
Роман, Вы забыли упомянуть, что в MQL5 нет интерфейсов. Любые разговоры о интерфейсах в сегодняшнем MQL5 это злостная инсинуация и демагогия.
p.s. Но даже если бы интерфейсы в MQL5 появились, вопрос с структурами и перечислениями так и остался бы нерешенным.
Роман, Вы забыли упомянуть, что в MQL5 нет интерфейсов. Любые разговоры о интерфейсах в сегодняшнем MQL5 это злостная инсинуация и демагогия.
p.s. Но даже если бы интерфейсы в MQL5 появились, вопрос с структурами и перечислениями так и остался бы нерешенным.
В MQL5 на данный момент невозможно в принципе написать шаблонные методы, которые будут одновременно работать для классов, структур и перечислений из-за особенностей передачи данных.
Вот о том и речь. Но среда MQL5 знает о своих объектах все! Она владеет и указателями на объекты и знает все идентификаторы перечислений (EnumToString). Вот поэтому GetHashCode нужна как системная и всеядная функция.
А еще разрешите наконец-то множественное наследование интерфейсов. Перепишите Generic на нормальные интерфейсы и будет конфетка.
Ситуация очевидна: разработчики MQ так часто обжигались от множественного наследования в C++ что теперь боятся любого его проявления. В итоге предлагается избежать одного треша (множественное наследование) путем использования другого треша: нелепых цепочек наследования.
Вы поймите, что интерфейсы никакого отношения к наследованию не имеют. Интерфейс - это декларация того, что класс обязуется предоставить заданный функционал. Если два класса реализуют одну и туже функциональность, они не должны наследоваться друг от друга. Наследование = зло.
Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий
Библиотека Generic классов - ошибки, описание, вопросы, особенности использования и предложения
Roman Konopelko, 2017.12.18 16:29
1) Коэффициент прироста объема(capacity) не равен 1.2, для расчета нового объема в CHashMap используется метод CPrimeGenerator::ExpandPrime:
В данном методе старый размер коллекции умножается на два, далее для полученного значения находим ближайшее с верху простое число и возвращаем его, как новый объем.
Про начальное значение capacity - согласен, он очень маленький.
Но с другой стороны всегда есть конструкторы, в которых явно можно указать начальный объем:
Поэтому особого смысла здесь что-то менять не вижу.
Да, был не прав, каюсь.
Действительно, коэффициент прироста объема(capacity) для CHashMap больше 2-х.
Спасибо за указание на ошибку и извините за потраченное время.
С другой стороны удалось уделить время на изучению реализации CPrimeGenerator.
И имеются несколько предложений, в основном на улучшение быстродействия.
1. Устранить неоднозначность поведения:
Если передать "INT_MAX - 10" в качества параметра в CPrimeGenerator::ExpandPrime, то вернется результат "INT_MAX".
Если передать "INT_MAX - 10" в качества параметра в CPrimeGenerator::GetPrime, то вернется тот же результат: "INT_MAX - 10".
Так же в обоих случаях возвращаемое значение не является простым числом, что вводит пользователя в заблуждение.
2. При вызове GetPrime для чисел больше 7199369 в приоритете становится экономия памяти, однако это не оправдывает относительную низкую производительность и бесполезные расчеты.
Предлагается:
- добавить сравнение числа с последним значением массива CPrimeGenerator::s_primes[] и не выполнять ненужный перебор всех 72-х элементов массива.
- заменить динамический поиск простого числа (идет перебор все чисел подряд) на массив предопределенных значений на подобии CPrimeGenerator::s_primes[], но не с квадратическим приростом, а линейным.
Прирост значений будет составлять порядка 1 миллиона (цифра аналогична приросту s_primes на последних элементах массива).
Количество элементов до 3000, значения в диапазоне от 8М до INT_MAX.
Поиск по массиву будет осуществляться через upper bound binary search, количество необходимых итераций - 12.
3. При вызове GetPrime для чисел меньше 7199369 в худшем случае выполняется линейный перебор всех 72-х значений массива CPrimeGenerator::s_primes[].
Предлагается:
- уменьшить количество эллементов в массиве до 70 шт. (удалив первых два, или первый и последний):
- если входное значение меньше или равно 6-ому значению в новом массиве CPrimeGenerator::s_primes - то перебирать числа линейно (до 6-ти сравнений).
- иначе использовать upper bound binary search между 7-м и 70-м значениями массива (порядка 6-ти итераций).
Идея заключается в использовании линейного перебора лишь до той поры, пока не существует проигрыш в производительности по сравнению с бинарным поиском.
Предложенное количество элементов - 6-ть используется для примера, в реальности все зависит от конкретной реализации upper bound binary search.
Общий прирост производительности в виду невысокой интенсивности вызова конкретной функции может быть не на столько выгоден, что бы производить какие-либо работы по улучшению данной функциональности.