সি #, 10039 28164 সংখ্যা
6 0{28157} 169669
সম্পাদনা: আমি কিছু ছোটখাট পরিবর্তন করে কোয়ালটাগের অ্যালগরিদমের উপর ভিত্তি করে অন্য একটি প্রোগ্রাম তৈরি করেছি:
- আমি L000 ... 000R ফর্মের সংখ্যাগুলি সন্ধান করছি, যেখানে এলটি যৌথ বামে রয়েছে, আর ডান সংমিশ্রণ। আমি বাম সংমিশ্রণ নম্বর এলকে একাধিক অঙ্কের অনুমতি দিয়েছি, যদিও এটি বেশিরভাগ ক্ষেত্রে একটি শৈলীর পরিবর্তন, এবং এটি সম্ভবত অ্যালগরিদমের কার্যকারিতা প্রভাবিত করে না।
- অনুসন্ধানে গতি বাড়ানোর জন্য আমি মাল্টিথ্রেডিং যুক্ত করেছি।
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Threading;
using System.Threading.Tasks;
using Mpir.NET;
class Program
{
const int PrimeNotFound = int.MaxValue;
private static BitArray _primeSieve;
private static HashSet<Tuple<int, int>> _templatesToSkip = new HashSet<Tuple<int, int>>();
static void Main(string[] args)
{
int bestDigitCount = 0;
foreach (Tuple<int, int> template in GetTemplates())
{
int left = template.Item1;
int right = template.Item2;
if (SkipTemplate(left, right))
continue;
int zeroCount = GetZeroCountOfPrime(left, right);
if (zeroCount != PrimeNotFound)
{
int digitCount = left.ToString().Length + right.ToString().Length + zeroCount;
if (digitCount >= bestDigitCount)
{
string primeStr = left + " 0{" + zeroCount + "} " + right;
Console.WriteLine("testing " + primeStr);
bool isFragile = IsFragile(left, right, zeroCount);
Console.WriteLine(primeStr + " is fragile: " + isFragile);
if (isFragile)
bestDigitCount = digitCount;
}
_templatesToSkip.Add(template);
}
}
}
private static int GetZeroCountOfPrime(int left, int right)
{
_zeroCount = 0;
int threadCount = Environment.ProcessorCount;
Task<int>[] tasks = new Task<int>[threadCount];
for (int i = 0; i < threadCount; i++)
tasks[i] = Task.Run(() => InternalGetZeroCountOfPrime(left, right));
Task.WaitAll(tasks);
return tasks.Min(task => task.Result);
}
private static int _zeroCount;
private static int InternalGetZeroCountOfPrime(int left, int right)
{
const int maxZeroCount = 40000;
int zeroCount = Interlocked.Increment(ref _zeroCount);
while (zeroCount <= maxZeroCount)
{
if (zeroCount % 1000 == 0)
Console.WriteLine("testing " + left + " 0{" + zeroCount + "} " + right);
if (IsPrime(left, right, zeroCount))
{
Interlocked.Add(ref _zeroCount, maxZeroCount);
return zeroCount;
}
else
zeroCount = Interlocked.Increment(ref _zeroCount);
}
return PrimeNotFound;
}
private static bool SkipTemplate(int left, int right)
{
for (int leftDiv = 1; leftDiv <= left; leftDiv *= 10)
for (int rightDiv = 1; rightDiv <= right; rightDiv *= 10)
if (_templatesToSkip.Contains(Tuple.Create(left / leftDiv, right % (rightDiv * 10))))
return true;
return false;
}
private static bool IsPrime(int left, int right, int zeroCount)
{
return IsPrime(left.ToString() + new string('0', zeroCount) + right.ToString());
}
private static bool IsPrime(string left, string right, int zeroCount)
{
return IsPrime(left + new string('0', zeroCount) + right);
}
private static bool IsPrime(string s)
{
using (mpz_t n = new mpz_t(s))
{
return n.IsProbablyPrimeRabinMiller(20);
}
}
private static bool IsFragile(int left, int right, int zeroCount)
{
string leftStr = left.ToString();
string rightStr = right.ToString();
for (int startIndex = 0; startIndex < leftStr.Length - 1; startIndex++)
for (int count = 1; count < leftStr.Length - startIndex; count++)
if (IsPrime(leftStr.Remove(startIndex, count), rightStr, zeroCount))
return false;
for (int startIndex = 1; startIndex < rightStr.Length; startIndex++)
for (int count = 1; count <= rightStr.Length - startIndex; count++)
if (IsPrime(leftStr, rightStr.Remove(startIndex, count), zeroCount))
return false;
return true;
}
private static IEnumerable<Tuple<int, int>> GetTemplates()
{
const int maxDigitCount = 8;
PreparePrimeSieve((int)BigInteger.Pow(10, maxDigitCount));
for (int digitCount = 2; digitCount <= maxDigitCount; digitCount++)
{
for (int leftCount = 1; leftCount < digitCount; leftCount++)
{
int rightCount = digitCount - leftCount;
int maxLeft = (int)BigInteger.Pow(10, leftCount);
int maxRight = (int)BigInteger.Pow(10, rightCount);
for (int left = maxLeft / 10; left < maxLeft; left++)
for (int right = maxRight / 10; right < maxRight; right++)
if (IsValidTemplate(left, right, leftCount, rightCount))
yield return Tuple.Create(left, right);
}
}
}
private static void PreparePrimeSieve(int limit)
{
_primeSieve = new BitArray(limit + 1, true);
_primeSieve[0] = false;
_primeSieve[1] = false;
for (int i = 2; i * i <= limit; i++)
if (_primeSieve[i])
for (int j = i * i; j <= limit; j += i)
_primeSieve[j] = false;
}
private static bool IsValidTemplate(int left, int right, int leftCount, int rightCount)
{
int rightDigit = right % 10;
if ((rightDigit != 1) && (rightDigit != 9))
return false;
if (left % 10 == 0)
return false;
if ((left + right) % 3 == 0)
return false;
if (!Coprime(left, right))
return false;
int leftDiv = 1;
for (int i = 0; i <= leftCount; i++)
{
int rightDiv = 1;
for (int j = 0; j <= rightCount; j++)
{
int combination = left / leftDiv * rightDiv + right % rightDiv;
if (_primeSieve[combination])
return false;
rightDiv *= 10;
}
leftDiv *= 10;
}
return true;
}
private static bool Coprime(int a, int b)
{
while (b != 0)
{
int t = b;
b = a % b;
a = t;
}
return a == 1;
}
}
পুরানো উত্তর:
8 0{5436} 4 0{4600} 1
ভঙ্গুর প্রাইমগুলির জন্য কয়েকটি উল্লেখযোগ্য নিদর্শন:
600..00X00..009
900..00X00..009
800..00X00..001
999..99X99..999
যেখানে এক্স 1, 2, 4, 5, 7 বা 8 হতে পারে।
এই জাতীয় সংখ্যার জন্য আমাদের কেবলমাত্র (দৈর্ঘ্য - 1) সম্ভাব্য Remove
অপারেশনগুলি বিবেচনা করতে হবে । অন্যান্য Remove
ক্রিয়াকলাপগুলি হ'ল ডুপ্লিকেট বা স্পষ্টত সম্মিলিত সংখ্যা উত্পাদন করে produce আমি 800 টিরও বেশি সংখ্যার সাথে এই জাতীয় সমস্ত সংখ্যার সন্ধান করার চেষ্টা করেছি এবং লক্ষ্য করেছি যে বাকীগুলির চেয়ে 4 টি নিদর্শনগুলি আরও ঘন ঘন আসে: 8007001, 8004001, 9997999 এবং 6004009. এমিল এবং জাকুব যেহেতু 999X999 নিদর্শনটি ব্যবহার করছে, তাই আমি ঠিক 8004001 ব্যবহার করার সিদ্ধান্ত নিয়েছি কিছু বিভিন্ন যোগ করতে।
আমি অ্যালগরিদমে নিম্নলিখিত অপটিমাইজেশন যুক্ত করেছি:
- আমি 7000 সংখ্যার সাথে সংখ্যাগুলি থেকে অনুসন্ধান শুরু করি এবং তারপরে প্রতিবার একটি ভঙ্গুর প্রাইম পাওয়া গেলে 1500 দ্বারা বৃদ্ধি দৈর্ঘ্য। যদি কোনও প্রদত্ত দৈর্ঘ্যের সাথে কোনও ভঙ্গুর প্রাইম না থাকে তবে আমি এটি 1 দিয়ে বাড়িয়ে দেব 7 7000 এবং 1500 কেবল স্বেচ্ছাসেবী সংখ্যা যা উপযুক্ত বলে মনে হয়।
- আমি একই সাথে বিভিন্ন দৈর্ঘ্যের সংখ্যার সন্ধান করতে মাল্টিথ্রেডিং ব্যবহার করছি।
- সদৃশ চেক প্রতিরোধ করতে প্রতিটি প্রধান পরীক্ষার ফলাফল একটি হ্যাশ টেবিলের মধ্যে সংরক্ষণ করা হয়।
- আমি এমপির.এনইটি থেকে মিলার-রবিন বাস্তবায়ন ব্যবহার করছি , যা খুব দ্রুত (এমপিআইআর জিএমপির একটি কাঁটাচামচ)।
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using Mpir.NET;
class Program
{
const string _template = "8041";
private static ConcurrentDictionary<Tuple<int, int>, byte> _compositeNumbers = new ConcurrentDictionary<Tuple<int, int>, byte>();
private static ConcurrentDictionary<int, int> _leftPrimes = new ConcurrentDictionary<int, int>();
private static ConcurrentDictionary<int, int> _rightPrimes = new ConcurrentDictionary<int, int>();
static void Main(string[] args)
{
int threadCount = Environment.ProcessorCount;
Task[] tasks = new Task[threadCount];
for (int i = 0; i < threadCount; i++)
{
int index = i;
tasks[index] = Task.Run(() => SearchFragilePrimes());
}
Task.WaitAll(tasks);
}
private const int _lengthIncrement = 1500;
private static int _length = 7000;
private static object _lengthLock = new object();
private static object _consoleLock = new object();
private static void SearchFragilePrimes()
{
int length;
lock (_lengthLock)
{
_length++;
length = _length;
}
while (true)
{
lock (_consoleLock)
{
Console.WriteLine("{0:T}: length = {1}", DateTime.Now, length);
}
bool found = false;
for (int rightCount = 1; rightCount <= length - 2; rightCount++)
{
int leftCount = length - rightCount - 1;
if (IsFragilePrime(leftCount, rightCount))
{
lock (_consoleLock)
{
Console.WriteLine("{0:T}: {1} {2}{{{3}}} {4} {2}{{{5}}} {6}",
DateTime.Now, _template[0], _template[1], leftCount - 1,
_template[2], rightCount - 1, _template[3]);
}
found = true;
break;
}
}
lock (_lengthLock)
{
if (found && (_length < length + _lengthIncrement / 2))
_length += _lengthIncrement;
else
_length++;
length = _length;
}
}
}
private static bool IsFragilePrime(int leftCount, int rightCount)
{
int count;
if (_leftPrimes.TryGetValue(leftCount, out count))
if (count < rightCount)
return false;
if (_rightPrimes.TryGetValue(rightCount, out count))
if (count < leftCount)
return false;
if (!IsPrime(leftCount, rightCount))
return false;
for (int i = 0; i < leftCount; i++)
if (IsPrime(i, rightCount))
return false;
for (int i = 0; i < rightCount; i++)
if (IsPrime(leftCount, i))
return false;
return true;
}
private static bool IsPrime(int leftCount, int rightCount)
{
Tuple<int, int> tuple = Tuple.Create(leftCount, rightCount);
if (_compositeNumbers.ContainsKey(tuple))
return false;
using (mpz_t n = new mpz_t(BuildStr(leftCount, rightCount)))
{
bool result = n.IsProbablyPrimeRabinMiller(20);
if (result)
{
_leftPrimes.TryAdd(leftCount, rightCount);
_rightPrimes.TryAdd(rightCount, leftCount);
}
else
_compositeNumbers.TryAdd(tuple, 0);
return result;
}
}
private static string BuildStr(int leftCount, int rightCount)
{
char[] chars = new char[leftCount + rightCount + 1];
for (int i = 0; i < chars.Length; i++)
chars[i] = _template[1];
chars[0] = _template[0];
chars[leftCount + rightCount] = _template[3];
chars[leftCount] = _template[2];
return new string(chars);
}
}