C ++、275,000,000+
我々のようなその大きさが正確に表現されペアを参照します(X、0)として、正直ペアおよび他のすべての対に不正対振幅のM、Mは対の誤報告の大きさです。最初のプログラム前の投稿は:honest-の緊密に関連するカップルや不正対のセット使用
(X、0)と(X、1)十分な大きさのために、それぞれ、X。2番目のプログラムでは、不正なペアの同じセットを使用しましたが、整数マグニチュードのすべての正直なペアを探すことで、正直なペアのセットを拡張しました。プログラムは10分以内に終了しませんが、その結果の大部分が非常に早い段階で検出されるため、ランタイムの大部分が無駄になります。このプログラムは、あまり頻繁ではない正直なペアを探し続ける代わりに、空き時間を使って次の論理的なことを行います。不正なペアのセットを拡張します。
前の投稿から、十分に大きいすべての整数rについて、sqrt(r 2 + 1)= rであることがわかります。ここで、sqrtは浮動小数点平方根関数です。攻撃の計画は、何らかの十分に大きい整数r に対してx 2 + y 2 = r 2 + 1となるようなペアP =(x、y)を見つけることです。これは簡単ですが、このようなペアを個別に探すのは遅すぎて面白くありません。前のプログラムで正直なペアを作成したのと同じように、これらのペアをまとめて見つけたいと思います。
ましょう{ V、W }ベクトルの正規直交対です。すべての実スカラーrについて、|| r v + w || 2 = R 2 + 1。でℝ 2、これは、ピタゴラスの定理の直接の結果です:
私たちは、ベクトルを探しているVとWが存在するような整数 Rれるxはとyはまた整数であるが。ちなみに、我々は前の二つのプログラムで使用不正ペアのセットは、単に本の特別な場合、であったことを注記として、{ V、Wは }の標準基づいたℝ 2。今回は、より一般的な解決策を見つけたいと思います。これは、ピタゴラスのトリプレット(整数のトリプレット(a、b、c)がa 2 + b 2 = c 2を満たす場所です。、前のプログラムで使用した)がカムバックします。
してみましょう(a、b、c)は、ピタゴラスのトリプレットなります。ベクトルv =(b / c、a / c)およびw =(-a / c、b / c)(および
w =(a / c、-b / c))は正規直交であり、検証が容易です。 。結局のところ、ピタゴラスのトリプレットの選択には、xとyが整数であるような整数rが存在します。これを証明し、rとPを効果的に見つけるには、少しの数/群理論が必要です。詳細は省きます。いずれにしても、積分r、x、yがあると仮定します。まだいくつかのことが足りません。rが必要です。十分に大きくするために、このメソッドからより多くの同様のペアを導出する高速な方法が必要です。幸いなことに、これを達成する簡単な方法があります。
Pのvへの射影はr vなので、r = P ・ v =(x、y)・(b / c、a / c)= xb / c + ya / c、これはすべて xb + ya = rc。その結果、すべての整数 nに対して、(x + bn)2 +(y + an)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 + bn、y + an)のペアの2乗の大きさは(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にR及び(4,3)のPはに私たちを取り、R '= 2 + 5 = 7とP' =(+ 4 1、2 + 3)=(5、5)。見よ、5 2 + 5 2 = 7 2 + 1。次の座標はr '' = 12およびP '' =(9、8)であり、9 2 + 8 2 = 12 2 + 1などです...
いったんrが十分な大きさで、我々は大きさの単位で不誠実なペアを取得を開始5。それはおよそ27,797,402 / 5不正なペアです。
だから今、私たちは整数の大きさの不正なペアをたくさん持っています。最初のプログラムの正直なペアとそれらを簡単に組み合わせて誤検出を形成できます。また、慎重に2番目のプログラムの正直なペアを使用することもできます。これは基本的にこのプログラムが行うことです。前のプログラムと同様に、その結果のほとんどを非常に早い段階で見つけます-数秒以内に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);
}