«Опровергнуть» последнюю теорему Ферма [закрыто]


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
дан 04

Ответы:


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.
Рори О'Кейн

1
+1 за использование TI-Basic, это был мой первый язык программирования :)
Kik

2
@ThaneBrimhall Это ирония, калькулятор не
справился

35

Ява

Этот парень Ферма, должно быть, спал. Я получаю сотни решений уравнений. Я просто преобразовал свою формулу 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, а не сила.
Маринус

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 в случае оператора for * не вызывает функции библиотечного ввода-вывода, а * - нет обращаются к изменяемым объектам или изменяют их, а * не выполняет операции синхронизации (1.10) или атомарные операции (пункт 29), которые могут быть приняты реализацией для завершения.
dan04

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

8
Ага, я так собирался опубликовать это. Для всех, кто запутался: у Джона Регера есть хорошее объяснение здесь .
Во

13

Ява

Похоже, теорема верна для 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 бита).


Вы можете это объяснить?
Анубиан Нуб

@AnubianNoob сделано
aditsu

9

питон

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

Кто сказал, что с должно быть больше, чем а и б ?


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.

А также Уайлс не один.

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 на тип с плавающей запятой, эквивалентный double. К тому времени, когда мы достигли 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.