¿Cómo conducir el compilador C #, C ++ o Java para calcular 1 + 2 + 3 +… + 1000 en tiempo de compilación?


122

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 .


17
#error "500500" ¿Un error de compilación cuenta como "completado"?
Mysticial

44
La sugerencia esencialmente significa que puede usar plantillas de C ++. Obviamente no es lo mismo, pero este es para imprimir de 1 a 1000, estoy seguro de que puede modificarlo para agregarlo a mil ... stackoverflow.com/questions/4568645/…
Joe

8
const int value = 1 + 2 + 3.... + 1000; Console.WriteLine(value);; P
George Duckett

8
A veces pienso que algunas preguntas de la entrevista se hacen simplemente para demostrar la superioridad intelectual del entrevistador sobre el entrevistado.
Chris Dwyer

44
¿Pediste mucho dinero antes de que te hicieran esta pregunta?
Salman A

Respuestas:


118

¡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:

template<unsigned Cur, unsigned Goal>
struct adder{
  static unsigned const sub_goal = (Cur + Goal) / 2;
  static unsigned const tmp = adder<Cur, sub_goal>::value;
  static unsigned const value = tmp + adder<sub_goal+1, Goal>::value;
};

template<unsigned Goal>
struct adder<Goal, Goal>{
  static unsigned const value = Goal;
};

Código de prueba:

template<unsigned Start>
struct sum_from{
  template<unsigned Goal>
  struct to{
    template<unsigned N>
    struct equals;

    typedef equals<adder<Start, Goal>::value> result;
  };
};

int main(){
  sum_from<1>::to<1000>::result();
}

Salida para GCC:

error: declaración de 'struct sum_from <1u> :: a <1000u> :: igual a <500500u>'

Ejemplo en vivo en Ideone .

Salida para MSVC10:

error C2514: 'sum_from<Start>::to<Goal>::equals<Result>' : class has no constructors
      with
      [
          Start=1,
          Goal=1000,
          Result=500500
      ]

@hsalimi: edité la respuesta para mostrar realmente un código que hace el trabajo. :)
Xeo

Wow, realmente me impresionaste :-)
Gupta

@hsalimi: Fue el Dr. Erwin Unruh quien inventó esta técnica en la reunión de Normalización de C ++ de 1997 en Estocolmo. Calculó una serie de números primos.
Dietmar Kühl

Para que funcione sin recursividad, puede usar la fórmula de N * (N + 1) / 2 para calcular la suma.
Adam Gritt

2
@hsalimi En caso de que quiera ver muchos más ejemplos fantásticos de metaprogramación de plantillas en C ++, sugiero el diseño moderno de C ++ de Andrei Alexandrescu.
Darhuuk

89

C # ejemplo de error en tiempo de compilación.

class Foo
{
    const char Sum = (1000 + 1) * 1000 / 2;
}

Produce el siguiente error de compilación:

Constant value '500500' cannot be converted to a 'char' 

44
@ildjarn Bueno, hay una diferencia entre las respuestas de la plantilla de C ++ y esta: aquí solo funciona debido al plegado constante, mientras que la plantilla permite un código arbitrario (?). Sigue siendo una buena idea asignarlo a un personaje.
Voo

@Voo Sí, pero para ser justos, C # simplemente no se compara con C ++ para este tipo de programación.
Marlon

3
@ Marion Y realmente no considero que sea un error en el diseño del lenguaje;) la meta programación de plantillas puede ser muy poderosa, pero otros lenguajes aún pueden hacer la mayoría de las cosas con otras soluciones que no tienen todos esos obstáculos. Tuve que trabajar en un proyecto que tardó horas en compilarse (no es completamente cierto, fue increíblemente rápido si no aumentamos el límite de instanciación recursiva ... falló en segundos) y fue horrible de mantener. Probablemente sea una razón por la que no soy muy fanático de él ..
Voo

@Voo: el enfoque de FredOverflow también se basa en el plegado constante. En cuanto a la compilación lenta, culpe a su compilador, no al lenguaje (pista: Clang compila C ++ rápidamente ).
ildjarn

@ildjarn Clang compila plantillas extremadamente complicadas, muy anidadas y horriblemente complejas rápidamente? Supongo que todo es posible y ya no puedo probarlo (gracias a Dios) pero no puedo imaginarlo. También estoy hablando del enfoque de Xeo, no del de Fred aquí.
Voo

51

Debería escribir un programa que pueda conducir al compilador a calcular esta suma mientras compila e imprimir el resultado cuando se complete la compilación.

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:

template<int> struct print_n {};

print_n<1000 * 1001 / 2>::foobar go;

El compilador luego dice:

error: 'foobar' in 'struct print_n<500500>' does not name a type

Para un ejemplo más interesante de esta técnica, vea Resolver el problema de las ocho reinas en tiempo de compilación .


También podría dejar que print_npermanezca indefinido, vea mi respuesta.
Xeo

2
@David Pero Gauss necesitaba una forma inteligente, no tenía una computadora para hacerlo de la manera más estúpida.
Daniel Fischer

31

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:

{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_GHC -ddump-splices #-}
module Main where

main :: IO ()
main = print $(let x = sum [1 :: Int .. 1000] in [| x |])

Compilarlo:

$ ghc compsum.hs
[1 of 1] Compiling Main             ( compsum.hs, compsum.o )
Loading package ghc-prim ... linking ... done.
<snip more "Loading package ..." messages>
Loading package template-haskell ... linking ... done.
compsum.hs:6:16-56: Splicing expression
    let x = sum [1 :: Int .. 1000] in [| x |] ======> 500500
Linking compsum ...

Y también tenemos un programa de trabajo.


20

La vida será mucho más fácil con C ++ 11 que agrega constexprfunciones para el cálculo del tiempo de compilación, aunque actualmente solo son compatibles con gcc 4.6 o posterior.

constexpr unsigned sum(unsigned start, unsigned end) {
    return start == end ? start :
        sum(start, (start + end) / 2) +
        sum((start + end) / 2 + 1, end);
}

template <int> struct equals;
equals<sum(1,1000)> x;

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:

$ g++-mp-4.6 --std=c++0x test.cpp -c
test.cpp:8:25: error: aggregate 'equals<500500> x' has incomplete type and cannot be defined

Por supuesto, puedes usar la fórmula:

constexpr unsigned sum(unsigned start, unsigned end) {
    return (start + end) * (end - start + 1) / 2;
}

// static_assert is a C++11 assert, which checks
// at compile time.
static_assert(sum(0,1000) == 500500, "Sum failed for 0 to 1000");

1
+1, totalmente olvidado constexprpor un momento. Tal vez me encantan las plantillas demasiado. :(
Xeo

Este es un buen uso de constexpr para abordar la pregunta (vea la implementación de Adder): kaizer.se/wiki/log/post/C++_constexpr_foldr
Matt

Esa fórmula puede desbordarse; el último paso es / 2manejar la gama completa de unsignedresultados 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 los total += ibucles.
Peter Cordes

14

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á:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface MyInterface {

    int offset() default 0;

    int last() default 100;
}

La fábrica de procesadores:

public class MyInterfaceAnnotationProcessorFactory implements AnnotationProcessorFactory {

    public Collection<String> supportedOptions() {
        System.err.println("Called supportedOptions.............................");
        return Collections.EMPTY_LIST;
    }

    public Collection<String> supportedAnnotationTypes() {
        System.err.println("Called supportedAnnotationTypes...........................");
        return Collections.singletonList("practiceproject.MyInterface");
    }

    public AnnotationProcessor getProcessorFor(Set<AnnotationTypeDeclaration> set, AnnotationProcessorEnvironment ape) {
        System.err.println("Called getProcessorFor................");
        if (set.isEmpty()) {
            return AnnotationProcessors.NO_OP;
        }
        return new MyInterfaceAnnotationProcessor(ape);
    }
}

El procesador de anotaciones real:

public class MyInterfaceAnnotationProcessor implements AnnotationProcessor {

    private AnnotationProcessorEnvironment ape;
    private AnnotationTypeDeclaration atd;

    public MyInterfaceAnnotationProcessor(AnnotationProcessorEnvironment ape) {
        this.ape = ape;
        atd = (AnnotationTypeDeclaration) ape.getTypeDeclaration("practiceproject.MyInterface");
    }

    public void process() {
        Collection<Declaration> decls = ape.getDeclarationsAnnotatedWith(atd);
        for (Declaration dec : decls) {
            processDeclaration(dec);
        }
    }

    private void processDeclaration(Declaration d) {
        Collection<AnnotationMirror> ams = d.getAnnotationMirrors();
        for (AnnotationMirror am : ams) {
            if (am.getAnnotationType().getDeclaration().equals(atd)) {
                Map<AnnotationTypeElementDeclaration, AnnotationValue> values = am.getElementValues();
                int offset = 0;
                int last = 100;
                for (Map.Entry<AnnotationTypeElementDeclaration, AnnotationValue> entry : values.entrySet()) {
                    AnnotationTypeElementDeclaration ated = entry.getKey();
                    AnnotationValue v = entry.getValue();
                    String name = ated.getSimpleName();
                    if (name.equals("offset")) {
                        offset = ((Integer) v.getValue()).intValue();
                    } else if (name.equals("last")) {
                        last = ((Integer) v.getValue()).intValue();
                    }
                }
                //find the sum
                System.err.println("Sum: " + ((last + 1 - offset) / 2) * (2 * offset + (last - offset)));
            }
        }
    }
}

Luego creamos un archivo fuente. clase simple que usa la anotación MyInterface:

 @MyInterface(offset = 1, last = 1000)
public class Main {

    @MyInterface
    void doNothing() {
        System.out.println("Doing nothing");
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        Main m = new Main();
        m.doNothing();
        MyInterface my = (MyInterface) m.getClass().getAnnotation(MyInterface.class);
        System.out.println("offset: " + my.offset());
        System.out.println("Last: " + my.last());
    }
}

El procesador de anotaciones se compila en un archivo jar, luego la herramienta apt se usa para compilar el archivo fuente como:

apt -cp "D:\Variance project\PracticeProject\dist\practiceproject.jar" -factory practiceproject.annotprocess.MyInterfaceAnnotationProcessorFactory "D:\Variance project\PracticeProject2\src\practiceproject2\Main.java"

La salida del proyecto:

Called supportedAnnotationTypes...........................
Called getProcessorFor................
Sum: 5000
Sum: 500500

9

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.

template<int t_startVal, int t_baseVal = 0, int t_result = 0>
struct SumT
{
    enum { result = SumT<t_startVal - 1, t_baseVal, t_baseVal + t_result +
        t_startVal>::result };
};

template<int t_baseVal, int t_result>
struct SumT<0, t_baseVal, t_result>
{
    enum { result = t_result };
};

template<int output_value>
struct Dump
{
    enum { value = output_value };
    int bad_array[0];
};

enum
{
    value1 = SumT<400>::result,                // [1,400]
    value2 = SumT<400, 400, value1>::result,   // [401, 800]
    value3 = SumT<200, 800, value2>::result    // [801, 1000]
};

Dump<value3> dump;

Cuando compila esto, debería ver esta salida del compilador algo como esto:

1>warning C4200: nonstandard extension used : zero-sized array in struct/union
1>          Cannot generate copy-ctor or copy-assignment operator when UDT contains a 
zero-sized array
1>          templatedrivensum.cpp(33) : see reference to class template 
instantiation 'Dump<output_value>' being compiled
1>          with
1>          [
1>              output_value=500500
1>          ]

Muy buena idea para desglosar, creo que voy a incorporar eso en mi respuesta de alguna manera. +1 :)
Xeo

9

Me siento obligado a dar este código C, ya que nadie más lo ha hecho aún:

#include <stdio.h>
int main() {
   int x = 1+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16+17+18+19+20+
           21+22+23+24+25+26+27+28+29+30+31+32+33+34+35+36+37+38+39+40+
           41+42+43+44+45+46+47+48+49+50+51+52+53+54+55+56+57+58+59+60+
           61+62+63+64+65+66+67+68+69+70+71+72+73+74+75+76+77+78+79+80+
           81+82+83+84+85+86+87+88+89+90+91+92+93+94+95+96+97+98+99+100+     
           101+102+103+104+105+106+107+108+109+110+111+112+113+114+115+116+117+118+119+120+
           121+122+123+124+125+126+127+128+129+130+131+132+133+134+135+136+137+138+139+140+
           141+142+143+144+145+146+147+148+149+150+151+152+153+154+155+156+157+158+159+160+
           161+162+163+164+165+166+167+168+169+170+171+172+173+174+175+176+177+178+179+180+
           181+182+183+184+185+186+187+188+189+190+191+192+193+194+195+196+197+198+199+200+
           201+202+203+204+205+206+207+208+209+210+211+212+213+214+215+216+217+218+219+220+
           221+222+223+224+225+226+227+228+229+230+231+232+233+234+235+236+237+238+239+240+
           241+242+243+244+245+246+247+248+249+250+251+252+253+254+255+256+257+258+259+260+
           261+262+263+264+265+266+267+268+269+270+271+272+273+274+275+276+277+278+279+280+
           281+282+283+284+285+286+287+288+289+290+291+292+293+294+295+296+297+298+299+300+
           301+302+303+304+305+306+307+308+309+310+311+312+313+314+315+316+317+318+319+320+
           321+322+323+324+325+326+327+328+329+330+331+332+333+334+335+336+337+338+339+340+
           341+342+343+344+345+346+347+348+349+350+351+352+353+354+355+356+357+358+359+360+
           361+362+363+364+365+366+367+368+369+370+371+372+373+374+375+376+377+378+379+380+
           381+382+383+384+385+386+387+388+389+390+391+392+393+394+395+396+397+398+399+400+
           401+402+403+404+405+406+407+408+409+410+411+412+413+414+415+416+417+418+419+420+
           421+422+423+424+425+426+427+428+429+430+431+432+433+434+435+436+437+438+439+440+
           441+442+443+444+445+446+447+448+449+450+451+452+453+454+455+456+457+458+459+460+
           461+462+463+464+465+466+467+468+469+470+471+472+473+474+475+476+477+478+479+480+
           481+482+483+484+485+486+487+488+489+490+491+492+493+494+495+496+497+498+499+500+
           501+502+503+504+505+506+507+508+509+510+511+512+513+514+515+516+517+518+519+520+
           521+522+523+524+525+526+527+528+529+530+531+532+533+534+535+536+537+538+539+540+
           541+542+543+544+545+546+547+548+549+550+551+552+553+554+555+556+557+558+559+560+
           561+562+563+564+565+566+567+568+569+570+571+572+573+574+575+576+577+578+579+580+
           581+582+583+584+585+586+587+588+589+590+591+592+593+594+595+596+597+598+599+600+
           601+602+603+604+605+606+607+608+609+610+611+612+613+614+615+616+617+618+619+620+
           621+622+623+624+625+626+627+628+629+630+631+632+633+634+635+636+637+638+639+640+
           641+642+643+644+645+646+647+648+649+650+651+652+653+654+655+656+657+658+659+660+
           661+662+663+664+665+666+667+668+669+670+671+672+673+674+675+676+677+678+679+680+
           681+682+683+684+685+686+687+688+689+690+691+692+693+694+695+696+697+698+699+700+
           701+702+703+704+705+706+707+708+709+710+711+712+713+714+715+716+717+718+719+720+
           721+722+723+724+725+726+727+728+729+730+731+732+733+734+735+736+737+738+739+740+
           741+742+743+744+745+746+747+748+749+750+751+752+753+754+755+756+757+758+759+760+
           761+762+763+764+765+766+767+768+769+770+771+772+773+774+775+776+777+778+779+780+
           781+782+783+784+785+786+787+788+789+790+791+792+793+794+795+796+797+798+799+800+
           801+802+803+804+805+806+807+808+809+810+811+812+813+814+815+816+817+818+819+820+
           821+822+823+824+825+826+827+828+829+830+831+832+833+834+835+836+837+838+839+840+
           841+842+843+844+845+846+847+848+849+850+851+852+853+854+855+856+857+858+859+860+
           861+862+863+864+865+866+867+868+869+870+871+872+873+874+875+876+877+878+879+880+
           881+882+883+884+885+886+887+888+889+890+891+892+893+894+895+896+897+898+899+900+
           901+902+903+904+905+906+907+908+909+910+911+912+913+914+915+916+917+918+919+920+
           921+922+923+924+925+926+927+928+929+930+931+932+933+934+935+936+937+938+939+940+
           941+942+943+944+945+946+947+948+949+950+951+952+953+954+955+956+957+958+959+960+
           961+962+963+964+965+966+967+968+969+970+971+972+973+974+975+976+977+978+979+980+
           981+982+983+984+985+986+987+988+989+990+991+992+993+994+995+996+997+998+999+1000;
  printf("%d\n", x);
}

¡Y todo lo que necesito hacer es verificar el ensamblaje para encontrar mi respuesta!

gcc -S compile_sum.c;
grep "\$[0-9]*, *-4" compile_sum.s

Y veo

movl    $500500, -4(%rbp)

Característica de una implementación específica, no el lenguaje C.
Cachorro

55
¿Cuántos compiladores de C sabes que no son una "implementación específica" de C?
Carl Walsh

@Puppy: si xfuera 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 (como int 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.
Peter Cordes

7

Extendido de la respuesta de Carl Walsh para imprimir realmente el resultado durante la compilación:

#define VALUE (1+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16+17+18+19+20+\
21+22+23+24+25+26+27+28+29+30+31+32+33+34+35+36+37+38+39+40+\
41+42+43+44+45+46+47+48+49+50+51+52+53+54+55+56+57+58+59+60+\
61+62+63+64+65+66+67+68+69+70+71+72+73+74+75+76+77+78+79+80+\
81+82+83+84+85+86+87+88+89+90+91+92+93+94+95+96+97+98+99+100+\
101+102+103+104+105+106+107+108+109+110+111+112+113+114+115+116+117+118+119+120+\
121+122+123+124+125+126+127+128+129+130+131+132+133+134+135+136+137+138+139+140+\
141+142+143+144+145+146+147+148+149+150+151+152+153+154+155+156+157+158+159+160+\
161+162+163+164+165+166+167+168+169+170+171+172+173+174+175+176+177+178+179+180+\
181+182+183+184+185+186+187+188+189+190+191+192+193+194+195+196+197+198+199+200+\
201+202+203+204+205+206+207+208+209+210+211+212+213+214+215+216+217+218+219+220+\
221+222+223+224+225+226+227+228+229+230+231+232+233+234+235+236+237+238+239+240+\
241+242+243+244+245+246+247+248+249+250+251+252+253+254+255+256+257+258+259+260+\
261+262+263+264+265+266+267+268+269+270+271+272+273+274+275+276+277+278+279+280+\
281+282+283+284+285+286+287+288+289+290+291+292+293+294+295+296+297+298+299+300+\
301+302+303+304+305+306+307+308+309+310+311+312+313+314+315+316+317+318+319+320+\
321+322+323+324+325+326+327+328+329+330+331+332+333+334+335+336+337+338+339+340+\
341+342+343+344+345+346+347+348+349+350+351+352+353+354+355+356+357+358+359+360+\
361+362+363+364+365+366+367+368+369+370+371+372+373+374+375+376+377+378+379+380+\
381+382+383+384+385+386+387+388+389+390+391+392+393+394+395+396+397+398+399+400+\
401+402+403+404+405+406+407+408+409+410+411+412+413+414+415+416+417+418+419+420+\
421+422+423+424+425+426+427+428+429+430+431+432+433+434+435+436+437+438+439+440+\
441+442+443+444+445+446+447+448+449+450+451+452+453+454+455+456+457+458+459+460+\
461+462+463+464+465+466+467+468+469+470+471+472+473+474+475+476+477+478+479+480+\
481+482+483+484+485+486+487+488+489+490+491+492+493+494+495+496+497+498+499+500+\
501+502+503+504+505+506+507+508+509+510+511+512+513+514+515+516+517+518+519+520+\
521+522+523+524+525+526+527+528+529+530+531+532+533+534+535+536+537+538+539+540+\
541+542+543+544+545+546+547+548+549+550+551+552+553+554+555+556+557+558+559+560+\
561+562+563+564+565+566+567+568+569+570+571+572+573+574+575+576+577+578+579+580+\
581+582+583+584+585+586+587+588+589+590+591+592+593+594+595+596+597+598+599+600+\
601+602+603+604+605+606+607+608+609+610+611+612+613+614+615+616+617+618+619+620+\
621+622+623+624+625+626+627+628+629+630+631+632+633+634+635+636+637+638+639+640+\
641+642+643+644+645+646+647+648+649+650+651+652+653+654+655+656+657+658+659+660+\
661+662+663+664+665+666+667+668+669+670+671+672+673+674+675+676+677+678+679+680+\
681+682+683+684+685+686+687+688+689+690+691+692+693+694+695+696+697+698+699+700+\
701+702+703+704+705+706+707+708+709+710+711+712+713+714+715+716+717+718+719+720+\
721+722+723+724+725+726+727+728+729+730+731+732+733+734+735+736+737+738+739+740+\
741+742+743+744+745+746+747+748+749+750+751+752+753+754+755+756+757+758+759+760+\
761+762+763+764+765+766+767+768+769+770+771+772+773+774+775+776+777+778+779+780+\
781+782+783+784+785+786+787+788+789+790+791+792+793+794+795+796+797+798+799+800+\
801+802+803+804+805+806+807+808+809+810+811+812+813+814+815+816+817+818+819+820+\
821+822+823+824+825+826+827+828+829+830+831+832+833+834+835+836+837+838+839+840+\
841+842+843+844+845+846+847+848+849+850+851+852+853+854+855+856+857+858+859+860+\
861+862+863+864+865+866+867+868+869+870+871+872+873+874+875+876+877+878+879+880+\
881+882+883+884+885+886+887+888+889+890+891+892+893+894+895+896+897+898+899+900+\
901+902+903+904+905+906+907+908+909+910+911+912+913+914+915+916+917+918+919+920+\
921+922+923+924+925+926+927+928+929+930+931+932+933+934+935+936+937+938+939+940+\
941+942+943+944+945+946+947+948+949+950+951+952+953+954+955+956+957+958+959+960+\
961+962+963+964+965+966+967+968+969+970+971+972+973+974+975+976+977+978+979+980+\
981+982+983+984+985+986+987+988+989+990+991+992+993+994+995+996+997+998+999+1000)

char tab[VALUE];

int main()
{
    tab = 5;
}

salidas gcc:

test.c: In function 'main':
test.c:56:9: error: incompatible types when assigning to type 'char[500500]' fro
m type 'int'

2

Puede usar (y sobre todo abusar) macros / plantillas de C ++ para hacer metaprogramación . AFAIK, Java no permite el mismo tipo de cosas.


2
Realmente no es una respuesta a la pregunta.
Ikke

Creo que tienes razón. En java no puede usar el mismo truco de recursión de plantilla, ya que un parámetro de clase genérico no puede ser un valor, debe ser una clase.
Eyal Schneider

La función genérica del compilador de C # le permite hacer algunos cálculos en tiempo de compilación. Ver la publicación de Eric Lippert sobre esto.
Allon Guralnek

1

En teoría, puedes usar esto:

#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;
}

(basado en el código que Xeo publicó). Pero GCC me da este error:

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

además de una enorme pseudo-stacktrace.


Tengo que usar la bandera: -ftemplate-depth-1000
Jetti

@hsalimi: Sí También funciona para 1000, una vez que agregue la bandera. Pero no se imprime en tiempo de compilación , y Xeo ha cambiado su respuesta para responder realmente a este problema específico, por lo que creo que mi respuesta es obsoleta. :-)
ruakh

1

Usando Java puedes hacer algo similar a la respuesta de 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;
}

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

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

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.

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

No manejaste el compilador para calcular 500500 , lo siento.
Xeo

1
¿Es esto en referencia a las tres soluciones? en la solución 1 tomé un código de Java y lo compilé y el compilador imprimió 500500. que se parece mucho al compilador que computa 500500. ¿cómo es que no es el compilador que computa 500500?
benmmurphy

Sí, lo cierto es que estaba hablando de las soluciones 2 y 3. Leí esta respuesta ya en una actualización anterior y volví a la más nueva y de alguna manera parece haber olvidado la primera solución.
Xeo

Yo diría que las soluciones 2 y 3 también lo están computando. puede agregar un número arbitrario de controles para que básicamente lo esté haciendo 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 :)
benmmurphy

1

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.

#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;
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.