В недавнем интервью мне задали действительно странный вопрос. Интервьюер спросил меня, как я могу вычислить 1 + 2 + 3 + ... + 1000, просто используя функции компилятора. Это означает, что мне не разрешено писать программу и выполнять ее, но я должен просто написать программу, которая могла бы заставить компилятор вычислить эту сумму во время компиляции и распечатать результат, когда компиляция завершится. В качестве подсказки он сказал мне, что я могу использовать обобщенные и препроцессорные функции компилятора. Можно использовать компилятор C ++, C # или Java. Любые идеи???
Этот вопрос не имеет отношения к вычислению суммы без заданных здесь циклов . Кроме того, следует отметить, что сумму СЛЕДУЕТ вычислять во время компиляции. Печать только результата с использованием директив компилятора C ++ недопустима.
Читая больше об опубликованных ответах, я обнаружил, что решение проблем во время компиляции с использованием шаблонов C ++ называется метапрограммированием . Это метод, который был случайно обнаружен доктором Эрвином Унру в процессе стандартизации языка C ++. Вы можете прочитать больше об этой теме на вики-странице метапрограммирования . Кажется, что можно написать программу на Java, используя аннотации java. Вы можете посмотреть ответ мамы ниже.
Хорошая книга о мета-программирования на языке C ++ является это одна . Стоит взглянуть, если интересно.
Полезной библиотекой метапрограммирования C ++ является Boost MPL по этой ссылке .
const int value = 1 + 2 + 3.... + 1000; Console.WriteLine(value);
; PОтветы:
Обновлено сейчас с улучшенной глубиной рекурсии! Работает на MSVC10 и GCC без увеличения глубины. :)
Простая рекурсия во время компиляции + добавление:
Testcode:
Вывод для GCC:
Живой пример на Идеоне .
Вывод для MSVC10:
источник
Пример C # ошибки во время компиляции.
Выдает следующую ошибку компиляции:
источник
Популярный трюк для печати числа во время компиляции - это попытка получить доступ к несуществующему члену шаблона, созданному с номером, который вы хотите напечатать:
Затем компилятор говорит:
Более интересный пример этой техники см. В разделе Решение проблемы восьми ферзей во время компиляции .
источник
print_n
неопределенность, посмотрите мой ответ.Поскольку в вопросе интервью не были указаны ни компилятор, ни язык, я осмелюсь представить решение на Haskell с использованием GHC:
Скомпилируйте это:
И у нас тоже есть рабочая программа.
источник
Жизнь будет намного проще с C ++ 11, который добавляет
constexpr
функции для расчета времени компиляции, хотя в настоящее время они поддерживаются только gcc 4.6 или новее.Стандарт требует только, чтобы компилятор поддерживал глубину рекурсии 512, поэтому ему все равно нужно избегать линейной глубины рекурсии. Вот результат:
Конечно, вы можете просто использовать формулу:
источник
constexpr
на мгновение. Может, я просто слишком люблю шаблоны. :(/ 2
чтобы обработать весь диапазон возможныхunsigned
результатов, значение, которое вы сдвигаете вправо, должно быть шириной n + 1 бит, но это не так. Можно изменить формулу, чтобы избежать этого, как это делает clang для диапазонов переменных времени выполнения: godbolt.org/z/dUGXqg показывает, что clang знает формулу закрытой формы и использует ее для оптимизацииtotal += i
циклов.В java я подумал об использовании обработки аннотаций. Инструмент apt сканирует исходный файл перед фактическим синтаксическим анализом исходного файла для команды javac.
Во время компиляции исходных файлов вывод будет распечатан:
Завод процессора:
Фактический процессор аннотаций:
Затем мы создаем исходный файл. простой класс, использующий аннотацию MyInterface:
Обработчик аннотаций компилируется в файл jar, затем инструмент apt используется для компиляции исходного файла как:
Результат проекта:
источник
Вот реализация, которая работает в VC ++ 2010. Мне пришлось разбить вычисления на 3 этапа, поскольку компилятор жаловался, когда шаблоны повторяются более 500 раз.
Когда вы скомпилируете это, вы должны увидеть этот вывод компилятора примерно так:
источник
Я чувствую себя обязанным предоставить этот код на C, поскольку никто еще не сделал этого:
И все, что мне нужно сделать, это проверить сборку, чтобы найти свой ответ!
И я вижу:
источник
x
был глобальным, компилятор был бы (более или менее) необходим для оценки выражения во время компиляции. ISO C не допускает инициализаторы переменных времени выполнения для глобальных объектов. Конечно, конкретная реализация может вызвать вызов функции static-init, подобной конструктору, которая вычисляет ее во время выполнения и сохраняет. Но ISO C позволяет использовать константы времени компиляции в качестве размеров массива (например,int y[x];
в определении структуры или в качестве другого глобального), поэтому любая гипотетическая пессимизирующая реализация все равно должна будет поддерживать это.Расширен из ответа Карла Уолша, чтобы фактически распечатать результат во время компиляции:
gcc выводит:
источник
Вы можете использовать (и в большинстве случаев злоупотреблять) макросы / шаблоны C ++ для метапрограммирования . AFAIK, Java не допускает подобных вещей.
источник
Теоретически можно использовать это:
(на основе кода, опубликованного Xeo). Но GCC дает мне эту ошибку:
плюс огромная псевдостековая трассировка.
источник
Используя java, вы можете сделать то же самое, что и ответ C #:
вы можете сделать это в scala, используя числа peano, потому что вы можете заставить компилятор выполнять рекурсию, но я не думаю, что вы можете сделать то же самое в c # / java
другое решение, не использующее -Xprint, но еще более изворотливое
без использования каких-либо флагов компилятора. поскольку вы можете проверить произвольное количество констант (а не только 500500), это решение должно быть приемлемым.
источник
500500
, извините.for (i = 0; i < 100000; ++i) {if (i == 1000*1000/2) print i}
. у меня есть файл java размером 160 МБ, который делает это, и он работает :)Хотя это действительно работает с небольшими числами, clang ++ возвращает мне ошибку компилятора, если я использую sum_first, где N> 400.
источник