Нет. Результат операций с плавающей точкой зависит от порядка операций: в общем случае (a+b)+c != a+(b+c). Распараллелить вычисления, гарантируя стабильный порядок операций - это очень сложная задача, которая решается крайне редко, только в критических случаях.
Можно я буду пользоваться комментариями в качестве личных заметок при чтении ваших статей? Вы дали ссылку на файл SROA.cpp, и выясняется, что SROA - это Scalar Replacement Of Aggregates. Очень интересное и говорящее название! Давайте отвлечёмся от финод, и посмотрим на более простой случай.
Мне кажется, что инлайнинг функций - это вид SROA (даже если в том .cpp его нет), только оно работает над кодом, а не над памятью. Если мы возьмём такой код, то инлайнинг позволяет избавиться от вызова print:
Hidden text
typedef struct {
int x, y;
} point;
void print(point *p) {
printf("(%d, %d)", p->x, p->y);
}
int main () {
point p;
p.x = 1;
p.y = 2;
print (&p);
return 0;
}
То есть, после инлайнинга мы получим следующий код:
Hidden text
typedef struct {
int x, y;
} point;
int main () {
point p;
p.x = 1;
p.y = 2;
printf("(%d, %d)", p.x, p.y);
return 0;
}
Причём в данном случае основная польза не в том, что мы избавились от накладных расходов на вызов функции. Компилятору трудно что-то доказать про кусок памяти, когда работа с ним разбросана по множеству функций. А ведь если нет доказательства, нет и оптимизации (мы же не хотим, чтобы компилятор нам всё поломал?)
То есть, в данном случае польза от инлайнинга в том, что компилятор может теперь рассуждать об аргументах функции printf, поскольку они теперь живут в том же месте, где и была создана структура p.
То есть, польза в том, что мы не обязаны использовать load/store для доступа к полям структуры: SROA позволяет убрать агрегатную структуру point, и заменить её на две локальных переменных p_x и p_y:
Hidden text
int main () {
int p_x = 1;
int p_y = 2;
printf("(%d, %d)", p_x, p_y);
return 0;
}
А дальше проталкивание констант позволяет убрать и их:
Hidden text
int main () {
printf("(%d, %d)", 1, 2);
return 0;
}
Возвращаясь к данной статье, автор рассматривает фрейм функции как агрегатную структуру с параметрами и локальными переменными, и заменяет где можно доступ к этой структуре через load/store на SSA-значения. А это, в свою очередь, уже позволит компилятору делать рассуждения.
Я планирую дальше дорабатывать этот компилятор, правда пока не знаю в каком ключе лучше двигаться.
Проверка (а лучше вывод) типов. Можно вообще перейти к динамической типизации, к замыканиям и к сборщикам мусора. Ну а если статическая, добавляйте классы, множественное наследование и таблицы виртуальных методов, там есть чем заняться. А вообще самый шик - это сделать минимально рабочую версию компилятора, и расширять возможности языка на самом языке.
Да кто ж будет игрушечный компилятор транслировать под каждую архитектуру? Лично мне нравятся проекты без внешних зависимостей, зачем в учебном коде llvm?
Интересно, что функции типа sin и ln набраны италиком, что недопустимо. Надо бы поправить sympy...
Насчёт всех уравнений не знаю, но вот все семьи уравнений встречаются точно. Насколько их необходимо решать символьно - вопрос отдельный.
Я чётко сказал "оригинал текста". Ваш текст - это не компиляция всех вами приведённых ссылок, а творческая переработка одного-двух источников.
Сюжет захватывающий, но это не отменяет необходимости аккуратной работы с источниками.
Да ладно вам, дайте уже придраться ;)
Я-то свои плюсы поставил.
Производная x^2 равна не 2, а 2x, если что.
А ссылку на оригинал текста ставить нынче не модно?
https://boehs.org/node/everything-i-know-about-the-xz-backdoor
Сейчас распараллеливание вычислений есть просто везде.
Кроме того, мы же нейросети обсуждали? Вы вот сейчас серьезно представили сетку в один тред? :)
И даже на одной и той же машине порядок меняется.
Нет. Результат операций с плавающей точкой зависит от порядка операций: в общем случае (a+b)+c != a+(b+c). Распараллелить вычисления, гарантируя стабильный порядок операций - это очень сложная задача, которая решается крайне редко, только в критических случаях.
Можно я буду пользоваться комментариями в качестве личных заметок при чтении ваших статей? Вы дали ссылку на файл SROA.cpp, и выясняется, что SROA - это Scalar Replacement Of Aggregates. Очень интересное и говорящее название! Давайте отвлечёмся от финод, и посмотрим на более простой случай.
Мне кажется, что инлайнинг функций - это вид SROA (даже если в том .cpp его нет), только оно работает над кодом, а не над памятью. Если мы возьмём такой код, то инлайнинг позволяет избавиться от вызова
print
:Hidden text
То есть, после инлайнинга мы получим следующий код:
Hidden text
Причём в данном случае основная польза не в том, что мы избавились от накладных расходов на вызов функции. Компилятору трудно что-то доказать про кусок памяти, когда работа с ним разбросана по множеству функций. А ведь если нет доказательства, нет и оптимизации (мы же не хотим, чтобы компилятор нам всё поломал?)
То есть, в данном случае польза от инлайнинга в том, что компилятор может теперь рассуждать об аргументах функции
printf
, поскольку они теперь живут в том же месте, где и была создана структураp
.То есть, польза в том, что мы не обязаны использовать load/store для доступа к полям структуры: SROA позволяет убрать агрегатную структуру
point
, и заменить её на две локальных переменныхp_x
иp_y
:Hidden text
А дальше проталкивание констант позволяет убрать и их:
Hidden text
Возвращаясь к данной статье, автор рассматривает фрейм функции как агрегатную структуру с параметрами и локальными переменными, и заменяет где можно доступ к этой структуре через load/store на SSA-значения. А это, в свою очередь, уже позволит компилятору делать рассуждения.
На всякий случай, если кто тоже споткнулся, то это определение дано через одну статью :)
да, согласен, спасибо
Hidden text
В прод - безусловно. Для обучения - сильно не факт
Можно отбивку пробелом использовать, наверное
Ну, если даже GCC не стесняется генерировать ассемблер :)
А почему последний икс в скобках?
Я-то запустил, и не только хелловорлд :)
А зависимости это... Неопрятненько, что ли. Кусок магии остаётся, нет чувства полного удовлетворения.
Проверка (а лучше вывод) типов. Можно вообще перейти к динамической типизации, к замыканиям и к сборщикам мусора. Ну а если статическая, добавляйте классы, множественное наследование и таблицы виртуальных методов, там есть чем заняться. А вообще самый шик - это сделать минимально рабочую версию компилятора, и расширять возможности языка на самом языке.
Да кто ж будет игрушечный компилятор транслировать под каждую архитектуру? Лично мне нравятся проекты без внешних зависимостей, зачем в учебном коде llvm?
Да не надо на меня никаких ссылок, пользуйтесь, если найдёте пользу.