एक पूर्णांक पर झूठी सकारात्मक


12

लीडरबोर्ड

 User            Language      Score
 =========================================
 Ell             C++11         293,619,555
 feersum         C++11         100,993,667
 Ell             C++11          78,824,732
 Geobits         Java           27,817,255
 Ell             Python         27,797,402
 Peter Taylor    Java                2,468
 <reference>     Julia                 530

पृष्ठभूमि

पूर्णांक निर्देशांक के 2-डी ग्रिड पर काम करते समय, आप कभी-कभी यह जानना चाहते हैं कि क्या दो वैक्टर (पूर्णांक घटकों के साथ) में एक ही परिमाण है। बेशक, यूक्लिडियन ज्यामिति में एक सदिश (x,y)का परिमाण किसके द्वारा दिया जाता है

√(x² + y²)

तो एक भोली कार्यान्वयन दोनों वैक्टर के लिए इस मूल्य की गणना कर सकता है और परिणामों की तुलना कर सकता है। न केवल उस अनावश्यक वर्गमूल गणना को उकसाता है, यह फ्लोटिंग पॉइंट अशुद्धियों के साथ भी परेशानी का कारण बनता है, जो झूठी सकारात्मकता उत्पन्न कर सकता है: वैक्टर जिनके परिमाण भिन्न हैं, लेकिन जहां फ्लोटिंग पॉइंट प्रतिनिधित्व में महत्वपूर्ण अंक सभी समान हैं।

इस चुनौती के प्रयोजनों के लिए, हम एक झूठी सकारात्मक को समन्वित जोड़े की जोड़ी के रूप में परिभाषित करते हैं (a,b)और (c,d)जिसके लिए:

  • 64-बिट अहस्ताक्षरित पूर्णांक के रूप में प्रदर्शित होने पर उनका वर्ग परिमाण भिन्न होता है।
  • जब 64-बिट बाइनरी फ्लोटिंग पॉइंट संख्या के रूप में प्रतिनिधित्व किया जाता है और 64-बिट स्क्वायर रूट ( IEEE 758 के अनुसार ) के माध्यम से गणना की जाती है, तो उनका परिमाण समान होता है ।

एक उदाहरण के रूप में, 16-बिट अभ्यावेदन (64 के बजाय) का उपयोग करते हुए, वैक्टर की सबसे छोटी 1 जोड़ी जो एक झूठी सकारात्मक पैदावार देती है

(25,20) and (32,0)

उनके चुकता वर्ग परिमाण हैं 1025और 1024। वर्गमूल पैदावार लेना

32.01562118716424 and 32.0

लेकिन 16-बिट फ्लोट्स में इन दोनों को काट दिया जाता है 32.0

इसी तरह, 32-बिट अभ्यावेदन के लिए एक झूठी सकारात्मक उपज देने वाली सबसे छोटी 2 जोड़ी है

(1659,1220) and (1951,659)

1 "सबसे छोटा" जैसा कि उनके 16-बिट फ्लोटिंग पॉइंट परिमाण द्वारा मापा जाता है।
2 "सबसे छोटा" जैसा कि उनके 32-बिट फ्लोटिंग पॉइंट परिमाण द्वारा मापा जाता है।

अंत में, यहाँ कुछ 64-बिट के वैध मामले हैं:

 (51594363,51594339) and (54792160,48184783)
 (54356775,54353746) and (54620742,54088476)
 (54197313,46971217) and (51758889,49645356)
 (67102042,  956863) and (67108864,       6) *

* आखिरी मामला 64-बिट झूठी सकारात्मक के लिए सबसे छोटी संभव परिमाण के साथ कई में से एक है।

चुनौती

10,000 से भी कम बाइट्स कोड में, एक ही धागे का उपयोग करके, आप समन्वय सीमा में 64-बिट (बाइनरी) फ़्लोटिंग पॉइंट संख्याओं के लिए कई गलत सकारात्मकताएं ढूंढ सकते हैं 0 ≤ y ≤ x(अर्थात, केवल यूक्लिडियन विमान के पहले ओकटेंट के भीतर) ऐसे कि 10 मिनट के भीतर । यदि दो प्रस्तुतियाँ समान संख्या में जोड़े के लिए टाई करती हैं, तो टाई ब्रेकर उन जोड़ियों में से अंतिम खोजने के लिए लिया गया वास्तविक समय है।x² + y² ≤ 253

आपके प्रोग्राम को किसी भी समय (व्यावहारिक कारणों से) 4 जीबी से अधिक मेमोरी का उपयोग नहीं करना चाहिए ।

अपने प्रोग्राम को दो मोड में चलाना संभव है: एक जो हर जोड़ी को आउटपुट करता है जैसा कि यह पाता है, और एक जो अंत में पाए गए जोड़े की संख्या को आउटपुट करता है। पहले का उपयोग आपकी जोड़ी की वैधता (आउटपुट के कुछ नमूने को देखकर) को सत्यापित करने के लिए किया जाएगा और दूसरे का उपयोग वास्तव में समय पर जमा करने के लिए किया जाएगा। ध्यान दें कि मुद्रण में केवल अंतर होना चाहिए । विशेष रूप से, गणना कार्यक्रम उन जोड़े की संख्या को हार्डकोड नहीं कर सकता है जो इसे पा सकते हैं। यह अभी भी उसी लूप का प्रदर्शन करना होगा जिसका उपयोग सभी नंबरों को प्रिंट करने के लिए किया जाएगा, और केवल प्रिंटिंग को ही छोड़ दें!

मैं अपने विंडोज 8 लैपटॉप पर सभी सबमिशन का परीक्षण करूंगा, इसलिए कृपया टिप्पणियों में पूछें कि क्या आप कुछ गैर-सामान्य भाषा का उपयोग करना चाहते हैं।

ध्यान दें कि जोड़े को पहले और दूसरे समन्वित जोड़े के स्विचिंग के तहत दो बार नहीं गिना जाना चाहिए ।

ध्यान दें कि मैं आपकी प्रक्रिया रूबी नियंत्रक के माध्यम से चलाऊंगा, जो आपकी प्रक्रिया को मार देगा यदि यह 10 मिनट के बाद समाप्त नहीं हुआ है। तब तक जोड़े जाने वाले जोड़े की संख्या का उत्पादन सुनिश्चित करें। आप या तो स्वयं समय का ध्यान रख सकते हैं और परिणाम को 10 मिनट बीतने से ठीक पहले प्रिंट कर सकते हैं, या आप केवल छिटपुट रूप से पाए जाने वाले जोड़े की संख्या का उत्पादन कर सकते हैं, और मैं आपके स्कोर के रूप में अंतिम संख्या ले लूंगा।


एक पक्ष की टिप्पणी के रूप में, एक साथ यह निर्धारित करना संभव है कि पूर्णांक एक पूर्ण वर्ग है या नहीं और इसकी सटीक वर्गमूल की भी कुशलता से गणना करता है। मेरे सिस्टम पर हार्डवेयर वर्गमूल की तुलना में निम्नलिखित एल्गोरिथ्म 5x तेज है (64-बिट अहस्ताक्षरित पूर्णांक की तुलना में 80-बिट लंबा डबल करने के लिए): math.stackexchange.com/questions/41337/…
टोड लेहमैन

जवाबों:


5

C ++, 275,000,000+

हम उन जोड़ों का उल्लेख करेंगे जिनकी परिमाण सटीक रूप से प्रतिनिधित्व करने योग्य है, जैसे कि (x, 0) , ईमानदार जोड़े के रूप में और अन्य सभी जोड़ों को परिमाण m के बेईमान जोड़े के रूप में , जहाँ m जोड़े की गलत-कथित परिमाण है। पिछली पोस्ट के पहले कार्यक्रम में ईमानदार और बेईमान-जोड़े के कसकर संबंधित जोड़ों का एक सेट इस्तेमाल किया गया था :
(x, 0) और (x, 1) , क्रमशः काफी बड़े x के लिए। दूसरे कार्यक्रम में बेईमान जोड़ों के एक ही सेट का इस्तेमाल किया गया, लेकिन सभी ईमानदार जोड़े की अभिन्न परिमाण को देखते हुए ईमानदार जोड़े के सेट को बढ़ाया गया। कार्यक्रम दस मिनट के भीतर समाप्त नहीं होता है, लेकिन यह अपने परिणामों के विशाल बहुमत को बहुत पहले ही ढूंढ लेता है, जिसका अर्थ है कि अधिकांश रनटाइम बर्बाद हो जाता है। इस कार्यक्रम में हमेशा कम-लगातार ईमानदार जोड़े की तलाश में रहने के बजाय, यह कार्यक्रम अगली तार्किक बात करने के लिए खाली समय का उपयोग करता है: बेईमान जोड़े के सेट का विस्तार करना ।

पिछली पोस्ट से हम जानते हैं कि सभी बड़े-पर्याप्त पूर्णांक r , sqrt (r 2 + 1) = r के लिए , जहाँ sqrt चल-बिंदु वर्गमूल फ़ंक्शन है। हमले की हमारी योजना कुछ बड़े-पर्याप्त पूर्णांक आर के लिए जोड़े पी = (एक्स, वाई) जैसे कि x 2 + y 2 = r 2 + 1 है । यह करने के लिए पर्याप्त सरल है, लेकिन व्यक्तिगत रूप से ऐसे जोड़े की तलाश दिलचस्प होने के लिए बहुत धीमी है। हम इन जोड़ियों को थोक में ढूंढना चाहते हैं, जैसे हमने पिछले कार्यक्रम में ईमानदार जोड़े के लिए किया था।

बता दें कि { v , w } वैक्टरों की एक असाधारण जोड़ी है। सभी वास्तविक स्केलर r के लिए , || r v + w || 2 = आर 2 + 1 । में 2 , इस पाइथागोरस प्रमेय का एक सीधा परिणाम है:

चित्र 1

हम वैक्टर v और w की तलाश कर रहे हैं जैसे कि एक पूर्णांक r मौजूद है जिसके लिए x और y पूर्णांक भी हैं। एक तरफ ध्यान दें, ध्यान दें कि हम पिछले दो कार्यक्रमों में इस्तेमाल किया बेईमान जोड़े के सेट बस इस है, जहां का एक विशेष मामला था के रूप में { v , w } के मानक आधार था 2 ; इस बार हम एक अधिक सामान्य समाधान खोजने की इच्छा रखते हैं। यह वह जगह है जहाँ पाइथागोरस ट्रिपलेट्स (पूर्णांक तीनों (ए, बी, सी) 2 + बी 2 = सी 2 को संतुष्ट करते हैं, जो हमने पिछले कार्यक्रम में इस्तेमाल किया था) उनकी वापसी।

आज्ञा देना (ए, बी, सी) एक पायथागॉरियन ट्रिपल हो। वैक्टर v = (b / c, a / c) और w = (-a / c, b / c) (और भी
w = (a / c -b / c) ) orthonormal हैं, जिन्हें सत्यापित करना आसान है । जैसा कि यह पता चला है, पायथागॉरियन ट्रिपल के किसी भी विकल्प के लिए, एक पूर्णांक आर मौजूद है जैसे कि x और y पूर्णांक हैं। यह साबित करने के लिए, और प्रभावी रूप से आर और पी को खोजने के लिए , हमें थोड़ी संख्या / समूह सिद्धांत की आवश्यकता है; मैं विवरणों को बख्शता जा रहा हूं। किसी भी तरह से, मान लें कि हमारे पास हमारे अभिन्न आर , एक्स और वाई हैं । हम अभी भी कुछ चीजों से कम हैं: हमें r की आवश्यकता हैपर्याप्त रूप से बड़ा होना और हम इस एक से कई और समान जोड़े प्राप्त करना चाहते हैं। सौभाग्य से, इसे पूरा करने का एक सरल तरीका है।

ध्यान दें कि P पर v का प्रक्षेपण r v है , इसलिए r = P · v = (x, y) · (b / c, a / c) = xb / c + ya / c , यह सब कहना है कि xb + य = आरसी । परिणामस्वरूप, सभी पूर्णांकों के लिए n , (x + bn) 2 + (y + a) 2 = (x 2 + y 2 ) + 2 (xb + ya) n + (a 2 + b 2 ) n 2 = ( r 2 + 1) + 2 (rc) n + (c 2 ) n 2 = (r + cn) 2 + 1। दूसरे शब्दों में, प्रपत्र के जोड़े के वर्ग परिमाण
(x + अरब, y + एक) है (r + cn) 2 + 1 है, जो वास्तव में जोड़े हम देख रहे हैं की तरह है! बड़े पर्याप्त n के लिए , ये परिमाण r + cn के बेईमान जोड़े हैं ।

एक ठोस उदाहरण को देखना हमेशा अच्छा होता है। यदि हम पायथागॉरियन ट्रिपलेट (3, 4, 5) लेते हैं , तो r = 2 पर हमारे पास P = (1, 2) है (आप जांच सकते हैं कि (1, 2) · (4/5, 3/5) = 2 और, स्पष्ट रूप से, 1 2 + 2 2 = 2 2 + 1 ।) जोड़ना 5 के लिए आर और (4, 3) के पी करने के लिए हमें ले जाता है आर '= 2 + 5 = 7 और पी' = (1 + 4, 2 + 3) = (5, 5) । लो और निहारना, 5 2 + 5 2 = 7 2 + 1। अगले निर्देशांक आर '' = 12 और पी '' = (9, 8) हैं , और फिर से, 9 2 + 8 2 = 12 2 + 1 , और इसी तरह, और इतने पर ...

चित्र 2

एक बार जब आर काफी बड़ा हो जाता है, तो हम 5 की परिमाण वृद्धि के साथ बेईमान जोड़े प्राप्त करना शुरू करते हैं । यह लगभग 27,797,402 / 5 बेईमान जोड़े हैं।

तो अब हमारे पास बहुत सारे अभिन्न-परिमाण बेईमान जोड़े हैं। हम झूठे-सकारात्मक बनाने के लिए पहले कार्यक्रम के ईमानदार जोड़े के साथ उन्हें आसानी से जोड़ सकते हैं, और उचित देखभाल के साथ हम दूसरे कार्यक्रम के ईमानदार जोड़े का भी उपयोग कर सकते हैं। यह मूल रूप से यह कार्यक्रम क्या करता है। पिछले कार्यक्रम की तरह, यह भी --- पर अपने अधिकांश परिणामों को बहुत जल्दी पाता है --- यह कुछ सेकंड के भीतर 200,000,000 झूठे सकारात्मक को प्राप्त करता है --- और फिर काफी धीमा हो जाता है।

के साथ संकलित करें g++ flspos.cpp -oflspos -std=c++11 -msse2 -mfpmath=sse -O3। परिणामों को सत्यापित करने के लिए, इसे जोड़ें -DVERIFY(यह विशेष रूप से धीमा होगा)

के साथ चला flspos। वर्बोज़ मोड के लिए कोई भी कमांड-लाइन तर्क।

#include <cstdio>
#define _USE_MATH_DEFINES
#undef __STRICT_ANSI__
#include <cmath>
#include <cfloat>
#include <vector>
#include <iterator>
#include <algorithm>

using namespace std;

/* Make sure we actually work with 64-bit precision */
#if defined(VERIFY) && FLT_EVAL_METHOD != 0 && FLT_EVAL_METHOD != 1
#   error "invalid FLT_EVAL_METHOD (did you forget `-msse2 -mfpmath=sse'?)"
#endif

template <typename T> struct widen;
template <> struct widen<int> { typedef long long type; };

template <typename T>
inline typename widen<T>::type mul(T x, T y) {
    return typename widen<T>::type(x) * typename widen<T>::type(y);
}
template <typename T> inline T div_ceil(T a, T b) { return (a + b - 1) / b; }
template <typename T> inline typename widen<T>::type sq(T x) { return mul(x, x); }
template <typename T>
T gcd(T a, T b) { while (b) { T t = a; a = b; b = t % b; } return a; }
template <typename T>
inline typename widen<T>::type lcm(T a, T b) { return mul(a, b) / gcd(a, b); }
template <typename T>
T div_mod_n(T a, T b, T n) {
    if (b == 0) return a == 0 ? 0 : -1;
    const T n_over_b = n / b, n_mod_b = n % b;
    for (T m = 0; m < n; m += n_over_b + 1) {
        if (a % b == 0) return m + a / b;
        a -= b - n_mod_b;
        if (a < 0) a += n;
    }
    return -1;
}

template <typename T> struct pythagorean_triplet { T a, b, c; };
template <typename T>
struct pythagorean_triplet_generator {
    typedef pythagorean_triplet<T> result_type;
private:
    typedef typename widen<T>::type WT;
    result_type p_triplet;
    WT p_c2b2;
public:
    pythagorean_triplet_generator(const result_type& triplet = {3, 4, 5}) :
        p_triplet(triplet), p_c2b2(sq(triplet.c) - sq(triplet.b))
    {}
    const result_type& operator*() const { return p_triplet; }
    const result_type* operator->() const { return &p_triplet; }
    pythagorean_triplet_generator& operator++() {
        do {
            if (++p_triplet.b == p_triplet.c) {
                ++p_triplet.c;
                p_triplet.b = ceil(p_triplet.c * M_SQRT1_2);
                p_c2b2 = sq(p_triplet.c) - sq(p_triplet.b);
            } else
                p_c2b2 -= 2 * p_triplet.b - 1;
            p_triplet.a = sqrt(p_c2b2);
        } while (sq(p_triplet.a) != p_c2b2 || gcd(p_triplet.b, p_triplet.a) != 1);
        return *this;
    }
    result_type operator()() { result_type t = **this; ++*this; return t; }
};

int main(int argc, const char* argv[]) {
    const bool verbose = argc > 1;

    const int min = 1 << 26;
    const int max = sqrt(1ll << 53);

    const size_t small_triplet_count = 1000;
    vector<pythagorean_triplet<int>> small_triplets;
    small_triplets.reserve(small_triplet_count);
    generate_n(
        back_inserter(small_triplets),
        small_triplet_count,
        pythagorean_triplet_generator<int>()
    );

    int found = 0;
    auto add = [&] (int x1, int y1, int x2, int y2) {
#ifdef VERIFY
        auto n1 = sq(x1) + sq(y1), n2 = sq(x2) + sq(y2);
        if (x1 < y1 || x2 < y2 || x1 > max || x2 > max ||
            n1 == n2 || sqrt(n1) != sqrt(n2)
        ) {
            fprintf(stderr, "Wrong false-positive: (%d, %d) (%d, %d)\n",
                    x1, y1, x2, y2);
            return;
        }
#endif
        if (verbose) printf("(%d, %d) (%d, %d)\n", x1, y1, x2, y2);
        ++found;
    };

    int output_counter = 0;
    for (int x = min; x <= max; ++x) add(x, 0,    x, 1);
    for (pythagorean_triplet_generator<int> i; i->c <= max; ++i) {
        const auto& t1 = *i;

        for (int n = div_ceil(min, t1.c); n <= max / t1.c; ++n)
            add(n * t1.b, n * t1.a,    n * t1.c, 1);

        auto find_false_positives = [&] (int r, int x, int y) {
            {
                int n = div_ceil(min - r, t1.c);
                int min_r = r + n * t1.c;
                int max_n = n + (max - min_r) / t1.c;
                for (; n <= max_n; ++n)
                    add(r + n * t1.c, 0,    x + n * t1.b, y + n * t1.a);
            }
            for (const auto t2 : small_triplets) {
                int m = div_mod_n((t2.c - r % t2.c) % t2.c, t1.c % t2.c, t2.c);
                if (m < 0) continue;
                int sr = r + m * t1.c;
                int c = lcm(t1.c, t2.c);
                int min_n = div_ceil(min - sr, c);
                int min_r = sr + min_n * c;
                if (min_r > max) continue;
                int x1 = x + m * t1.b, y1 = y + m * t1.a;
                int x2 = t2.b * (sr / t2.c), y2 = t2.a * (sr / t2.c);
                int a1 = t1.a * (c / t1.c), b1 = t1.b * (c / t1.c);
                int a2 = t2.a * (c / t2.c), b2 = t2.b * (c / t2.c);
                int max_n = min_n + (max - min_r) / c;
                int max_r = sr + max_n * c;
                for (int n = min_n; n <= max_n; ++n) {
                    add(
                        x2 + n * b2, y2 + n * a2,
                        x1 + n * b1, y1 + n * a1
                    );
                }
            }
        };
        {
            int m = div_mod_n((t1.a - t1.c % t1.a) % t1.a, t1.b % t1.a, t1.a);
            find_false_positives(
                /* r = */ (mul(m, t1.c) + t1.b) / t1.a,
                /* x = */ (mul(m, t1.b) + t1.c) / t1.a,
                /* y = */ m
            );
        } {
            int m = div_mod_n((t1.b - t1.c % t1.b) % t1.b, t1.a, t1.b);
            find_false_positives(
                /* r = */ (mul(m, t1.c) + t1.a) / t1.b,
                /* x = */ m,
                /* y = */ (mul(m, t1.a) + t1.c) / t1.b
            );
        }

        if (output_counter++ % 50 == 0)
            printf("%d\n", found), fflush(stdout);
    }
    printf("%d\n", found);
}

अच्छा! :) मुझे अपनी मशीन पर 293,619,555 मिले और लीडरबोर्ड को अपडेट किया।
मार्टिन एंडर

8

अजगर, 27,797,402

बस बार को थोड़ा ऊंचा सेट करने के लिए ...

from sys import argv
verbose = len(argv) > 1
found = 0
for x in xrange(67108864, 94906266):
    found += 1
    if verbose:
        print "(%d, 0) (%d, 1)" % (x, x)
print found

यह सत्यापित करना आसान है कि सभी के लिए 67,108,864 <= x <= 94,906,265 = तल (sqrt (2 53 )) जोड़े (x, 0) और (x, 1) झूठी सकारात्मक हैं।

यह क्यों काम करता है : 67,108,864 = 2 26 । इसके अलावा, उपरोक्त सीमा में सभी संख्याएँ x कुछ 26 <= x '<2 26 के लिए 2 26 + x' के हैं । सभी सकारात्मक ई के लिए , (x + e) 2 = x 2 + 2xe + e 2 = x 2 + 2 27 e + 2x'e + e 2 । यदि हम (x + e) 2 = x 2 + 1 चाहते हैं, तो हमें कम से कम 2 27 e <= 1 , अर्थात e <= 2 -27 चाहिए
हालांकि, डबल परिशुद्धता चल बिन्दु संख्या के अपूर्णांश 52-बिट व्यापक है के बाद से, सबसे छोटी ऐसी है कि एक्स + ई> x है ई = 2 26 - 52 = 2 -26 । दूसरे शब्दों में, की तुलना में छोटी से छोटी प्रदर्शनीय संख्या अधिक से अधिक एक्स है x + 2 -26 , जबकि का परिणाम sqrt (एक्स 2 + 1) अधिक से अधिक है x + 2 -27 । चूंकि डिफ़ॉल्ट IEEE-754 राउंडिंग मोड गोल-से-निकटतम है; टाई-टू- इवन , यह हमेशा x के लिए गोल होगा और कभी भी x + 2 -26 के लिए नहीं होगा (जहां टाई-ब्रेक वास्तव में x = 67,108,864 के लिए प्रासंगिक है, अगर सब पर। कोई भी बड़ी संख्या x की परवाह किए बिना गोल होगी )।


C ++, 75,000,000+

उस 3 2 + 4 2 = 5 2 को याद करें । इसका मतलब है कि बिंदु है (4, 3) त्रिज्या के चक्र पर झूठ 5 के आसपास मूल केंद्रित। वास्तव में, सभी पूर्णांक n के लिए , (4n, 3n) त्रिज्या 5n के ऐसे वृत्त पर स्थित है । बड़े पर्याप्त n के लिए (जैसे, कि 5n> = 2 26 ), हम पहले से ही इस वृत्त पर सभी बिंदुओं के लिए एक गलत-सकारात्मक जानते हैं: (5n, 1) । महान! यह एक और 27,797,402 / 5 मुक्त झूठी सकारात्मक जोड़े वहीं है! लेकिन यहां क्यों रुके? (३, ४, ५) एकमात्र ऐसा त्रिगुण नहीं है।

सभी सकारात्मक पूर्णांक त्रिक के लिए इस कार्यक्रम के दिखता है (ए, बी, सी) ऐसी है कि एक 2 + b 2 = c 2 इस फैशन में है, और मायने रखता है झूठी सकारात्मक। यह बहुत तेजी से 70,000,000 झूठी सकारात्मक के लिए हो जाता है, लेकिन फिर संख्या बढ़ने के रूप में काफी धीमा हो जाता है।

के साथ संकलित करें g++ flspos.cpp -oflspos -std=c++11 -msse2 -mfpmath=sse -O3। परिणामों को सत्यापित करने के लिए, इसे जोड़ें -DVERIFY(यह विशेष रूप से धीमा होगा)

के साथ चला flspos। वर्बोज़ मोड के लिए कोई भी कमांड-लाइन तर्क।

#include <cstdio>
#include <cmath>
#include <cfloat>

using namespace std;

/* Make sure we actually work with 64-bit precision */
#if defined(VERIFY) && FLT_EVAL_METHOD != 0 && FLT_EVAL_METHOD != 1
#   error "invalid FLT_EVAL_METHOD (did you forget `-msse2 -mfpmath=sse'?)"
#endif

template <typename T> inline long long sqr(T x) { return 1ll * x * x; }
template <typename T>
T gcd(T a, T b) { while (b) { T t = a; a = b; b = t % b; } return a; }

int main(int argc, const char* argv[]) {
    const bool verbose = argc > 1;

    const int min = 1 << 26;
    const int max = sqrt(1ll << 53);

    int found = 0;
    auto add = [=, &found] (int x1, int y1, int x2, int y2) {
#ifdef VERIFY
        auto n1 = sqr(x1) + sqr(y1), n2 = sqr(x2) + sqr(y2);
        if (n1 == n2 || sqrt(n1) != sqrt(n2)) {
            fprintf(stderr, "Wrong false-positive: (%d, %d) (%d, %d)\n",
                    x1, y1, x2, y2);
            return;
        }
#endif
        if (verbose) printf("(%d, %d) (%d, %d)\n", x1, x2, y1, y2);
        ++found;
    };

    for (int x = min; x <= max; ++x) add(x, 0,    x, 1);

    for (int a = 1; a < max; ++a) {
        auto a2b2 = sqr(a) + 1;
        for (int b = 1; b <= a; a2b2 += 2 * b + 1, ++b) {
            int c = sqrt(a2b2);
            if (a2b2 == sqr(c) && gcd(a, b) == 1) {
                int max_c = max / c;
                for (int n = (min + c - 1) / c; n <= max_c; ++n)
                    add(n * a, n * b,    n * c, 1);
            }
        }

        if (a % 512 == 0) printf("%d\n", found), fflush(stdout);
    }

    printf("%d\n", found);
}

येश, यह एक प्रभावी रणनीति है। मैंने सोचा था कि 2**53इस नियम का पालन करने के लिए सीमा को चुना गया था, लेकिन मुझे लगता है कि नहीं।
23

मजेदार है कि इस रेंज में हर संख्या x ^ 2 और x ^ 2 + 1 के वर्गमूल के एक ही उदाहरण के बिना एक पूर्णांक के विभिन्न पक्षों पर गिरने से कैसे काम करती है + 1/2।
2

@xnor 64-बिट फ़्लोट में बिल्कुल प्रतिनिधित्व योग्य होने के लिए सीमा परिमाण के लिए चुना गया था।
मार्टिन एंडर

अरे, यह काम करता है, कौन परवाह करता है? ;) क्या आपका मतलब है कि कार्यक्रम को डमी लूप में गिना जाना चाहिए, या वास्तव में परिणामों को सत्यापित करना चाहिए?
एलए

@MartinButtner ओह, मैं देख रहा हूँ। ऐसा लगता है कि निचली बाउंड वह राशि है जिसे 2 के वर्गमूल से विभाजित किया गया है। मुझे समझ में आता है कि ऐसे नंबरों को क्यों काम करना चाहिए, लेकिन मैं उत्सुक हूं कि हर एक काम क्यों होता है।
xnor

4

सी ++ 11 - 100,993,667

संपादित करें: नया कार्यक्रम।

पुराने वाले ने बहुत ज्यादा मेमोरी का इस्तेमाल किया। यह एक हैश टेबल के बजाय एक विशाल वेक्टर सरणी का उपयोग करके मेमोरी के उपयोग को आधा कर देता है। इसके अलावा यह यादृच्छिक धागा cruft को हटाता है।

   /* by feersum  2014/9
   http://codegolf.stackexchange.com/questions/37627/false-positives-on-an-integer-lattice */
#include <iostream>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <vector>
using namespace std;
#define ul unsigned long long

#define K const



#define INS(A)   { bool already = false; \
    for(auto e = res[A.p[0][0]].end(), it = res[A.p[0][0]].begin(); it != e; ++it) \
        if(A.p[0][1] == it->y1 && A.p[1][0] == it->x2 && A.p[1][1] == it->y2) { \
            already = true; \
            break; } \
    if(!already) res[A.p[0][0]].push_back( {A.p[0][1], A.p[1][0], A.p[1][1]} ), ++n; }

#define XMAXMIN (1<<26)

struct ints3 {
    int y1, x2, y2;
};


struct pparm {
    int a,b,c,d;
    int E[4];
    pparm(int A,int B,int C, int D):
        E{B*B+D*D,A*B+C*D,A*A+C*C+2*(B+D),A+C}
    {
        a=A;b=B;c=C;d=D;
    }

};

struct ans {
    int p[2][2];

};
ostream&operator<<(ostream&o, ans&a)
{
    o<<'('<<a.p[0][0]<<','<<a.p[0][1]<<"),("<<a.p[1][0]<<','<<a.p[1][1]<<')'<<endl;
    return o;
}



vector<ints3> res[XMAXMIN];

bool print;
int n;

void gen(K pparm&p1, K pparm&p2)
{
#ifdef DBUG
    for(int i=0;i<2;i++){
    K pparm&p=i?p2:p1;
    cout<<' '<<p.a<<' '<<p.b<<' '<<p.c<<' '<<p.d<<' ';}
    cout<<endl;
#endif

    for(ul x = 0; ; ++x) {
        ans a;
        ul s[2];
        for(int i = 0; i < 2; i++) {
            K pparm &p = i?p2:p1;
            int *pt = a.p[i];
            pt[0] = p.b+x*(p.a+x);
            pt[1] = p.d+x*(p.c+x);
            s[i] = (ul)pt[0]*pt[0] + (ul)pt[1]*pt[1];
        }
        if(*s >> 53)
            break;
if(s[1] - s[0] != 1)
exit(4);

        if(sqrt(s[0]) == sqrt(s[1])) {
             for(int i = 0; i < 2; i++)
                if(a.p[i][0] > a.p[i][1])
                    swap(a.p[i][0], a.p[i][1]);
            if(a.p[0][0] > a.p[0][1])
                for(int i = 0; i < 2; i++)
                    swap(a.p[0][i], a.p[1][i]);
            INS(a)
        }
    }
}



int main(int ac, char**av)
{
    for(int i = 1; i < ac; i++) {
        print |= !strcmp(av[1], "-P");
    }


    #define JMAX 43000000
    for(ul j = 0; j < JMAX; j++) {
        pparm p1(-~j,j,~-j,0),p2(j,1,j,j);
        gen(p1,p2);
        if(!print && !(j%1024))
#ifdef DBUG
            cout<<j<<' ',
#endif
            cout<<n<<endl;

    }
    if(print) 
        for(vector<ints3>& v: res)
            for(ints3& i: v)
                printf("(%d,%d),(%d,%d)\n", &v - res, i.y1, i.x2, i.y2);

    return 0;
}

-Pसंख्या के बजाय अंक को प्रिंट करने के लिए एक तर्क के साथ चलाएं ।

मेरे लिए इसे काउंटिंग मोड में 2 मिनट और फ़ाइल (~ 4 जीबी) के लिए निर्देशित प्रिंटिंग के साथ लगभग 5 मिनट का समय लगता है, इसलिए यह I / O सीमित नहीं हुआ।

मेरा मूल कार्यक्रम साफ-सुथरा था, लेकिन मैंने इसे ज्यादातर गिरा दिया क्योंकि यह केवल 10 ^ 5 परिणामों के आदेश पर ही उत्पादन कर सकता था। यह क्या किया है फार्म के मापदंडों को देखने के लिए (x ^ 2 + Ax + B, x ^ 2 + Cx + D), (x ^ 2 + ax + b, x ^ 2 + cx + d) जैसे कि किसी के लिए x, (x ^ 2 + Ax + B) ^ 2 + (x ^ 2 + Cx + D) ^ 2 = (x ^ 2 + ax + b) ^ 2 + (x ^ 2 + cx + d) ^ 2 + 1. जब इस तरह के मापदंडों का ऐसा सेट मिला {a, b, c, d, A, B, C, D} तो यह अधिकतम के तहत सभी x मानों की जांच करने के लिए आगे बढ़ा। इस कार्यक्रम से अपने डिबग आउटपुट को देखते हुए, मैंने पैरामीटर के मानकीकरण के एक निश्चित पैरामीटर पर ध्यान दिया, जिसने मुझे बहुत अधिक संख्या में आसानी से उत्पादन करने की अनुमति दी। मैंने एल के नंबरों का प्रिंट आउट नहीं करने के लिए चुना क्योंकि मेरे पास बहुत सारे थे। उम्मीद है कि अब कोई हमारे दोनों संख्याओं के सेट को प्रिंट नहीं करेगा और विजेता होने का दावा करेगा :)

 /* by feersum  2014/9
   http://codegolf.stackexchange.com/questions/37627/false-positives-on-an-integer-lattice */
    #include <iostream>
    #include <cmath>
    #include <cstdlib>
    #include <cstring>
    #include <functional>
    #include <unordered_set>
    #include <thread>
using namespace std;
#define ul unsigned long long

#define h(S) unordered_##S##set
#define P 2977953206964783763LL
#define K const

#define EQ(T, F)bool operator==(K T&o)K{return!memcmp(F,o.F,sizeof(F));}

struct pparm {
    int a,b,c,d;
    int E[4];
    pparm(int A,int B,int C, int D):
        E{B*B+D*D,A*B+C*D,A*A+C*C+2*(B+D),A+C}
    {
        a=A;b=B;c=C;d=D;
    }
    EQ(pparm,E)
};

struct ans {
    int p[2][2];
    EQ(ans,p)
};
ostream&operator<<(ostream&o, ans&a)
{
    o<<'('<<a.p[0][0]<<','<<a.p[0][1]<<"),("<<a.p[1][0]<<','<<a.p[1][1]<<')'<<endl;
    return o;
}

#define HASH(N,T,F) \
struct N { \
    size_t operator() (K T&p) K { \
        size_t h = 0; \
        for(int i = 4; i--; ) \
            h=h*P+((int*)p.F)[i]; \
        return h; \
    }};

#define INS(r, a) { \
    bool new1 = r.insert(a).second; \
    n += new1; \
    if(print && new1) \
        cout<<a; }

HASH(HA,ans,p)

bool print;
int n;

void gen(h()<ans,HA>&r, K pparm&p1, K pparm&p2)
{
#ifdef DBUG
    for(int i=0;i<2;i++){
    K pparm&p=i?p2:p1;
    cout<<' '<<p.a<<' '<<p.b<<' '<<p.c<<' '<<p.d<<' ';}
    cout<<endl;
#endif

    for(ul x = 0; ; ++x) {
        ans a;
        ul s[2];
        for(int i = 0; i < 2; i++) {
            K pparm &p = i?p2:p1;
            int *pt = a.p[i];
            pt[0] = p.b+x*(p.a+x);
            pt[1] = p.d+x*(p.c+x);
            s[i] = (ul)pt[0]*pt[0] + (ul)pt[1]*pt[1];
        }
        if(*s >> 53)
            break;
if(s[1] - s[0] != 1)
exit(4);

        if(sqrt(s[0]) == sqrt(s[1])) {
             for(int i = 0; i < 2; i++)
                if(a.p[i][0] > a.p[i][1])
                    swap(a.p[i][0], a.p[i][1]);
            INS(r,a)
        }
    }
    //if(!print) cout<<n<<endl;
}

void endit()
{
    this_thread::sleep_for(chrono::seconds(599));
    exit(0);
}

int main(int ac, char**av)
{
    bool kill = false;
    for(int i = 1; i < ac; i++) {
        print |= ac>1 && !stricmp(av[1], "-P");
        kill |= !stricmp(av[i], "-K");
    }

    thread KILLER;
    if(kill)
        KILLER = thread(endit);

    h()<ans, HA> res;
    res.reserve(1<<27);

    #define JMAX 43000000
    for(ul j = 0; j < JMAX; j++) {
        pparm p1(-~j,j,~-j,0),p2(j,1,j,j);
        gen(res,p1,p2);
        if(!print && !(j%1024))
#ifdef DBUG
            cout<<j<<' ',
#endif
            cout<<n<<endl;

    }
    exit(0);
}

मुझे संकलक त्रुटियों का एक गुच्छा मिल रहा है: pastebin.com/enNcY9fx कोई सुराग क्या हो रहा है?
मार्टिन एंडर

@Martin कोई विचार नहीं ... मैंने अपनी पोस्ट को एक फ़ाइल में कॉपी किया, समान स्विच के साथ विंडोज 8 लैपटॉप पर संकलित। मेरे लिए ठीक काम करता है। आपके पास gcc का कौन सा संस्करण है?
फ़र्सम

Btw यदि वे त्रुटियों का कारण बनते हैं, तो आप बस धागे से संबंधित सभी बिट्स को हटा सकते हैं जो पूरी तरह से अनावश्यक हैं। वे केवल कुछ करते हैं यदि आप "-K" विकल्प का उपयोग करते हैं जिसकी आवश्यकता नहीं है।
feersum

g++ (GCC) 4.8.1। ठीक है, मैंने थ्रेड बिट्स को हटा दिया, लेकिन यह अभी भी stricmpकिसी कारण से पहचान नहीं रहा है।
मार्टिन एंडर

1
मुझे इस समय बहुत सी अन्य चीजें मिल रही हैं, इसलिए मैं आपको अपना दृष्टिकोण सुधारने के लिए अपना विचार बताऊंगा। रेंज के शीर्ष छोर के पास त्रिज्या-वर्ग के साथ, आप त्रिज्या-वर्ग के बीच टकराव भी प्राप्त कर सकते हैं जो कि 2. से भिन्न होता है
पीटर टेलर

1

जावा, ब्रेसेनहम-एसके सर्कल स्कैन

स्वाभाविक रूप से मैं अन्नुलस के व्यापक अंत में शुरू करके अधिक टक्कर प्राप्त करने की उम्मीद करता हूं। मैं प्रत्येक टक्कर के लिए एक स्कैन कर रही है, जिसके लिए मूल्यों को रिकॉर्ड करके कुछ सुधार की उम्मीद surplusके बीच है 0और r2max - r2समावेशी, लेकिन अपनी परीक्षण है कि इस संस्करण की तुलना में धीमी साबित कर दिया है। इसी तरह int[]दो-तत्व सरणियों और सूचियों के निर्माण के बजाय एक एकल बफर का उपयोग करने का प्रयास करता है। प्रदर्शन अनुकूलन वास्तव में एक अजीब जानवर है।

जोड़े के आउटपुट के लिए एक कमांड-लाइन तर्क के साथ, और सरल गणना के बिना चलाएं।

import java.util.*;

public class CodeGolf37627 {
    public static void main(String[] args) {
        final int M = 144;
        boolean[] possible = new boolean[M];
        for (int i = 0; i <= M/2; i++) {
            for (int j = 0; j <= M/2; j++) {
                possible[(i*i+j*j)%M] = true;
            }
        }

        long count = 0;
        double sqrt = 0;
        long r2max = 0;
        List<int[]> previousPoints = null;
        for (long r2 = 1L << 53; ; r2--) {
            if (!possible[(int)(r2 % M)]) continue;

            double r = Math.sqrt(r2);
            if (r != sqrt) {
                sqrt = r;
                r2max = r2;
                previousPoints = null;
            }
            else {
                if (previousPoints == null) previousPoints = findLatticePointsBresenham(r2max, (int)r);

                if (previousPoints.size() == 0) {
                    r2max = r2;
                    previousPoints = null;
                }
                else {
                    List<int[]> points = findLatticePointsBresenham(r2, (int)r);
                    for (int[] p1 : points) {
                        for (int[] p2 : previousPoints) {
                            if (args.length > 0) System.out.format("(%d, %d) (%d, %d)\n", p1[0], p1[1], p2[0], p2[1]);
                            count++;
                        }
                    }
                    previousPoints.addAll(points);
                    System.out.println(count);
                }
            }
        }
    }

    // Surprisingly, this seems to be faster than doing one scan for all two or three r2s.
    private static List<int[]> findLatticePointsBresenham(long r2, long r) {
        List<int[]> rv = new ArrayList<int[]>();
        // Require 0 = y = x
        long x = r, y = 0, surplus = r2 - r * r;
        while (y <= x) {
            if (surplus == 0) rv.add(new int[]{(int)x, (int)y});

            // Invariant: surplus = r2 - x*x - y*y >= 0
            y++;
            surplus -= 2*y - 1;
            if (surplus < 0) {
                x--;
                surplus += 2*x + 1;
            }
        }

        return rv;
    }
}

1

जावा - 27,817,255

इनमें से ज्यादातर वही हैं जो एल को दिखाते हैं , और बाकी पर आधारित हैं (j,0) (k,l)। प्रत्येक के लिए j, मैं कुछ चौकों पर वापस जाता हूं और जांचता हूं कि क्या शेष एक झूठी सकारात्मक देता है। यह मूल रूप से केवल 25k (लगभग 0.1%) के साथ पूरे समय का लाभ उठाता है (j,0) (j,1), लेकिन लाभ एक लाभ है।

यह मेरी मशीन पर दस मिनट के भीतर खत्म हो जाएगा, लेकिन मुझे नहीं पता कि आपके पास क्या है। क्योंकि कारण, अगर यह समय समाप्त होने से पहले खत्म नहीं होता है , तो इसमें काफी खराब स्कोर होगा। उस स्थिति में, आप लाइन 8 पर विभाजक को घुमा सकते हैं ताकि यह समय में समाप्त हो जाए (यह बस यह निर्धारित करता है कि यह प्रत्येक के लिए कितना पीछे चलता है j)। कुछ विभिन्न प्रभागों के लिए, स्कोर हैं:

11    27817255 (best on OPs machine)
10    27818200
8     27820719
7     27822419 (best on my machine)

प्रत्येक मैच के लिए आउटपुट चालू करने के लिए (और, भगवान, यदि आप ऐसा करते हैं तो धीमा है), बस 10 और 19 को अनकंफर्टेबल करें।

public class FalsePositive {
    public static void main(String[] args){
        long j = 67108864;
        long start = System.currentTimeMillis();
        long matches=0;
        while(j < 94906265 && System.currentTimeMillis()-start < 599900){
            long jSq = j*j;
            long limit = (long)Math.sqrt(j)/11; // <- tweak to fit inside 10 minutes for best results
            matches++; // count an automatic one for (j,0)(j,1)
            //System.out.println("("+j+",0) ("+j+",1)");        
            for(int i=1;i<limit;i++){
                long k = j-i;
                long kSq = k*k;
                long l = (long)Math.sqrt(jSq-kSq);
                long lSq = l*l;
                if(kSq+lSq != jSq){
                    if(Math.sqrt(kSq+lSq)==Math.sqrt(jSq)){
                        matches++;
                        //System.out.println("("+j+",0) ("+k+","+l+")");        
                    }
                }
            }
            j++;
        }
        System.out.println("\n"+matches+" Total matches, got to j="+j);
    }
}

संदर्भ के लिए, यह पहले 20 आउटपुट देता है (विभाजक = 7 के लिए, (j,0)(j,1)प्रकारों को छोड़कर ):

(67110083,0) (67109538,270462)
(67110675,0) (67109990,303218)
(67111251,0) (67110710,269470)
(67111569,0) (67110668,347756)
(67112019,0) (67111274,316222)
(67112787,0) (67111762,370918)
(67115571,0) (67115518,84346)
(67117699,0) (67117698,11586)
(67117971,0) (67117958,41774)
(67120545,0) (67120040,260368)
(67121043,0) (67120118,352382)
(67122345,0) (67122320,57932)
(67122449,0) (67122444,25908)
(67122633,0) (67122328,202348)
(67122729,0) (67121972,318784)
(67122849,0) (67122568,194224)
(67124195,0) (67123818,224970)
(67125201,0) (67125172,62396)
(67125705,0) (67124632,379540)
(67126195,0) (67125882,204990)

0

जूलिया, 530 झूठी सकारात्मक

यहां बहुत भोली ब्रूट फोर्स खोज है, जिसे आप संदर्भ कार्यान्वयन के रूप में देख सकते हैं।

num = 0
for i = 60000000:-1:0
    for j = i:-1:ifloor(0.99*i)
        s = i*i + j*j
        for x = ifloor(sqrt(s/2)):ifloor(sqrt(s))
            min_y = ifloor(sqrt(s - x*x))
            max_y = min_y+1
            for y = min_y:max_y
                r = x*x + y*y
                if r != s && sqrt(r) == sqrt(s)
                    num += 1
                    if num % 10 == 0
                        println("Found $num pairs")
                    end
                    #@printf("(i,j) = (%d,%d); (x,y) = (%d,%d); s = %d, r = %d\n", i,j,x,y,s,r)
                end
            end
        end
    end
end

आप @printfपंक्ति को जोड़कर जोड़े (और उनके सटीक चुकता परिमाण) को प्रिंट कर सकते हैं ।

मूल रूप से यह x = y = 6e7पहली समन्वित जोड़ी के लिए खोज शुरू करता है और एक्सरे के लगभग 1% को डी-एक्स्री करने से पहले स्कैन करता है। फिर ऐसी प्रत्येक समन्वय जोड़ी के लिए, यह एक टक्कर के लिए एक ही परिमाण के पूरे चाप (ऊपर और नीचे की ओर) की जांच करता है।

कोड मानता है कि यह 64-बिट सिस्टम पर चलाया जाता है, ताकि डिफ़ॉल्ट पूर्णांक और फ्लोटिंग-पॉइंट प्रकार 64-बिट वाले हों (यदि नहीं, तो आप उन्हें int64()और float64()निर्माणकर्ताओं के साथ बना सकते हैं )।

यह एक परिणाम 530 परिणाम देता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.