Comment piloter un compilateur C #, C ++ ou Java pour calculer 1 + 2 + 3 +… + 1000 au moment de la compilation?


122

Dans une interview récente, on m'a posé une question vraiment étrange. L'intervieweur m'a demandé comment puis-je calculer 1 + 2 + 3 + ... + 1000 simplement en utilisant les fonctionnalités du compilateur. Cela signifie que je ne suis pas autorisé à écrire un programme et à l'exécuter, mais je devrais simplement écrire un programme qui pourrait conduire le compilateur à calculer cette somme pendant la compilation et imprimer le résultat lorsque la compilation est terminée. À titre indicatif, il m'a dit que je pourrais utiliser les fonctionnalités génériques et pré-processeur du compilateur. Il est possible d'utiliser un compilateur C ++, C # ou Java. Des idées???

Cette question n'est pas liée au calcul de la somme sans aucune boucle posée ici . En outre, il convient de noter que la somme DEVRAIT être calculée lors de la compilation. Imprimer uniquement le résultat à l'aide des directives du compilateur C ++ n'est pas acceptable.


En lisant plus sur les réponses publiées, j'ai trouvé que la résolution de problèmes lors de la compilation à l'aide de modèles C ++ s'appelle une métaprogrammation . C'est une technique qui a été découverte accidentellement par le Dr Erwin Unruh, lors du processus de normalisation du langage C ++. Vous pouvez en savoir plus sur ce sujet sur la page wiki de la méta-programmation . Il semble qu'il soit possible d'écrire le programme en Java en utilisant des annotations java. Vous pouvez jeter un oeil à la réponse de maress ci-dessous.

Un joli livre sur la méta-programmation en C ++ est celui-ci . Cela vaut la peine de jeter un coup d'œil si vous êtes intéressé.

Une bibliothèque de méta-programmation C ++ utile est le MPL de Boost ce lien .


17
#error "500500" Une erreur de compilation compte-t-elle comme "terminer"?
Mysticial

4
L'indication signifie essentiellement que vous utilisez des modèles C ++. Evidemment pas le même mais celui-ci est pour imprimer 1 à 1000, je suis sûr que vous pouvez le modifier pour l'ajouter à mille ... stackoverflow.com/questions/4568645
Joe

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

8
Parfois, je pense que certaines questions d'entrevue sont posées simplement pour prouver la supériorité intellectuelle de l'intervieweur sur l'interviewé.
Chris Dwyer

4
Avez-vous demandé beaucoup d'argent avant qu'on vous pose cette question?
Salman A

Réponses:


118

Mis à jour maintenant avec une profondeur de récursion améliorée! Fonctionne sur MSVC10 et GCC sans profondeur accrue. :)


Récurrence simple à la compilation + ajout:

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

Testcode:

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();
}

Sortie pour GCC:

erreur: déclaration de 'struct sum_from <1u> :: to <1000u> :: equals <500500u>'

Exemple en direct sur Ideone .

Sortie pour MSVC10:

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

@hsalimi: J'ai édité la réponse pour montrer en fait du code qui fait le travail. :)
Xeo

Wow, tu m'as vraiment impressionné :-)
Gupta

@hsalimi: C'est le Dr Erwin Unruh qui a inventé cette technique lors de la réunion de normalisation C ++ de 1997 à Stockholm. Il a calculé une série de nombres premiers.
Dietmar Kühl

Pour le faire fonctionner sans récursivité, vous pouvez utiliser la formule de N * (N + 1) / 2 pour calculer la somme.
Adam Gritt

2
@hsalimi Au cas où vous voudriez voir beaucoup plus d'exemples fantastiques de métaprogrammation de modèles en C ++, je suggère le Design C ++ moderne par Andrei Alexandrescu.
Darhuuk

89

Exemple C # d'erreur au moment de la compilation.

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

Produit l'erreur de compilation suivante:

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

4
@ildjarn Eh bien, il y a une différence entre les réponses du modèle c ++ et celle-ci: cela ne fonctionne ici qu'à cause du repliement constant alors que le modèle permet un code arbitraire (?). Encore une bonne idée de l'attribuer à un caractère!
Voo le

@Voo Oui, mais pour être honnête, C # ne se compare tout simplement pas au C ++ pour ce type de programmation.
Marlon

3
@Marion Et je ne considère vraiment pas qu'une erreur dans la conception du langage;) La métaprogrammation modèle peut être toute puissante, mais d'autres langages peuvent encore faire la plupart des choses avec d'autres solutions qui n'ont pas tous ces pièges. J'ai dû travailler sur un projet qui prenait des heures à compiler (ce n'est pas tout à fait vrai - c'était incroyablement rapide si nous n'augmentions pas la limite d'instanciation récursive ... cela a échoué en quelques secondes) et était horrible à maintenir. Probablement une raison pour laquelle je ne suis pas très fan de celui-ci ..
Voo

@Voo: L'approche de FredOverflow repose également sur un pliage constant. En ce qui concerne la compilation lente, blâmez votre compilateur, pas le langage (indice - Clang compile C ++ rapidement ).
ildjarn

@ildjarn Clang compile rapidement des modèles extrêmement compliqués, vraiment profondément imbriqués et horriblement complexes? Je suppose que tout est possible et je ne peux plus le tester (Dieu merci) mais je ne peux pas l'imaginer. Je parle également de l'approche de Xeo et non de Fred ici.
Voo le

51

Je devrais juste écrire un programme qui pourrait conduire le compilateur à calculer cette somme lors de la compilation et imprimer le résultat une fois la compilation terminée.

Une astuce populaire pour imprimer un nombre lors de la compilation consiste à essayer d'accéder à un membre inexistant d'un modèle instancié avec le numéro que vous souhaitez imprimer:

template<int> struct print_n {};

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

Le compilateur dit alors:

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

Pour un exemple plus intéressant de cette technique, consultez Résoudre le problème des huit reines au moment de la compilation .


Vous pouvez aussi laisser print_nrester indéfini, voir ma réponse.
Xeo

2
@David Mais Gauss avait besoin d'un moyen intelligent, il n'avait pas d'ordinateur pour le faire rapidement.
Daniel Fischer

31

Puisque ni le compilateur ni le langage n'ont été spécifiés dans la question de l'entretien, j'ose soumettre une solution dans Haskell en utilisant GHC:

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

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

Compilez-le:

$ 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 ...

Et nous avons également un programme de travail.


20

La vie sera beaucoup plus facile avec C ++ 11 qui ajoute des constexprfonctions pour le calcul du temps de compilation, bien qu'elles ne soient actuellement prises en charge que par gcc 4.6 ou version ultérieure.

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;

La norme exige uniquement que le compilateur prenne en charge une profondeur de récursivité de 512, il doit donc toujours éviter la profondeur de récursivité linéaire. Voici le résultat:

$ 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

Bien sûr, vous pouvez simplement utiliser la formule:

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, totalement oublié constexprpendant un moment. Peut-être que j'aime trop les modèles. :(
Xeo

C'est une bonne utilisation de constexpr pour répondre à la question (voir l'implémentation d'Adder): kaizer.se/wiki/log/post/C++_constexpr_foldr
Matt

Cette formule peut déborder; la dernière étape consiste / 2à gérer la gamme complète des unsignedrésultats possibles , la valeur que vous déplacez à droite devrait être de n + 1 bits de large, mais ce n'est pas le cas. Il est possible de réorganiser la formule pour éviter cela, comme le fait clang pour les plages de variables d'exécution: godbolt.org/z/dUGXqg montre que clang connaît la formule de forme fermée et l'utilise pour optimiser les total += iboucles.
Peter Cordes

14

En java, j'ai pensé à utiliser le traitement des annotations. L'outil apt analyse le fichier source avant d'analyser le fichier source avec la commande javac.

Lors de la compilation des fichiers source, la sortie sera imprimée:

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

    int offset() default 0;

    int last() default 100;
}

L'usine de processeurs:

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

Le processeur d'annotations actuel:

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

Ensuite, nous créons un fichier source. classe simple qui utilise l'annotation 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());
    }
}

Le processeur d'annotations est compilé dans un fichier jar, puis l'outil apt est utilisé pour compiler le fichier source comme:

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

La sortie du projet:

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

9

Voici une implémentation qui fonctionne sous VC ++ 2010. J'ai dû diviser les calculs en 3 étapes puisque le compilateur s'est plaint lorsque les modèles ont récidivé plus de 500 fois.

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;

Lorsque vous compilez ceci, vous devriez voir cette sortie du compilateur quelque chose comme ceci:

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>          ]

Très belle idée de la décomposer, je pense que je vais intégrer cela dans ma réponse d'une manière ou d'une autre. +1 :)
Xeo

9

Je me sens obligé de donner ce code C, puisque personne d'autre ne l'a encore:

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

Et il ne me reste plus qu'à vérifier l'assemblage pour trouver ma réponse!

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

Et je vois:

movl    $500500, -4(%rbp)

Fonctionnalité d'une implémentation spécifique, pas du langage C.
Puppy

5
Combien de compilateurs C connaissez-vous qui ne sont pas une "implémentation spécifique" de C?
Carl Walsh

@Puppy: Si xétait global, le compilateur serait (plus ou moins) nécessaire pour évaluer l'expression au moment de la compilation. ISO C n'autorise pas les initialiseurs de variables d'exécution pour les globaux. Bien sûr, une implémentation spécifique peut émettre un appel à une fonction static-init de type constructeur qui la calcule lors de l'exécution et stocke. Mais ISO C vous permet d'utiliser des constantes de temps de compilation comme tailles de tableau (comme int y[x];dans une définition de struct ou comme un autre global par exemple), donc toute implémentation hypothétique de pessimisation devrait toujours prendre en charge cela.
Peter Cordes

7

Extension de la réponse de Carl Walsh pour imprimer le résultat lors de la compilation:

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

sorties gcc:

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

2

Vous pouvez utiliser (et surtout abuser) des macros / modèles C ++ pour faire de la métaprogrammation . AFAIK, Java ne permet pas le même genre de chose.


2
Pas vraiment une réponse à la question.
Ikke

Je pense que tu as raison. En java, vous ne pouvez pas utiliser la même astuce de récursivité de modèle, car un paramètre de classe générique ne peut pas être une valeur - il doit s'agir d'une classe.
Eyal Schneider

La fonctionnalité génériques du compilateur C # vous permet d'effectuer des calculs au moment de la compilation. Voir le post d'Eric Lippert à ce sujet.
Allon Guralnek

1

En théorie, vous pouvez utiliser ceci:

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

(basé sur le code publié par Xeo). Mais GCC me donne cette erreur:

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

plus un énorme pseudo-stacktrace.


Je dois utiliser le drapeau: -ftemplate-depth-1000
Jetti

@hsalimi: Oui. Cela fonctionne également pour 1000, une fois que vous ajoutez le drapeau. Mais il ne s'imprime pas au moment de la compilation , et Xeo a changé sa réponse pour répondre réellement à ce problème spécifique, donc je pense que ma réponse est obsolète. :-)
ruakh

1

En utilisant java, vous pouvez faire une chose similaire à la réponse 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;
}

vous pouvez le faire dans scala en utilisant des nombres peano car vous pouvez forcer le compilateur à faire de la récursivité mais je ne pense pas que vous puissiez faire la même chose en c # / java

une autre solution n'utilisant pas -Xprint mais encore plus douteuse

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

sans utiliser d'indicateur de compilation. puisque vous pouvez rechercher un nombre arbitraire de constantes (pas seulement 500500), cette solution devrait être acceptable.

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

Vous n'avez pas conduit le compilateur à calculer 500500 , désolé.
Xeo

1
est-ce en référence aux trois solutions? dans la solution 1, j'ai pris du code java et je l'ai compilé et le compilateur a imprimé 500500. cela ressemble beaucoup au compilateur calculant 500500. comment n'est-ce pas le compilateur calculant 500500?
benmmurphy

Ouais, c'est vrai, je parlais des solutions 2 et 3. J'ai déjà lu cette réponse sur une mise à jour antérieure et suis revenu sur la plus récente et semble avoir oublié la première solution.
Xeo

je dirais que les solutions 2 et 3 le calculent également. vous pouvez ajouter un nombre arbitraire de vérifications, ce que vous faites essentiellement for (i = 0; i < 100000; ++i) {if (i == 1000*1000/2) print i}. J'ai un fichier java de 160 Mo qui fait cela et cela fonctionne :)
benmmurphy

1

Bien que cela fonctionne réellement avec de petits nombres, clang ++ me renvoie une erreur de compilation si j'utilise sum_first où 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;
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.