Classic Proof Fallacy [fermé]


18

L'arrière-plan

Donc, nous connaissons tous la preuve classique qui va comme ceci:

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!)
de bien sûr, l'erreur est que vous ne pouvez pas diviser par 0. Puisque a = b, a - b = 0, il y avait donc une division cachée par 0.

Le défi

Vous devez reproduire cette preuve. Tout d'abord, déclarez deux entiers a et b (peu importe comment vous les appelez) égaux. Déclarez ensuite aMod et bMod comme étant des versions modifiables de a et b et initialement égales à a et b, respectivement. Vous devez les multiplier tous les deux par a, puis soustraire b * b des deux. Vous devez ensuite diviser par a - b puis les diviser par b (ou a) pour obtenir. Ensuite, imprimez aMod et bMod avec un signe égal entre eux.

Les sournois

Bien sûr, puisque vous avez déclaré a et b égaux, a - b = 0 et la division par 0 provoque une erreur. Vous devez donc le simuler de manière créative. De plus, comme vous essayez de répliquer la preuve, le résultat de toutes les opérations sur aMod et bMod ne doit pas être égal lors de l'impression. Ils ne doivent pas nécessairement correspondre exactement à 2 et 1, juste deux nombres qui ne sont pas égaux.

Voici un exemple:

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

Peut-être pas le meilleur, mais il illustre le point.

Bonus sournois

Au lieu d'imprimer le signe égal, vous pouvez imprimer uniquement les deux variables (aMod et bMod), puis avoir un code qui semble comparer les deux variables pour l'égalité mais en réalité se trouve qu'elles sont égales (et imprime une certaine forme de true).

N'oubliez pas qu'il s'agit d'un concours de popularité, donc le plus grand nombre de votes positifs l'emporte.
De plus, une nouvelle version des mathématiques appelée Mathématiques 2.0 a utilisé des failles standard pour invalider automatiquement une preuve.


Voici un lien Wikipédia de l'erreur mathématique pour que les gens puissent mieux comprendre

3
Je vote pour fermer cette question comme hors sujet car les défis sournois ne sont plus sur le sujet sur ce site. meta.codegolf.stackexchange.com/a/8326/20469
cat

Réponses:


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

Production:

[1, NaN]

Notez que 0/0 = NaN

Allusion

Essayez d'ajouter des points-virgules.
Ce programme est en fait var a=3,b=3,a2=3,b2=3[a2,b2]=...=[a2/(a-b),b2/(a-b)];console.log([a2/a,b2/a]).
Et le NaN l'est [3/0,undefined/0]/3.


Sensationnel. C'était très intelligent, "accidentellement" en oubliant d'ajouter des points-virgules, faisant (presque) du programme entier une phrase continue.
user155698

3

Python 2

Je suis sûr que c'est évident car tout le monde connaît Python, mais voici ma tentative:

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)

Il sort True.

Allusion:

Vérifiez ma division.


puisque tout le monde utilise Python . Je connais python, mais je l'utilise rarement
rpax

@rpax C'est ce que je voulais dire.
mbomb007

Désolé, je n'ai pas bien lu votre réponse.
rpax

2

Rubis

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

Allusion:

,

Explication:

Les deux lignes qui se terminent par des virgules entraînent un comportement différent du programme. Sans les virgules, la méthode prend un seul argument a, définit bégal à a, effectue les transformations de la preuve sur chacun (sauf en raison de parenthèses manquantes, elle ne se divise pas par 0), et génère le résultat (avec une entrée de 3 , il produirait "-1 = -1". Cependant, avec la virgule de fin, la b = aligne fait partie de la signature de la méthode, ce qui signifie qu'elle déclare un deuxième argument avec une valeur par défaut. L'invocation de la méthode à la fin passe dans le résultat de STDOUT.write($/), qui est 1 (le nombre d'octets qu'il a écrit à STDOUT, car il $/est prédéfini à un caractère de nouvelle ligne.) Donc a est 3 et b est 1, résultant en l'équation commençant par "3 = 1". les ordures.


Belle astuce là-bas avec vos nouvelles lignes.
LegionMammal978

Pourriez-vous ajouter une explication pour les non-rubis?
kirbyfan64sos

@ kirbyfan64sos Bien sûr, c'est fait.
histocrate

2

GolfScript

Attention: ce programme triche un peu, en ce qu'il n'imprime pas aMod et bMod

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

Essayez-le ici !

Alors que se passe-t-il?

La première chose que vous avez pu remarquer est les "trigraphes interdits". Mais rappelez-vous, c'est GolfScript, pas C! Aussi, probablement remarqué qu'il ne dit pas réellement "int main ()", il dit "1nt main ()". Dans GolfScript, le «1» signifie pousser 1 sur la pile et le «nt main» est traité comme deux variables non initialisées, qui ne font rien. Les deux parenthèses ajoutent d'abord 1 au numéro supérieur de la pile, puis soustraient une, s'annulant essentiellement. Les crochets indiquent un bloc qui est poussé sur la pile, puis le point-virgule le fait disparaître immédiatement. Donc, à la fin, nous avons juste le "1" d'origine qui a été poussé, et à la fin d'un programme GolfScript, la pile est imprimée. Cette réponse a été inspirée par celle- ci.


Trigraphes détectés. Activation du système -1 automatique. Erreur: -1 échec (4792, RPLS)
CalculatorFeline

C'est sournois, car cela vous fait croire qu'il n'a pas réussi à vous duper. +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.

La sortie quand areEqual(4,4)est appelée (ou tout autre couple vraiment):

false

Pourquoi?

Dans Prolog, l'opérateur "=" n'est pas une affectation; c'est "l'unification". Par conséquent, Amod = Amod * Aéchoue car Amoda déjà été unifié avec A, et ne peut donc pas être unifié avec Amod * A. Prolog arrête alors immédiatement l'exécution de la règle actuelle et revient false.


2
Je pense que cela devrait être l'inverse, vous devez sortir "true" lorsque les deux valeurs sont différentes, pas "false" lorsqu'elles sont égales ^^ '
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);

Sortie:
http://jsbin.com/furino/2/edit?js,output JsBin ne semble pas pouvoir exécuter ce code. Utilisez plutôt la console du navigateur.

Pourquoi?

scrollMaxX et screenX sont déjà des variables existantes. Ils sont intégrés dans le navigateur. Ainsi, le résultat peut varier. Le mot clé let ne modifie que temporairement leur valeur.

Un autre JavaScript: il ne suit pas exactement les règles, il ne sort que si les variables sont égales ou non.

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

Pourquoi?

NaN n'est pas égal à NaN selon les spécifications du flottant IEEE. Merci à Alex Van Liew d'avoir souligné que cela ne s'applique pas uniquement à Javascript.


NaNn'est pas égal aux NaNspécifications du flottant IEEE. En fait, un moyen rapide de tester si vous avez un NaNin C est de le comparer avec lui-même. Cela s'applique donc à toutes les langues, pas seulement à JS.
Alex Van Liew

1
@AlexVanLiew Intéressant. Je ne le savais pas! Ok, en changeant légèrement ma réponse et en ajoutant du crédit là où c'est dû.
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})

Production:

-3 = 3

Pourquoi?

[a: b] est une carte, pas une liste. Pas si sournois, je sais :(


Vous êtes censé avoir a égal b à la fin.
mbomb007

La fin de l'erreur originale est 2 = 1, donc la fin de toute réponse ici ne devrait pas être "vraie"
Cain

Je pensais au BONUS sournois. Ça ne fait rien. "Au lieu d'imprimer le signe égal, vous pouvez imprimer uniquement les deux variables (aMod et bMod), puis avoir un code qui semble comparer les deux variables pour l'égalité mais en réalité se trouve qu'elles sont égales (et imprime une certaine forme de vrai) . "
mbomb007

0

C

L'erreur de preuve classique nécessite un malentendu de la syntaxe C classique. Malheureusement, j'ai rencontré des développeurs "de haut niveau uniquement" qui sont convaincus que C est cassé à cause de résultats similaires à ce code. Si vous savez comment C fonctionne, cela devient assez évident, mais si vous avez vu le code et supposé qu'il s'agissait d'un langage différent, il se peut que ce ne soit pas le cas.

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

Bien sûr, cela ne fonctionne pas aussi bien lorsqu'il est écrit de manière plus idiomatique avec des #include <stdio.h>int et placés devant les déclarations.


Mais comment ça marche?
CalculatorFeline

Notez tout d'abord qu'en c si vous «oubliez» l'int dans une déclaration, il suppose le type int afin d'être rétrocompatible avec k & r c. Recherchez ensuite l'opérateur, en c et faites attention à sa priorité. Notez ensuite le = au lieu de == dans la dernière instruction if.
LambdaBeta
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.