Định hướng từ chối của Fermat của Fermat [đóng]


49

Viết một chương trình, bằng ngôn ngữ bạn chọn, dường như tìm thấy thành công một ví dụ cho Định lý cuối cùng của Fermat . Nghĩa là tìm các số nguyên a , b , c > 0 và n > 2 sao cho a n + b n = c n .

Tất nhiên, bạn không thể thực sự làm điều đó, trừ khi có một lỗ hổng trong bằng chứng của Andrew Wiles. Tôi có nghĩa là giả nó , bằng cách dựa vào

  • tràn số nguyên
  • lỗi làm tròn dấu phẩy động
  • hành vi không xác định
  • các kiểu dữ liệu với các định nghĩa bất thường về phép cộng, lũy thừa hoặc đẳng thức
  • trình biên dịch / trình thông dịch lỗi
  • Hoặc một cái gì đó dọc theo các đường dây.

Bạn có thể mã hóa cứng một số hoặc tất cả các biến a, b, c, hay n, hoặc tìm kiếm cho họ bằng cách làm vòng như thế for a = 1 to MAX.

Đây không phải là một mã golf; đó là một cuộc thi để tìm giải pháp thông minh và tinh tế.


trên thực tế, bạn có thể có những cái như tất cả chúng ngoài số mũ, phải từ 3 trở lên. Vì vậy, 1 ^ 3 + 1 ^ 3 = 1 ^ 3 thật đơn giản.

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

Câu trả lời:


57

J

Trên thực tế, Fermat đã thực hiện khá sai lầm: Thực sự sai đối với bất kỳ b, c hoặc n nào nếu a là 1:

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

Có lẽ chỉ có thể, các quy tắc ưu tiên của Fermat không hoàn toàn đúng sang trái.


19
+1 Nghiêm phải sang trái thực sự. Chỉ dành cho những người đọc từ trái sang phải; ký hiệu bình thường cho người cuối cùng sẽ là1^(9 + (3^(9 = (42^9))))
seequ

1
Lén lút, não tôi sắp tan chảy cho đến khi tôi thấy bình luận của @ TheRare
German_guy

3
Đây có phải là một tính năng dự định của J? Đây là loại điều thực sự sẽ khiến mọi người phát điên.
qwr

2
@qwr Trong J, tất cả các đánh giá là từ phải sang trái, với một số ngoại lệ. Nghe có vẻ lạ nhưng thực sự khá gọn gàng.
xem

1
@ dan04 Không đúng nói đúng. 1^i.5đánh giá để 1 1 1 1 1.
ɐɔıʇǝɥʇuʎs

36

TI-Basic

1782^12+1841^12=1922^12

Đầu ra (đúng)

1


1
Tôi đã xem tập phim đó rất thường xuyên, không bao giờ nhận thấy điều đó. Bắt tốt đẹp!
dom0

1
Câu trả lời này chỉ hoạt động như được viết bằng TI-89-hương vị TI-Basic. Trên TI-84 + SE, mã có lỗi cú pháp, vì phiên bản TI-Basic đó không cho phép khoảng trắng. Nhưng câu trả lời vẫn hoạt động trên một máy tính cũ hơn nếu bạn xóa khoảng trắng, viết 1782^12+1841^12=1922^12.
Rory O'Kane

1
+1 khi sử dụng TI-Basic, đó là ngôn ngữ lập trình đầu tiên của tôi :)
Kik

2
@ThaneBrimhall Đó là sự trớ trêu, một máy tính thất bại trong một bài toán đơn giản
qwr

35

Java

Anh chàng Fermat này chắc đã ngủ rồi. Tôi nhận được hàng trăm giải pháp cho các phương trình. Tôi chỉ chuyển đổi công thức Excel của mình sang chương trình 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));
    }
}

Các ^nhà điều hành thực sự có nghĩa là XOR trong Java, như trái ngược với lũy thừa trong điển hình đồng bằng văn bản


Bất kỳ cơ hội trên một công phu về lý do tại sao điều này làm việc?
Vality

20
@Vality: ^trong Java là xor, không phải power.
bến tàu

3
về mặt kỹ thuật này hoạt động trên hầu hết mọi ngôn ngữ dựa trên C
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;
}

Được biên dịch với clang++ -O3 -o fermat fermat.cpp, thử nghiệm với 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

Rõ ràng chúng tôi đã tìm thấy a, b, c> 0 sao cho a 3 + b 3 = c 3 (điều này cũng hoạt động với n = 4, 5, 6, ...).

In a, b và c có thể hơi khó khăn mặc dù ...


1
@ dan04: Rất tiếc, quên ++trong clang++.
Ventero

2
Nhân tiện, đây không phải là một lỗi biên dịch. Tiêu chuẩn C (và C ++) cho phép thực hiện bất cứ điều gì ở đây, vì val.ucó thể tràn (nó sẽ khác nếu nó uint32_tthay thế). Ngoài ra, mã này cũng sử dụng unionkhông đúng cách (theo tiêu chuẩn, bạn không thể ghi vào một trường và đọc trường khác), nhưng điều này được nhiều trình biên dịch cho phép (theo tài liệu của họ).
Konrad Borowski

3
Lý do điều này được cho phép là một phần của tiêu chuẩn C ++ có nội dung: Một vòng lặp, bên ngoài câu lệnh for-init trong trường hợp câu lệnh for, * không thực hiện cuộc gọi đến các hàm I / O của thư viện và * không truy cập hoặc sửa đổi các đối tượng dễ bay hơi và * thực hiện không có hoạt động đồng bộ hóa (1.10) hoặc hoạt động nguyên tử (Điều 29) có thể được giả định bằng cách thực hiện để chấm dứt.
dan04

3
@ dan04 Từ ngữ chính xác đó thực sự đã bị xóa khỏi tiêu chuẩn trong một bản nháp sau này, xem US 38 trong open-std.org/jtc1/sc22/wg21/docs/ con / 2010 / n3196.htm - nhưng tất nhiên, nó chỉ được khái quát. Đây là lý do tại sao in ra a,b,c(hoặc bất cứ điều gì, cho vấn đề đó) fermat()làm cho chức năng không bao giờ trở lại.
Ventero

8
Argh tôi đã rất muốn đăng cái đó. Đối với bất cứ ai bối rối: John Regehr có một lời giải thích tốt đẹp ở đây .
Voo

13

Java

Có vẻ như định lý giữ cho n = 3, nhưng tôi đã tìm thấy các mẫu đối với 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));
    }
}

Đầu ra:

true

Giải trình:

Ngay cả khi các con số có vẻ nhỏ, chúng vẫn tràn khi tăng lên sức mạnh thứ 4. Trong thực tế, 64 4 + 496 4 = 528 4 - 2 34 , nhưng 2 34 trở thành 0 khi bị giới hạn ở int (32 bit).


Bạn có thể giải thích điều này?
Anubian Noob

@AnubianNoob đã hoàn thành
aditsu

9

Con trăn

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

Ai nói rằng c phải lớn hơn ab ?


2
Nó in Truevì math.pow trả về các số có dấu phẩy động và chúng không có đủ độ chính xác để có câu trả lời chính xác False.
hạt nhân

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

Cách tiếp cận này tìm thấy một loạt các giải pháp khác nhau. Ví dụ:

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

Làm thế nào nó hoạt động

Dòng đầu tiên nên bắt đầu bằng một ~để diễn giải đầu vào. Thay vì, ví dụ, số 3, biến Nchứa chuỗi 3\n.
Trong khi 2 3 ?tính toán 3 , 2 N ?đẩy chỉ mục của một ký tự có mã ASCII 2 vào N(-1 không tìm thấy).
Bằng cách này, 43 N ?82 N ?đẩy -151 N ?đẩy 0(51 là mã ký tự ASCII của 3).
-1 + 0 = -1, điều kiện được thỏa mãn và (43,51,82)là một "giải pháp".


4

C

Tất nhiên, tất cả các bạn đều đang tìm kiếm các mẫu phản, bạn tiếp tục nhận được số nguyên tràn. Thêm vào đó, bạn đang rất chậm bằng cách lặp lại trên c. Đây là một cách tốt hơn để làm điều đó!

#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 có thể là tuyệt vời trên phạm vi, nhưng nó vẫn thiếu một chút chính xác ...


4

C

Tất cả chúng ta đều ghét tràn số nguyên, vì vậy chúng tôi sẽ sử dụng số mũ nhỏ nvà một số chuyển đổi dấu phẩy động. Nhưng định lý vẫn không giữ được 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");
}

Đầu ra:

Disproved for 2139095040, 2139095040, 2139095040, 42: yes

Disproved for 2139095040, 2139095040, 2139095040, 90: yes

Trong IEEE 754, số 2139095040 hoặc 0x7F800000, biểu thị vô cực dương trong các loại dấu phẩy động chính xác đơn. Tất cả các pow(...)cuộc gọi sẽ trả về + Vô cực và + Vô cực bằng + Vô cực. Một nhiệm vụ dễ dàng hơn là từ chối định lý Pythagore bằng cách sử dụng 0x7F800001 (NaN yên tĩnh) không bằng chính nó theo tiêu chuẩn.


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 là ma thuật, bạn biết đấy.

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

Và cũng không phải là một.

Javascript Numberkhông đủ lớn.


2

T-SQL

Để bác bỏ định lý của anh chàng Fermat này, chúng ta chỉ cần tìm một ví dụ phản biện. Có vẻ như, anh ta siêu lười biếng, và chỉ thử nó cho hoán vị thực sự nhỏ. Thực tế, anh ta thậm chí không cố gắng. Tôi đã tìm thấy một ví dụ ngược lại chỉ trong 0 <a, b, c <15 và 2 <e <15. Xin lỗi tôi là một người chơi golf trong tim vì vậy tôi sẽ giải mã mã này sau!

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)

Trả về 1, có nghĩa là chúng tôi đã tìm thấy một ví dụ truy cập!

Bí quyết là trong khi e đầu tiên trông giống như một bí danh, thì thực sự đó là một cách lén lút thay đổi kiểu dữ liệu của e từ kiểu int sang kiểu dấu phẩy động tương đương với một dấu hai. Vào thời điểm chúng tôi đạt 14, chúng tôi vượt quá độ chính xác của số dấu phẩy động để chúng tôi có thể thêm 1 vào số đó và chúng tôi vẫn không mất gì cả. Việc thu nhỏ là một cái cớ tốt đẹp để giải thích cho tuyên bố đôi có vẻ ngớ ngẩn của tôi về một bí danh cột trong RCte. Nếu tôi không làm điều này, nó sẽ tràn ra rất lâu trước khi chúng tôi đạt 14 ^ 14.


1

JavaScript

Có vẻ như anh chàng này đã vào một cái gì đó ổn. Lên thuốc nếu bạn hỏi tôi Với các ràng buộc, không có tập hợp giá trị nào có thể được tìm thấy mà định lý đúng.

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

alert(lhs === rhs);

Như trong Java, ^toán tử là toán tử XOR bitwise trong JavaScript. Cách chính xác để tính sức mạnh của một số là sử dụng Math.pow.


2
Đối với Fermat, số mũ ( n) phải là >= 3.
đệ quy

Điểm hay, mã vẫn hoạt động mặc dù :)
thomaux

0

Một mẫu khác 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.