En una entrevista reciente, me hicieron una pregunta realmente extraña. El entrevistador me preguntó cómo puedo calcular 1 + 2 + 3 + ... + 1000 simplemente usando las funciones del compilador. Esto significa que no se me permite escribir un programa y ejecutarlo, pero debería escribir un programa que pueda conducir al compilador a calcular esta suma mientras se compila e imprimir el resultado cuando se complete la compilación. Como sugerencia, me dijo que puedo usar funciones genéricas y de preprocesador del compilador. Es posible usar C ++, C # o el compilador de Java. ¿¿¿Algunas ideas???
Esta pregunta no está relacionada con el cálculo de la suma sin ningún bucle que se haga aquí . Además, debe tenerse en cuenta que la suma DEBE calcularse durante la compilación. Imprimir solo el resultado usando las directivas del compilador C ++ no es aceptable.
Al leer más sobre las respuestas publicadas, descubrí que resolver problemas durante la compilación usando plantillas de C ++ se llama metaprogramación . Esta es una técnica que fue descubierta accidentalmente por el Dr. Erwin Unruh, durante el proceso de estandarización del lenguaje C ++. Puede leer más sobre este tema en la página wiki de metaprogramación . Parece que es posible escribir el programa en Java usando anotaciones de Java. Puede echar un vistazo a la respuesta de maress a continuación.
Un buen libro sobre el meta-programación en C ++ es éste . Vale la pena echarle un vistazo si está interesado.
Una útil biblioteca de metaprogramación de C ++ es MPL de Boost en este enlace .
const int value = 1 + 2 + 3.... + 1000; Console.WriteLine(value);
; PRespuestas:
¡Actualizada ahora con profundidad de recursión mejorada! Funciona en MSVC10 y GCC sin mayor profundidad. :)
Recurrencia en tiempo de compilación simple + adición:
Código de prueba:
Salida para GCC:
Ejemplo en vivo en Ideone .
Salida para MSVC10:
fuente
C # ejemplo de error en tiempo de compilación.
Produce el siguiente error de compilación:
fuente
Un truco popular para imprimir un número durante la compilación es intentar acceder a un miembro inexistente de una plantilla instanciada con el número que desea imprimir:
El compilador luego dice:
Para un ejemplo más interesante de esta técnica, vea Resolver el problema de las ocho reinas en tiempo de compilación .
fuente
print_n
permanezca indefinido, vea mi respuesta.Dado que ni el compilador ni el idioma se especificaron en la pregunta de la entrevista, me atrevo a presentar una solución en Haskell usando GHC:
Compilarlo:
Y también tenemos un programa de trabajo.
fuente
La vida será mucho más fácil con C ++ 11 que agrega
constexpr
funciones para el cálculo del tiempo de compilación, aunque actualmente solo son compatibles con gcc 4.6 o posterior.El estándar solo requiere que el compilador admita una profundidad de recursión de 512, por lo que aún debe evitar la profundidad de recursión lineal. Aquí está la salida:
Por supuesto, puedes usar la fórmula:
fuente
constexpr
por un momento. Tal vez me encantan las plantillas demasiado. :(/ 2
manejar la gama completa deunsigned
resultados posibles , el valor que está cambiando a la derecha debería ser n + 1 bits de ancho, pero no lo es. Es posible reorganizar la fórmula para evitar eso, como lo hace clang para rangos variables de tiempo de ejecución: godbolt.org/z/dUGXqg muestra que clang conoce la fórmula de forma cerrada y la usa para optimizar lostotal += i
bucles.En Java, pensé en usar el procesamiento de anotaciones. La herramienta apt escanea el archivo fuente antes de analizar el archivo fuente al comando javac.
Durante la compilación de los archivos de origen, la salida se imprimirá:
La fábrica de procesadores:
El procesador de anotaciones real:
Luego creamos un archivo fuente. clase simple que usa la anotación MyInterface:
El procesador de anotaciones se compila en un archivo jar, luego la herramienta apt se usa para compilar el archivo fuente como:
La salida del proyecto:
fuente
Aquí hay una implementación que funciona bajo VC ++ 2010. Tuve que dividir los cálculos en 3 etapas ya que el compilador se quejó cuando las plantillas se repitieron más de 500 veces.
Cuando compila esto, debería ver esta salida del compilador algo como esto:
fuente
Me siento obligado a dar este código C, ya que nadie más lo ha hecho aún:
¡Y todo lo que necesito hacer es verificar el ensamblaje para encontrar mi respuesta!
Y veo
fuente
x
fuera global, el compilador sería (más o menos) requerido para evaluar la expresión en tiempo de compilación. ISO C no permite inicializadores variables en tiempo de ejecución para globales. Por supuesto, una implementación específica podría emitir una llamada a una función static-init de tipo constructor que la computa en tiempo de ejecución y almacena. Pero ISO C le permite usar constantes de tiempo de compilación como tamaños de matriz (comoint y[x];
en una definición de estructura o como otra global, por ejemplo), por lo que cualquier implementación hipotética de pesimismo aún tendría que soportar eso.Extendido de la respuesta de Carl Walsh para imprimir realmente el resultado durante la compilación:
salidas gcc:
fuente
Puede usar (y sobre todo abusar) macros / plantillas de C ++ para hacer metaprogramación . AFAIK, Java no permite el mismo tipo de cosas.
fuente
En teoría, puedes usar esto:
(basado en el código que Xeo publicó). Pero GCC me da este error:
además de una enorme pseudo-stacktrace.
fuente
Usando Java puedes hacer algo similar a la respuesta de C #:
puedes hacer esto en scala usando números peano porque puedes forzar al compilador a hacer recursión pero no creo que puedas hacer lo mismo en c # / java
otra solución que no usa -Xprint pero aún más dudosa
sin usar ningún indicador del compilador. ya que puede verificar un número arbitrario de constantes (no solo 500500) esta solución debería ser aceptable.
fuente
500500
, lo siento.for (i = 0; i < 100000; ++i) {if (i == 1000*1000/2) print i}
. Tengo un archivo Java de 160 MB que hace esto y funciona :)Aunque esto realmente funciona con números pequeños, clang ++ me devuelve un error de compilación si estoy usando sum_first donde N> 400.
fuente