Как использовать компилятор C #, C ++ или Java для вычисления 1 + 2 + 3 + ... + 1000 во время компиляции? - PullRequest
120 голосов
/ 06 января 2012

В недавнем интервью мне задали действительно странный вопрос.Интервьюер спросил меня, как я могу вычислить 1 + 2 + 3 + ... + 1000, просто используя функции компилятора.Это означает, что мне не разрешено писать программу и выполнять ее, но я должен просто написать программу, которая могла бы заставить компилятор вычислять эту сумму во время компиляции и печатать результат по завершении компиляции.В качестве подсказки он сказал мне, что я могу использовать обобщенные и препроцессорные функции компилятора.Можно использовать компилятор C ++, C # или Java.Любые идеи ???

Этот вопрос не связан с вычислением суммы без каких-либо циклов заданных здесь .Кроме того, следует отметить, что сумма ДОЛЖНА быть рассчитана во время компиляции.Печать только результата с использованием директив компилятора C ++ недопустима.


Читая больше о опубликованных ответах, я обнаружил, что решение проблем во время компиляции с использованием шаблонов C ++ называется метапрограммирование .Это метод, который был случайно обнаружен доктором Эрвином Унру во время стандартизации языка C ++.Вы можете прочитать больше об этой теме на вики-странице метапрограммирования .Кажется, что написать программу на Java можно, используя аннотации Java.Вы можете взглянуть на ответ мамы ниже.

Хорошая книга о метапрограммировании на C ++ - эта .Стоит посмотреть, если интересно.

Полезной библиотекой метапрограммирования C ++ является MPL Boost эта ссылка .

Ответы [ 13 ]

1 голос
/ 13 марта 2014

Хотя на самом деле это работает с небольшими числами, clang ++ возвращает мне ошибку компилятора, если я использую sum_first, где N> 400.

#include <iostream>

using namespace std;


template <int N>
struct sum_first
{
   static const int value = N + sum_first<N - 1>::value;
};

template <>
struct sum_first<0>
{
    static const int value = 0;
};

int main()
{
    cout << sum_first<1000>::value << endl;
}
1 голос
/ 12 августа 2012

Используя java, вы можете сделать то же самое, что и ответ C #:

public class Cheat {
    public static final int x = (1000 *1001/2);
}

javac -Xprint Cheat.java

public class Cheat {

  public Cheat();
  public static final int x = 500500;
}

вы можете сделать это в scala с использованием чисел peano , потому что вы можете заставить компилятор выполнять рекурсию, но я не думаю, что вы можете сделать то же самое в c # / java

другое решение, не использующее -Xprint, но еще более хитрое

public class Cheat {
  public static final int x = 5/(1000 *1001/2 - 500500);
}

javac -Xlint:all Cheat.java

Cheat.java:2: warning: [divzero] division by zero
  public static final int x = 5/(1000 *1001/2 - 500500);
                            ^
1 warning

без использования флагов компилятора. так как вы можете проверить произвольное количество констант (не только 500500), это решение должно быть приемлемым.

public class Cheat {
  public static final short max = (Short.MAX_VALUE - 500500) + 1001*1000/2;
  public static final short overflow = (Short.MAX_VALUE - 500500 + 1) + 1001*1000/2;

}

Cheat.java:3: error: possible loss of precision
  public static final short overflow = (Short.MAX_VALUE - 500500 + 1) + 1001*1000/2;
                                                                  ^
  required: short
  found:    int
1 error
1 голос
/ 06 января 2012

Теоретически вы можете использовать это:

#include <iostream>

template<int N>
struct Triangle{
  static int getVal()
  {
    return N + Triangle<N-1>::getVal();
  }
};

template<>
struct Triangle<1>{
  static int getVal()
  {
    return 1;
  }
};

int main(){
   std::cout << Triangle<1000>::getVal() << std::endl;
   return 0;
}

(основываясь на коде, который разместил Xeo). Но GCC дает мне эту ошибку:

triangle.c++:7: error: template instantiation depth exceeds maximum of 500 (use -ftemplate-depth-NN to increase the maximum) instantiating struct Triangle<500>

плюс огромная псевдостековая трассировка.

...