Classic Proof Fallacy [geschlossen]


18

Der Hintergrund

Also kennen wir alle den klassischen Beweis, der so aussieht:

a = b
a² = ab
a² - b² = ab - b²
(ab) (a + b) = b (ab)
(a + b) = b
b + b = b
2b = b
2 = 1 (Ha ha!)
von Natürlich ist der Fehler, dass Sie nicht durch 0 teilen können. Da a = b, a - b = 0, gab es eine versteckte Division durch 0.

Die Herausforderung

Sie müssen diesen Beweis replizieren. Erklären Sie zunächst zwei ganze Zahlen a und b (es ist egal, wie Sie sie nennen) als gleich. Dann deklarieren Sie aMod und bMod als änderbare Versionen von a und b und anfangs gleich a und b. Sie müssen beide mit a multiplizieren und dann b * b von beiden subtrahieren. Sie müssen dann durch a - b dividieren und dann durch b (oder a) dividieren, um zu erhalten. Drucken Sie dann aMod und bMod mit einem Gleichheitszeichen dazwischen aus.

Die Hinterhältigen

Da Sie a und b als gleich deklariert haben, verursacht a - b = 0 und Teilen durch 0 natürlich einen Fehler. Sie müssen es also kreativ vortäuschen. Da Sie versuchen, den Proof zu replizieren, darf das Ergebnis aller Operationen auf aMod und bMod beim Drucken nicht gleich sein. Sie müssen nicht genau 2 und 1 sein, sondern nur zwei Zahlen, die nicht gleich sind.

Hier ist ein Beispiel:

#include <iostream>
#define subtract(a, b) a - b

using namespace std;
int main()
{
    int a = 4, b = 4;
    int a_2 = a, b_2 = b;

    a_2 *= a;
    b_2 *= b;

    a_2 -= b * b;
    b_2 -= b * b;

    a_2 = a_2 / subtract(a, b);
    b_2 = b_2 / subtract(-b, -a); // a - b == (-b) - (-a)

    a_2 /= a;
    b_2 /= a;

    cout << a_2 << " = " << b_2 << " because I did the same operations on both of them.";

    return 0;
}

Vielleicht nicht die beste, aber sie verdeutlicht den Punkt.

Bonus Unterhand

Anstatt das Gleichheitszeichen auszudrucken, können Sie auch nur die beiden Variablen (aMod und bMod) ausdrucken und dann einen Code zum Vergleichen der beiden Variablen auf Gleichheit verwenden true.

Denken Sie daran, dies ist ein Beliebtheitswettbewerb, daher gewinnt die höchste Anzahl von Upvotes.
Eine neue Version der Mathematik namens Mathematik 2.0 hat außerdem Standardlücken verwendet, die einen Beweis automatisch ungültig machen.


Hier ist ein Wikipedia-Link zum mathematischen Irrtum, damit die Leute es besser verstehen können

3
Ich stimme dafür, diese Frage als "Off-Topic" zu schließen, da hinterhältige Herausforderungen auf dieser Site nicht mehr zum Thema gehören. meta.codegolf.stackexchange.com/a/8326/20469
cat

Antworten:


17

JavaScript

var a=3,b=3,a2=3,b2=3
[a2,b2]=[a2*a,b2*a]
[a2,b2]=[a2-b*b,b2-b*b]
[a2,b2]=[a2/(a-b),b2/(a-b)]
console.log([a2/a,b2/a])

Ausgabe:

[1, NaN]

Beachten Sie, dass 0/0 = NaN

Hinweis

Versuchen Sie, einige Semikolons hinzuzufügen.
Dieses Programm ist eigentlich var a=3,b=3,a2=3,b2=3[a2,b2]=...=[a2/(a-b),b2/(a-b)];console.log([a2/a,b2/a]).
Und das NaN ist [3/0,undefined/0]/3.


Wow. Das war sehr clever, "aus Versehen" zu vergessen, Semikolons hinzuzufügen, die (fast) das ganze Programm zu einem Folgesatz machen.
user155698

3

Python 2

Ich bin mir ziemlich sicher, dass es offensichtlich ist, da jeder Python kennt, aber hier ist mein Versuch:

a=b=1
x,y=a*a,a*b
x,y=x-b*b,y-b*b
x,y=a+b/a-b,b
x,y=x/a,y/a
print(x==y)

Es gibt aus True.

Hinweis:

Überprüfen Sie meine Abteilung.


da jeder Python benutzt . Ich kenne Python, aber ich benutze es selten
rpax

@rpax Das habe ich gemeint.
mbomb007

Entschuldigung, ich habe Ihre Antwort nicht richtig gelesen.
rpax

2

Rubin

def calculate a,
  b = a
  left, right = a, b
  left, right = [left, right].map { |x| x * a     }
  left, right = [left, right].map { |x| x - b*b   }
  left, right = [left, right].map { |x| x / a - b }
  left, right = [left, right].map { |x| x / b     }
  puts $/=[left, right].join(' = ')
end

calculate 3,
STDOUT.write($/)

ideone

Hinweis:

,

Erläuterung:

Die zwei Zeilen, die mit Kommas enden, bewirken, dass sich das Programm anders verhält als es würde. Ohne Komma nimmt die Methode ein einzelnes Argument a, setzt bgleich a, führt die Transformationen aus dem Proof für jedes Argument durch (mit Ausnahme einiger fehlender Klammern, die nicht durch 0 dividiert werden) und gibt das Ergebnis aus (mit Eingabe von 3) Mit dem nachgestellten Komma wird die b = aZeile jedoch Teil der Methodensignatur, was bedeutet, dass ein zweites Argument mit einem Standardwert deklariert wird result of STDOUT.write($/), was 1 ist (die Anzahl der Bytes, die an STDOUT geschrieben wurden, da dies $/für ein Newline-Zeichen vordefiniert ist). a ist also 3 und b ist 1, was dazu führt, dass die Gleichung mit "3 = 1" beginnt. Müll raus.


Netter Trick da mit deinen Newlines.
LegionMammal978

Könnten Sie eine Erklärung für Nicht-Rubyisten hinzufügen?
kirbyfan64sos

@ kirbyfan64sos Sicher, fertig.
Histokrat

2

GolfScript

Achtung: Dieses Programm schummelt ein wenig, da es nicht aMod und bMod druckt

1nt main(){
  int a = 2, b = 2;
  int aMod,bMod;
//The next line should throw and error, but why doesn't it??/
  aMod = (a*a - b*b) / (a-b);
//The next line should throw and error, but why doesn't it??/
  bMod = (b*a - b*b) / (a-b);
//The if should fail, but it works??/
  if(aMod == bMod)
    printf("1");
  return 0;
};

Probieren Sie es hier aus !

So was ist los?

Das erste, was Sie vielleicht bemerkt haben, sind die "verbotenen Trigraphen". Aber denken Sie daran, das ist GolfScript, nicht C! Wahrscheinlich ist auch aufgefallen, dass dort nicht "int main ()" steht, sondern "1nt main ()". In GolfScript bedeutet "1", 1 auf den Stapel zu schieben, und "nt main" wird als zwei nicht initialisierte Variablen verarbeitet, die nichts bewirken. Die beiden Klammern addieren zuerst 1 zur obersten Zahl des Stapels und subtrahieren dann eine, wodurch sie sich im Wesentlichen selbst aufheben. Die Klammern kennzeichnen einen Block, der auf den Stapel geschoben wird, und das Semikolon entfernt ihn sofort. Am Ende haben wir also nur die ursprüngliche "1", die aufgedruckt wurde, und am Ende eines GolfScript-Programms wird der Stapel gedruckt. Diese Antwort wurde von dieser inspiriert .


Trigraphen erkannt. Automatisches -1-System aktivieren. Fehler: -1 fehlgeschlagen (4792, RPLS)
CalculatorFeline

Das ist hinterhältig, weil es dich dazu verleitet zu denken, dass es dir nicht gelungen ist, dich zu täuschen. +1
Rɪᴋᴇʀ

1

Prolog

areEqual(A, B) :-
    Amod = A,
    Bmod = B,

    Amod = Amod * A,
    Bmod = Bmod * B,

    Amod = Amod - B*B,
    Bmod = Bmod - B*B,

    Amod = Amod / (A-B),
    Bmod = Bmod / (A-B),

    Amod = Amod / A,
    Bmod = Bmod / A,

    Amod == Bmod.

Die Ausgabe, wenn areEqual(4,4)angerufen wird (oder irgendwelche anderen Zahlen wirklich):

false

Warum?

In Prolog ist der Operator "=" keine Beeinflussung; es ist "Vereinigung". Daher Amod = Amod * Ascheitert, weil Amodbereits mit vereinheitlicht Awurde und somit unmöglich mit vereinheitlicht werden kann Amod * A. Prolog beendet dann sofort die Ausführung der aktuellen Regel und kehrt zurück false.


2
Ich denke, es sollte umgekehrt sein, Sie müssen "true" ausgeben, wenn die beiden Werte unterschiedlich sind, nicht "false", wenn sie gleich sind ^^ '
Katenkyo

1

JavaScript

//Very badly written code!
//No! It is "poetic" code!
while(true){break;}{ 
let scrollMaxX = 3, screenX = 3;
var scrollBarWithBeerMax = scrollMaxX, Yscroll = screenX; for(var i = 0; i<1; i++){}}

scrollBarWithBeerMax *= scrollMaxX;
Yscroll *= screenX;

scrollBarWithBeerMax -= screenX * screenX;
Yscroll -= screenX * screenX;

scrollBarWithBeerMax /= (scrollMaxX - screenX);
Yscroll /= (scrollMaxX - screenX);

alert(scrollBarWithBeerMax + ' = ' + Yscroll);

Ausgabe:
http://jsbin.com/furino/2/edit?js,output JsBin scheint diesen Code nicht ausführen zu können. Verwenden Sie stattdessen die Browserkonsole.

Warum?

scrollMaxX und screenX sind bereits vorhandene Variablen. Sie sind im Browser integriert. Somit kann das Ergebnis variieren. Das Schlüsselwort let ändert seinen Wert nur vorübergehend.

Ein weiteres JavaScript: Es folgt nicht genau den Regeln, sondern gibt nur aus, ob die Variablen gleich sind oder nicht.

var a = 2;
var b = 2;

var a_duplicate = a;
var b_duplicate = b;

a_duplicate*=a
b_duplicate*=b;

a_duplicate-=b*b;
b_duplicate-=b*b;

a_duplicate/=(a-b);
b_duplicate/=(a-b);

alert(a_duplicate==b_duplicate);

Warum?

NaN entspricht nicht den IEEE-Float-Spezifikationen für NaN. Vielen Dank an Alex Van Liew für den Hinweis, dass dies nicht nur für Javascript gilt.


NaNentspricht nicht den NaNIEEE-Float-Spezifikationen. Ein schneller Weg, um zu testen, ob Sie ein NaNin C haben, ist, es mit sich selbst zu vergleichen. Das gilt also für alle Sprachen, nicht nur für JS.
Alex Van Liew

1
@AlexVanLiew Interessant. Ich wusste das nicht! Ok, ändere meine Antwort leicht und füge Gutschrift hinzu, wo es fällig ist.
Stefnotch

0

Fantom

a := 3
b := 3
duplicates := [a:b]
duplicates = duplicates.map {it * a}
duplicates = duplicates.map {it - b*b}
duplicates = duplicates.map {it / a-b}
echo(duplicates.join("") |Int a_2, Int b_2 ->Str| {"" +  a_2 + " = " + b_2})

Ausgabe:

-3 = 3

Warum?

[a: b] ist eine Karte, keine Liste. Nicht so hinterhältig, ich weiß :(


Du sollst a gleich b am Ende haben.
mbomb007

Das Ende des ursprünglichen Irrtums ist 2 = 1, daher sollte das Ende jeder Antwort hier nicht "wahr" sein
Kain,

Ich dachte an den BONUS hintergangen. Keine Ursache. "Anstatt das Gleichheitszeichen auszudrucken, können Sie nur die beiden Variablen (aMod und bMod) ausdrucken und dann den Code haben, der die beiden Variablen auf Gleichheit zu vergleichen scheint, aber in Wirklichkeit ist, dass sie gleich sind (und irgendeine Form von wahr ausgeben). . "
mbomb007

0

C

Der klassische Beweisfehler erfordert ein Missverständnis der klassischen C-Syntax. Leider habe ich einige "High-Level-Only" -Entwickler getroffen, die überzeugt sind, dass C aufgrund von Ergebnissen, die diesem Code ähneln, nicht funktioniert. Wenn Sie wissen, wie C funktioniert, wird dies ziemlich offensichtlich, aber wenn Sie den Code gesehen und angenommen haben, dass es sich um eine andere Sprache handelt, ist dies möglicherweise nicht der Fall.

a,b,LHS,RHS;
main(){
    a=2; b=2;
    LHS=a; RHS=b;

    //multiply both sides by a
    LHS,RHS *= a; 
    //subtract b squared from both sides
    LHS,RHS -= b*b; 
    //assert that it factors correctly
    if (LHS,RHS != (a+b)*(a-b), b*(a-b)) printf("ERROR!\n");
    //'hard' division, just to be sure the compiler doesn't remove it
    LHS,RHS /=! (a-b);
    //assert that a+a really is b+b
    if (a+a != b+b) printf("ERROR!\n");
    //now just divide them by b
    printf("%d = %d ? ", LHS/b, RHS/b);
    if (RHS = LHS) 
        printf("true!");
    else
        printf("false!");
}

Natürlich funktioniert es nicht ganz so gut, wenn es idiomatischer mit #include <stdio.h>und int's geschrieben wird, die vor den Deklarationen geworfen werden.


Wie funktioniert das?
CalculatorFeline

Beachten Sie zunächst, dass in c, wenn Sie das int in einer Deklaration 'vergessen', der Typ int angenommen wird, um mit k & r c abwärtskompatibel zu sein. Schlagen Sie als nächstes den Operator, in c nach und achten Sie auf dessen Vorrang. Beachten Sie als nächstes das = anstelle von == in der letzten if-Anweisung.
LambdaBeta
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.