All streams
Search
Write a publication
Pull to refresh
5
0
Send message
Только им не показывайте, а то ведь всерьёз начнут применять)

На онлайн компиляторе не смог повторить, но локальный gcc однозначно лучше компилирует перестановку через временную переменную (swap4), чем xor варианты:
objdump
0000000000000000 <_Z5swap1PiS_>:
   0:   8b 07                   mov    eax,DWORD PTR [rdi]
   2:   33 06                   xor    eax,DWORD PTR [rsi]
   4:   89 07                   mov    DWORD PTR [rdi],eax
   6:   33 06                   xor    eax,DWORD PTR [rsi]
   8:   89 06                   mov    DWORD PTR [rsi],eax
   a:   31 07                   xor    DWORD PTR [rdi],eax
   c:   c3                      ret

0000000000000010 <_Z5swap2PiS_>:
  10:   8b 07                   mov    eax,DWORD PTR [rdi]
  12:   8b 0e                   mov    ecx,DWORD PTR [rsi]
  14:   48 31 c8                xor    rax,rcx
  17:   48 31 c1                xor    rcx,rax
  1a:   48 31 c8                xor    rax,rcx
  1d:   89 07                   mov    DWORD PTR [rdi],eax
  1f:   89 0e                   mov    DWORD PTR [rsi],ecx
  21:   c3                      ret

0000000000000030 <_Z5swap3PiS_>:
  30:   8b 0f                   mov    ecx,DWORD PTR [rdi]
  32:   8b 06                   mov    eax,DWORD PTR [rsi]
  34:   89 07                   mov    DWORD PTR [rdi],eax
  36:   89 0e                   mov    DWORD PTR [rsi],ecx
  38:   c3                      ret

0000000000000040 <_Z5swap4PiS_>:
  40:   8b 07                   mov    eax,DWORD PTR [rdi]
  42:   8b 16                   mov    edx,DWORD PTR [rsi]
  44:   89 17                   mov    DWORD PTR [rdi],edx
  46:   89 06                   mov    DWORD PTR [rsi],eax
  48:   c3                      ret




Впрочем, если компилировать с
жёстко заданными значениями
int main()
{
    int a=6,b=7,c=8;
    swap(&a,&c);
    return a-c;
}

то результаты получаются следующие:
0000000000000050 <_Z5main1v>:
  50:   b8 02 00 00 00          mov    eax,0x2
  55:   c3                      ret

0000000000000060 <_Z5main2v>:
  60:   b8 06 00 00 00          mov    eax,0x6
  65:   b9 08 00 00 00          mov    ecx,0x8
  6a:   48 31 c8                xor    rax,rcx
  6d:   48 31 c1                xor    rcx,rax
  70:   48 31 c8                xor    rax,rcx
  73:   29 c8                   sub    eax,ecx
  75:   c3                      ret

0000000000000080 <_Z5main3v>:
  80:   b9 06 00 00 00          mov    ecx,0x6
  85:   b8 08 00 00 00          mov    eax,0x8
  8a:   29 c8                   sub    eax,ecx
  8c:   c3                      ret

0000000000000090 <_Z5main4v>:
  90:   b8 02 00 00 00          mov    eax,0x2
  95:   c3                      ret



лучшим окажется тот код, который без вставок!
А всё потому, что ваша версия загружает в память промежуточные результаты.
Если строго следовать написанному мной алгоритму, swap работает, а версия 3 даже без каких либо xor-ов.
ideone.com/NeRdWe
Если говорим о базовой интерпретации, то переменная — это адрес в памяти, которая будет дважды загружена в разные регистры, после чего произойдёт обмен и выгрузка обратно в память. Таким образом swap(a,a) корректно отработает через xor.

В случае со swap оптимизировать не надо в любом случае — это задача компилятора знать особенности всех платформ и скорости выполнения инструкций (и особенности конвейера и кеша они тоже учитывают), а также проследить, что за a и b передаются в функцию, и на основании этого выдать оптимальный код.

Но здесь возникает проблема определённости, так как мы перестаём понимать сложность алгоритма, и однажы оказывается, что размещение в памяти 1 млрд+1 букв занимает на 0.2 сек меньше, чем 1 млрд просто.
Судя по сложившейся системе наименования для SSD «параллелепипед умеренной жёсткости» будет в самый раз)
«автопилоты» — если бы вы знали, как эти автопилоты работают, скорее всего побоялись бы выходить на улицу, зная что по ней поедет такое. но спутники летают… только там технологии и принципы разработки немного кардинально другие.
чтобы ctrl shift вправо, надо обе руки держать на клавиатуре, а если рука занята мышкой, то быстрее выделить. а вот пользоваться компьютером без мыши и без какого-то знания программирования — это вряд ли.
«а наоборот» — думал, напишите, что: а наоборот — подчиняются им и выполняют все их команды.
Где-то читал, что xchg a,b работает дольше, чем xor a,b; xor b, a; xor a,b; но в реальной программе может и такого не произойти. С высокой вероятностью оптимизатор решит не перемещать значения в памяти, а заменить все последующие ссылки a на b и наоборот (если сможет).
К сожалению, я в курсе состояния современной профессиональной разработки.
«терять для этого время» — действительно, просто покажите ваш код, где вы выбрали лучший язык, архитектуру и методологию разработки. А книги Дейкстры у меня итак уже есть.
Если у вас есть конструктивная критика работ Дейкстры, то было бы интересно узнать детали и ваши предложения, как сделать лучше. Понятие «современному накопленному опыту» — слишком широкое и включает в себя не менее широкое «накопленного современного говнокода». Но подозреваю, что постоянные взломы и утечки происходят не из-за кода, написанного Дейкстрой или под его руковоством.
Нам в школе рассказали о лагранжевой механике. Мельком на факультативном занятии, больше к теме не возвращались. Сейчас очень жалею об этом, поскольку в учебниках объясняют даже меньше, чем в нашей школе, а вопросы больше задавать некому. И ведь предложи нам порешать задачки — через пол года или даже быстрее скорее всего я бы задал те же вопросы.

Поэтому совсем не очевидно. Вместо ньютоновской — не стоит, но после — очень спорный вопрос?!
Паскаль до сих пор живёт в среде делфи, на которой и по сей день пишут миниатюрные графические приложения.
По п.1) Недавно проводил исследование необычной формулы, описывающей изгиб металлических платин, и тоже зачем-то сначала рисовал графики. Они оказались совершенно бесполезны и не информативны. После этого переделал программу, чтобы она умела возвращать только одно-единственное числовое значение, и дописал вторую программу, в которой изложил проверяемую гипотезу. Проверив пять гипотез посредством 10 млн запусков первой программы она заключила, что формула фейковая и коэффициенты в ней подгоняли, что ошибку легче всего искать на 30% длины стержня с очень маленькой толщиной, а графики же, поскольку я не знал, что точно ищу, то все оказались мейнстримными частными случаями. Графики тоже нужны — но в конце, когда расчёты уже проведены, и вы точно знаете, что на вашем графике есть то, что вы искали.

Я думаю, есть множество других задач, где визуализация намного более важна, чем в расчёте физических процессов. Как вы пришли к вашим выводам?
Если крипта станет хоть немного популярной, и на неё начнут покупать продукты и бытовые товары, это будут миллионы-миллиарды транзакций в сутки (до 100 тыс. в секунду по-хорошему). С какой скоростью будет разрастаться цепочка, какая будет нагрузка на сети, чтобы её синхронизировать, какие мощности потребуются, чтобы вычислять хеши? Сейчас криптовалюты хорошо себ чувствуют только потому, что количество транзакций в них смехотворно мало по сравнению со всемй экономикой.
Касательно оптимизации. Поигрался с кодом:
prime :: (Integral a) => a -> Bool
prime 1 = True
prime x = and [ x `mod` y /= 0 | y <- [2..(x-1)] ]

Выглядит красиво, не поспорить,
а теперь запускаем:
> prime(1999993)
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МБ на диске расчитывал. Но ладно.
Код на си:
int try_div(int a,int b)
{
	return a%b;
}

int test_prime(int arg)
{
	if(arg<2) return -1;
	if(2==arg) return 0;
	if(!(arg%2)) return 2;
	for(int i=3;i<arg;i+=1)
		if(!(try_div(arg,i)))
			return i;
	return 0;
}

int main(int argc,char**argv)
{
	int j;
	for(int i=3997850;i<3997870;i++){
		j=test_prime(i);
		WriteI(1,i);
		WriteC(1,"\t");
		WriteI(1,j);
		WriteC(1,"\n");}
	return 0;
}


Результат 0.01 сек
3997850 2
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. Если нет, то странно, и непонятно, где проходит граница.

К си претензия непонятна, ибо в нём граница очень чёткая: список синтактический конструкций задан стандартом, и это встроенное, а все функции — это определяемое (в исходном си вроде бы перегрузки операторов нет). Это вопрос не морали или идеологии, а того, как быстро находить исходники каких-то понятий, если они есть, или понять, что их не нет.
Потому что хорошо, когда каждый язык решает свой круг задач и не претендует на универсальность.
Вы можете определять сложение как:
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;})

и не определить.

Где-то внутри компилятора оно так и записано, но можно было вынести это в файл, чтобы любой мог по своим потребностям что-то добавить или изменить, а не проклинать разработчиков и строить костыли. Иначе, подозреваю, не так много лет пройдёт, и хаскелл станет «ещё одним универсальным языком».
Тогда однозначно включаем хаскелл в школьную программу вместо лиспа. Этот язык развивает чувство юмора. Ещё его можно использовать в паре с си: на хаскелле описывать, что нужно вычислить, а на си описывать элементарные алгоритмы, которыми будет оперировать вычислитель хаскела.
Не исключено. В работах Теслы мне были больше интересны его достижения не в области электричества, а в области психологии. И лишь стараниями конспирологов пришлось занялся изучением патентов, чтобы показать, что не только никто не скрывает его открытия, но они даже повсеместно применяются (многие).
Тема интересная, если посоветуете какие-нибудь дополнительные источники, буду признателен.
Когда политика смешивается с историей, знание заканчивается. Если содержание патентов более-менее объективно и находится в свободном доступе, то залезть в голову историческим персонажам и узнать, кто что придумал, а что украл — нет.
Таким образом в документах, которые сейчас мы называем «патентами Теслы», описаны физические принципы и механизмы, актуальные до сих пор — это факт. Кто был истинным автором, как на саом деле работали эти устройства, да и были ли они вообще (патент не требует демонстрации опытного образца) — это вряд ли кто-то сможет достоверно определить.

Information

Rating
Does not participate
Registered
Activity