Em uma entrevista recente, me fizeram uma pergunta realmente estranha. O entrevistador me perguntou como posso calcular 1 + 2 + 3 + ... + 1000 apenas usando os recursos do compilador. Isso significa que não tenho permissão para escrever e executá-lo, mas devo escrever um programa que possa conduzir o compilador a calcular essa soma durante a compilação e imprimir o resultado quando a compilação for concluída. Como sugestão, ele me disse que eu posso usar os recursos genéricos e pré-processador do compilador. É possível usar o compilador C ++, C # ou Java. Alguma ideia???
Esta questão não está relacionada ao cálculo da soma sem nenhum loop solicitado aqui . Além disso, deve-se notar que a soma DEVE ser calculada durante a compilação. Imprimir apenas o resultado usando diretivas do compilador C ++ não é aceitável.
Lendo mais sobre as respostas postadas, descobri que resolver problemas durante a compilação usando modelos C ++ é chamado metaprogramação . Essa é uma técnica descoberta acidentalmente pelo Dr. Erwin Unruh, durante o processo de padronização da linguagem C ++. Você pode ler mais sobre este tópico na página wiki de metaprogramação . Parece que é possível escrever o programa em Java usando anotações java. Você pode dar uma olhada na resposta de maress abaixo.
Um bom livro sobre metaprogramação em C ++ é este . Vale a pena dar uma olhada se estiver interessado.
Uma útil biblioteca de metaprogramação em C ++ é o MPL da Boost neste link .
const int value = 1 + 2 + 3.... + 1000; Console.WriteLine(value);
; PRespostas:
Atualizado agora com maior profundidade de recursão! Funciona no MSVC10 e no GCC sem aumentar a profundidade. :)
Recursão simples em tempo de compilação + adição:
Código de teste:
Saída para o GCC:
Exemplo ao vivo no Ideone .
Saída para MSVC10:
fonte
Exemplo de c # para erro em tempo de compilação.
Produz o seguinte erro de compilação:
fonte
Um truque popular para imprimir um número durante a compilação é tentar acessar um membro inexistente de um modelo instanciado com o número que você deseja imprimir:
O compilador então diz:
Para um exemplo mais interessante dessa técnica, consulte Solucionar o problema das oito rainhas em tempo de compilação .
fonte
print_n
ficar indefinido, veja minha resposta.Como nem o compilador nem o idioma foram especificados na pergunta da entrevista, ouso enviar uma solução em Haskell usando o GHC:
Compile-o:
E também temos um programa de trabalho.
fonte
A vida será muito mais fácil com o C ++ 11, que adiciona
constexpr
funções para o cálculo do tempo de compilação, apesar de atualmente serem suportadas apenas pelo gcc 4.6 ou posterior.O padrão requer apenas que o compilador suporte uma profundidade de recursão de 512, portanto, ele ainda precisa evitar a profundidade de recursão linear. Aqui está a saída:
Claro que você pode apenas usar a fórmula:
fonte
constexpr
por um momento. Talvez eu apenas ame demais modelos. :(/ 2
lidar com toda a gama deunsigned
resultados possíveis , o valor que você está mudando para a direita teria que ter n + 1 bits de largura, mas não é. É possível reorganizar a fórmula para evitar isso, como o clang faz para intervalos de variáveis de tempo de execução: godbolt.org/z/dUGXqg mostra que o clang conhece a fórmula de forma fechada e a usa para otimizartotal += i
loops.Em java, pensei em usar o processamento de anotações. A ferramenta apt verifica o arquivo de origem antes de realmente analisar o arquivo de origem no comando javac.
Durante a compilação dos arquivos de origem, a saída será impressa:
A fábrica do processador:
O processador de anotação real:
Em seguida, criamos um arquivo de origem. classe simples que usa a anotação MyInterface:
O processador de anotação é compilado em um arquivo jar e, em seguida, a ferramenta apt é usada para compilar o arquivo de origem como:
A saída do projeto:
fonte
Aqui está uma implementação que funciona com o VC ++ 2010. Eu tive que dividir os cálculos em três estágios, pois o compilador reclamou quando os modelos ocorreram mais de 500 vezes.
Quando você compila isso, deve ver esta saída do compilador mais ou menos assim:
fonte
Sinto-me obrigado a fornecer esse código C, já que ninguém mais o fez:
E tudo o que preciso fazer é verificar a montagem para encontrar minha resposta!
E eu vejo:
fonte
x
fosse global, o compilador seria (mais ou menos) necessário para avaliar a expressão em tempo de compilação. O ISO C não permite inicializadores de variável de tempo de execução para globais. Obviamente, uma implementação específica pode emitir uma chamada para uma função static-init do tipo construtor que a calcula no tempo de execução e armazena. Mas o ISO C permite que você use constantes de tempo de compilação como tamanhos de matriz (comoint y[x];
em uma definição de estrutura ou como outra global, por exemplo), portanto, qualquer implementação hipotética de pessimização ainda precisará suportar isso.Estendido da resposta de Carl Walsh para realmente imprimir o resultado durante a compilação:
saídas gcc:
fonte
Você pode usar (e abusar principalmente) de macros / modelos C ++ para fazer metaprogramação . AFAIK, Java não permite o mesmo tipo de coisa.
fonte
Em teoria, você pode usar isso:
(com base no código que o Xeo postou). Mas o GCC me dá esse erro:
além de um enorme pseudo-stacktrace.
fonte
Usando java, você pode fazer algo semelhante à resposta em C #:
você pode fazer isso no scala usando números peano porque você pode forçar o compilador a fazer recursão, mas eu não acho que você possa fazer a mesma coisa em c # / java
outra solução que não usa -Xprint, mas ainda mais desonesta
sem usar nenhum sinalizador do compilador. Como você pode verificar um número arbitrário de constantes (não apenas 500500), esta solução deve ser aceitável.
fonte
500500
, desculpe.for (i = 0; i < 100000; ++i) {if (i == 1000*1000/2) print i}
. Eu tenho um arquivo java 160MB que faz isso e ele funciona :)Embora isso realmente funcione com números pequenos, o clang ++ retorna um erro de compilador se eu estiver usando sum_first em que N> 400.
fonte