Classic Proof Fallacy [zamknięte]

18

Tło

Wszyscy znamy klasyczny dowód, który wygląda następująco:

A = B
a² = AB
a² - b² = AB - b²
(ab), (A + B) = b (ab),
(A + B) = b
b + b =
2b = B
2 = 1 (Ha!)
O Oczywiście błąd polega na tym, że nie można podzielić przez 0. Ponieważ a = b, a - b = 0, więc podział był ukryty przez 0.

Wyzwanie

Musisz powtórzyć ten dowód. Najpierw zadeklaruj dwie liczby całkowite a i b (nie ma znaczenia, jak je nazwiesz) równe. Następnie zadeklaruj aMod i bMod jako modyfikowalne wersje aib, początkowo równe odpowiednio aib. Musisz je pomnożyć przez a, a następnie odjąć b * b od obu. Musisz podzielić przez -b, a następnie podzielić przezb (lub a), aby uzyskać. Następnie wydrukuj aMod i bMod ze znakiem równości między nimi.

Podstępni

Oczywiście, ponieważ zadeklarowałeś aib równe, a - b = 0, a dzielenie przez 0 powoduje błąd. Musisz więc kreatywnie to sfałszować. Ponadto, ponieważ próbujesz odtworzyć dowód, wynik wszystkich operacji na aMod i bMod nie może być równy po wydrukowaniu. Nie muszą równać się dokładnie 2 i 1, tylko dwie liczby, które nie są równe.

Oto przykład:

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

Może nie najlepszy, ale ilustruje sens.

Bonus Underhanded

Zamiast drukować znak równości, możesz wydrukować tylko dwie zmienne (aMod i bMod), a następnie mieć kod, który wydaje się porównywać dwie zmienne pod kątem równości, ale w rzeczywistości leży, że są one równe (i drukuje jakąś formę true).

Pamiętaj, że jest to konkurs popularności, więc wygrywa najwyższa liczba głosów pozytywnych.
Ponadto nowa wersja matematyki o nazwie Mathematics 2.0 wykorzystała standardowe luki automatyczne unieważniające dowód.

użytkownik155698
źródło
Oto link Wikipedii do
3
Głosuję za zamknięciem tego pytania jako nie na temat, ponieważ słabe wyzwania nie są już na ten temat na tej stronie. meta.codegolf.stackexchange.com/a/8326/20469
kot

Odpowiedzi:

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

Wynik:

[1, NaN]

Zauważ, że 0/0 = NaN

Wskazówka

Spróbuj dodać kilka średników.
Ten program jest w rzeczywistości var a=3,b=3,a2=3,b2=3[a2,b2]=...=[a2/(a-b),b2/(a-b)];console.log([a2/a,b2/a]).
A NaN jest [3/0,undefined/0]/3.

jimmy23013
źródło
Łał. Było to bardzo sprytne, „przypadkowo” zapominając o dodaniu średników, dzięki czemu (prawie) cały program jest zdania uruchamiającego.
user155698
3

Python 2

Jestem prawie pewien, że to oczywiste, ponieważ wszyscy znają Python, ale oto moja próba:

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)

Wyprowadza True.

Wskazówka:

Sprawdź mój dział.

mbomb007
źródło
ponieważ wszyscy używają Pythona . Znam pytona, ale rzadko go używam
rpax
@rpax Właśnie to miałem na myśli.
mbomb007
Przepraszam, nie przeczytałem poprawnie twojej odpowiedzi.
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

Wskazówka:

,

Wyjaśnienie:

Dwa wiersze, które kończą się przecinkami, powodują, że program zachowuje się inaczej niż powinien. Bez przecinków metoda pobiera pojedynczy argument a, ustawia wartość brówną a, wykonuje transformacje z dowodu na każdym (z wyjątkiem niektórych brakujących nawiasów, nie dzieli się przez 0), i zwraca wynik (z wejściem 3 , wyświetli "-1 = -1". Jednak z przecinkiem końcowym b = alinia staje się częścią podpisu metody, co oznacza, że ​​deklaruje drugi argument z wartością domyślną. Wywołanie metody na końcu przechodzi w wynik STDOUT.write($/), który wynosi 1 (liczba bajtów, które zapisał do STDOUT, ponieważ $/jest predefiniowany do znaku nowego wiersza). Zatem a to 3, a b to 1, co powoduje, że równanie zaczyna się od „3 = 1”. wyrzucać śmieci.

histocrat
źródło
Niezła sztuczka z twoimi nowymi liniami.
LegionMammal978
Czy możesz dodać wyjaśnienie nie-rubyistów?
kirbyfan64sos
@ kirbyfan64sos Pewnie, gotowe.
histocrat
2

GolfScript

Ostrzeżenie: ten program trochę oszukuje, ponieważ nie drukuje aMod i 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;
};

Wypróbuj tutaj !

Więc co się dzieje?

Pierwszą rzeczą, którą mogłeś zauważyć, są „zakazane trigrafie”. Pamiętaj jednak, że to jest GolfScript, a nie C! Prawdopodobnie zauważył również, że tak naprawdę nie mówi „int main ()”, ale „1nt main ()”. W GolfScript „1” oznacza pchnięcie 1 na stos, a „nt main” zostaje przetworzone jako dwie niezainicjowane zmienne, które nic nie robią. Dwa nawiasy najpierw dodają 1 do najwyższego numeru stosu, a następnie odejmują jeden, zasadniczo anulując się. Nawiasy kwadratowe oznaczają blok, który zostaje wypchnięty na stos, a następnie średnik od razu go wysuwa. Na koniec mamy po prostu oryginalną cyfrę „1”, która została wypchnięta, a na końcu programu GolfScript stos jest drukowany. Ta odpowiedź została zainspirowana .

K Zhang
źródło
Wykryto kaligrafie. Aktywacja systemu automatycznego -1. Błąd: -1 nie powiodło się (4792, RPLS)
CalculatorFeline
Jest to podstępne, ponieważ wabi cię do myślenia, że ​​cię nie oszukał. +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.

Dane wyjściowe po areEqual(4,4)wywołaniu (lub jakiejkolwiek innej parze liczb):

false

Dlaczego?

W Prologu operator „=” nie ma wpływu; to „Unifikacja”. Dlatego Amod = Amod * Azawodzi, ponieważ Amodzostał już zjednoczony A, a zatem nie może być zjednoczony Amod * A. Prolog natychmiast przestaje wykonywać bieżącą regułę i wraca false.

Fatalizować
źródło
2
Myślę, że powinno być na odwrót, musisz podać „prawda”, gdy dwie wartości są różne, a nie „fałsz”, gdy są równe ^^ '
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);

Dane wyjściowe:
http://jsbin.com/furino/2/edit?js,out JsBin nie wydaje się być w stanie wykonać tego kodu. Zamiast tego użyj konsoli przeglądarki.

Dlaczego?

scrollMaxX i screenX to już istniejące zmienne. Są one wbudowane w przeglądarce. Zatem wynik może się różnić. Słowo kluczowe let tylko tymczasowo zmienia swoją wartość.

Kolejny kod JavaScript: nie jest dokładnie zgodny z regułami, wyświetla tylko wtedy, gdy zmienne są równe, czy nie.

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

Dlaczego?

NaN nie jest równy NaN według specyfikacji pływaka IEEE. Podziękowania dla Alexa Van Liewa za zwrócenie uwagi, że nie dotyczy to tylko Javascript.

Stefnotch
źródło
NaNnie jest równa NaNspecyfikacji pływaka IEEE. W rzeczywistości szybkim sposobem sprawdzenia, czy masz NaNw C, jest porównanie go z samym sobą. Dotyczy to wszystkich języków, nie tylko JS.
Alex Van Liew
1
@AlexVanLiew Ciekawe. Nie wiedziałem tego! Ok, zmieniając nieco moją odpowiedź i dodając kredyt tam, gdzie jest to należne.
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})

Wynik:

-3 = 3

Dlaczego?

[a: b] to mapa, a nie lista. Nie taki podstępny, wiem :(

Kain
źródło
Powinieneś mieć a równe b na końcu.
mbomb007
Koniec pierwotnego błędu to 2 = 1, więc koniec żadnej odpowiedzi tutaj nie powinien być „prawdziwy”
Kain
Myślałem o BONUSie podstępnym. Nieważne. „Zamiast drukować znak równości, możesz wydrukować tylko dwie zmienne (aMod i bMod), a następnie mieć kod, który wydaje się porównywać dwie zmienne pod kątem równości, ale w rzeczywistości leży to, że są one równe (i drukuje jakąś formę prawdy) . ”
mbomb007
0

do

Błąd klasyczny dowodu wymaga nieporozumienia w klasycznej składni C. Niestety spotkałem programistów „tylko na wysokim poziomie”, którzy są przekonani, że C jest uszkodzony z powodu wyników podobnych do tego kodu. Jeśli wiesz, jak działa C, staje się to dość oczywiste, ale jeśli widziałeś kod i zakładałeś, że jest to inny język, może nie być.

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

Oczywiście nie działa to tak dobrze, gdy jest napisane bardziej idiomatycznie #include <stdio.h>i int jest rzucane przed deklaracjami.

LambdaBeta
źródło
Jak to działa?
CalculatorFeline
Najpierw zauważ, że w c, jeśli „zapomnisz” int w deklaracji, zakłada on int, aby być kompatybilnym wstecz z k & rc. Następnie wyszukaj operator c i zwróć uwagę na jego pierwszeństwo. Następnie zanotuj = zamiast == w ostatniej instrukcji if.
LambdaBeta