Как-то раз случайно наткнулся на видео, не помню уж про что оно было, но упомянуто в нем было в том числе и про одну из нерешенных математических проблем. Как раз про совершенный кирпич Эйлера.
Кратко: суть состоит в решение системы четырех диофантовых уравнений второй степени. Это решение соответствует параллелепипеду, у которого все стороны и диагонали являются натуральными числами.
В общем, на текущий момент математики так и не нашли доказательства как существования совершенного кирпича, так и его невозможности.
Естественно, есть соблазн найти такой кирпич с помощью грубой силы. А раз есть соблазн, значит, есть и те, кто попытается им воспользоваться.
К сожалению, на текущий момент найти совершенный кирпич Эйлера таким методом тоже не удалось. И даже дойти до границы 64-битных чисел для длин сторон кирпича тоже.
Что, если честно, меня несколько удивило. Ведь производительность современных компьютеров просто край как высока. Несколько десятков миллиардов целочисленных операций в секунду.
Естественно, я не удержался и решил сам попробовать, не мудрствуя лукаво, грубой силой в лоб. Ну и в общем да, получил то, что и следовало ожидать: два вложенных цикла – это совсем не быстро, даже с учетом того, что память при таких вычислениях мало задействована.
Оптимизация на ассемблере существенно ускорила вычисления, но, конечно, кардинально решить проблему не смогла: слишком высока размерность задачи.
Больше всего издержек при такой попытке поиска кирпичей Эйлера уходит на проверку того, будет ли целым корень из квадрата длины диагонали.
И тут, по крайней мере, пока квадрат длины не выходит за границы 64-битого беззнакового целого, очень помогают вычисления с плавающей точкой.
Сначала я сделал это на расширенном типе с плавающей точкой (extended), являющейся фишкой x87, так как 64-битное беззнаковое целое можно без какой-либо потери точности загрузить в регистр сопроцессора. Еще подумал: "О, вот и старенький x87 может для чего-нибудь пригодиться".
Однако потом в процессе тестов выяснил, что с достаточной степенью точности для данной задачи корни можно вычислять и на типе double. Впрочем, особой разницы в производительности не увидел.
Но, как только мы выйдем за границы 64 бит для квадратов длин диагоналей, вот возможно там тип extended, вместе с x87 и сгодится.
Целочисленные методы вычисления квадратного корня на основе метода Ньютона (он же вавилонский, он же Герона), даже при хорошем начальном приближении требуют минимум двух итераций с делением, что получается гораздо медленнее, чем с плавающей точкой. Главное, что бы хватало точности у этой самой плавающей точки. И вот тут я не уверен, что ближе к верхней границе 128-битного целого точности даже extended будет достаточно.
В практическом же смысле толку от этих самых кирпичей Эйлера я не вижу. Разве что в холода использовать комп в качестве нагревателя. )
И вот идея: так как кирпичи Эйлера трудно вычислимы, почему бы их не использовать в качестве криптовалюты? Тот же специальный вид криптографического хеша тоже особого смысла не имеет. А на майнинг опять же биткойнов потрачено, наверное, уже несколько тераватт*часов электроэнергии.
При этом хоть какую-то ценность все эти криптовалюты имеют до тех пор, пока у достаточно значительной части населения есть вера в крипту хотя бы с горчичное зерно. Как только такая вера пропадет, стоимость крипты мгновенно обнулится.
Кирпичи Эйлера тут ничем не лучше, но в процессе их расчета может хотя бы получилось решить одну их серьезных математических проблем.
Кстати, большого списка примитивных кирпичей Эйлера я так и не нашел. Наверняка он есть, это мне просто искать лень. Если я на первых двух страницах поисковой выдачи не нахожу нужного мне результата, то сразу как-то теряю интерес к процессу поиска. )
Так я делаю, конечно, когда ищу что-то не сильно важное. А кирпичи Эйлера – это тот самый случай.
Так что выложу те кирпичи, которые я в процессе своих экспериментов насчитал. По ссылке лежат примитивные кирпичи, отсортированные по возрастанию нечетной стороны, далее для каждого кирпича указаны меньшая четная, затем большая. Ну и длины диагоналей.
Так как внешний цикл у меня был по нечетной стороне, то остановился я на таком размере, что бы все возможные варианты квадратов диагоналей с учетом четных сторон не превышали диапазона 64-битных чисел.
Возможно, где-то ошибся в программе, так что абсолютно точно не уверен, что нашел все примитивные кирпичи для указанных условий.
Ну и немного статистики. Выяснилось, что примерно 80% длин дают только один вариант кирпича, а вот оставшиеся 20% – несколько. Интересно, что это за числа и чем вызвано такое их свойство? Не знаю, есть ли у математиков ответ на такой вопрос.
Лидером среди нечетных длин является число 51975 – оно дает 12 различных кирпичей, или 24 пифагоровых тройки. Далее идут 32175 и 58905 – по 11 кирпичей.
Четные числа немного отстают. Лидер тут 23760 – 11 кирпичей, 71280 – 9, и у 55440 и 118800 – по 8. Причем такое свойство гораздо чаще встречается у стороны, кратной 16, чем у стороны, кратной лишь только четырем.
Лидер, кратный 4 - 33660, дает 7 кирпичей.
Из найденных вариантов самый близкий к совершенному варианту оказался кирпич с длинами сторон 37835, 269280 и 1244484. Главная диагональ у него 1273846.00006476, что совсем близко к целому числу.
Это дает надежду, что совершенный кирпич Эйлера все же существует. Но скорее всего длины сторон лежат за пределами 64-битных целых, так как значительная часть этого диапазона уже проверена исследователями.
А вот в диапазоне 128-битных целых такой кирпич вполне может прятаться.
Интересная проблема, я тоже не знал о ней, спасибо что поделились! Главное - очень простая, даже школьнику понятная задачка и почему в школе о таких не рассказывают... мне вот было бы очень интересно узнать о чем современные математики голову ломают!
ОтветитьУдалить> Больше всего издержек при такой попытке поиска кирпичей Эйлера уходит на проверку того, будет ли целым корень из квадрата длины диагонали.
А не смотрели в сторону более хитрых алгоритмов перебора? Я ради интереса погуглил и наткнулся на: http://unsolvedproblems.org/S58.pdf и http://www.christianboyer.com/eulerbricks/searchingmethod.htm (более замудренный, перебирает не подряд) Я вроде даже понял что они делают, все на целых числах, без вычисления корня, и конечно все еще ничего не нашли...
> Кстати, большого списка примитивных кирпичей Эйлера я так и не нашел.
На http://www.christianboyer.com/eulerbricks есть ссылка на "30414 primitive 3D solutions with smallest edge < 2.325e+10" Можно сравнить на сколько они совпадают с Вашими :)
Решил реализовать алгоритм описанный в http://unsolvedproblems.org/S58.pdf, правда без длинной арифметики, на java, ничего особо не оптимизируя, только скопировал математику из статьи. Получилось не особо быстро: перебор нечетного ребра до 75919, а четных - всех потенциально возможных занимает 12 секунд, при больших значениях знаковый 64-битный тип переполняется. А за сколько у Вас перебор выполняется, если не секрет?
УдалитьКод здесь: https://gist.github.com/ivankolesnikov/98642bb08f73171949bc9f71bc1e6fec
Чуток код обновил: ускорил в 2 раза и частично перевел на длинную арифметику. Теперь x <= 75919 перебирает где-то за 6 сек, а <=500К за 4,5 минуты. Не быстро...
Удалить> А не смотрели в сторону более хитрых алгоритмов перебора?
УдалитьНет, мне было интересно, насколько быстро тупой перебор работает. Выяснил, что не очень.
Первый вариант по твоим ссылкам я тоже находил, но углубляться не стал.
> Можно сравнить на сколько они совпадают с Вашими :)
О, спасибо за ссылочку. Совпадают, но не со всем. ))) Я, как обычно, нехило так протупил, был невнимателен и упустил некоторые важные детали. В результате у меня, конечно, кирпичи Эйлера, но многие являются составными, а не примитивными. Надо будет просеять их как-нибудь на досуге.
> Теперь x <= 75919 перебирает где-то за 6 сек, а <=500К за 4,5 минуты. Не быстро...
Ну, у меня-то существенно медленнее. Видимо, надо все же углубиться )
> но углубляться не стал.
УдалитьЯ бы наверное тоже не стал, но на улице пару дней жара под 40, в гараже к обеду тоже пекло, вот решил посмотреть и втянулся, интересные Вы задачки находите :)))
> Ну, у меня-то существенно медленнее.
Зато просто и понятно, я думал может корень уже более-менее быстрый и все эти сложности ни к чему, но нет, похоже хитрые-непонятные алгоритмы все еще имеют смысл.
> Надо будет просеять их как-нибудь на досуге.
Ваше "просеять" навело меня на мысль что можно ведь решето использовать для поиска делителей вместо перебора всех вариантов... Спасибо за неосознанную подсказку!
Это ускорило мое решение где-то на пару порядков, а так как число делителей растет довольно медленно (если у нечетных чисел до 100К, в среднем 9,4 делителя, то для чисел до 1М - всего 11,7 делителей), то скорость нового алгоритма падает довольно медленно по мере возрастания нечетной стороны.
Новая реализация перебирает x<=100М за 10 минут.
А у нас тут в Сибири какое-то в этом году прохладное лето.
Удалить>...можно ведь решето использовать для поиска делителей...
Ого! Круто, интересно, и не понятно )))
То есть ты каким-то образом ускорил поиск Y=(X^2 - i^2)/2i?
Да у нас тоже в этом году прохладно по сравнению с предыдущими годами, это вот первые пару деньков супер жарких, обычно за ночь все остывает, а тут и днем жара и ночью не особо холодно.
УдалитьАга, в той статье, в начале, рассматривают x=d1*d2*d3; y=(d2^2-d1^2)*d3/2 поиск, требующий перебор 2-х делителей X, вместо 1-го для X^2. Вроде тоже самое, но не совсем...
Так как X намного меньше чем X^2, то можно предварительно найти все делители для всех X используя решето. Не уверен, что алгоритм так называется, но очень похоже на решето Эратосфена, только вместо проставления флага, добавляем делитель в список делителя, в итоге для каждого делимого получаем список делителей, да еще и в отсортированном порядке. А далее при поиске Y два вложенных цикла по делителям X для D1 и D2. Как я выше писал, этот список в среднем крохотный.
В реальности же я строю решето блоками: построил для 1М нечетных чисел, проверил их все, далее строю новое решето для следующего миллиона, это вроде не намного медленнее, но по памяти существенно экономнее.
Реализация все там же: https://gist.github.com/ivankolesnikov/98642bb08f73171949bc9f71bc1e6fec, в файле v2.