पर्ल - 116 बाइट्स 87 बाइट्स (नीचे अपडेट देखें)
#!perl -p
$.<<=1,$_>>=2until$_&3;
{$n=$_;@a=map{$n-=$a*($a-=$_%($b=1|($a=0|sqrt$n)>>1));$_/=$b;$a*$.}($j++)x4;$n&&redo}
$_="@a"
शेबबैंग को एक बाइट के रूप में गिना, क्षैतिज पवित्रता के लिए नई कड़ियाँ जोड़ी गईं।
कुछ संयोजन कोड-गोल्फ सबसे तेज़-कोड सबमिशन।
औसत (सबसे खराब?) मामला जटिलता ओ (लॉग एन) ओ (एन 0.07 ) लगता है । कुछ भी नहीं मैंने 0.001 के मुकाबले धीमी गति से रन पाया है, और मैंने 900000000 - 999999999 से पूरी श्रृंखला की जाँच की है । यदि आपको ऐसा कुछ मिलता है, जो उससे अधिक समय लेता है, ~ 0.1 या अधिक, तो कृपया मुझे बताएं।
नमूना उपयोग
$ echo 123456789 | timeit perl four-squares.pl
11110 157 6 2
Elapsed Time: 0:00:00.000
$ echo 1879048192 | timeit perl four-squares.pl
32768 16384 16384 16384
Elapsed Time: 0:00:00.000
$ echo 999950883 | timeit perl four-squares.pl
31621 251 15 4
Elapsed Time: 0:00:00.000
इनमें से अंतिम दो अन्य सबमिशन के लिए सबसे बुरी स्थिति हैं। दोनों उदाहरणों में, दिखाया गया समाधान वास्तव में जाँच की गई पहली चीज़ है। के लिए 123456789, यह दूसरा है।
यदि आप मानों की श्रेणी का परीक्षण करना चाहते हैं, तो आप निम्न स्क्रिप्ट का उपयोग कर सकते हैं:
use Time::HiRes qw(time);
$t0 = time();
# enter a range, or comma separated list here
for (1..1000000) {
$t1 = time();
$initial = $_;
$j = 0; $i = 1;
$i<<=1,$_>>=2until$_&3;
{$n=$_;@a=map{$n-=$a*($a-=$_%($b=1|($a=0|sqrt$n)>>1));$_/=$b;$a*$i}($j++)x4;$n&&redo}
printf("%d: @a, %f\n", $initial, time()-$t1)
}
printf('total time: %f', time()-$t0);
सबसे अच्छा जब एक फ़ाइल के लिए पाइप। रेंज 1..1000000मेरे कंप्यूटर पर लगभग 14s लेता है (प्रति सेकंड 71000 मान), और सीमा O (लॉग एन) औसत जटिलता के 999000000..1000000000साथ संगत लगभग 20s (50000 मान प्रति सेकंड) लेता है।
अपडेट करें
संपादित करें : यह पता चलता है कि यह एल्गोरिदम एक के समान है जो कि मानसिक कैलकुलेटर द्वारा कम से कम एक सदी के लिए उपयोग किया गया है ।
मूल रूप से पोस्टिंग के बाद से, मैंने 1..1000000000 से सीमा पर हर मूल्य की जांच की है । 699731569 मूल्य द्वारा 'सबसे खराब स्थिति' व्यवहार का प्रदर्शन किया गया , जिसने एक समाधान पर पहुंचने से पहले 190 संयोजनों का एक शानदार परीक्षण किया । यदि आप 190 को एक छोटा स्थिरांक मानते हैं - और मैं निश्चित रूप से करता हूं - आवश्यक सीमा पर सबसे खराब मामला व्यवहार ओ (1) माना जा सकता है । यही कारण है कि, एक विशाल मेज से समाधान की तलाश में जितनी तेजी से, और औसतन, संभवतः काफी तेज है।
हालांकि एक और बात। 190 पुनरावृत्तियों के बाद , 144400 से बड़ा कुछ भी पहले पास से आगे नहीं बढ़ा । चौड़ाई-प्रथम ट्रैवर्सल के लिए तर्क बेकार है - इसका उपयोग भी नहीं किया जाता है। उपरोक्त कोड को थोड़ा छोटा किया जा सकता है:
#!perl -p
$.*=2,$_/=4until$_&3;
@a=map{$=-=$%*($%=$=**.5-$_);$%*$.}$j++,(0)x3while$=&&=$_;
$_="@a"
जो केवल खोज का पहला पास करता है। हमें इस बात की पुष्टि करने की आवश्यकता है कि 144400 से नीचे कोई मान नहीं है जिसे दूसरे पास की आवश्यकता थी, हालांकि:
for (1..144400) {
$initial = $_;
# reset defaults
$.=1;$j=undef;$==60;
$.*=2,$_/=4until$_&3;
@a=map{$=-=$%*($%=$=**.5-$_);$%*$.}$j++,(0)x3while$=&&=$_;
# make sure the answer is correct
$t=0; $t+=$_*$_ for @a;
$t == $initial or die("answer for $initial invalid: @a");
}
संक्षेप में, सीमा 1..1000000000 के लिए , एक निकट-स्थिर समय समाधान मौजूद है, और आप इसे देख रहे हैं।
अद्यतन अद्यतन
@ डेनिस और मैंने इस एल्गोरिथ्म में कई सुधार किए हैं। आप नीचे दी गई टिप्पणियों में प्रगति का पालन कर सकते हैं, और बाद में चर्चा कर सकते हैं, अगर वह आपकी रुचि रखता है। आवश्यक सीमा के लिए पुनरावृत्तियों की औसत संख्या केवल 4 से घटकर 1.229 हो गई है , और 1..1000000000 के लिए सभी मानों का परीक्षण करने के लिए आवश्यक समय 18m 54 से सुधर कर 2m 41s हो गया है। पहले सबसे खराब स्थिति में 190 पुनरावृत्तियों की आवश्यकता थी ; सबसे खराब स्थिति, अब 854382778 , केवल 21 की जरूरत है ।
अंतिम पायथन कोड निम्नलिखित है:
from math import sqrt
# the following two tables can, and should be pre-computed
qqr_144 = set([ 0, 1, 2, 4, 5, 8, 9, 10, 13,
16, 17, 18, 20, 25, 26, 29, 32, 34,
36, 37, 40, 41, 45, 49, 50, 52, 53,
56, 58, 61, 64, 65, 68, 72, 73, 74,
77, 80, 81, 82, 85, 88, 89, 90, 97,
98, 100, 101, 104, 106, 109, 112, 113, 116,
117, 121, 122, 125, 128, 130, 133, 136, 137])
# 10kb, should fit entirely in L1 cache
Db = []
for r in range(72):
S = bytearray(144)
for n in range(144):
c = r
while True:
v = n - c * c
if v%144 in qqr_144: break
if r - c >= 12: c = r; break
c -= 1
S[n] = r - c
Db.append(S)
qr_720 = set([ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121,
144, 145, 160, 169, 180, 196, 225, 241, 244, 256, 265, 289,
304, 324, 340, 361, 369, 385, 400, 409, 436, 441, 481, 484,
496, 505, 529, 544, 576, 580, 585, 601, 625, 640, 649, 676])
# 253kb, just barely fits in L2 of most modern processors
Dc = []
for r in range(360):
S = bytearray(720)
for n in range(720):
c = r
while True:
v = n - c * c
if v%720 in qr_720: break
if r - c >= 48: c = r; break
c -= 1
S[n] = r - c
Dc.append(S)
def four_squares(n):
k = 1
while not n&3:
n >>= 2; k <<= 1
odd = n&1
n <<= odd
a = int(sqrt(n))
n -= a * a
while True:
b = int(sqrt(n))
b -= Db[b%72][n%144]
v = n - b * b
c = int(sqrt(v))
c -= Dc[c%360][v%720]
if c >= 0:
v -= c * c
d = int(sqrt(v))
if v == d * d: break
n += (a<<1) - 1
a -= 1
if odd:
if (a^b)&1:
if (a^c)&1:
b, c, d = d, b, c
else:
b, c = c, b
a, b, c, d = (a+b)>>1, (a-b)>>1, (c+d)>>1, (c-d)>>1
a *= k; b *= k; c *= k; d *= k
return a, b, c, d
यह दो पूर्व-संकलित सुधार तालिकाओं का उपयोग करता है, आकार में एक 10kb, अन्य 253kb। उपरोक्त कोड में इन तालिकाओं के लिए जनरेटर फ़ंक्शन शामिल हैं, हालांकि इनका संकलन समय पर किया जाना चाहिए।
अधिक विनम्र आकार के सुधार तालिकाओं वाला एक संस्करण यहां पाया जा सकता है: http://codepad.org/1ebJC2OV इस संस्करण में प्रति टर्म औसतन 1.620 पुनरावृत्तियों की आवश्यकता होती है , जिसमें 38 का सबसे खराब मामला होता है , और पूरी रेंज लगभग 3 से 21 वर्ष में चलती है। बी केand लिए बिटवाइज़ का उपयोग करके, थोड़ा समय बनाया जाता हैमॉडुलो के बजाय करेक्शन के जाता है।
सुधार
यहां तक कि मान भी विषम मानों की तुलना में एक समाधान का उत्पादन करने की अधिक संभावना रखते हैं।
मानसिक गणना लेख पहले के नोटों से जुड़ा हुआ है कि यदि, चार के सभी कारकों को हटाने के बाद, विघटित होने का मूल्य सम है, तो इस मान को दो से विभाजित किया जा सकता है, और समाधान का पुनर्निर्माण किया जा सकता है:

यद्यपि यह मानसिक गणना के लिए समझ में आता है (छोटे मानों को गणना करना आसान हो जाता है), यह एल्गोरिदमिक रूप से बहुत अर्थ नहीं देता है। यदि आप 256 रैंडम 4 -टुपल्स लेते हैं, और वर्गों के योग 8 की जांच करते हैं , तो आप पाएंगे कि मान 1 , 3 , 5 और 7 प्रत्येक औसत 32 बार पहुंच गए हैं । हालाँकि, मान 2 और 6 प्रत्येक 48 बार तक पहुँच चुके हैं। 2 से विषम मानों को गुणा करने पर, औसतन 33% कम पुनरावृत्तियों में एक समाधान मिलेगा । पुनर्निर्माण निम्नलिखित है:

देखभाल करने की आवश्यकता है कि ए और बी में समान समानता है, साथ ही साथ सी और डी भी है , लेकिन अगर कोई समाधान सभी में पाया गया, तो एक उचित आदेश मौजूद होने की गारंटी है।
असंभव रास्तों की जाँच करने की आवश्यकता नहीं है।
दूसरे मूल्य का चयन करने के बाद, बी , किसी समाधान के लिए पहले से ही असंभव हो सकता है, किसी भी दिए गए मोडो के लिए संभव द्विघात अवशेष। वैसे भी जाँच करने के बजाय, या अगली यात्रा पर जाने के बाद, b का मान छोटी मात्रा द्वारा इसे घटाकर 'सुधारा' जा सकता है जो संभवतः समाधान का कारण बन सकता है। दो सुधार तालिकाएँ इन मानों को संग्रहीत करती हैं, एक b के लिए और दूसरा c के लिए । उच्च मॉडुलो का उपयोग करना (अधिक सटीक रूप से, अपेक्षाकृत कम द्विघात अवशेषों के साथ मोडुलो का उपयोग करना) बेहतर परिणाम देगा। मूल्य एक किसी भी सुधार की जरूरत नहीं है; n को भी संशोधित करके , सभी मानों कोa वैध हैं।