All streams
Search
Write a publication
Pull to refresh
1
0
Константин @Comdiv

Программист

Send message
В общем случае у сходящегося ряда нет красивой формулы. Я имел ввиду численный метод
На хаскеле? Сохраняя вашу нотацию,

Где обработка найденного и не найденного? Почему разные функции?
На плюсах?
Круто, ничего не скажешь
А чего вы тогда реализацию printf не ищете или не пишете свою
1. Так уж получилось, что printf использую только для примеров, в обычном коде — нет. Знали бы Вы, сколько глюков на ней висит.
2. Чем объёмней и сложней код, тем меньше его пишут врукопашную, но когда нужно специальное поведение, то пишется своё, да. Без этого никуда
Да хоть в одну, хоть в десять — руками это каждый раз писать сомнительное удовольствие.
Покажите свой вариант.
Я и говорю о множестве всех частных случаев в виде линейного поиска.
А, кстати, раз так, то сумму сходящегося ряда Вы тоже с помощью lookup будете делать?
Нет. Вам не нужно знать ...
Наоборот, это нужно знать. Только тогда, исходя из ограничений задачи, можно выбрать оптимальное представление.
(у вас нет ребалансировки, например),
В том и прелесть, что я делаю только то, что нужно. С++ код к тому же, ощутимо разбухший, хотя это опять-таки сильно гуляет в зависимости от компилятора, его настроек и целевой платформы.
столько же времени и ресурсов, сколько распарсить строку lookup a bs, мне верится очень с трудом.
Конечно не столько же — чтобы достоверно узнать, что делает lookup a bs, нужно будет искать реализацию lookup.

Надо найти второй элемент пары, первый элемент которой равен данному элементу

Что-то вроде этого?
for (i = 0; i < len && a[i].key != key; i += 1);
if (i < len) {
  found(a[i].value);
} else {
  not_found();
}

Обязательно нужно это влепить в 1-у строку? Я-то и цикл написал в 1-у строку для примера любителям считать строки, а не потому, что я так пишу.
А какой тезис вы выдвигаете?
Это означает, что для того, чтобы написать вариант на С++, приближающийся снизу по скорости, надо знать всё то же, что и на Си, плюс нюансы библиотеки С++. Выгоды, на мой взгляд, нет исходя из контекста нашего разговора.

С моим вариантом, с кастомным хешем и reserve? Ради любопытства, а насколько?
Как выяснилось, очень зависит от сочетания компилятора и процессора. На рабочем ноутбуке на c gcc 10%, на домашнем, на котором всё новее — 5%. А на clang Си наоборот, сильно отстаёт.
Не моментально.
Я же говорю по своему опыту, а не из абстрактных соображений.
Кстати, как в одну строку будет выглядеть
Пожалуйста, конкретней, и почему в 1-у строку?
но утверждать, что каждый раз копипастить цикл проще, чем писать слово из нескольких букв
А кто это утверждает? Я не понимаю, зачем там копирование. Вы простые команды в терминале копируете или сами пишете? Так и тут, тем более о копировании речь не идёт, поскольку всегда есть своя специфика. Линейный поиск — это частный случай схемы, которая существует даже тогда, когда нет никакого хранилища, в котором искать. Например, сумма сходящегося ряда воплощается по той же схеме. Что Вы там копировать будете?
Так как язык изучается обычно не более одного раза
Я постоянно обращаюсь к внешней памяти по инструменту, потому что не могу запомнить всех важных деталей. И чем сложней инструмент, тем хуже.
Да, кроме тех случаев, где я об этом забываю.
Есть 2-a сценария:
  1. Переполнение невозможно исходя из задачи, потому что известны ограничения на возможные значения. Здесь переполнение, которое может случится только из-за ошибки в алгоритме, должно контролироваться компилятором (gcc -ftrapv, использовать только signed)
  2. Переполнение возможно, потому что данные косвенно или прямо получены из источников, где нужные диапазоны значений не гарантируются. В таком случае нужно проверять возможность переполнения и обеспечить их корректную обработку.

Необработанные переполнения — это возможный источник уязвимостей и других проблем.
Здорово, что Вы написали свою программу, но сравнив её с тестом, я очень легко нашёл недостающий компонент:
result.reserve(1023);
Получается, что С++ hash array приближается к скорости C кода только если воспользуется знаниями, которыми обладает разработчик, который может написать hash array самостоятельно — hash функцией и нужными значением резерва. Когда я попытался применить reserve(1023) в тесте, естественно, получил отлуп — map, сделанная через деревья, не имеет такого метода. Единого интерфейса тоже нет.

Также у меня Си код всё равно выполняется быстрей на статистически различимую величину. А С++ hash array в test проекте c reserve() выполняется быстрей на статистически различимую величину, чем представленная Вами программа, полностью написанная на C++.

В общем, я не увидел того, что можно было бы назвать справляется.
Когнитивная нагрузка, по-видимому, обусловлена выбором инструмента. В Си или Go линейный поиск считывается моментально, и именно очевидный простейший алгоритм позволяет быть увереным, что там нет никаких особых деталей, и он делает ровно то, что задано и ничего больше. А писать это нужно, чтобы из-за экономии в 10-20 строк на проект не усложнять язык. Те, кому по душе сложные языки с этим не согласятся, но и обратный подход они-то могу понять?
Не знаю, он там уже и так задействован.
Значит, инвертируйте вопрос. Сколько избыточных строк кода будет, если написать свой линейный поиск?
// вариант линейного поиска для тех, кто любит экономить строки
for (i = 0; i < len && a[i] != b; i += 1);


Но у меня есть просто куча других мест, где задействованы...
Можно глянуть?
Исходников С-версии у вас не сохранилось случаем, кстати?
В статье была ссылка на github, иначе в чём смысл разглагольствований?
Под справляются Вы имеете ввиду, что такое
[1, 2, 3, 4 ,5].contains(n)

автоматически превращается в такое?
0 != ((1 << n) & 62)


Мой скромный опыт показывает, что ассоциативный массив на template С++ не справляется с наколенным воплощением на Си
Я не увидел
Да нет там ничего сложного.
Не могли бы Вы изобразить в своей интерпретации, как это сделали раньше в сообщении, где писали
Уже даже таких простых шаблонов без выведения типов уже хватило бы, но нет, «это слишком сложно».
Зависит от задач, в том-то и дело. Если это целые неотрицательные, то как-то так:
bool sum(int len, int a[len], int *sum, int *i) {
  *i = 0;
  *sum = 0;
  while ((*i < len) 
      && (a[*i] >= 0) 
      && (*sum <= INT_MAX - a[*i])) 
  {
     *sum += a[*i];
     *i += 1;
  }
  return *i >= len;
}

В других случаях это будет по другому.
Что, разумеется? Вы написали, что
Да нет там ничего сложного.

И показали пример, который не учитывал всех нюансов. Не могли бы Вы теперь показать пример с несложным учётом такой возможности? По ссылке я не понял, что там учитывается, извините.
sum!float([ 1.1 , 2.2 , 3.2 ]);
sum!int([ 1 , 2 , 3 ]);

В настоящих задачах нужно учитывать возможность переполнения. В дробях и целых оно учитывается по разному. Учтено ли это в Вашем несложном примере?
Пока не воплощена на практике идея суперкомпиляции Валентина Турчина, это утверждение остаётся благим пожеланием.

Information

Rating
Does not participate
Location
Киев, Киевская обл., Украина
Registered
Activity