Остання спростування останньої теореми Ферма [закрито]


49

Напишіть програму на обраній вами мові, яка, як видається, успішно знайде контрприклад до Останньої теореми Ферма . Тобто знайдіть цілі числа a , b , c > 0 і n > 2 такі, що a n + b n = c n .

Звичайно, ти справді не можеш цього зробити, якщо тільки в доказі Ендрю Вілз є недолік. Я маю на увазі підробку , спираючись на

  • ціле переповнення
  • Помилка округлення з плаваючою комою
  • невизначена поведінка
  • типи даних із незвичними визначеннями додавання, експоненції чи рівності
  • помилки компілятора / інтерпретатора
  • або щось у цьому напрямку.

Ви можете жорстко закодувати деякі або всі змінні a, b, c, або n, або шукати їх, роблячи петлю подобаються for a = 1 to MAX.

Це не код гольфу; це конкурс на пошук розумних і тонких рішень.


насправді ви можете мати такі як усі, крім показника, який повинен бути 3 або вище. Отже, 1 ^ 3 + 1 ^ 3 = 1 ^ 3 це так просто.

2
@Siver: 1³ + 1³ = 2; 1³ = 1; 2 ≠ 1
dan04

Відповіді:


57

J

Насправді, Ферма зробив досить грубі помилки: це насправді неправильно для будь-яких b, c або n, якщо a 1:

   1^3 + 4^3 = 5^3
1
   1^4 + 5^4 = 11^4
1
   1^9 + 3^9 = 42^9
1

Може бути, можливо, правила пріоритету Ферма були не строго справа наліво.


19
+1 Суворо право наліво дійсно. Просто для людей, які читають зліва направо; нормальною позначкою для останнього буде1^(9 + (3^(9 = (42^9))))
seequ

1
Підлий, мій мозок збирався танути, поки я не побачив коментар @ TheRare
german_guy

3
Це цільова особливість J? Це та річ, яка насправді призведе до розуму людей.
qwr

2
@qwr У J всі оцінки - справа наліво, за деякими винятками. Це звучить дивно, але насправді досить акуратно.
seequ

1
@ dan04 Не зовсім суто кажучи. 1^i.5оцінює до 1 1 1 1 1.
ɐɔıʇǝɥʇuʎs

36

TI-Basic

1782^12+1841^12=1922^12

Вихід (вірно)

1


1
Я бачив той епізод так часто, ніколи цього не помічав. Приємний улов!
dom0

1
Ця відповідь працює лише так, як написано з TI-89-ароматом TI-Basic. У TI-84 + SE код має синтаксичну помилку, оскільки ця версія TI-Basic не дає пробілів. Але відповідь все-таки працює на старшому калькуляторі, якщо ви видалите пробіли, пишучи 1782^12+1841^12=1922^12.
Rory O'Kane

1
+1 за використання TI-Basic, це була моя перша мова програмування :)
Кік

2
@ThaneBrimhall Це іронія, що калькулятор не вдається просту математичну задачу
qwr

35

Java

Цей хлопець Ферма, мабуть, спав. Я отримую сотні рішень рівнянь. Я просто перетворив свою формулу Excel в програму Java.

public class FermatNoMore {
    public static void main(String[] args) {
        for (int n = 3; n < 6; n++)
            for (int a = 1; a < 1000; a++)
                for (int b = 1; b < 1000; b++)
                    for (int c = 1; c < 1000; c++)
                        if ((a ^ n + b ^ n) == (c ^ n))
                            System.out.println(String.format("%d^%d + %d^%d = %d^%d", a, n, b, n, c, n));
    }
}

^Оператор фактично означає XOR в Java, на відміну від експоненціаціі в типовому простому тексті


Будь-який шанс на детальну інформацію про те, чому це працює?
Vality

20
@Vality: ^у Java є xor, а не потужність.
marinus

3
це технічно працює майже на будь-яких мовах на основі С
phuclv

19

C ++

#include <cstdlib>
#include <iostream>

unsigned long pow(int a, int p) {
  unsigned long ret = a;

  for (int i = 1; i < p; ++i)
    ret *= a;

  return ret;
}

bool fermat(int n) {
  // surely we can find a counterexample with 0 < a,b,c < 256;
  unsigned char a = 1, b = 1, c = 1;

  // don't give up until we've found a counterexample
  while (true) {
    if (pow(a, n) + pow(b, n) == pow(c, n)) {
      // found one!
      return true;
    }

    // make sure we iterate through all positive combinations of a,b,c
    if (!++a) {
      a = 1;
      if (!++b) {
        b = 1;
        if (!++c)
          c = 1;
      }
    }
  }

  return false;
}

int main(int argc, char** argv) {
  if (fermat(std::atoi(argv[1])))
   std::cout << "Found a counterexample to Fermat's Last Theorem" << std::endl;
}

Складено clang++ -O3 -o fermat fermat.cpp, протестовано Ubuntu clang version 3.4.1-1~exp1 (branches/release_34) (based on LLVM 3.4.1):

./fermat 3
Found a counterexample to Fermat's Last Theorem

Ми, очевидно, знайшли a, b, c> 0, так що a 3 + b 3 = c 3 (це також працює для n = 4, 5, 6, ...).

Друк a, b і c може виявитися трохи складним, хоча ...


1
@ Dan04: Ой, забув ++ін clang++.
Вентеро

2
До речі, це не помилка компілятора. Стандарт C (і C ++) дозволяє робити тут що завгодно, оскільки val.uможе переповнюватись (інакше було б, якби uint32_tзамість цього). Крім того, цей код також використовується unionнеправильно (згідно стандарту, ви не можете писати в одне поле та читати інше поле), але це дозволено багатьма компіляторами (відповідно до їх документації).
Конрад Боровський

3
Причиною цього дозволено є розділ стандарту C ++, який говорить: Цикл, який за межами for-init-оператора у випадку для оператора, * не здійснює викликів до функцій вводу / виводу бібліотеки, і * не робить отримувати доступ або змінювати летючі об'єкти, і * не виконує жодних операцій синхронізації (1.10) або атомних операцій (п. 29) реалізація не може вважати, що реалізація припиняється.
dan04

3
@ dan04 Точне формулювання фактично було вилучено зі стандарту в більш пізньому проекті, див. US 38 в open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3196.htm - але, звичайно, це було лише узагальнений. Це причина, чому друк a,b,c(або що-небудь з цього приводу) у fermat()змушує цю функцію ніколи не повертатися.
Вентеро

8
Argh Я так збирався відправити цю пошту. Для будь-якого , хто переплутав: Джон Регер має приємне пояснення тут .
Voo

13

Java

Схоже, теорема має значення n = 3, але я знайшов зустрічніприклади для n = 4:

public class Fermat {
    public static int p4(final int x) {
        return x * x * x * x;
    }

    public static void main(final String... args) {
        System.out.println(p4(64) + p4(496) == p4(528));
    }
}

Вихід:

true

Пояснення:

Навіть якщо цифри здаються невеликими, вони переповнюються, коли піднімаються до 4-ї потужності. Насправді 64 4 + 496 4 = 528 4 - 2 34 , але 2 34 стає 0 при обмеженні на int (32 біт).


Чи можете ви пояснити це?
Anubian Noob

@AnubianNoob зроблено
aditsu

9

Пітон

import math
print math.pow(18014398509481984,3) + math.pow(1, 3) \
      == math.pow(18014398509481983,3)

Хто каже, що c має бути більшим за a і b ?


2
Він друкує , Trueбо Math.pow повертає число з плаваючою точкою, і вони не мають достатньої точності , щоб отримати правильну відповідь, False.
kernigh

5

GolfScript

# Save the number read from STDIN in variable N and format for output.

:N"n="\+

{
  [{100rand)}3*] # Push an array of three randomly selected integers from 1 to 100.
  .{N?}/         # Compute x**N for each of the three x.
  +=!            # Check if the sum of the topmost two results equals the third.
}{;}while        # If it doesn't, discard the array and try again.

# Moar output formatting.

~]["a=""\nb=""\nc="""]]zip

Такий підхід знаходить купу різних рішень. Наприклад:

$ golfscript fermat.gs <<< 3
n=3
a=43
b=51
c=82

Як це працює

Перший рядок повинен починатися з ~інтерпретації введення. Замість, наприклад, число 3, змінна Nмістить рядок 3\n.
Поки 2 3 ?обчислює 3 , 2 N ?висуває індекс символу з кодом ASCII 2 у N(-1 для не знайдено).
Таким чином, 43 N ?і 82 N ?поштовх -1і 51 N ?штовхає 0(51 є ASCII код символу 3).
Оскільки -1 + 0 = -1умова виконується і (43,51,82)є "рішенням".


4

С

Ну і звичайно, що ви всі знаходите контрприклади, ви продовжуєте отримувати цілі переливи. Крім того, ви дуже повільно перебираєтесь на c. Це набагато кращий спосіб зробити це!

#include <stdio.h>
#include <math.h>

int main(void) {
  double a, b, c;
  for (a = 2; a < 1e100; a *= 2) {
    for (b = 2; b < 1e100; b *= 2) {
      c = pow(pow(a, 3) + pow(b, 3), 1.0/3);
      if (c == floor(c)) {
        printf("%f^3 + %f^3 == %f^3\n", a, b, c);
      }
    }
  }
  return 0;
}

double може бути чудовим у діапазоні, але все одно дещо бракує точності ...


4

С

Всі ми ненавидимо цілі числа переливів, тому ми будемо використовувати невеликий показник nта деякі перетворення з плаваючою комою. Але теорема все-таки не дотримуватиметься a = b = c = 2139095040.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

int a, b, c;
int n;

int disprove(int a, int b, int c, int n)
{
    // Integers are so prone to overflow, so we'll reinforce them with this innocent typecast.
    float safe_a = *((float *)&a);
    float safe_b = *((float *)&b);
    float safe_c = *((float *)&c);

    return pow(safe_a, n) + pow(safe_b, n) == pow(safe_c, n);
}

int main(void)
{
    srand(time(NULL));

    a = b = c = 2139095040;
    n = rand() % 100 + 3;

    printf("Disproved for %d, %d, %d, %d: %s\n", a, b, c, n, disprove(a, b, c, n) ? "yes" : "no");
}

Вихід:

Disproved for 2139095040, 2139095040, 2139095040, 42: yes

Disproved for 2139095040, 2139095040, 2139095040, 90: yes

У IEEE 754 число 2139095040 або 0x7F800000 являє собою позитивну нескінченність для одноточних типів з плаваючою точкою. Усі pow(...)дзвінки повертаються + нескінченність, а + нескінченність дорівнює + нескінченність. Простішим завданням було б спростувати теорему Піфагора, використовуючи 0x7F800001 (Тихий NaN), який не є рівним собі за стандартом.


2

Javascript

var a, b, c, MAX_ITER = 16;
var n = 42;
var total = 0, error = 0;

for(a = 1 ; a <= MAX_ITER ; a++) {
  for(b = 1 ; b <= MAX_ITER ; b++) {
    for(c = 1 ; c <= MAX_ITER ; c++) {
      total++;
      if(Math.pow(a, n) + Math.pow(b, n) == Math.pow(c, n)) {
        error++;
        console.log(a, b, c);
      }
    }
  }
}

console.log("After " + total + " calculations,");
console.log("I got " + error + " errors but Fermat ain't one.");

42 - це магія.

> node 32696.js
After 2176 calculations,
I got 96 errors but Fermat ain't one.

А також Wiles - це не одна.

Javascript Numberнедостатньо великий.


2

T-SQL

Щоб спростувати теорему цього хлопця Ферма, нам просто потрібно знайти зустрічний приклад. Здається, він був дуже ледачий, і спробував це лише для справді невеликої перестановки. Насправді він навіть не намагався. Я знайшов приклад зустрічного лише в 0 <a, b, c <15 та 2 <e <15. Вибачте, що я в серці гольфіст, тому пізніше я скасую цей код!

with T(e)as(select 1e union all select (e+1) from T where e<14)select isnull(max(1),0)FROM T a,T b,T c,T e where e.e>2 and power(a.e,e.e)+power(b.e,e.e)=power(c.e,e.e)

Повертається 1, тобто ми знайшли зустрічний приклад!

Хитрість полягає в тому, що хоча перший e схожий на псевдонім, він насправді є підлий спосіб зміни типу даних e з int на тип з плаваючою точкою, еквівалентний подвійному. На той момент, коли ми дісталися до 14, ми перебуваємо поза точністю числа з плаваючою точкою, тому ми можемо додати до нього 1, і ми все ще нічого не втрачаємо. Мінімація є приємним приводом для пояснення мого, здавалося б, нерозумного подвійного оголошення псевдоніму стовпця в rcte. Якби я цього не зробив, він би переповнився задовго до того, як ми дійшли до 14 ^ 14.


1

JavaScript

Здається, цей хлопець був на чомусь гаразд. На наркотики, якщо ви запитаєте мене. Враховуючи обмеження, не можна знайти набору значень, для яких теорема справедлива.

var a = 1,
    b = 1,
    c = 1,
    n = 3,
    lhs = (a^n + b^n),
    rhs = c^n;

alert(lhs === rhs);

Як і в Java, ^оператор - це побітовий оператор XOR в JavaScript. Правильний спосіб обчислити потужність числа - використовувати Math.pow.


2
Для Ферма експонентом ( n) має бути >= 3.
рекурсивна

Добре, що код все ще працює :)
thomaux

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.