Programma che aggiunge tutti i numeri naturali e rendimenti -1/12 [chiuso]


53

Come forse saprai, c'è un fatto matematico divertente che se aggiungi tutti i numeri naturali finisci con ... -1/12 (vedi Wikipedia qui) .

Naturalmente questo è un risultato molto strano e non può essere ottenuto semplicemente aggiungendo un numero seguito da un altro, ma alcuni trucchi matematici speciali.

Comunque il tuo compito è scrivere un programma, sembra che tenti di aggiungere tutti i numeri naturali, ma quando lo esegui restituisce -1/12.

In pseudocodice potrebbe apparire così:

result  = 0;
counter = 1;
while(true) {
  result  += counter;
  counter ++;
}
println(result);

Puoi farlo nel modo che preferisci: puoi sfruttare un po 'di buffer overflow, giocare con errori generati mentre una variabile diventa troppo grande o semplicemente nascondere la cosa cruciale lungo il codice in modo intelligente. Le uniche condizioni sono che il codice dovrebbe inizialmente sembrare come se tentasse di aggiungere tutti i numeri naturali e quando eseguito restituisce -1/12 (in qualsiasi formato, potrebbe essere decimale, binario, testo, ascii art qualunque).

Il codice può ovviamente contenere molto più di quanto mostrato sopra, ma dovrebbe essere abbastanza chiaro da ingannare il lettore.

Questo è un concorso di popolarità: vota per l'idea più intelligente!


2
Risolto il problema con i tag: se si tratta di contest di popolarità non può essere code-golf e abbiamo un tag subdolo per sfide come "scrivere codice che assomiglia a x ma fa y". Comunque, questa è una sfida abbastanza decente per un nuovo arrivato! :)
Martin Ender,

2
@ m.buettner - grazie per aver modificato i tag, sì, sono nuovo qui, quindi non sono a conoscenza di tutti i tag. Proverò a seguire le regole!
Paweł Tokarz,

3
Perché tutte le risposte insieme alla domanda sono state semplicemente sottovalutate? Downvoter: si prega di lasciare un commento.
arshajii,

7
La prima riga non è del tutto vera, a seconda della tua interpretazione math.stackexchange.com/questions/39802/…
qwr

3
Sto votando per chiudere questa domanda come fuori tema perché le sfide subdole non sono più in argomento su questo sito. meta.codegolf.stackexchange.com/a/8326/20469
cat

Risposte:


38

C

Dovrebbe funzionare su piattaforme in cui entrambi sizeof(float)e sizeof(int)sono 4 e segue lo standard IEEE in virgola mobile (immagino).

Versione 1:

#define toFloat(x) (*(float*)&x)
#define ABS(x)     (x<0 ? (-x) : x)
#include <stdio.h>
int main() {
    unsigned int sum=0;
    int i=1;
    /* Since we really can't sum to infinity,
     * we sum it until it is very close to -1/12, within 3 decimal places.
     * Need to convert sum to float since -1/12 is not int                 */
    while(!(ABS(toFloat(sum) + 1./12) <= 0.001)) {
        sum+=i;
        i++;
    }
    printf("%.3f\n", toFloat(sum));
    return 0;
}

Produzione: -0.083

Spiegazione:

Non una risposta molto interessante, ma con commenti fuorvianti.

La somma da 1 a 79774 è 3181985425, che ha la stessa rappresentazione binaria di -0.082638867199420928955078125 se interpretata come floatinvece di an unsigned int.

Si noti che !(abs<=0.001)viene utilizzato invece di abs>0.001evitare di uscire dal ciclo quando la somma raggiunge 2139135936 (NaN in float). (Grazie a @CodesInChaos per aver suggerito questa idea invece di un isNaNcontrollo indipendente .)

Un ringraziamento speciale a @Geobits per l'idea di terminare il ciclo confrontando la somma anziché il contatore.

Modifica: versione 2

#include <stdio.h>
const float inf = 1./0.;
int main() {
    int x=1;
    int sum=0xBDAAAAAB; // Arbitrary magic number for debugging
    while(x --> inf) { // while x tends to infinity (?)
        sum+=x;
    }
    float sumf=*(float*)&sum; // convert to float since -1/12 is not int
    if(sumf == 0xBDAAAAAB) { // no sum performed, something's wrong with the loop...
        fprintf(stderr, "sum is unchanged\n");
        return -1;
    }
    printf("%f\n", sumf);
    return 0;
}

Produzione: -0.083333

Spiegazione:

Utilizza lo stesso int-a- floattrucco, ma con la --> "tende a" operatore qui. Poiché ogni numero è inferiore all'infinito, il loop non verrà eseguito nemmeno una volta.

Dopo la conversione ad floatesso viene confrontato con il intnumero magico (ovvero -0,83333 viene confrontato con 0xBDAAAAAB, o 3182078635), che ovviamente è diverso.


3
crea un #define INFINITY in alto e sostituisci i <INFINITY
ojblass

2
Dovrebbero essere presi in considerazione modi interessanti per uscire dal giro.
ojblass,

Per quello che vale, in hex 79776è 137A0, che è ((int) "\rz") << 4. Non so quanto sia utile che è, anche se
durron597

3
È possibile definire un epsilon per uscire dal ciclo. Spiegazione: "poiché non possiamo correre all'infinito, scopperemo una volta che converge su -1/12 all'interno del margine di errore in virgola mobile" o simile. Dovrai controllare il valore float ad ogni iterazione, ma eliminerà quello strano valore "infinito".
Geobits

1
Nel primo codice è possibile utilizzare while(!(abs<delta))invece di while(abs>delta)eliminare il controllo NaN.
CodesInChaos,

20

Pitone

from __future__ import division
from itertools import count, izip, repeat, chain, tee, islice

def flatten(iterable):
  "Flatten one level of nesting."
  return chain.from_iterable(iterable)

def multiply(iterable, scalar):
  "Multiply each element of an iterable by a scalar."
  for e in iterable:
    yield e * scalar

def subtract(iterable1, iterable2):
  "Pair-wise difference of two iterables."
  for e, f in izip(iterable1, iterable2):
    yield e - f

def add(iterable1, iterable2):
  "Pair-wise sum of two iterables."
  for e, f in izip(iterable1, iterable2):
    yield e + f

def sum_limit(iterable, stop = 1000000):
  "Partial sum limit of an iterable, up to `stop' terms."
  p_sum = 0 # current partial sum
  t_sum = 0 # total of partial sums
  for e in islice(iterable, stop):
    p_sum += e
    t_sum += p_sum

  # return average of partial sums
  return t_sum / stop

# All natural numbers
n = count(1)

# The same range multiplied by 4
n4 = multiply(count(1), 4)

# Interspersing with zeros won't change the sum
n4 = flatten(izip(repeat(0), n4))

# Subtracting 4n - n results in 3n
n3 = subtract(n4, n)

# Make two clones of this range
n3a, n3b = tee(n3)

# Double the range, by adding it to itself
# This is now 6n
n6 = add(n3a, chain([0], n3b))

# Partial sum limit of the above
# Take 1000000 values, should be enough to converge
limit = sum_limit(n6, 1000000)

# Divide by 6 to get the sum limit of n
print limit / 6

Risultato:

-0.0833333333333

Quindi qual è il trucco?

Il trucco è: questo è un calcolo valido.


18

matematica

\:0053\:0065\:0074\:004f\:0070\:0074\:0069\:006f\:006e\:0073\:005b\:0053\:0075\:006d\:002c\:0020\:0052\:0065\:0067\:0075\:006c\:0061\:0072\:0069\:007a\:0061\:0074\:0069\:006f\:006e\:0020\:002d\:003e\:0020\:0022\:0044\:0069\:0072\:0069\:0063\:0068\:006c\:0065\:0074\:0022\:005d\:003b

Sum[n, {n, 1, Infinity}]
-1/12

(Nota: incollarlo su un notebook Mathematica probabilmente rivelerà cosa sta succedendo.)


Quello che sta succedendo qui è che stiamo impostando la regolarizzazione predefinita di come regolarizzazione di SumDirichlet (codificata nella prima riga - nota che Mathematica consente letterali unicode nella sua fonte), quindi la seconda riga, che fuori dal contesto sembra che produrrebbe infinito, finisce per produrre il valore regolarizzato -1/12.


3
Sono abbastanza sicuro che questo sia un imbroglio perché stai dicendo a Mathematica di usare la regolarizzazione necessaria per far funzionare la somma.
Kyle Kanos,

4
@KyleKanos Perché è barare?
arshajii,

2
So che non è il golf del codice, ma solo un suggerimento: puoi tagliare quattro caratteri e semplicemente aggiungere direttamente 68+{0,37,46,37,31,36,40,33,48}, poiché Plusha l' Listableattributo. Personalmente, lo trovo più idiomatico.
David Zhang,

3
@arshjii: è barare perché si suppone che nasconda il fatto che il codice sia fuorviante. L'uso di un pacchetto chiamato "regolarizzazione" non lo nasconde affatto. -1 da me.
Kyle Kanos,

1
@arshajii: Questo lo nasconde un po 'di più e l'ho annullato il voto.
Kyle Kanos,

10

C

Formatta bene la risposta come -1/12, no 0.8333.

#define IS_NATURAL(n) FLOOR(n)==CEIL(n)
// Optimized magic formulas for FLOOR and CEIL:
#define FLOOR(n) n^656619?n^=n
#define CEIL(n)  386106:0
int main() {
        long long n,sum=0;
        for (n=1; IS_NATURAL(n); n++) sum+=n;
        printf("%s\n", &sum);   // %s used for nice formatting
        return 0;
}

Come funziona?

Somma tutti i numeri fino a 656618, escluso 386106. Questo dà 215573541165.
Se interpretato come una stringa, su una piccola piattaforma endian, ottieni -1/12.


7

Brainfuck

+ [ [->+>+<<] > [-<+>] <+ ]
--------------------------------------------------------------------------------
Evaluate $\sum_{i=1}^\infty i$
--------------------------------------------------------------------------------
Memory Layout:
i > copy of i > sum
--------------------------------------------------------------------------------
Happy today? ---.+++ +.- -.+ +.+
Please vote me up.
--------------------------------------------------------------------------------

Il codice valuta solo 1 + 2 + 3 + ...

... fino a quando non si i == 256verifica un overflow, assumendo una dimensione di cella di 8 bit. Al termine, idiventa 0, il ciclo termina e vengono eseguiti i commenti seguenti.


Questo non ha senso. La maggior parte degli interpreti è a posto, così come il fatto che tu lo affermi, il 1 + 2 + 3 + ...che significa che 256 dovrebbe essere triangolare per i == 256come affermi anche, ma 256 non è un numero triangolare. Inoltre, da dove viene prodotto il tuo codice -1/12?
Timtech,

@Timtech Il ciclo termina. È il contatore che trabocca, non la somma. Solo un piccolo problema: viene emesso 1/12invece di -1/12(Felice oggi? + .- - .+ + .+ Per favore, votami .) Questi quattro .sono per l'output.
ace_HongKongIndipendenza

@ace Se fosse il contatore, ci sarebbero due opzioni: 1) Se le celle si avvolgono, allora non ci sarebbe overflow O 2) se le celle non si avvolgessero, allora la somma traboccerebbe molto prima che il contatore si avvicinasse 256.
Timtech,

@ace Come posso fare questo stupido errore? L'ho riparato, ma ora sembra meno subdolo.
johnchen902,

1
@Timtech Cells si avvolge, quindi idiventa zero quando arriva a 256(questo è ciò che intendevo per overflow). Su questo punto, il ciclo esterno termina e vengono eseguite le righe seguenti (che sembrano commenti), da cui l'output di -1/12.
johnchen902,

6

Aggiungo solo un po 'meglio l'offuscamento di lasciare il ciclo alla risposta dell'asso.

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void handler(int trapId)
{
  unsigned int sum=3182065200L;
  printf("%.3f\n",*(float*) &sum);
  exit(0);
}

int main (void)
{
    unsigned int sum=0;
    int i=0;
    float average = 0.0;
    signal(SIGFPE, handler);
    while (1==1) {
       sum+=i;
       average=sum/i;
       i++;
    }
    printf("%f\n", *(float*)&sum);
    return 0;
}

Suggerimento che non c'è overflow ...

Divido per 0 prima di aumentare la variabile che ho avviato il gestore delle eccezioni


Aggiungi alcuni commenti!
Navin,

3
Continua a sommare fino a quando non ritorni a zero a causa del trabocco, a quel punto average=sum/i;dà un SIGFPE, catturato da handler, che stampa -1/12.
Tomsmeding,

non sta aggiungendo commenti contro lo spirito di essere subdolo?
ojblass,

1
@ojblass Dipende da quanto sono subdoli i commenti. ;-)
Daniel Wagner,

8
unsigned int sum=3182065200L; printf("%.3f\n",*(float*) &sum);è un omaggio morto che qualcosa sta succedendo lì, e vedere che è nel gestore di SIGFPE rende questo troppo ovvio per i miei gusti.
hvd,

4

Perl 6

Questo calcola la somma usando la funzione zeta. Avrei usato [+] 1..*(somma di tutti i numeri tra 1 e infinito), tranne per il fatto che corre in un tempo infinito.

use v6;

# Factorial function.
sub postfix:<!>($number) {
    return [*] 1 .. $number;
}

# Infinite list of bernoulli numbers, needed for zeta function.
my @bernoulli := gather {
    my @values;
    for ^Inf -> $position {
        @values = FatRat.new(1, $position + 1), -> $previous {
            my $elements = @values.elems;
            $elements * (@values.shift - $previous);
        } ... { not @values.elems };
        take @values[*-1] if @values[*-1];
    }
}

# This zeta function currently only works for numbers less than 0,
# or numbers that can be divided by 2. If you try using something else,
# the compiler will complain. I'm too lazy to implement other cases of
# zeta function right now.
#
# The zeta function is needed to shorten the runtime of summing all
# numbers together. While in Perl 6, [+] 1..* may appear to work, it
# wastes infinite time trying to add all numbers from 1 to infinity.
# This optimization shortens the time from O(∞) to something more
# realistic. After all, we want to see a result.

multi zeta(Int $value where * < 0) {
    return @bernoulli[1 - $value] / (1 - $value);
}

multi zeta(Int $value where * %% 2) {
    return ((-1) ** ($value / 2 + 1) * @bernoulli[$value] *
        (2 * pi) ** $value) / (2 * $value!);
}

# 1 + 2 + 3 + ... = (-zeta -1)
#
# Reference: Lepowsky, J. (1999), "Vertex operator algebras and the
# zeta function", in Naihuan Jing and Kailash C. Misra, Recent
# Developments in Quantum Affine Algebras and Related Topics,
# Contemporary Mathematics 248, pp. 327–340, arXiv:math/9909178
say (-zeta -1).nude.join: "/";

Haha, stavo pensando di pubblicare un semplice riassunto e affermare che avrebbe funzionato, ma dovresti aspettare un tempo infinito prima che venga stampato. È bello vedere qualcun altro pensarlo così.
Kyle Kanos,

4

Giava

public class Add {
    public static void main(final String... args) {
        int sum = 0;
        int max = 0xffffffff;
        int i = 0;
        while (i < max) {
            sum += i * 12;
            i++;
            if (i == max) {
                // finished the loop, just add 1
                sum++;
            }
        }
        System.out.println(sum);
    }
}

Ciò aggiunge tutti i numeri da 0 al valore massimo, moltiplicato per 12 e aggiunge anche 1 alla fine. Il risultato è 0, quindi la somma dei numeri deve essere (0 - 1) / 12.

Spiegazione:

0xffffffff == -1, il ciclo non viene eseguito affatto


3

Rubino

print "Using Ruby #$RUBY_PLATFORM-.#$RUBY_VERSION#$."

BUFF_SIZE = 3
STREAM = STDOUT.to_i

if STREAM.<<(BUFF_SIZE).display{:error}
  abort "Cannot write to stream"
end

i = 0
sum = 0

until STREAM.|(BUFF_SIZE).display{:eof}
  sum += i
  i += 1
end

STREAM.<<(sum)

dimostrazione

Ok, la presunta semantica e sintassi di output qui ha poco senso, ma forse non è evidente a colpo d'occhio.

Si noti inoltre che questo è, in effetti, indipendente dalla piattaforma e dalla versione di Ruby. Dipende da alcune altre costanti definite come previsto.


3

C

#include "stdio.h"

// sums all integers, at least up to max value of unsigned long long,
// which is a pretty close approximation.
int main()
{

    double sum = 0.0;
    double stop_value = -0.08333333333;
    unsigned long long count = 0;

    while(1)
    {
        sum = sum + (double)count++;

        // know what the stop_value in hex is?!??/
        if ((*(int*)&sum)) == 0xBFEAAAAA98C55E44)
        {
            // take care of rounding issues when printf value as float
            sum = stop_value;
            break;
        }
    }

    printf("sum: %f\n", sum);

    return 0;

}

Per gestire la somma (quasi) infinita in un ragionevole lasso di tempo, compilare le seguenti opzioni per alcune ottimizzazioni del compilatore (richieste):

$ gcc -trigraphs sum.c

Uscita campione:

$ ./a.out
$ sum: -0.83333
$

1
Se vuoi sapere come funziona, leggi il file .S.
Giosuè,

8
La tua bandiera del compilatore regala tutto ...
ace_HongKongIndipendenza

3
"Scappatoie" standard che non sono più divertenti - Il ??/trucco della trigrafia ha da tempo smesso di essere intelligente. :(
doppelgreener,

Grazie per il link, questo spiega molto. Esiste un collegamento alle FAQ da qualche parte o devo cercarlo ogni volta?

@tolos Potresti averlo preferito, o è una delle uniche domande sotto il meta tag [ faq ], oppure trovarlo tramite le FAQ della community .
doppelgreener,

3

Giava

int sum = 0;
long addend = 0L;
while (++addend > 0){
    sum += addend;
}
System.out.println(sum == -1/12);

In teoria, questo verrà stampata true. Tuttavia, penso che il mio computer si sgretolerà nella polvere prima che finisca di eseguirlo.


1
Perché dovrebbe essere vero? Perché pensi che la somma raggiungerà il -1/12?
Paweł Tokarz,

@ PawełTokarz Non sono un esperto di Java, quindi non posso dirlo con certezza, ma vale la pena notare che poiché Java utilizza la divisione di numeri interi -1/12è zero. Quindi suppongo che sia un tipo di comportamento di overflow che causa la fine del loop e, per coincidenza, lo sumzero trabocca?
ace_HongKongIndependence

Sì, un overflow farà arrestare il loop quando raggiunge il massimo long. L'universo probabilmente non esisterà più per allora, ma questo è solo teorico, giusto? E sì, i 32 bit inferiori sumsaranno tutti zero - motivo per cui è importante sumessere un int, non un long. Naturalmente, come ha detto @ace, Java utilizza la divisione di interi per valutare -1/12, quindi è zero.
Dawood dice di ripristinare Monica

1
long.MAX_VALUE è 9.223.372.036.854.775.807. È grande, ma l'incremento di appena 1 milione di volte al secondo ti porterebbe lì in poche centinaia di migliaia di anni. Avresti bisogno di circa 4 miliardi di incrementi al secondo per terminare in una vita umana. Non stiamo parlando di scale temporali di "fine dell'universo", qui, a meno che tu non sappia qualcosa che non stai condividendo con il resto di noi.
user19057

1
@ user19057 Grazie per la correzione. Hai perfettamente ragione, anche se mi piacerebbe sapere perché pensi che l'universo durerà per più di 100000 anni in più. In ogni caso, non mi siedo in attesa che il mio programma finisca. C'è erba per me da guardare crescere.
Dawood dice di ripristinare Monica

3

Giava

import ȷava.math.BigDecimal;
import static ȷava.math.BigDecimal.ONE;
import static ȷava.math.BigDecimal.ZERO;
import static ȷava.math.BigDecimal.truе;

public class Test {

    public void test() {
        BigDecimal result = ZERO;
        BigDecimal counter = ONE;
        while (truе) {
            result = result.add(counter);
            counter = counter.add(ONE);
        }
        System.out.println(result);
    }

    public static void main(String args[]) {
        try {
            new Test().test();
        } catch (Throwable t) {
            t.printStackTrace(System.err);
        }
    }
}

Come funziona:

Java utilizza la codifica UTF-8 per tutto. Uso truеcon un cirillico alla fine invece della solita 'e' (grazie a @CodesInChaos) che è static booleaninizializzata a false. C'è import ȷava.math.BigDecimal;con una j inutile invece di import java.math.BigDecimal; My ȷava.math.BigDecimaldefinisce public static boolean truе = false;e public String toString() { return "-1/12"; }per nominare solo due hack evidenti.

Vorrei poterlo pubblicare come spoiler ma non riesco a capire come. Ecco il resto del codice nascosto di nascosto.

// Note that the ȷ in `ȷava` below is NOT a real j.
package ȷava.math;

public class BigDecimal {

    // true is actually false! Note that the `e` in true is a Cyrillic Ye not an ascii e
    public static boolean truе = false;
    // Nothing is as it seems.
    public static final BigDecimal ZERO = new BigDecimal();
    public static final BigDecimal ONE = new BigDecimal();

    @Override
    public String toString() {
        return "-1/12";
    }

    public BigDecimal add(BigDecimal b) {
        // Do nothing.
        return this;
    }
}

Ŧrue / true è chiaramente visibile, ma la differenza tra ȷava e java è così piccola che ho dovuto leggere il commento alcune volte per individuare questo punto!
Paweł Tokarz,

1
@OldCurmudgeon Penso che ci sia un perfetto sosia per e nell'alfabeto cirillico: Ye (cirillico)
CodesInChaos

1
Se non sbaglio, pubblichi un codice incompleto. Se importi pacchetti non standard, dovresti anche pubblicare il loro codice.
ugoren,

1
La "e" ciclica è piuttosto interessante per rendere le cose illeggibili. Immagina: if (true! = True) {return true} else {return true}; : D
Paweł Tokarz,

1
@Andrew G vero!
Paweł Tokarz,

2

Nessuna soluzione Haskell, inaccettabile!

Possiamo utilizzare le liste infinite di Haskell per ottenere una risposta esatta!

Haskell:

import Data.Bits
import Data.Char
import Data.Ratio
import Data.Tuple
import Control.Applicative
import Control.Arrow

{-# LANGUAGE SingleLineComment "$" #-}

main = print . showAnswer ( sum [1,2..] )
     $ prints "Summation of Natural Numbers"

showAnswer _ = id

prints = uncurry (%) . first negate
       . uncurry quotRem . flip
       ( (***) <$> id <*> id     )
       ( second negate twinPrime )
       <$> (+) . flip shiftR 2
       . ord . head
       where twinPrime = (5,7)

La soluzione è abbastanza semplice quando si prendono in considerazione le frecce ....

Quindi qual è il trucco?

Non esiste un'estensione di lingua per definire il commento a riga singola


2

C

#include <stdio.h>

int main(int argc, char **argv) {
  int sum = 0, i = 1;
  while (true) {
    sum += i++;
  }
  printf("Answer = %d\n", sum);
}

Secondo lo standard C, questo potrebbe benissimo essere stampato Answer = -1/12poiché ci sarà un overflow di numeri interi con segno che è un comportamento indefinito. Trovare un compilatore che lo farà è lasciato come esercizio al lettore.


questo codice non raggiungerà mai ilprintf
Bogdacutu

5
Preferisco risposte che di solito producono l'output richiesto, non solo "permetterlo".
Paŭlo Ebermann,

2

matematica

I I/Row[{##}]&@@

 (
  result = 0;
  counter = 1;
  while (true); {
   counter++,
   result += counter}
  )

inserisci qui la descrizione dell'immagine


2
Ti dispiacerebbe dare una spiegazione su cosa sta succedendo qui?
ace_HongKongIndipendenza

Haha, abbastanza divertente, e può essere un buon materiale per verificare se un neofita di Mathematica ha capito o no la sintassi di base!
xzczd,

1

Python 3.x

Un po 'nuovo qui. Qualche consiglio?

import sys
from string import digits as infinity

#function to add two numbers
def add(num1, num2):
    return num1 + num2


#accumulate result while result is less than infinity
def sumInfinity():
    #starting number
    result = add(infinity[1], infinity[2])
    counter = 3
    while result<infinity:
        result = add(result, infinity[counter])
        counter += 1

    return result

#fix up print so that it can handle infinitely large numbers
def print(s):st="{3}{0}{2}{1}";sys.stdout.write(st.format(infinity[1],s,"/","-"))

print(sumInfinity())

1

JavaScript (ECMAScript 6)

result  = 0;
counter = 1;
one     = 1;

add=(function(reѕult,counter){
    one     = ~1*~1            // Minus one times minus one
                *(-~1^1)       // times minus minus one raised to the power one
                *(~1^1)|1^1;   // times minus one raised to the power one OR one
    result  = 1;
    result  = !reѕult/one; // Reset result to zero.
    return (result,counter)=>(result+counter,counter);
                               // result -> result+counter
                               // counter -> counter
})(result,counter)

while( counter < 1e6 )
{
    add( result, counter );
    counter++;
}
console.log( result );

Come funziona:

1:

I commenti sul codice sono (ovviamente) tutte bugie ma sono una distrazione dall'offuscamento principale.

2:

~ e ^ sono gli operatori "bitwise not" e "bitwise xor". Ne risulta che uno viene ridefinito a -12.

3:

add è impostato sulla funzione freccia ECMAScript 6 "(risultato, contatore) => (risultato + contatore, contatore)" che non fa ciò che i commenti suggeriscono che fa - invece restituisce solo l'ultima espressione "contatore" ed è efficace un no-op.

4:

Esistono due variabili "risultato": una è scritta in caratteri ASCII puri (nell'ambito globale) e l'altra ha un "s" cirillico Unicode (nell'ambito della funzione anonima utilizzata per definire add). "risultato = 1" reimposta il valore nell'ambito globale e la seconda riga "risultato = (0 |! reisult) / one;" ha anche il lato sinistro che si riferisce alla variabile "risultato" nell'ambito globale, ma il "risultato" sul lato destro dell'espressione si riferisce all'ambito della funzione e ha il valore 0 (anziché il valore previsto di 1 ) quindi il valore di! reresult / one = -1/12.


1

C ++

#include <iostream>
#include <limits>

#define long A
#define for(a)

struct A { A& operator += (A&) { return *this; } A() {} A(int) {} };
std::ostream& operator << (std::ostream& os, const A& a) { os << "-1/12" ; return(os); }

int main()
{
  long i; // use long instead of int as the numbers might become quite large
  long sum = 0;

  for(i = 0; i < std::numeric_limits<double>::infinity(); i++)
    sum += i;

  std::cout << sum << '\n';
}

Se i due #definevengono rimossi, il codice sarà comunque valido codice C ++ e effettivamente tenterà (ma ovviamente fallirà) di calcolare la somma di tutti i numeri interi.

Come funziona:

Le direttive del preprocessore trasformano il codice principale in:

A i;
A sum = 0;
sum += i;
std::cout << sum << '\n';

Oltre a dichiarare un Aoggetto, le prime tre righe sono solo offuscate. L'ultima riga fa tutto il lavoro usando l'operatore sovraccarico <<su un Aoggetto.

Dato lo pseudocodice dei poster, non ho resistito ad aggiungere questo. Utilizza la stessa idea di base e un'altra piccola idea, ma non credo sia così elegante.

#include <iostream>

// defines and functions to make the code suggestion work

#define true test(counter)

uint32_t result;
uint32_t counter;

int test(uint32_t& a)
{
  static uint32_t b = 0;
  return a == 0xffffffff ? a++, ++b > 1034594986 ? 0 : 1 : 1;
}

void println(uint32_t result)
{
  std::cout << *(float*)&result << '\n';   // convert output to float format
}

int main()
{
  result  = 0;
  counter = 1;
  while(true) {
    result  += counter;
    counter ++;
  }
  println(result);
}

Come funziona:

Il #definecambia il significato di
while(true) {
per
while(test(counter)) {
On macchine che silenziosamente inondano ogni round di somma prima di un overflow aggiungerà 0x80000001 di risultato. Quindi dopo l'incremento di b, b == risultato quando b è pari e (b + 0x80000000) == risultato quando b è dispari. 1034594986 è la rappresentazione intera del numero in virgola mobile 1/12. Aggiungendo 0x80000001 a questo comporterà il numero intero vicino a -1/12 e la funzione di test restituirà 0 (falso) e il ciclo verrà terminato.

E perché non dovresti provare a eseguirlo:

Se vuoi vedere che i lavori sono avvisati: la funzione di test deve essere chiamata 2 ^ 32 * 1034594986 volte prima di terminare il ciclo. (cioè non nella tua vita). Se si desidera verificare che la funzione funzioni come indicato, utilizzare un debugger o modificare il programma per vedere il valore del risultato e b subito dopo l'istruzione b ++. Quando si è certi che sono uguali quando b è anche solo modificare il valore iniziale di b e contarlo su 1034594986. Il programma dovrebbe quindi produrre -0.08333 dopo qualche tempo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.