39 बाइट्स हो रही हैं
यह एक विवरण है कि मुझे 39-बाइट समाधान कैसे मिला, जो डेनिस और जोनाथनफ्र्रेच ने अलग-अलग पाया। या, बल्कि, यह बताता है कि कोई व्यक्ति उत्तर में कैसे पहुंच सकता है, एक तरह से यह मेरे वास्तविक मार्ग की तुलना में बहुत अच्छा है, जो कीचड़ युक्त तर्क और मृत सिरों से भरा था।
n=0
exec"print n;n=n+2^-(n+2^n)%3;"*400
यह थोड़ा कम गोल्फ और अधिक parens के साथ लेखन, यह इस तरह दिखता है:
n=0
for _ in range(400):
print n
n=(n+2)^(-((n+2)^n))%3
बिट समानताएँ
हम अपने 47-बाइट समाधान से एक विचार के साथ शुरू करते हैं कि फॉर्म के सभी नंबरों को आउटपुट करने के लिए n=2*k+bजहां kगिनती होती है 0,1,...,399और bएक समता बिट है जो समग्र संख्या 1 को भी बनाता है।
par(x)की बिट समता के लिए लिखते हैं x, कि ^सभी में बिट्स का xor ( ) है x। यह 0 है यदि 1-बिट्स की संख्या समान है (संख्या बुराई है), और यदि 1-बिट्स की विषम संख्या है। इसके लिए n=2*k+b, हमारे पास par(n) = par(k)^bबुराई को प्राप्त करने की par(n)==0आवश्यकता है b=par(k), अर्थात nपूर्ववर्ती बिट्स की थोड़ी समानता होना।
गोल्फ में मेरी पहली प्रयासों को व्यक्त करने पर थे par(k), पहले सीधे पर साथ bin(k).count('1')%2साथ, और फिर थोड़ा हेरफेर ।
समता अद्यतन
फिर भी, एक छोटी अभिव्यक्ति प्रतीत नहीं हुई। इसके बजाय, यह महसूस करने में मदद मिली कि काम करने के लिए अधिक जानकारी है। वर्तमान संख्या की बिट समता की गणना करने के बजाय,
k ----> par(k)
जैसे ही हम वृद्धि kकरते हैं हम बिट समता को अपडेट कर सकते हैं k+1।
k ----> par(k)
|
v
k+1 ----> par(k+1)
यही है, जब से हम गिनती कर रहे हैं k=0,1,2,..., हमें केवल हर बार खरोंच से गणना करने के बजाय वर्तमान बिट समता बनाए रखने की आवश्यकता है। बिट समता अद्यतन par(k+1)^par(k)बिट्स की संख्या की समता है जिसमें से जाने में फ़्लिप किया kजाता है k+1, अर्थात par((k+1)^k)।
par(k+1) ^ par(k) = par((k+1)^k)
par(k+1) = par(k) ^ par((k+1)^k)
के प्रपत्र (k+1)^k
अब हमें गणना करने की आवश्यकता है par((k+1)^k)। ऐसा लग सकता है कि हम कहीं नहीं गए हैं क्योंकि कंप्यूटिंग बिट समता वास्तव में समस्या है जिसे हम हल करने की कोशिश कर रहे हैं। लेकिन, संख्याओं के रूप में व्यक्त (k+1)^kकिया गया है 1,3,7,15,.., जो कि 2 की शक्ति से नीचे है, एक तथ्य जो अक्सर बिट हैक्स में उपयोग किया जाता है । आइए देखते हैं कि ऐसा क्यों है।
जब हम वृद्धि करते हैं k, तो बाइनरी कैरीज़ का प्रभाव अंतिम 0और सभी 1को अपने अधिकार में लाना है, 0अगर कोई नहीं था तो एक नया अग्रणी बनाता है। उदाहरण के लिए, ले लोk=43=0b101011
**
101011 (43)
+ 1
------
= 101100 (44)
101011 (43)
^101100 (44)
------
= 000111 (77)
एक ले जाने वाले कॉलम के साथ चिह्नित हैं *। इनमें एक 1बदलाव होता है 0और कैरी बिट पर गुजरता है 1, जो बाईं ओर प्रचारित करता रहता है जब तक कि यह एक हिट नहीं हो 0जाता k, जो बदल जाता है 1। बाईं ओर आगे कोई भी बिट अप्रभावित है। तो, जब k^(k+1)जाँच करता है जो थोड़ा अपनी जगह बदल kकरने के लिए k+1, यह सबसे दायीं ओर की स्थिति पाता है 0और 1अपने अधिकार के लिए की। यही है, बदले हुए बिट्स एक प्रत्यय बनाते हैं, इसलिए परिणाम 0 होता है और उसके बाद 1 या उससे अधिक होता है। अग्रणी शून्य के बिना, द्विआधारी संख्याएं 1, 11, 111, 1111, ...हैं जो 2 की शक्ति से नीचे हैं।
कम्प्यूटिंग par((k+1)^k)
अब जब हम समझते हैं कि (k+1)^kयह सीमित है 1,3,7,15,..., तो आइए ऐसी संख्याओं की बिट समता की गणना करने का एक तरीका खोजें। यहाँ, एक उपयोगी तथ्य यह है कि 1,2,4,8,16,...वैकल्पिक मोडुलो और के 3बीच , तब से । तो, ले जा सापेक्ष देता है , वास्तव में अपने बिट parities होते हैं। उत्तम!122==-1 mod 31,3,7,15,31,63...31,0,1,0,1,0...
तो, हम अद्यतन के par(k+1) = par(k) ^ par((k+1)^k)रूप में कर सकते हैं
par(k+1) = par(k) ^ ((k+1)^k)%3
bजिस वेरिएबल को हम समता में संचित कर रहे हैं, उसका उपयोग करके यह दिखता है
b^=((k+1)^k)%3
कोड लिखना
इसे एक साथ कोड में डालते हुए, हम शुरू करते हैं kऔर समता bदोनों पर 0, फिर बार-बार प्रिंट n=2*k+bऔर अपडेट करते हैं b=b^((k+1)^k)%3और k=k+1।
46 बाइट्स
k=b=0
exec"print 2*k+b;b^=(k+1^k)%3;k+=1;"*400
इसे ऑनलाइन आज़माएं!
हम चारों ओर कोष्ठक हटाया k+1में ((k+1)^k)%3क्योंकि अजगर पूर्वता पहले वैसे भी, अजीब के रूप में यह लग रहा है इसके अलावा करता है।
कोड में सुधार
हम एक एकल चर के साथ सीधे काम करके n=2*k+bऔर उस पर सीधे अपडेट करके बेहतर प्रदर्शन कर सकते हैं। करने से k+=1मेल खाती है n+=2। और, अद्यतन करने से b^=(k+1^k)%3मेल खाती है n^=(k+1^k)%3। यहां, k=n/2अपडेट करने से पहले n।
44 बाइट्स
n=0
exec"print n;n^=(n/2+1^n/2)%3;n+=2;"*400
इसे ऑनलाइन आज़माएं!
हम पुनर्लेखन करके n/2+1^n/2इसे (याद कर सकते हैं) छोटा कर सकते हैं(n/2+1)^n/2
n/2+1 ^ n/2
(n+2)/2 ^ n/2
(n+2 ^ n)/2
चूंकि /2अंतिम बिट को हटाता है, इससे कोई फर्क नहीं पड़ता कि हम इसे एक्सर-इन के पहले या बाद में करते हैं। तो, हमारे पास है n^=(n+2^n)/2%3। हम उस मोडुलो को ध्यान में रखते हुए एक और बाइट को बचा सकते हैं 3, /2इसके *2बराबर है -, यह देखते हुए कि n+2^nविभाजन के बिना फर्श के साथ वास्तविक विभाजन है। यह देता हैn^=-(n+2^n)%3
41 बाइट्स
n=0
exec"print n;n^=-(n+2^n)%3;n+=2;"*400
इसे ऑनलाइन आज़माएं!
अंत में, हम संचालन n^=c;n+=2को एक में जोड़ सकते हैं n=(n+2)^c, जहां cथोड़ा सा है। यह काम करता है क्योंकि ^cकेवल अंतिम बिट पर कार्य +2करता है और अंतिम बिट के बारे में परवाह नहीं करता है, इसलिए संचालन शुरू होता है। फिर से, पूर्वता हमें परेंस को लिखने और लिखने से रोकता है n=n+2^c।
39 बाइट्स
n=0
exec"print n;n=n+2^-(n+2^n)%3;"*400
इसे ऑनलाइन आज़माएं!