Wie kann man einen C # -, C ++ - oder Java-Compiler steuern, um 1 + 2 + 3 +… + 1000 zur Kompilierungszeit zu berechnen?


122

In einem kürzlich geführten Interview wurde mir eine wirklich seltsame Frage gestellt. Der Interviewer fragte mich, wie ich 1 + 2 + 3 + ... + 1000 nur mit Compiler-Funktionen berechnen kann. Dies bedeutet, dass ich kein Programm schreiben und ausführen darf, sondern nur ein Programm schreiben sollte, das den Compiler dazu bringen könnte, diese Summe während der Kompilierung zu berechnen und das Ergebnis nach Abschluss der Kompilierung zu drucken. Als Hinweis sagte er mir, dass ich Generika und Vorprozessorfunktionen des Compilers verwenden könnte. Es ist möglich, C ++, C # oder Java-Compiler zu verwenden. Irgendwelche Ideen???

Diese Frage bezieht sich nicht auf die Berechnung der Summe ohne die hier gestellten Schleifen . Zusätzlich sollte beachtet werden, dass die Summe während der Kompilierung berechnet werden sollte. Es ist nicht akzeptabel, nur das Ergebnis mit C ++ - Compileranweisungen zu drucken.


Als ich mehr über die veröffentlichten Antworten las, stellte ich fest, dass das Lösen von Problemen beim Kompilieren mit C ++ - Vorlagen als Metaprogrammierung bezeichnet wird . Dies ist eine Technik, die Dr. Erwin Unruh versehentlich bei der Standardisierung der C ++ - Sprache entdeckt hat. Weitere Informationen zu diesem Thema finden Sie auf der Wiki-Seite der Metaprogrammierung . Es scheint möglich zu sein, das Programm mit Java-Annotationen in Java zu schreiben. Sie können sich die Antwort von Maress unten ansehen .

Ein schönes Buch über Metaprogrammierung in C ++ ist dieses . Bei Interesse einen Blick wert.

Eine nützliche C ++ - Metaprogrammierbibliothek ist Boosts MPL dieser Link .


17
#error "500500" Zählt ein Kompilierungsfehler als "Abschluss"?
Mysticial

4
Der Hinweis bedeutet im Wesentlichen, dass Sie C ++ - Vorlagen verwenden. Offensichtlich nicht dasselbe, aber dieses ist für das Drucken von 1 bis 1000, ich bin sicher, Sie können es ändern, um es zu tausend hinzuzufügen ... stackoverflow.com/questions/4568645/…
Joe

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

8
Manchmal denke ich, dass einige Interviewfragen nur gestellt werden, um die intellektuelle Überlegenheit des Interviewers gegenüber dem Interviewten zu beweisen.
Chris Dwyer

4
Haben Sie viel Geld verlangt, bevor Ihnen diese Frage gestellt wurde?
Salman A

Antworten:


118

Jetzt mit verbesserter Rekursionstiefe aktualisiert ! Funktioniert mit MSVC10 und GCC ohne größere Tiefe. :) :)


Einfache Rekursion zur Kompilierungszeit + Addition:

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

Ausgabe für GCC:

Fehler: Deklaration von 'struct sum_from <1u> :: to <1000u> :: entspricht <500500u>'

Live-Beispiel auf Ideone .

Ausgabe für MSVC10:

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

@hsalimi: Ich habe die Antwort so bearbeitet, dass tatsächlich Code angezeigt wird, mit dem die Aufgabe erledigt wird. :)
Xeo

Wow, du hast mich wirklich beeindruckt :-)
Gupta

@hsalimi: Es war Dr. Erwin Unruh, der diese Technik 1997 beim C ++ - Standardisierungstreffen in Stockholm erfand. Er berechnete eine Reihe von Primzahlen.
Dietmar Kühl

Damit es ohne Rekursion funktioniert, können Sie die Summe mit der Formel N * (N + 1) / 2 berechnen.
Adam Gritt

2
@hsalimi Für den Fall, dass Sie viel mehr fantastische Beispiele für die Metaprogrammierung von Vorlagen in C ++ sehen möchten, empfehle ich Modern C ++ Design von Andrei Alexandrescu.
Darhuuk

89

C # -Beispiel zum Fehler beim Kompilieren.

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

Erzeugt den folgenden Kompilierungsfehler:

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

4
@ildjarn Nun, es gibt einen Unterschied zwischen den Antworten der C ++ - Vorlage und dieser: Dies funktioniert hier nur aufgrund der ständigen Faltung, während die Vorlage beliebigen (?) Code zulässt. Immer noch eine gute Idee, es einem Char zuzuweisen!
Voo

@Voo Ja, aber um fair zu sein, ist C # für diese Art der Programmierung einfach nicht mit C ++ zu vergleichen.
Marlon

3
@Marion Und ich denke wirklich nicht, dass ein Fehler im Sprachdesign;) Template-Meta-Programmierung zwar sehr mächtig ist, aber andere Sprachen können die meisten Dinge mit anderen Lösungen tun, die nicht all diese Fallstricke haben. Ich musste an einem Projekt arbeiten, dessen Kompilierung Stunden dauerte (nicht ganz richtig - es war unglaublich schnell, wenn wir das rekursive Instanziierungslimit nicht erhöhten. Es schlug in Sekunden fehl) und war schrecklich zu warten. Wahrscheinlich ein Grund, warum ich nicht viel ein Fan davon bin ..
Voo

@Voo: FredOverflows Ansatz basiert ebenfalls auf ständiger Faltung. Wenn Sie langsam kompilieren, geben Sie Ihrem Compiler die Schuld, nicht der Sprache (Hinweis - Clang kompiliert C ++ schnell ).
ildjarn

@ildjarn Clang kompiliert extrem komplizierte, wirklich tief verschachtelte und schrecklich komplexe Vorlagen schnell? Ich gehe davon aus, dass alles möglich ist und ich kann es nicht mehr testen (Gott sei Dank), aber ich kann es mir nicht vorstellen. Ich spreche auch von Xeos Ansatz, nicht von Fred hier.
Voo

51

Ich sollte einfach ein Programm schreiben, das den Compiler dazu bringen könnte, diese Summe während der Kompilierung zu berechnen, und das Ergebnis drucken, wenn die Kompilierung abgeschlossen ist.

Ein beliebter Trick zum Drucken einer Nummer während der Kompilierung ist der Versuch, auf ein nicht vorhandenes Mitglied einer Vorlage zuzugreifen, die mit der zu druckenden Nummer instanziiert ist:

template<int> struct print_n {};

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

Der Compiler sagt dann:

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

Ein interessanteres Beispiel für diese Technik finden Sie unter Lösen des Problems mit acht Königinnen zur Kompilierungszeit .


Sie könnten genauso gut print_nundefiniert bleiben lassen , siehe meine Antwort.
Xeo

2
@ David Aber Gauß brauchte einen klugen Weg, er hatte keinen Computer, um es so dumm schnell zu machen.
Daniel Fischer

31

Da in der Interviewfrage weder Compiler noch Sprache angegeben wurden, wage ich es, in Haskell eine Lösung mit GHC einzureichen:

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

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

Kompilieren Sie es:

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

Und wir haben auch ein Arbeitsprogramm.


20

Mit C ++ 11, das constexprFunktionen für die Berechnung der Kompilierungszeit hinzufügt, wird das Leben viel einfacher , obwohl sie derzeit nur von gcc 4.6 oder höher unterstützt werden.

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;

Der Standard verlangt nur, dass der Compiler eine Rekursionstiefe von 512 unterstützt, sodass die lineare Rekursionstiefe weiterhin vermieden werden muss. Hier ist die Ausgabe:

$ 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

Natürlich können Sie einfach die Formel verwenden:

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, constexprfür einen Moment total vergessen . Vielleicht liebe ich Vorlagen einfach zu sehr. :(
Xeo

Dies ist eine gute Verwendung von constexpr, um die Frage zu beantworten (siehe die Adder-Implementierung): kaizer.se/wiki/log/post/C++_constexpr_foldr
Matt

Diese Formel kann überlaufen; Der letzte Schritt besteht / 2darin, den gesamten Bereich möglicher unsignedErgebnisse zu verarbeiten. Der Wert, den Sie nach rechts verschieben, muss n + 1 Bit breit sein, ist es aber nicht. Es ist möglich, die Formel neu anzuordnen , um dies zu vermeiden, wie dies bei clang für Bereiche mit Laufzeitvariablen der Fall ist : godbolt.org/z/dUGXqg zeigt, dass clang die Formel in geschlossener Form kennt und sie zur Optimierung von total += iSchleifen verwendet.
Peter Cordes

14

In Java habe ich über die Verwendung der Annotationsverarbeitung nachgedacht. Das apt-Tool scannt die Quelldatei, bevor die Quelldatei tatsächlich mit dem Befehl javac analysiert wird.

Während der Kompilierung der Quelldateien wird die Ausgabe ausgedruckt:

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

    int offset() default 0;

    int last() default 100;
}

Die Prozessorfabrik:

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

Der eigentliche Annotationsprozessor:

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

Dann erstellen wir eine Quelldatei. einfache Klasse, die MyInterface-Annotation verwendet:

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

Der Anmerkungsprozessor wird in eine JAR-Datei kompiliert. Anschließend wird das Quell-Tool mit dem apt-Tool wie folgt kompiliert:

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

Die Ausgabe des Projekts:

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

9

Hier ist eine Implementierung, die unter VC ++ 2010 funktioniert. Ich musste die Berechnungen in drei Phasen aufteilen, da sich der Compiler beschwerte, als die Vorlagen mehr als 500 Mal rekursiv waren.

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;

Wenn Sie dies kompilieren, sollte diese Ausgabe des Compilers ungefähr so ​​aussehen:

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

Sehr schöne Idee, es aufzuschlüsseln, ich denke, ich werde das irgendwie in meine Antwort einfließen lassen. +1 :)
Xeo

9

Ich fühle mich verpflichtet, diesen C-Code anzugeben, da noch niemand:

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

Und alles, was ich tun muss, ist die Baugruppe zu überprüfen, um meine Antwort zu finden!

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

Und ich verstehe:

movl    $500500, -4(%rbp)

Merkmal einer bestimmten Implementierung, nicht der C-Sprache.
Welpe

5
Wie viele C-Compiler kennen Sie, die keine "spezifische Implementierung" von C sind?
Carl Walsh

@Puppy: Wenn xglobal, müsste der Compiler (mehr oder weniger) den Ausdruck zur Kompilierungszeit auswerten. ISO C erlaubt keine Initialisierer von Laufzeitvariablen für Globals. Natürlich könnte eine bestimmte Implementierung einen Aufruf einer konstruktorähnlichen statischen Init-Funktion auslösen, die sie zur Laufzeit berechnet und speichert. Mit ISO C können Sie jedoch Kompilierungszeitkonstanten als Arraygrößen verwenden (wie int y[x];z. B. in einer Strukturdefinition oder als eine andere globale), sodass jede hypothetische pessimisierende Implementierung dies weiterhin unterstützen müsste.
Peter Cordes

7

Ausgehend von Carl Walshs Antwort, um das Ergebnis während der Kompilierung tatsächlich auszudrucken:

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

gcc-Ausgänge:

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

2

Sie können C ++ - Makros / Vorlagen verwenden (und meistens missbrauchen), um Metaprogrammierungen durchzuführen . AFAIK, Java erlaubt nicht das Gleiche.


2
Keine wirkliche Antwort auf die Frage.
Ikke

Ich glaube, Du hast recht. In Java können Sie nicht denselben Vorlagenrekursionstrick verwenden, da ein generischer Klassenparameter kein Wert sein kann - er muss eine Klasse sein.
Eyal Schneider

Mit der generischen Funktion des C # -Compilers können Sie einige Berechnungen zur Kompilierungszeit durchführen. Siehe dazu Eric Lipperts Beitrag .
Allon Guralnek

1

Theoretisch können Sie dies verwenden:

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

(basierend auf dem Code, den Xeo gepostet hat). Aber GCC gibt mir diesen Fehler:

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

plus eine enorme Pseudo-Stacktrace.


Ich muss die Flagge benutzen: -ftemplate-depth-1000
Jetti

@hsalimi: Ja. Es funktioniert auch für 1000, sobald Sie das Flag hinzufügen. Es wird jedoch nicht zur Kompilierungszeit gedruckt , und Xeo hat seine Antwort geändert, um dieses spezielle Problem tatsächlich zu beantworten. Daher halte ich meine Antwort für veraltet. :-)
Ruakh

1

Mit Java können Sie etwas Ähnliches wie mit der C # -Antwort tun:

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

Sie können dies in Scala mit Peano-Zahlen tun, weil Sie den Compiler zur Rekursion zwingen können, aber ich glaube nicht, dass Sie dasselbe in c # / java tun können

Eine andere Lösung, die -Xprint nicht verwendet, aber noch zwielichtiger ist

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

ohne Compiler-Flags zu verwenden. Da Sie nach einer beliebigen Anzahl von Konstanten suchen können (nicht nur nach 500500), sollte diese Lösung akzeptabel sein.

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

Sie haben den Compiler nicht zum Rechnen gefahren 500500, sorry.
Xeo

1
bezieht sich dies auf alle drei Lösungen? In Lösung 1 habe ich Java-Code genommen und kompiliert, und der Compiler hat 500500 ausgedruckt. Das sieht dem Compiler, der 500500 berechnet, sehr ähnlich. Wie ist das nicht, wenn der Compiler 500500 berechnet?
Benmmurphy

Ja, stimmt, ich habe über Lösung 2 und 3 gesprochen. Ich habe diese Antwort bereits in einem früheren Update gelesen und bin auf die neueste zurückgekommen und habe irgendwie die erste Lösung vergessen.
Xeo

Ich würde sagen, Lösung 2 & 3 berechnen es auch. Sie können eine beliebige Anzahl von Überprüfungen hinzufügen, damit Sie dies im Grunde tun for (i = 0; i < 100000; ++i) {if (i == 1000*1000/2) print i}. Ich habe eine 160 MB Java-Datei, die dies tut und es funktioniert :)
Benmmurphy

1

Obwohl dies tatsächlich mit kleinen Zahlen funktioniert, gibt mir clang ++ einen Compilerfehler zurück, wenn ich sum_first verwende, wobei N> 400 ist.

#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;
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.