Xác định hàm f sao cho f (f (n)) = -n với mọi số nguyên khác không n


43

Thử thách này được lấy cảm hứng từ một blog lập trình tôi thường xuyên. Xin vui lòng xem bài viết gốc ở đây: Câu đố lập trình


Thử thách

Xác định hàm f:Q->Qsao f(f(n)) = -ncho tất cả các số nguyên khác không nQtập hợp các số hữu tỷ ở đâu.

Chi tiết

Trong bất kỳ ngôn ngữ nào bạn thích, vui lòng xác định một chức năng hoặc chương trình fchấp nhận làm tham số một số nvà trả về hoặc xuất một số f(n).

Đầu vào có thể được cung cấp thông qua cơ chế nào là tự nhiên nhất đối với ngôn ngữ của bạn: đối số chức năng, đọc từ STDIN, đối số dòng lệnh, vị trí ngăn xếp, đầu vào bằng giọng nói, dấu hiệu băng đảng, v.v.

Đầu ra phải là giá trị trả về từ một chức năng / chương trình hoặc được in ra STDOUT.

Tôi muốn hạn chế câu trả lời cho các chức năng không tận dụng trạng thái chương trình hoặc bộ nhớ / dữ liệu toàn cầu có thể nhìn thấy từ bên ngoài chức năng f. Ví dụ: giữ một bộ đếm bên ngoài số fđó fđược gọi bao nhiêu lần và chỉ thực hiện phủ định dựa trên số này không phải là rất khó khăn hoặc thú vị đối với bất kỳ ai. Các quyết định đưa fra chỉ nên dựa vào dữ liệu trong fphạm vi từ vựng của.

Tuy nhiên, hạn chế này có thể không phù hợp với một số ngôn ngữ hướng ngăn xếp hoặc các loại ngôn ngữ khác không phân biệt các loại dữ liệu hoặc phạm vi này. Hãy sử dụng phán đoán tốt nhất của bạn để giữ với tinh thần của thách thức này.


Chấm điểm

Quy tắc golf mã phổ biến được áp dụng - điểm của bạn là số byte trong mã nguồn của bạn.

Câu trả lời tối thiểu yêu cầu tên miền và tên miền fphải là một tập hợp con của các tỷ lệ hợp lý Q. Nếu bạn giới hạn tên miền và tên miền của fmình cho các số nguyên Z, thì điểm của bạn là trần của 90% số byte trong mã nguồn của bạn.

Tiebreak

Trong trường hợp hòa, sau đây sẽ được sử dụng theo thứ tự:

  1. Số ít nhất của không khoảng trắng in ký tự trong mã nguồn của bạn
  2. Ngày và giờ sớm nhất của câu trả lời

Biên tập

Bạn không cần phải hỗ trợ các số có kích thước tùy ý. Vui lòng giải thích các tập hợp ZQdưới dạng kiểu dữ liệu trong ngôn ngữ bạn đã chọn (thường là số nguyên và dấu phẩy động).

Nếu giải pháp của bạn hoàn toàn dựa vào cấu trúc cơ bản hoặc mẫu bit của một loại dữ liệu, vui lòng mô tả các giới hạn của nó và cách sử dụng nó.


20
f (n) = i * n - toán học thuần túy: P
Johannes Kuhn

8
@JohannesKuhn đây là lý do tại sao tên miền và tên miền bị giới hạn trong các tỷ lệ hợp lý
ardew

Bạn có thể giải thích những gì f:Q->Qcó nghĩa là?
beary605

@ beary605 có nghĩa flà một thành viên ánh xạ hàm của Q(số hữu tỷ) cho các thành viên khác (có thể giống nhau) của Q. xem en.wikipedia.org/wiki/Function_(mathatures)#Notation
ardew

7
Tôi biết tôi đã nhìn thấy điều này gần đây, nhưng phải mất một thời gian để nhớ nơi. Một phiên bản ít được chỉ định chặt chẽ hơn trên StackOverflow gần đây đã bị đóng. Hơn 100 câu trả lời.
Peter Taylor

Câu trả lời:


12

J, 9 điểm (10 ký tự)

Dựa trên câu trả lời stackoverflow :

   (*-[*_1&^)

Ý tưởng đầu tiên (13 ký tự):

   ((-*)-2&|*+:)

   ((-*)-2&|*+:) _10 _9 _8 _7 _6 _5 _4 _3 _2 _1 0 1 2 3 4 5 6 7 8 9 10
_9 10 _7 8 _5 6 _3 4 _1 2 0 _2 1 _4 3 _6 5 _8 7 _10 9

   ((-*)-2&|*+:) _9 10 _7 8 _5 6 _3 4 _1 2 0 _2 1 _4 3 _6 5 _8 7 _10 9
10 9 8 7 6 5 4 3 2 1 0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _10

Điều này hoạt động cho đầu vào số nguyên, nhưng điều này tạo ra đầu ra tưởng tượng cho các giá trị dấu phẩy động (hàm phải tạo đầu ra hợp lý cho đầu vào hợp lý theo thông số kỹ thuật)
Biến động

5
@Volatility, thông số kỹ thuật khó hiểu, nhưng khi tôi đọc nó, nó cho phép hạn chế tên miền và tên miền đối với số nguyên.
Peter Taylor

Bạn có cần dấu ngoặc đơn không?
Cyoce

14

Con trăn: 61 34 30 29 27 điểm

f: Q -> Q

trong toán học:

       | 0.5-x   if x is in Q \ Z
f(x) = |
       | x+0.5   if x is in Z

trong Python:

f=lambda x:.5+[x,-x][x%1>0]

thử nghiệm với

filter(lambda n: n[0] != -n[1], map(lambda n:(n,f(f(n))),range(0,50)))

logic đằng sau này:

Khi bạn lấy một số nguyên nvà đặt nó vào, fbạn sẽ nhận được x+0.5. Đây không phải là một số nguyên nữa, vì vậy ứng dụng tiếp theo sẽ 0.5-(x+0.5)-x.

Tín dụng

Nhờ vào

  • Bakuriu vì đã tước nó từ 61 ký tự xuống còn 34 ký tự.
  • Biến động để tiếp tục giảm kích thước mã xuống 30 ký tự.
  • sao chép để giảm kích thước mã xuống 29 ký tự (và khắc phục sự cố dấu phẩy động tiềm ẩn).
  • aditsu đã đề cập đến một sự không nhất quán đi kèm với những thay đổi ở trên.

Ghi chú

Đầu tiên tôi nghĩ rằng nó sẽ ổn thôi

f = lambda n: 1j*n

nhưng f: N-> C của nó và điều đó không được phép: - /


1
Có thể rút xuống: f=lambda x:x%1>0and(-x+x%1)or x+.1dài chỉ 34 ký tự.
Bakuriu

f=lambda x:[x+.1,x%1-x](x%1>0)chỉ 30
Biến động

1
Một char ngắn hơn : f=lambda x:[x+.5,.5-x][x%1>0]. Lưu ý việc sử dụng .5 thay vì .1 để giải quyết các vấn đề chính xác
sao chép

1
@AJMansfield 1.48 không phải là số nguyên.
Martin Thoma

1
Không, điều đó không có nghĩa. Nếu anh ta đề cập đến điều đó, anh ta nên viết "tất cả các số hữu tỷ". f:Q->Qkhông có nghĩa là f ánh xạ số hữu tỷ thành số hữu tỷ. Mà định nghĩa của tôi về f không.
Martin Thoma

11

C, 41 điểm (41 hoặc 45 ký tự)

Hoạt động bằng cả 32 và 64 bit.

f : Z -> Z(ngoại trừ INT_MAX):

f(n){return (abs(n)%2*2-1)*n+n?(-n<n)*2-1:0;}

Nếu chúng tôi không phải bao gồm, 0chúng tôi có thể cạo một số ký tự (41 ký tự):

f : Z -> Z(ngoại trừ 0& INT_MAX):

f(n){return (abs(n)%2*2-1)*n+(-n<n)*2-1;}

Hàm này hoạt động bằng cách chia tất cả các số nguyên thành 4 nhóm dựa trên dấu hiệu và tính chẵn lẻ của chúng.

Vì vậy, chúng tôi có 4 kết hợp khác nhau:

+ even, + odd, - even, - odd

Khi chúng ta cần chuyển đổi dấu của số, nhưng không phải là chẵn lẻ sau hai lần vượt qua, chúng ta sẽ nhận được hai chuỗi có thể khác nhau:

  + even -> - odd -> - even -> + odd -\
^-------------------------------------/

  + even -> + odd -> - even -> - odd -\
^-------------------------------------/

Trong ví dụ này tôi đã chọn cái đầu tiên.

Đầu tiên chúng ta cần ánh xạ tất cả các số nguyên dương chẵn thành các số nguyên âm lẻ. Chúng tôi thực hiện điều này bằng cách thay đổi dấu và tăng số (bạn cũng có thể chọn giảm số thay thế):

f1(n) = -n + 1

Sau đó, chúng ta cần ánh xạ tất cả các số nguyên âm lẻ sang các số nguyên âm. Chúng ta cần đảm bảo rằng f2(f1(n)) = -n:

f2(f1(n)) = -n
f2(-n + 1) = -n
f2(-n) = -n - 1
f2(n) = n - 1

Sử dụng các phương pháp tương tự mà chúng tôi tìm thấy f3f4:

f3(n) = -n - 1
f4(n) =  n + 1

Để kết hợp các chức năng này thành một chức năng duy nhất, chúng tôi quan sát rằng mỗi lần nchúng tôi chuyển đổi dấu hiệu nvà mỗi lần ntích cực, chúng tôi sẽ tăng thêm một và nếu không thì chúng tôi giảm dần theo một:

f1(n) = -n + 1 (+ even)
f2(n) =  n - 1 (- odd)
f2(n) = -n - 1 (- even)
f4(n) =  n + 1 (+ odd)

Điều này do đó có thể được viết lại như sau:

f(n) = odd(n) * n + sign(n)

trong đó odd(n)trả về 1cho số lẻ và -1cho số chẵn.

Có tổng cộng 4 giải pháp:

f(n) = odd(n) * n + sign(n)  (edge cases: f(f(0))  -> -2, f(f(INT_MAX))   -> -8)
f(n) = even(n) * n - sign(n) (edge cases: f(f(0))  -> -2, f(f(INT_MIN+1)) -> -6)
f(n) = odd(n) * n - sign(n)  (edge cases: f(f(1))  -> -3, f(f(INT_MIN))   -> -5)
f(n) = even(n) * n + sign(n) (edge cases: f(f(-1)) -> -1, f(f(INT_MIN))   -> -5)

INT_MINcó thể luôn luôn được coi là trường hợp cạnh trong cả 4 hàm là -INT_MIN == INT_MIN=> f(f(INT_MIN)) = INT_MIN.


Điều này về cơ bản giống như câu trả lời GolfScript của tôi (ngoại trừ giải thích rõ hơn). Điều này có làm việc cho 0 không?
Ben Reich

@BenReich Như đã nêu trong câu trả lời, nó không hoạt động 0và 3 số khác.
Tyilo

1
@Tylio Tôi thấy bây giờ. Có ý nghĩa. Có vẻ như bạn chỉ nên nhận phần Zthưởng nếu bạn bao gồm 0, ít nhất.
Ben Reich

@BenReich Đã xóa phần thưởng cho đến khi tôi sửa nó.
Tyilo

9

Đây là tôi đi vào nó.

long f(int i){return i;}
int f(long i){return -i;}

Ví dụ trực tiếp :

int main()
{
  for(int i=-10; i<10; i=i+3)
    std::cout << f(f(i)) << "\n";
}

Các loại đầu vào cn được tùy chỉnh phù hợp với nhu cầu của bạn. Phiên bản này hoạt động cho các chữ nguyên có độ lớn nhỏ hơn 2 ^ 32-1.


2
Vấn đề nói f:Q->Q, không phải f:Z->Z.
AJMansfield

@AJMansfield phần ghi điểm của thông số kỹ thuật có nghĩa là cung cấp điểm thưởng cho các chức năng được xác định f:Z->Z, xin lỗi vì từ ngữ khó hiểu
ardew

6
Vấn đề với câu trả lời này là nó xuất hiện để xác định hai hàm riêng biệt, trong khi thông số kỹ thuật yêu cầu bạn chỉ xác định một hàm. nhưng tôi không có ý bắt đầu một cuộc tranh luận về ngữ nghĩa, nó vẫn là một giải pháp rất chu đáo
vào

@ardnew, oh bạn nói đúng. Tôi đã được chỉ ra phản đối hợp lệ này chỉ vài giây trước khi chia sẻ nó với Lounge <C ++> trên trò chuyện SO. Tôi tự hỏi trình biên dịch tạo ra cái gì (nếu nó không thực hiện được các cuộc gọi), nhưng lắp ráp của tôi rất tệ.
rubenvb

1
Tôi nghĩ bạn có thể xóa khoảng trống trongreturn -i
Cyoce

6

JavaScript, 18

f=n=>n%1?.5-n:n+.5

Sử dụng ký hiệu mũi tên chất béo mới (Firefox 22).

Phiên bản khác (18):

f=n=>n%1?-.5/n:.5/n

Phiên bản trước (20):

f=n=>n-~~n?.5-n:n+.5

Thí dụ:

> [-3,-2,-1,1,2,3].map(f).map(f)
[3, 2, 1, -1, -2, -3]

10
Có vẻ như JavaScript đang phát triển thành CoffeeScript.
Peter Taylor

4

Toán học 18

f=#+1/2-4#(#-⌊#⌋)&

Đây ⌊...⌋là chức năng sàn. Nó chỉ sử dụng số hữu tỷ (không phải danh sách, số phức, v.v.)

f[10]
f[f[10]]

21/2

-10

f[-5]
f[f[-5]]

-9/2

5


3

ngôn ngữ lắp ráp x86 (FASM). Đối số và kết quả là trong đăng ký eax.

Nó hoạt động đúng cho -2 ^ 30 <N <+ 2 ^ 30-1

Mã thực thi 16 byte.

        use32

f_n:
        lea     edx, [2*eax]
        xor     edx, eax
        btc     eax, 30
        shl     edx, 1
        jnc     .end
        neg     eax
.end:
        retn

Nitpicking số của bạn; 2E30 sẽ là 2 * 10 ^ 30 chứ không phải 2 ^ 30 như tôi nghĩ bạn muốn.
Nick T

@NickT Sai lầm của tôi. Đã sửa.
johnfound

Tôi khá chắc chắn rằng bạn phải đếm các byte trong mã nguồn.
nyuszika7h

3

Lisp thường gặp: 35 byte

(defun f(x)(/(if(> 1 x)-1/2 1/2)x))

Lược đồ (và vợt): 36 byte

(define(f x)(/(if(> 1 x)-1/2 1/2)x))

Ungolfed với ý kiến ​​và giải thích:

(define (f x)
  (/             ;; divide
     (if (> 1 x) ;; if x is below 1 
         -1/2    ;; then -1/2 (the fraction)
         1/2)    ;; else 1/2 (the fraction)
      x))        ;; gets divided with x

Đối với bất kỳ số xtrong [1,->]những ifsẽ biến thành những phần nhỏ 1/2mà là một con số chính xác thực sự trong cả hai ngôn ngữ.

Phần chia sau đó sẽ trở thành (/ 1/2 x)phân số sẽ trở thành 1/(x*2)phần luôn nằm bên dưới 1. Đối với 1nó sẽ là 1/2, cho 21/4, vv

Đối với bất kỳ số nào dưới 1, ifnó sẽ chuyển thành phân số -1/2, điều này làm cho hàm thực hiện (/ -1/2 x)được -1/(2*x)nhưng vì chúng ta có thể mong đợi giá trị là kết quả của lần chạy trước, chúng ta có thể thay thế x cho 1 / (x * 2) tạo một ứng dụng kép-1/((1/(x*2))*2) = -x

Ví dụ, kể từ khi 1biến thành 1/2ứng dụng thứ hai là(/ -1/2 1/2) ==> -1


Cái này hoạt động ra sao?
AJMansfield

@AJMansfield đã thêm một số thông tin. Chỉ cần hỏi nếu có bất cứ điều gì không rõ ràng. Đọc cú pháp LISP giống như tiếng Hy Lạp nếu bạn chưa học nó và phải mất vài tuần để làm quen.
Sylwester

3

C, 60 (⌈66 * .9⌉)

int f(int x){if(!x&1||!~x)return ~x;if(x<0)return x-1;return x+1;}

Đây là một phiên bản không kiểm duyệt:

int f(int x){
    if(!x&1 || !~x) return ~x;
    if(x<0) return x-1;
    return x+1;
}

Phương pháp này hoạt động chỉ sử dụng số nguyên, do đó, nó được thưởng 90% điểm. Ban đầu tôi đã viết nó bằng java, nhưng nhận ra rằng chương trình này đặc biệt có thể được hưởng lợi từ các toán tử logic kiểu C.

Vì không có số nguyên tương ứng với -INT_MIN, f(f(INT_MIN))trả về INT_MINthay thế.

Ánh xạ cơ bản là đại số khá đơn giản. Thực hiện câu lệnh x=f(x)thay thế x bằng:

  • x+1, nếu xlà tích cực và lẻ
  • -x+1, nếu xlà tích cực và thậm chí
  • x-1, nếu xlà âm và lẻ
  • -x-1, nếu xlà âm và thậm chí

Kết quả của mỗi trường hợp sẽ thuộc trường hợp tiếp theo vào lần tiếp theo hàm được áp dụng cho x.

Như bạn có thể thấy, soạn một trường hợp với trường hợp theo sau nó mang lại -x.

Mã này là kết quả của một số đơn giản hóa thông minh của hàm để tận dụng cấu trúc bit của các số nguyên khen của hai.


3

> <> , 21 + 3 = 24 byte, 22 điểm

:0)$:0($:1$2%2*-*+-n;

Sử dụng trình thông dịch Python chính thức và sử dụng -vtùy chọn dòng lệnh để nhập dữ liệu vào, với chi phí là 3 byte.

Tôi có cảm giác rằng điều này có thể tốt hơn - tôi sẽ tiếp tục nhìn vào nó và cố gắng đánh nó xuống.

Đưa ra đầu vào n, đầu ra chương trình

(n>0) - ((n<0) + n * (1 - 2*(n%2)))

ở đâu (n>0)(n<0)là booleans. Điều này tương đương với câu trả lời Python của Gelatin

(n>0) - (n<0) - n * (-1)**n

nhưng ><>không có toán tử lũy thừa tích hợp nên chúng tôi sử dụng (1 - 2*(n%2))thay thế (-1)**n.

Điều gì sau đây là lý thuyết toán học - đọc nếu (và chỉ khi) bạn quan tâm:

Với bất kỳ chức năng f: Z -> Znào f(f(n)) = -ncho tất cả ntrong Z, chúng ta thấy ngay rằng f(f(f(f(n)))) = n, hay nói cách khác, f^4là chức năng nhận dạng. Cụ thể, flà không thể đảo ngược, và chức năng nghịch đảo của nó là f^3. Như vậy flà một hoán vị của Z, và vì f^4 = Id, nó sau đó mỗi quỹ đạo (hay chu kỳ) của fcó kích thước hoặc 1, 2hoặc 4.

Tiếp theo, chúng ta thấy điều đó f(0) = 0. Bằng chứng:, f(0) = f(-0) = f(f(f(0))) = -f(0)vì vậy f(0) = 0, như mong muốn. Ngược lại, giả sử xlà trong một chu kỳ dài 1hoặc 2, vì vậy f(f(x)) = x. Sau đó là -x = xnhư vậy x = 0.

Do đó, fđược tạo thành hoàn toàn từ 4 chu kỳ, ngoại trừ điểm cố định (1 chu kỳ) tại 0.

Hơn nữa, cứ sau 4 chu kỳ phải có dạng (x, y, -x, -y)và bằng cách xoay vòng theo chu kỳ, chúng ta có thể cho rằng xycả hai đều dương. Ngược lại, mỗi sản phẩm như vậy của phân vùng 4 chu kỳ các số nguyên khác không xác định lựa chọn f.

Do đó, mỗi lựa chọn ftương ứng duy nhất với một đồ thị có hướng có các đỉnh là các số nguyên dương, sao cho mọi đỉnh là sự cố với chính xác một mũi tên, nhập hoặc thoát. Chính xác hơn, trong đồ thị vô hướng cơ bản, mọi đỉnh đều có độ chính xác 1. (Mỗi 4 chu kỳ (x y -x -y)xydương tương ứng với mũi tên x --> y.)

Các chức năng trong câu trả lời này (và nhiều câu trả lời khác ở đây) tương ứng với đồ thị ở đâu 1 --> 2, 3 --> 4và nói chung 2k-1 --> 2k.

Các biểu đồ như vậy được sắp xếp theo thứ tự vô hạn của các cặp theo thứ tự (a_n, p_n), trong đó mỗi cặp a_nlà một số nguyên dương và mỗi số p_nlà một 0hoặc 1: cho một chuỗi (a_1, p_1), (a_2, p_2), (a_3, p_3), ..., trước tiên chúng ta ghép 1với nhau 1 + a_1, và sau đó chúng ta tạo thành mũi tên 1 --> 1 + a_1hoặc mũi tên 1 + a_1 --> 1tùy thuộc vào việc p_10hay không 1. Về cơ bản, mũi tên là một <dấu hiệu hoặc một >dấu hiệu, tùy thuộc vào tính chẵn lẻ của p_1.

Tiếp theo, lấy số nguyên dương chưa ghép cặp nhỏ nhất kvà đếm từ k, chính xác a_2các bước, SK Picks bất kỳ số nào đã được ghép với một cái gì đó. Ghép nối kvới kết quả và đặt hướng của mũi tên tùy thuộc vào p_2như trên. Sau đó lặp lại với (a_3, p_3), vv

Mỗi mũi tên cuối cùng sẽ được xác định theo cách này, vì vậy quá trình được xác định rõ. Hàm trong câu trả lời này tương ứng với chuỗi (1,0), (1,0), (1,0), ..., vì tại bước nsố nguyên không ghép đôi nhỏ nhất 2n-1và không có số nguyên nào lớn hơn 2n-1đã được ghép với bất cứ thứ gì, vì vậy chúng tôi nhận được 2n-1 --> 2ncho mỗi n(mũi tên được định hướng theo cách này vì mỗi số p_nbằng nhau 0).

Cardinality của bộ này là (N*2)^N = N^N, mà ở đoạn cuối của câu trả lời này bằng 2^N, cardinality của các số thực.


Các tùy chọn dòng lệnh thường là một byte mỗi.
con mèo

@cat Xem phần "Yêu cầu đặc biệt" tại bài đăng meta này .
mathmandan

2

Để sửa câu trả lời J trước đó (Tôi không đủ uy tín để nhận xét về bản gốc):

(*+[*1-~2*2|])

Nó chỉ thay thế _1&^với 1-~2*2|], cho dấu hiệu ngược lại. Vì vậy, tôi đã thay đổi -thành một +(chỉ quan trọng trên đầu vào của 1_1).

Dưới đây là các bài kiểm tra:

   (*+[*1-~2*2|])6 3 _9 _8 1r2 _4.6 0 1 _1
7 _2 8 _9 1 7.28 0 2 _2
   (*+[*1-~2*2|])7 _2 8 _9 1 7.28 0 2 _2
_6 _3 9 8 0 _10.3568 0 _1 1

   NB. f^:2 = f@:f
   (*+[*1-~2*2|])^:(2)6 3 _9 _8 1r2 _4.6 0 1 _1
_6 _3 9 8 2 _5.0832 0 _1 1

Như bạn có thể thấy, miền và phạm vi là của tất cả các số thực, nhưng nó chỉ hoạt động cho các số nguyên (bao gồm 0).

Giải trình:

(   *     + [ *  1-~    2*     2|]    )
 signum n + n * pred (twice (n mod 2))

2

GolfScript ceiling(26*.9)=24

Golfscript chỉ xử lý số nguyên, do đó, áp dụng phần Zthưởng cho tổng cộng 24 điểm:

.{..0>2*(\)2%!2*(@*+}{ }if

Trường hợp đặc biệt 0 tài khoản cho 8 ký tự. Bỏ qua 0, chúng ta có thể có câu trả lời 17 điểm:

..0>2*(\)2%!2*(@*+

Mã này thực hiện như sau với một số nguyên xtrên đầu ngăn xếp:

  • Nếu xlà 0, để lại 0trên ngăn xếp và không áp dụng quy tắc nào nữa.
  • Nếu xlà chẵn, phủ định x.
  • Nếu xlà tích cực, thêm 1.
  • Nếu xlà âm, trừ 1.

Điều này kết nối một cách hợp lý các bộ 4 số trong một chu kỳ, trong đó fđi qua các phần tử của chu kỳ và các góc đối diện của chu kỳ là các số âm của nhau. Mỗi số nguyên là một phần của chính xác 1 chu kỳ như vậy, ngoại trừ 0 là trường hợp đặc biệt. Ví dụ {-8, -7, 7, 8}: cho :

  • 7 f -> 8
  • 8 f -> -7
  • -7 f -> -8
  • -8 f -> 7

Các trường hợp thử nghiệm có liên quan duy nhất tôi có thể nghĩ là một số lẻ âm, chẵn âm, lẻ dương, dương chẵn 0, và sau đó tôi đã ném vào -11vì sự gần gũi của chúng 0có thể gây ra vấn đề:

[-10 -5 -1 0 1 5 10]
{.{..0>2*(\)2%!2*(@*+}{ }if}:f;
{f f}%
-> [10,5,1,0,-1,-5,-10]

Tôi chắc chắn rằng GolfScript thực tế có thể được cải thiện phần nào. Nó không cảm thấy như nó sẽ mất 26 ký tự! Rất thích nghe một số gợi ý.


2

Java, chỉ để cho vui

Đây là một triển khai thực hiện một mệnh đề thực tế giữa và ℤ², đây là một hàm lẻ cùng một lúc (g (-x) == -g (x)). Nó coi phần tử ℤ² tương ứng là một số phức và nhân nó với "i", sau đó chuyển đổi thành.

f (x) = g⁻¹ (ig (x))
f (f (x)) = g⁻¹ (-g (x)) = - x

Hàm chạy trong O (1).

public class Ffn {
    public static int f(int n) {
        if (n == 0) {
            return 0;
        }
        // adjust sign
        int s = n > 0 ? 1 : -1;
        int m = n * s;
        // calculate square "radius"
        int r = (int) (Math.sqrt(2 * m - 1) + 1) / 2;
        int q = r * 2;
        // starting point
        int x = r, y = r;
        int k = q * (r - 1) + 1;

        if (m - k < q) {
            // go left
            x -= m - k;
        }
        else {
            // go left
            x -= q;
            // go down
            y -= m - k - q;
        }

        // multiply by i
        int x2 = -y * s, y2 = x * s;
        // adjust sign
        s = y2 < x2 || y2 == x2 && x2 < 0 ? -1 : 1;
        x2 *= s;
        y2 *= s;

        if (y2 == r) {
            // go left
            k += r - x2;
        }
        else {
            // go left and down
            k += q + r - y2;
        }
        return k * s;
    }

    public static void main(final String... args) {
        for (int i = 0; i < 1000000; ++i) {
            if (f(f(i)) != -i || f(f(-i)) != i) {
                System.out.println(i);
            }
        }
    }
}

Chúc mừng năm mới


Tôi tin rằng khoảng trắng là không cần thiết.
pppery

2

Trăn 3 - 38

Tương tự như câu trả lời của @ moose, nhưng , f(n) == n. Hoạt động cho tất cả các giá trị số nguyên.

f=lambda x:x*(isinstance(x,int)*2.0-1)

2

Perl, 33 (không phải khoảng trắng)

sub f{($=)=@_;$=-$_[0]?-$=:"$=.1"}

Biên tập:

  • $=.".1"rút ngắn lại "$=.1"(cảm ơn ardew).

Môn Toán:

môn Toán

Ung dung:

# script.pl
sub f {
  ($=) = @_;   # short for $= = int($_[0]); 
               # "int" is implicit in assignments to $=;
               # ($=) can be prepended by "local" to get
               # the function free of side effects.

  $= - $_[0] ? # short for $= != $_[0], check if input is integer
    -$=        # input is not an integer  
  : $= . ".1"  # input is integer
}  

# Testing
chomp;
$_ = sprintf "f(f($_)) = f(%s) = %s\n", f($_), f(f($_));

Ví dụ:

perl -p script.pl
7
f(f(7)) = f(7.1) = -7
2
f(f(2)) = f(2.1) = -2
0
f(f(0)) = f(0.1) = 0
-1
f(f(-1)) = f(-1.1) = 1
-10
f(f(-10)) = f(-10.1) = 10
-1.23
f(f(-1.23)) = f(1) = 1.1
3.4
f(f(3.4)) = f(-3) = -3.1
1.0
f(f(1.0)) = f(1.1) = -1

giải pháp mạnh mẽ - các trường hợp kiểm tra điểm nổi mà bạn không yêu cầu cho mỗi thông số kỹ thuật (nên đã cung cấp điểm thưởng cho điều đó!). Đây là thuật toán tương tự của bạn với một vài lần dọn dẹp vào lúc 22 ký tự:sub f{yzxzzc?-$_:x.$_}
ardew

1
@ardnew: Cảm ơn. Nhưng tôi không đồng ý rằng giải pháp của bạn sử dụng cùng một thuật toán. Thuật toán không phảisub f{yzxzzc?-$_:x.$_} là trạng thái tự do, nó sử dụng trạng thái thông qua biến . Bởi vì điều này, không còn là một hàm (theo nghĩa toán học), bởi vì các giá trị khác nhau có thể cho cùng một giá trị đầu vào tùy thuộc vào trạng thái (thời tiết có chứa hay không). Thuật toán của tôi không sử dụng trạng thái, Thông tin được mã hóa trong giá trị đầu ra. Số nguyên được chuyển đổi thành số thực bằng cách thêm . Và số thực được chuyển đổi trở lại số nguyên với dấu hiệu chuyển đổi. $_f$_x.1
Heiko Oberdiek

thú vị - không có dữ liệu trạng thái nào được sử dụng trong quá trình thực hiện của bạn sự phân công ban đầu và không phải vì một số thuộc tính đặc biệt của $=?
ardew

tôi đã không nhận ra tôi cũng đã thất bại yêu cầu của riêng tôi ( fđược xác định Q->Q) với xchar đó . cũng $=.".1"có thể rút ngắn thành"$=.1"
ardew

@ardnew: Thuộc tính đặc biệt của $=chỉ là nó chỉ lấy số nguyên. Điều tương tự có thể đạt được bằng cách sử dụng một biến thông thường : $a=int$_[0]. Nhưng chi phí thêm ba byte vì chức năng int.
Heiko Oberdiek

2

Julia, 26

julia> f(n::Int)=n//1
f (generic function with 1 method)
julia> f(n)=int(-n)
f (generic function with 2 methods)
julia> f(f(4))
-4

Không siêu cạnh tranh, nhưng rất Julian vì nó phụ thuộc vào nhiều công văn. Nó chỉ làm cho Rational hợp lý nếu nó là Int hoặc int có dấu trừ nếu nó là bất cứ thứ gì khác. Người ta có thể phản đối rằng đây là 2 hàm, nhưng Julia coi đây là một hàm với hai phương thức và nó tương đương với việc xác định một hàm với một biểu tượng if trên loại n.


Đó không phải là điều mà một nhà toán học sẽ gọi là hàm: trong Julia 3==3//1trả về truenhưng f(3//1)==f(3)trả về false.
Omar

2

Kẹo , 20 18 byte

Sử dụng 3 -> 4 -> -3 -> -4 -> 3 mẹo.

~A2%{|m}1A0>{+|-}.

Để gọi nó, sử dụng công tắc -i trên trình thông dịch

Ví dụ về phép gọi kép:

$ candy -i 7 -e '~A2%{|m}1A0>{+|-}.'
program length: 18
>>> 8
$ candy -i 8 -e '~A2%{|m}1A0>{+|-}.'
program length: 18
>>> -7
$ candy -i -7 -e '~A2%{|m}1A0>{+|-}.'
program length: 18
>>> -8
$ candy -i -8 -e '~A2%{|m}1A0>{+|-}.'
program length: 18
>>> 7

Hình thức dài:

peekA
pushA
digit2
mod          # even/odd
if
else
  negate     # negate even numbers
endif
digit1
pushA
digit0
greater      # positive/negative
if
  add        # add two numbers from stack (original stack value, and delta)
else
  sub        # diff two numbers from stack (original stack value, and delta)
endif
retSub

2

APL Dyalog, 9 điểm

×-⍨⊢ׯ1*⊢

Nguồn dài 9 byte và đủ điều kiện nhận tiền thưởng (hoàn toàn không giúp ích gì). Nó cũng sử dụng công thức từ câu trả lời SO hàng đầu.




1

Java, 113 byte

Cách tiếp cận khá đơn giản. Nó đã kết thúc nhiều byte hơn tôi dự đoán, nhưng có lẽ có thể bị đánh gôn xuống một chút.

public class F{public static int f(int x){if(x<0)x+=-2147483647-++x;x+=1073741824;return x<0?-2147483647-++x:x;}

Về cơ bản, nó tạo ra 4 "khu vực" khác nhau của x, sử dụng thực tế là Java vui vẻ cho phép các biến bao quanh. Tôi đã phải thực hiện một số chuyển đổi khó khăn cho các số âm, đó là lý do chính khiến việc này kết thúc lớn hơn dự đoán.

Hoạt động cho tất cả x ngoài -2147483648.


1

Cùng một dãy số (3, 4, -3, -4, 3 ...) như câu trả lời của golf, nhưng được thực hiện theo perl (42 ký tự sau khi khoảng trắng bị tước)

sub f{($_[0]%2?1:-1)*$_[0]+($_[0]<0?-1:1)}

Dễ đọc hơn:

sub f { ($_[0] % 2 ? $_[0] : -$_[0] ) + ( $_[0] < 0 ? -1 : 1 ) }

Hoặc thậm chí rõ ràng hơn:

sub f {
  my $n = shift;
  my $sign = $n >= 0 ? 1 : -1;
  # note that in perl $n % 2 is the same as int($n) % 2
  if( $n % 2 ) {
    # odd: add one to magnitude
    return $n + $sign
  } else {
    # even: subtract one from magnitude then invert
    return -($n - $sign)
  }
}

Đầu ra:

ski@anito:~/mysrc/.../acme$ echo 3 | perl -e 'sub f{($_[0]%2?1:-1)*$_[0] + ($_[0]<0?-1:1)}; my $x = <>; for(0..10) { print "$_: $x\n"; $x = f($x); }'
0: 3
1: 4
2: -3
3: -4
4: 3
5: 4
6: -3
7: -4
8: 3
9: 4
10: -3

Ở trên cũng hoạt động cho những người không có số nguyên: Ski @ anito: ~ / mysrc /.../ acme $ echo 1.1234 | perl -e 'sub f {($ _ [0]% 2? 1: -1) * $ _ [0] + ($ _ [0] <0? -1: 1)}; $ x = <> của tôi; cho (0..4) {in "$ _: $ x \ n"; $ x = f ($ x); } '0: 1.1234 1: 2.1234 2: -1.1234 3: -2.1234 4: 1.1234
skibrianski

1

Sed, 25 byte.

|sed s/0+/0-/|sed s/^/0+/

Sử dụng:

$ echo 1.23 |sed s/0+/0-/|sed s/^/0+/
0+1.23
$ echo 0+1.23 |sed s/0+/0-/|sed s/^/0+/
0+0-1.23

1

Matlab, 26 ký tự

f=@(n) (n<0)-(n<0)-n*(-1)^n

2
Đây không phải là một câu trả lời hợp lệ, vì tên miền và tên miền của hàm không được phức tạp.
Wrzlprmft

ồ, tôi xin lỗi ... tôi chỉ đọc tiêu đề và không cẩn thận ... Hãy xem liệu tôi có thể chỉnh sửa phần nào không
bla

1

C ++ - 63 55.8

Đây là giao diện của mã:

int f(int n){return (n&45056?n^45056:n|45056)*(n&45056?-1:1);}

Nó không hoạt động trên các số nguyên có byte thứ tư bằng 0xB vì nó sử dụng giá trị đó để theo dõi các lượt đi. Mặt khác hoạt động trên bất kỳ thành viên nào của Z, kể cả zero.


bạn có thể giải thích điều này? ở lần kiểm tra đầu tiên, có vẻ như bạn đang giữ một bộ đếm các cuộc gọi đến fvới một biến tĩnh. Nhưng sau đó, quan điểm của những sqrtgì?
ardew

Tôi dường như đã hiểu sai câu hỏi; nghĩ rằng một biến tĩnh là ổn vì C ++ là ngôn ngữ hướng ngăn xếp, nhưng tôi sẽ sửa mã. Mặt khác, tôi không biết tại sao tôi cần sqrtvì nó được làm tròn xuống bằng kiểu đúc. Tôi sẽ cấu trúc lại nó để nó hoạt động mà không có biến tĩnh.
Darkgamma

Tôi không biết bạn lấy 55.8từ đâu, nhưng mã hiện tại của bạn dài 62 byte. Chỉnh sửa: Đừng bận tâm, tôi đã không đọc câu hỏi đúng.
nyuszika7h

Hạn chế rằng byte thứ tư không thể bằng 0xB không may làm cho điều này không phải là một câu trả lời hợp lệ cho thách thức, đòi hỏi nó phải hoạt động trên (ít nhất) tất cả các số nguyên.
pppery

1

Được cập nhật với chức năng được cung cấp bởi Synthetica (rõ ràng là người sẽ nhận được tín dụng cho việc này ngay bây giờ)

Ngôn ngữ: Python

Số lượng ký tự: 41 bao gồm cả khoảng trắng

f=lambda x:-float(x) if str(x)==x else`x`

Vui lòng cung cấp tên của ngôn ngữ mà bạn đã sử dụng cũng cung cấp số lượng ký tự.
Chương trìnhFOX

Tôi thích cách này cũng hoạt động với các số nguyên. Làm tốt. :)
cjfaure

f=lambda x:-float(x) if str(x)==x else`x`ngắn hơn một chút: 41 bao gồm cả khoảng trắng
ɐɔɐɔ

Cảm ơn Synthetica, tôi thậm chí còn không biết về thủ thuật backticks! : D
HolySquirrel

Trên số nguyên ftrả về một chuỗi; đặc điểm kỹ thuật nói rằng nó phải trả về một số hữu tỷ.
Omar

1

Prolog, 36 byte

Mã số:

X*Y:-X//1=:=X,Y is 0.5+X;Y is 0.5-X.

Giải thích:

Dyadic predicate which converts integers to floats and floats back to negated integers.

Thí dụ:

10*X.
X = 10.5

10*Y,Y*X.
X = -10,
Y = 10.5


1

Chuột-2002 , 21 19 12 byte

$A1%[1%_|1%]

Xác định một hàm A; gọi nó như thế nào #A,#A,?;;(sẽ chờ người dùng nhập bất kỳ số nào). Ngoài ra, gọi nó như thế #A,#A,n;;nlà bất kỳ số.


1

Julia, 21

f(x)=(1-2(1>x>-1))/2x

Sau đó

julia> f(f(12//1))
-12//1

p // q là ký hiệu theo nghĩa đen của julia về các số hữu tỷ.

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.