мистика! пробовал через тот же сайт, только компилятор стоял gcc11 — код получался неоптимизирвоанным, а сейчас всё в порядке.
всё же некоторые возможности процессора пропадают безвозвратно, что бывает обидно. Например, 64х процессоры при умножении двух чисел возвращают два 64х битных числа, но старшее из них безвозвратно теряется, так как не удаётся построить такую конструкцию, из которой оптимизатор бы понял, что значение нужно сохранить. Как и флаг переноса при сложении. Их же специально придумали для удобства людей, а в высокоуровневых языках убрали — вот и проверяй потом на переполнение. А всякие расширения процессора можно и не вспоминать. Это возможно только в рамках стандартной или не очень библиотеки.
Только им не показывайте, а то ведь всерьёз начнут применять)
На онлайн компиляторе не смог повторить, но локальный gcc однозначно лучше компилирует перестановку через временную переменную (swap4), чем xor варианты:
А всё потому, что ваша версия загружает в память промежуточные результаты.
Если строго следовать написанному мной алгоритму, swap работает, а версия 3 даже без каких либо xor-ов. ideone.com/NeRdWe
Если говорим о базовой интерпретации, то переменная — это адрес в памяти, которая будет дважды загружена в разные регистры, после чего произойдёт обмен и выгрузка обратно в память. Таким образом swap(a,a) корректно отработает через xor.
В случае со swap оптимизировать не надо в любом случае — это задача компилятора знать особенности всех платформ и скорости выполнения инструкций (и особенности конвейера и кеша они тоже учитывают), а также проследить, что за a и b передаются в функцию, и на основании этого выдать оптимальный код.
Но здесь возникает проблема определённости, так как мы перестаём понимать сложность алгоритма, и однажы оказывается, что размещение в памяти 1 млрд+1 букв занимает на 0.2 сек меньше, чем 1 млрд просто.
«автопилоты» — если бы вы знали, как эти автопилоты работают, скорее всего побоялись бы выходить на улицу, зная что по ней поедет такое. но спутники летают… только там технологии и принципы разработки немного кардинально другие.
чтобы ctrl shift вправо, надо обе руки держать на клавиатуре, а если рука занята мышкой, то быстрее выделить. а вот пользоваться компьютером без мыши и без какого-то знания программирования — это вряд ли.
Где-то читал, что xchg a,b работает дольше, чем xor a,b; xor b, a; xor a,b; но в реальной программе может и такого не произойти. С высокой вероятностью оптимизатор решит не перемещать значения в памяти, а заменить все последующие ссылки a на b и наоборот (если сможет).
К сожалению, я в курсе состояния современной профессиональной разработки.
«терять для этого время» — действительно, просто покажите ваш код, где вы выбрали лучший язык, архитектуру и методологию разработки. А книги Дейкстры у меня итак уже есть.
Если у вас есть конструктивная критика работ Дейкстры, то было бы интересно узнать детали и ваши предложения, как сделать лучше. Понятие «современному накопленному опыту» — слишком широкое и включает в себя не менее широкое «накопленного современного говнокода». Но подозреваю, что постоянные взломы и утечки происходят не из-за кода, написанного Дейкстрой или под его руковоством.
Нам в школе рассказали о лагранжевой механике. Мельком на факультативном занятии, больше к теме не возвращались. Сейчас очень жалею об этом, поскольку в учебниках объясняют даже меньше, чем в нашей школе, а вопросы больше задавать некому. И ведь предложи нам порешать задачки — через пол года или даже быстрее скорее всего я бы задал те же вопросы.
Поэтому совсем не очевидно. Вместо ньютоновской — не стоит, но после — очень спорный вопрос?!
По п.1) Недавно проводил исследование необычной формулы, описывающей изгиб металлических платин, и тоже зачем-то сначала рисовал графики. Они оказались совершенно бесполезны и не информативны. После этого переделал программу, чтобы она умела возвращать только одно-единственное числовое значение, и дописал вторую программу, в которой изложил проверяемую гипотезу. Проверив пять гипотез посредством 10 млн запусков первой программы она заключила, что формула фейковая и коэффициенты в ней подгоняли, что ошибку легче всего искать на 30% длины стержня с очень маленькой толщиной, а графики же, поскольку я не знал, что точно ищу, то все оказались мейнстримными частными случаями. Графики тоже нужны — но в конце, когда расчёты уже проведены, и вы точно знаете, что на вашем графике есть то, что вы искали.
Я думаю, есть множество других задач, где визуализация намного более важна, чем в расчёте физических процессов. Как вы пришли к вашим выводам?
Если крипта станет хоть немного популярной, и на неё начнут покупать продукты и бытовые товары, это будут миллионы-миллиарды транзакций в сутки (до 100 тыс. в секунду по-хорошему). С какой скоростью будет разрастаться цепочка, какая будет нагрузка на сети, чтобы её синхронизировать, какие мощности потребуются, чтобы вычислять хеши? Сейчас криптовалюты хорошо себ чувствуют только потому, что количество транзакций в них смехотворно мало по сравнению со всемй экономикой.
Алгоритм точно такой же наивный с полным перебором. Но в 160 раз быстрее. Так что оговореннная архитектура наносит какие-то ограничения, но и без неё у хаскел оптимизатор упирается в намного более серьёзные ограничения. Он ещё 1.6 ГБ памяти потратил. Даже 4 млн по 8 байтному bool — всего 32 МБ промежуточных данных. Честно, нет идей, откуда такие большие числа.
А теперь вопрос: можно ли считать, что любая функция в хаскел либо имеет определение на хаскел, либо импортирована подобным образом? Если да, то это в точности то, о чём я писал в предыдущем комментарии, и хотелось бы посмотреть, каким образом из GMP сделали Integer. Если нет, то странно, и непонятно, где проходит граница.
К си претензия непонятна, ибо в нём граница очень чёткая: список синтактический конструкций задан стандартом, и это встроенное, а все функции — это определяемое (в исходном си вроде бы перегрузки операторов нет). Это вопрос не морали или идеологии, а того, как быстро находить исходники каких-то понятий, если они есть, или понять, что их не нет.
Потому что хорошо, когда каждый язык решает свой круг задач и не претендует на универсальность.
Вы можете определять сложение как:
instance Num Nat where
(+) a Zero = a
(+) a (Succ b) = Succ(a+b)
но вряд ли вас устроит такое определения для сложения 734211040 и 610489189. Впрочем, и оно ссылается на сложение, определённое в строенном типе. А его иначе как
(+) a b = ({
long ADD;
register long _a asm("rdi") = a
register long _b asm("rsi") = b
asm("mov rax,rdi\nadd rax,rsi":"=a" (ADD));
ADD;})
и не определить.
Где-то внутри компилятора оно так и записано, но можно было вынести это в файл, чтобы любой мог по своим потребностям что-то добавить или изменить, а не проклинать разработчиков и строить костыли. Иначе, подозреваю, не так много лет пройдёт, и хаскелл станет «ещё одним универсальным языком».
Тогда однозначно включаем хаскелл в школьную программу вместо лиспа. Этот язык развивает чувство юмора. Ещё его можно использовать в паре с си: на хаскелле описывать, что нужно вычислить, а на си описывать элементарные алгоритмы, которыми будет оперировать вычислитель хаскела.
Не исключено. В работах Теслы мне были больше интересны его достижения не в области электричества, а в области психологии. И лишь стараниями конспирологов пришлось занялся изучением патентов, чтобы показать, что не только никто не скрывает его открытия, но они даже повсеместно применяются (многие).
Тема интересная, если посоветуете какие-нибудь дополнительные источники, буду признателен.
всё же некоторые возможности процессора пропадают безвозвратно, что бывает обидно. Например, 64х процессоры при умножении двух чисел возвращают два 64х битных числа, но старшее из них безвозвратно теряется, так как не удаётся построить такую конструкцию, из которой оптимизатор бы понял, что значение нужно сохранить. Как и флаг переноса при сложении. Их же специально придумали для удобства людей, а в высокоуровневых языках убрали — вот и проверяй потом на переполнение. А всякие расширения процессора можно и не вспоминать. Это возможно только в рамках стандартной или не очень библиотеки.
На онлайн компиляторе не смог повторить, но локальный gcc однозначно лучше компилирует перестановку через временную переменную (swap4), чем xor варианты:
Впрочем, если компилировать с
то результаты получаются следующие:
лучшим окажется тот код, который без вставок!
Если строго следовать написанному мной алгоритму, swap работает, а версия 3 даже без каких либо xor-ов.
ideone.com/NeRdWe
В случае со swap оптимизировать не надо в любом случае — это задача компилятора знать особенности всех платформ и скорости выполнения инструкций (и особенности конвейера и кеша они тоже учитывают), а также проследить, что за a и b передаются в функцию, и на основании этого выдать оптимальный код.
Но здесь возникает проблема определённости, так как мы перестаём понимать сложность алгоритма, и однажы оказывается, что размещение в памяти 1 млрд+1 букв занимает на 0.2 сек меньше, чем 1 млрд просто.
«терять для этого время» — действительно, просто покажите ваш код, где вы выбрали лучший язык, архитектуру и методологию разработки. А книги Дейкстры у меня итак уже есть.
Поэтому совсем не очевидно. Вместо ньютоновской — не стоит, но после — очень спорный вопрос?!
Я думаю, есть множество других задач, где визуализация намного более важна, чем в расчёте физических процессов. Как вы пришли к вашим выводам?
Выглядит красиво, не поспорить,
True
it :: Prelude.Bool
(0.85 secs, 816,057,504 bytes)
> prime(3997859)
True
it :: Prelude.Bool
(1.64 secs, 1,631,185,144 bytes)
> prime x = and [ x `mod` y /= 0 | y < — [2..(div (x-1) 2)] ]
prime :: Integral a => a -> Prelude.Bool
(0.01 secs, 0 bytes)
> prime(1999993)
True
it :: Prelude.Bool
(0.41 secs, 408,056,872 bytes)
> prime(3997859)
True
it :: Prelude.Bool
(0.81 secs, 815,620,928 bytes)
Я, конечно, не ждал чуда с y^2, но на /2 от платформы, занимающей 800МБ на диске расчитывал. Но ладно.
3997851 3
3997852 2
3997853 29
3997854 2
3997855 5
3997856 2
3997857 3
3997858 2
3997859 0
3997860 2
3997861 7
3997862 2
3997863 3
3997864 2
3997865 5
3997866 2
3997867 47
3997868 2
3997869 3
Process returned 0 (0x0) execution time: 0.010 s
Алгоритм точно такой же наивный с полным перебором. Но в 160 раз быстрее. Так что оговореннная архитектура наносит какие-то ограничения, но и без неё у хаскел оптимизатор упирается в намного более серьёзные ограничения. Он ещё 1.6 ГБ памяти потратил. Даже 4 млн по 8 байтному bool — всего 32 МБ промежуточных данных. Честно, нет идей, откуда такие большие числа.
Нашёл пример интеграции хаскел и си:
github.com/mgrabmueller/rdtsc
А теперь вопрос: можно ли считать, что любая функция в хаскел либо имеет определение на хаскел, либо импортирована подобным образом? Если да, то это в точности то, о чём я писал в предыдущем комментарии, и хотелось бы посмотреть, каким образом из GMP сделали Integer. Если нет, то странно, и непонятно, где проходит граница.
К си претензия непонятна, ибо в нём граница очень чёткая: список синтактический конструкций задан стандартом, и это встроенное, а все функции — это определяемое (в исходном си вроде бы перегрузки операторов нет). Это вопрос не морали или идеологии, а того, как быстро находить исходники каких-то понятий, если они есть, или понять, что их не нет.
Вы можете определять сложение как:
но вряд ли вас устроит такое определения для сложения 734211040 и 610489189. Впрочем, и оно ссылается на сложение, определённое в строенном типе. А его иначе как
и не определить.
Где-то внутри компилятора оно так и записано, но можно было вынести это в файл, чтобы любой мог по своим потребностям что-то добавить или изменить, а не проклинать разработчиков и строить костыли. Иначе, подозреваю, не так много лет пройдёт, и хаскелл станет «ещё одним универсальным языком».
Тема интересная, если посоветуете какие-нибудь дополнительные источники, буду признателен.