Pull to refresh
66
Андрей@DistortNeo

Математик, программист

24
Subscribers
Send message
А вот я приверженец стратегии программирования, нацеленной на результат. Сначала ставим задачу, а затем с интересом её решаем, попутно изучая язык программирования. Переписывать через месяц код с новыми значениями — это нормально, это не трата времени, а естественный процесс обучения. А вот накапливать в течении года теорию и только потом приступить к практическую программированию — нереально.

Также я считаю, что не нужно смешивать следующие моменты:
1. Изучение архитектуры, логики и парадигм и технологий программирования.
2. Изучение синтаксиса языков.
3. Изучение алгоритмов и структур данных.
Мне становится грустно, когда я вижу студентов, которые без уверенного знания архитектуры и синтаксиса языка сразу лезут в алгоритмы.

Роль учебников для каждого индивидуальна. Я считаю чтение учебников скучным, для меня это пустая трата времени, т.к. теория без практики не откладывается. А если и использую учебники, то исключительно как документацию и справочный материал — впрочем, сейчас всё то же самое есть в интернете.

Многие, например, очень настойчиво советуют всякие модные книги по написанию совершенного кода и паттернам. Новичку эти книги будут вредны. Например, паттерн — это просто способ оформления кода с определённой логикой, а не готовое решение, которое обязательно нужно куда-нибудь воткнуть.

Ещё крайне важно знать английский язык. Потому что документация и обучающие примеры в подавляющем большинстве будут на английском.
Да, при миграции проекта с VS2015 на g++ я с кучей проблем, связанных с нестрогим пониманием стандарта, связывался.

В любом случае, пример не будет работать, если убрать I0 из базовых классов для I12 (т.е. сделать как цитируемом сообщении). Ну а static_cast — немного некрасивое решение.

А вот на такое и VS2015 ругнётся
struct I0 {
	virtual ~I0() {};
	virtual void base() = 0;
};

struct I1 : I0 {
	virtual ~I1() {};
	virtual void foo() = 0;
};

struct I2 : I1, I0 {
	virtual ~I2() {};
	virtual void bar() = 0;
};

struct I12 : I1, I2, I0 {
	~I12() override { printf("~I12\n"); }

	void base() override { printf("base\n"); }

	void foo() override { printf("foo\n"); }

	void bar() override { printf("bar\n"); }
};


И получаем вполне закономерную ошибку:

error: 'I0' is an ambiguous base of 'I12'
Виртуальное наследование нужно использовать для возможности множественного включения одного и того же интерфейса (см. мой пример выше).
Лучше не использовать продвинутые заменители концептов до их появления в стандарте.

Причины простые:
1. Крайне неинформативный вывод сообщений об ошибках в шаблонах.
2. Замедление скорости компиляции.
3. Не всегда очевидна логика работы шаблонных конструкций без вдумчивого анализа кода.
4. В конце концов, монструозные конструкции ломают IDE, в результате чего IDE превращается просто в редактор с подсветкой синтаксиса.

Указанный в публикации пример — исключение, подтверждающее правило.

P.S. Я бы просто воткнул в функцию static_assert.
Вычитание должно выполняться так же, как и на CPU.
Ну а если алгоритм неустойчивый и зависит от точности округления — это плохой алгоритм.
Смартфон за 10к рублей, из перечисленного:

— искать решения приходилось;
— теряет связь на второй симке (причём входящие на неё все равно принимает);
— сбрасывается настройка галки уведомлений от приложений после перезагрузки;
— HDR подвешивает камеру
Моя мысль находится немного в стороне.

Я согласен с тем, что изучать код по тестам даже проще, согласен с тем, что слабая связанность — благо для эффективного написания и поддержки кода.

Я лишь хотел указать на то, что слабая связанность в виде использования интерфейсов замедляет навигацию по коду, иногда существенно.
1. Закон Амдала никто не отменял. Лучше мало процессоров, но быстрых, чем много, но медленных, но с такой же суммарной произодительностью.

2. Да, там тоже есть SIMD. Но вот в чём проблема: если использовать эти инструкции явно, то придётся тестировать и отлаживать программу непосредственно на суперкомьютере. Либо писать просто код и надеяться, что компилятор сделает авто-векторизацию.
Оно вылезет, если один интерфейс наследуется от другого или нескольких.
Например, IList, который наследуется от ICollection и IEnumerable.

Пример C#:

interface IA {}
interface IB {}
interface IC {}
interface IAB: IA, IB {}

class CA: IA {}
class CB: CA, IAB, IC {}

Аналогичный код на C++ будет выглядеть так:

class IA { public: virtual ~IA() {} };
class IB { public: virtual ~IB() {} };
class IC { public: virtual ~IC() {} };
class IAB: virtual public IA, virtual public IB { public: virtual ~IAB() {} };

class CA: virtual public IA {};
class CB: public CA, virtual public IAB, virtual public IC {};

При этом на 64-битной аритектуре объект C# будет занимать 24 байта вне зависимости от числа интерфейсов, тогда как C++ — 40 байт, и каждый последующий интерфейс будет добавлять ещё по 8 байт.
Потому что для получения аналогичного функционала придётся познать все прелести множественного наследования (причём «интерфейсы» — ещё с виртуальным наследованием), за которое в приличном обществе бьют палкой по рукам.
Потому что именно так и происходит в реальном мире.
Поэтому правилом хорошего тона считается выкладывать препринт статьи в открытый доступ (издательства пока ещё это разрешают официально).
Если посмотреть документацию по CUDA, то можно увидеть, что применение этой опции приводит к приближённому вычислению наиболее дорогих операций: деления и извлечения корня, а также к приближённому вычислению трансцендентных функций (тригонометрия, логарифм, экспонента).
Операции сложения и умножения же выполняются с той же точностью.

И, кстати, для CPU эта опция также доступна: там тоже есть возможно быстро (в ~3 раза быстрее) вычислять обратное значение и корень.
К сожалению, за надёжность разработки приходится расплачиваться тем, что код становится менее удобным для изучения, когда хочется посмотреть не что функция делает, а как:

1. Увеличивается количество сущностей: вместо прямого вызова new конкретного класса вызывается абстрактная фабрика, возвращающая абстрактный класс: +2 интерфейса, +1 класс.

2. Усложняется навигация по коду: перейти по определению класса становится невозможно.

3. Может упасть производительность из-за виртуальных вызовов в вычилистельных задачах.

Ну и общие соображения:

4. В C++ нет интерфейсов. Их можно пытаться эмулировать абстрактными классами и множественным наследованием, но получить тот же функционал, что в C# и Java (композиция интерфейсов), все равно не получится.
Ошибка в вычислениях — это действительно что-то из ряда вон выходящее. Ещё более вероятно просто битую память получить (частое явление для видеокарт).

А небольшие различия бывают, это да:
http://stackoverflow.com/questions/13937328/division-of-floating-point-numbers-on-gpu-different-from-that-on-cpu

Но существенными я бы их не назвал. Если результат вашего алгоритм зависит от значения бита в младшем разряде, значит, вы что-то делаете не так. Гарантируется только определённая точность до определённого разряда.
Для фотореалистичной обработки гамму учитывать нужно. Гамма придумана для того, чтобы сделать более-менее равномерным распределение отсчётов шкалы в соответствии с человеческим восприятием.

Например, черный провод на белом фоне после размытия должен пропать, а белая нить на чёрном фоне — стать толще, почти не потеряв в яркости. Без преобразования гаммы оба объекта бы стали серыми.
Точность будет одинакова, т.к. устройства следуют стандарту IEEE 754.
Отличие игровой видеокарты от профессиональной заключается в повышенной производительности последней для double. Если же считать только во float, то игровая видеокарта будет предпочтительнее (как минимум, из-за цены).
Нисколько. В научной среде финансирование исследований идёт по следующей схеме:

1. Делаем исследование.
2. Получаем финансирование под почти полностью выполненное исследование.
3. Пока есть финансирование, занимаемся другими задачами.
Хорошая задача. Ещё и лазер с автонаведением приспособить для возгонки ччужеродных объектов.
А если серьёзно, то есть интерес со стороны металлургов.

Information

Rating
Does not participate
Location
Сербия
Date of birth
Registered
Activity

Specialization

Бэкенд разработчик
Старший