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 होते हैं। उत्तम!1
2
2==-1 mod 3
1,3,7,15,31,63...
3
1,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
इसे ऑनलाइन आज़माएं!