“反驳”费马的最后定理


49

用您选择的语言编写一个程序,该程序似乎可以成功找到Fermat的Last Theorem的反例。也就是说,找到整数abc > 0和n > 2使得a n + b n = c n

当然,除非安德鲁·威尔斯(Andrew Wiles)的证明有缺陷,否则您无法真正做到。我的意思是假的,依靠

  • 整数溢出
  • 浮点舍入误差
  • 未定义的行为
  • 具有加法,求幂或等式的异常定义的数据类型
  • 编译器/解释器错误
  • 或类似的规定。

你可以硬编码部分或全部变量abc,或n,或做循环寻找他们喜欢的for a = 1 to MAX

这不是代码高尔夫;这是寻找聪明而精妙的解决方案的竞赛。


实际上,除指数(必须为3或更高)外,您还可以拥有其他所有这些。因此,1 ^ 3 + 1 ^ 3 = 1 ^ 3就这么简单。

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

Answers:


57

Ĵ

实际上,费马确实犯了一个大错:如果a为1,则对于任何b,c或n都是错误的:

   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 2014年

1
鬼nea,我的大脑即将融化,直到我看到@TheRare的评论
german_guy 2014年

3
这是J的预期功能吗?这种事情确实会使人发疯。
qwr 2014年

2
@qwr在J中,所有评估都是从右到左,有些例外。听起来很奇怪,但实际上很整洁。
seequ 2014年

1
@ dan04严格来说不是正确的。1^i.5评估为1 1 1 1 1
ɐɔıʇǝɥʇuʎs

36

TI基本

1782^12+1841^12=1922^12

输出(真)

1


1
我经常看到那集,却从未注意到。好赶上!
dom0 2014年

1
该答案仅适用于具有TI-89风味的TI-Basic。在TI-84 + SE上,代码存在语法错误,因为该版本的TI-Basic不允许使用空格。但是,如果您删除空格并写入,答案仍然适用于较旧的计算器1782^12+1841^12=1922^12
罗里·奥肯

1
使用TI-Basic +1,这是我的第一种编程语言:)
2014年

2
@具有讽刺意味的是,计算器未能通过简单的数学问题
qwr

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中,而不是在典型的纯文本幂


是否有机会详细说明其工作原理?
价格

20
@Vality:^在Java中是xor,不是幂。
marinus 2014年

3
从技术上讲,这几乎适用于所有基于C的语言
phuclv 2014年

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++
Ventero 2014年

2
顺便说一句,这不是编译器错误。C(和C ++)标准允许在这里做任何事情,就像val.u溢出一样(如果uint32_t相反,它会有所不同)。此外,此代码还union以不正确的方式使用(根据标准,您不能写入一个字段,而不能读取另一个字段),但是许多编译器都允许这样做(根据其文档)。
Konrad Borowski14年

3
允许这样做的原因是C ++标准的一段内容:在for语句的情况下,在for-init-statement之外的循环*不会调用库I / O函数,而*不会访问或修改易失性对象,并且*不执行同步操作(1.10)或原子操作(第29条)可能会因实现而终止。
dan04 2014年

3
@ dan04确切的措词实际上已在以后的草案中从标准中删除,请参阅open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3196.htm中的 US 38- 当然,只是广义的。这就是为什么打印输出a,b,c(或任何事情)fermat()使函数永不返回的原因。
Ventero 2014年

8
啊,我正打算发布那个。对于任何困惑的人:约翰·雷格(John Regehr)在这里有一个很好的解释。
Voo

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

说明:

即使数字看起来很小,当升至四次方时它们也会溢出。在现实中,64 4 + 496 4 = 528 4 - 2 34,但2 34限制为int(32个比特)时变为0。


你能解释一下吗?
Anubian Noob 2014年

@AnubianNoob完成
aditsu

9

蟒蛇

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

谁说c必须大于ab


2
进行打印True是因为math.pow返回浮点数,而这些浮点数没有足够的精度来获取正确的答案False
kernigh 2014年

5

高尔夫脚本

# 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

这个怎么运作

第一行应以a开头~以解释输入。代替数字3,变量N包含字符串3\n
2 3 ?计算3时2 N ?将ASCII码为2的字符的索引压入N(-1为未找到)。
这种方式,43 N ?82 N ?按压-151 N ?按压0(51的ASCII字符代码3)。
由于-1 + 0 = -1,条件得到满足并且(43,51,82)是“解决方案”。


4

C

当然,你们所有人都在寻找反例,您不断得到整数溢出。另外,通过迭代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

C

我们都讨厌整数溢出,因此我们将使用一个小的指数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(...)调用都将返回+ Infinity,并且+ Infinity等于+ Infinity。一个更简单的任务是通过使用0x7F800001(Quiet NaN)来反驳勾股定理,根据标准,该0x7F800001不等于自身。


2

Java脚本

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中一样,^运算符是JavaScript中按位XOR运算符。计算数字幂的正确方法是使用Math.pow。


2
对于Fermat,exponent(n)必须为>= 3
2014年

好一点,代码仍然可以正常工作:)
thomaux

0

另一个BASIC反例

10 a = 858339
20 b = 2162359
30 c = 2162380
40 IF (a^10 + b^10) = c^10 THEN
50   PRINT "Fermat disproved!"
60 ENDIF
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.