সি ++, 275,000,000+
আমরা যেমন জোড়া যার মাত্রার সঠিকভাবে representable হয়, পড়ুন করব (এক্স, 0) হিসাবে, সৎ জোড়া এবং অন্যান্য সমস্ত জোড়া জন্য অসৎ জোড়া মাত্রার মি , যেখানে মি যুগল এর ভুলভাবে রিপোর্ট মাত্রার হয়। পূর্ববর্তী পোস্টের প্রথম প্রোগ্রামটিতে যথেষ্ট পরিমাণে এক্সের জন্য যথাক্রমে সৎ- এবং অসাধু-জোড়া:
(x, 0) এবং (x, 1) এর দৃ tight়ভাবে সম্পর্কিত দম্পতির একটি সেট ব্যবহৃত হয়েছিল। দ্বিতীয় প্রোগ্রামটি একই অসাধু জোড়ার সেটটি ব্যবহার করেছিল তবে অবিচ্ছেদ্য আকারের সমস্ত সৎ জোড়াকে সন্ধান করে সৎ জোড়ার সেটটি প্রসারিত করে। প্রোগ্রামটি দশ মিনিটের মধ্যে শেষ হয় না, তবে এটির ফলাফলগুলির সিংহভাগ সন্ধান পেয়েছে খুব শীঘ্রই, যার অর্থ বেশিরভাগ রানটাইম নষ্ট হয়ে যায়। সদা-কম ঘন ঘন সৎ জোড়গুলির সন্ধানের পরিবর্তে, এই প্রোগ্রামটি পরবর্তী যুক্তিযুক্ত জিনিসটি করার জন্য অতিরিক্ত সময় ব্যবহার করে: অসাধু জোড়ার সেট বাড়িয়ে দেয় ।
পূর্ববর্তী পোস্ট থেকে আমরা জানি যে সমস্ত বৃহত পর্যাপ্ত পূর্ণসংখ্যার জন্য r , sqrt (r 2 + 1) = r , যেখানে স্কয়ার্টটি হল ভাসমান-পয়েন্ট বর্গক্ষেত্রের ফাংশন। আমাদের আক্রমণের পরিকল্পনাটি কয়েকটি বড়-পর্যাপ্ত পূর্ণসংখ্যার r এর জন্য জোড়া = (x, y) যেমন x 2 + y 2 = r 2 + 1 এর সন্ধান করা । এটি করার পক্ষে যথেষ্ট সহজ, তবে নির্মমভাবে স্বতন্ত্রভাবে এই জাতীয় জোড়া অনুসন্ধান করা আকর্ষণীয় হতে খুব ধীর is আমরা আগের প্রোগ্রামগুলিতে যেমন সৎ জোড়ার জন্য করেছি ঠিক তেমনই আমরা এই জোড়াগুলিকেও বাল্কে সন্ধান করতে চাই।
যাক { বনাম , W } ভেক্টর একটি orthonormal যুগল হও। সমস্ত বাস্তব স্কেলারের জন্য r , || r v + w || 2 = আর 2 + 1 । ইন ℝ 2 , এই পিথাগোরাসের উপপাদ্য প্রত্যক্ষ ফল হল:
আমরা ভেক্টর v এবং w এর সন্ধান করছি যে সেখানে একটি পূর্ণসংখ্যা r রয়েছে যার জন্য x এবং y এছাড়াও পূর্ণসংখ্যা। একটি সাইড নোট, নোট যে আমরা আগের দুই প্রোগ্রাম ব্যবহার করা অসৎ যুগলের সেট কেবল এই, যেখানে একটি বিশেষ ক্ষেত্রে ছিল হিসাবে { বনাম , W } মান ভিত্তি ছিল ℝ 2 ; এবার আমরা আরও সাধারণ সমাধান খুঁজতে চাই। এই যেখানে পিথাগোরাস Triplets (পূর্ণসংখ্যার Triplets (A, B, C) পরিতৃপ্ত একটি 2 + খ 2 = C 2যা আমরা পূর্ববর্তী প্রোগ্রামে ব্যবহার করেছি) তাদের প্রত্যাবর্তন করে।
যাক (A, B, C) একটি পিথাগোরাস ত্রয়ী হও। ভেক্টর v = (বি / সি, এ / সি) এবং ডাব্লু = (-এ / সি, বি / সি) (এবং
ডাব্লু = (একটি / সি,-বি / সি) ) অর্থোন্নর, যাচাই করা সহজ । এটি সক্রিয় আউট হিসাবে, পিথাগোরাস ত্রয়ী কোন পছন্দ জন্য, অস্তিত্ব আছে একটি পূর্ণসংখ্যা R যেমন যে এক্স এবং ওয়াই পূর্ণসংখ্যা। এটি প্রমাণ করার জন্য, এবং কার্যকরভাবে r এবং P সন্ধান করার জন্য আমাদের অল্প সংখ্যক / গ্রুপ তত্ত্বের প্রয়োজন; আমি বিশদটি ছাড়াই যাচ্ছি। যে কোনও উপায়ে, ধরুন আমাদের কাছে আমাদের অবিচ্ছেদ্য r , x এবং y রয়েছে । আমরা এখনও কয়েকটি জিনিস থেকে কম: আমাদের আর দরকারযথেষ্ট বড় হওয়ার জন্য এবং আমরা এটির থেকে আরও অনেক অনুরূপ জোড়া আনার জন্য একটি দ্রুত পদ্ধতি চাই। ভাগ্যক্রমে, এটি সম্পাদন করার একটি সহজ উপায় রয়েছে।
লক্ষ্য করুন প্রজেকশন পি সম্মুখের বনাম হয় দ V , অত r = পি · বনাম = (X, Y) · (খ / সি, A / C) = xb / C + + আগে / C যে, সমস্ত এই বলে xb + + ইয়া = আরসি । ফলস্বরূপ, সমস্ত পূর্ণসংখ্যার জন্য এন , (x + বিএন) 2 + (y + an) 2 = (x 2 + y 2 ) + 2 (এক্সবি + ইয়া) এন + (একটি 2 + বি 2 ) এন 2 = ( আর 2 + 1) + 2 (আরসি) এন + (সি 2 ) এন 2 = (আর + সিএন) 2 + 1। অন্য কথায়, ফর্মের যুগলের স্কোয়ারড মাত্রার
(এক্স + + বাংলা ভাষায়, Y + একটি) হয় (R + + CN) 2 + 1 টি , যা ঠিক জোড়া আমরা খুঁজছেন ধরনের হয়! বড় পরিমাণে এন এর জন্য এগুলি দৈর্ঘ্যের আর + সিএন এর অসাধু জোড় ।
এটি একটি দৃ concrete় উদাহরণ দেখতে সর্বদা সুন্দর। যদি আমরা পাইথাগোরিয়ান ট্রিপলেট (3, 4, 5) নিই , তবে r = 2 এ আমাদের পি = (1, 2) রয়েছে (আপনি এটি পরীক্ষা করতে পারেন (1, 2) · (4/5, 3/5) = 2 এবং, স্পষ্ট, 1 2 +2 2 = 2 2 + 1 টি ।) যোগ করার পদ্ধতি 5 থেকে দ এবং (4, 3) থেকে পি আমাদেরকে লাগে R '= 2 +5 = 7 এবং পি' = (1 + + 4, 2+ 3) = (5, 5) । দেখুন এবং দেখুন, 5 2 + 5 2 = 7 2 + 1। পরবর্তী স্থানাঙ্কগুলি হ'ল r '' = 12 এবং পি '' = (9, 8) , এবং আবার, 9 2 + 8 2 = 12 2 + 1 এবং আরও কিছু ...
আর একবার যথেষ্ট পরিমাণে বড় হয়ে গেলে আমরা 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);
}