【问题标题】:n-th prime number problem, need to speed it up a bit第n个素数问题,需要加快速度
【发布时间】:2010-10-30 02:32:19
【问题描述】:

有一个简单的密码可以将数字转换为一系列 ( )

为了加密一个数字(0 .. 2147483647)到这个表示,我(认为我)需要:

  • 质因数分解
  • 对于给定的 pp 是 Prime),p 的顺序序列(即。PrimeOrd(2) == 0 , PrimeOrd(227) == 49)

一些例子

0 . 6 (()()) 1 () 7 (...()) 2 (()) 8 ((.())) 3 (.()) 9 (.(​​())) 4 ((())) 10 (().()) 5 (..()) 11 (..()) 227 (.................................................. ()) 2147483648 ((........()))

我的问题源代码


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

static class P
{
    static List<int> _list = new List<int>();

    public static int Nth(int n)
    {
        if (_list.Count == 0 || _list.Count < n)
            Primes().Take(n + 1);

        return _list[n];
    }

    public static int PrimeOrd(int prime)
    {
        if (_list.Count == 0 || _list.Last() < prime)
            Primes().First(p => p >= prime);

        return (_list.Contains(prime)) ? _list.FindIndex(p => p == prime) : -1;
    }

    public static List<int> Factor(int N)
    {
        List<int> ret = new List<int>();
        for (int i = 2; i ≤ N; i++)
            while (N % i == 0)
            {
                N /= i;
                ret.Add(i);
            }

        return ret;
    }

    public static IEnumerable<int> Primes()
    {
        _list = new List<int>();

        _list.Add(2);
        yield return 2;

        Func<int, bool> IsPrime = n => _list.TakeWhile(p => p ≤ (int)Math.Sqrt(n)).FirstOrDefault(p => n % p == 0) == 0;

        for (int i = 3; i < Int32.MaxValue; i += 2)
        {
            if (IsPrime(i))
            {
                _list.Add(i);
                yield return i;
            }
        }
    }

    public static string Convert(int n)
    {
        if (n == 0) return ".";
        if (n == 1) return "()";

        StringBuilder sb = new StringBuilder();
        var p = Factor(n);
        var max = PrimeOrd(p.Last());
        for (int i = 0; i ≤ max; i++)
        {
            var power = p.FindAll((x) => x == Nth(i)).Count;
            sb.Append(Convert(power));
        }
        return "(" + sb.ToString() + ")";
    }
}

class Program
{
    static void Main(string[] args)
    {
        string line = Console.ReadLine();
        try
        {
            int num = int.Parse(line);
            Console.WriteLine("{0}: '{1}'", num, P.Convert(num));
        }
        catch
        {
            Console.WriteLine("You didn't entered number!");
        }
    }
}

问题是程序 PrimeOrd 的缓慢。你知道一些更快的解决方案来找出素数中的素数顺序吗?

标题

如果您知道如何加快查找素数的顺序,请提出一些建议。 :-)

谢谢。


附:小于 2,147,483,648 的最大素数是 2,147,483,647,它是 105,097,565th 素数。没有必要期望比 2^31 更大的数字。

【问题讨论】:

  • 我认为您的部分商家信息丢失了...
  • 如果 2 是 PrimeOrd(0),那不就是 PrimeOrd(227) = 48?
  • 你能解释一下为什么 6 = 2 * 3 = (()()) 吗?
  • 如果 6 = (().()) 和 10 = (()..()) 你在这里输入正确吗?
  • 列表看起来仍然不完整。转换函数在哪里?

标签: c# optimization performance primes prime-factoring


【解决方案1】:

这不是您在运行时应该做的事情。更好的选择是预先计算所有这些素数,然后以某种方式将它们放入您的程序中(静态数组或要读入的文件)。然后,慢代码将作为开发过程的一部分运行(无论如何它都很慢 :-),不是在您需要速度的地方。

那么这只是某种查找的问题,而不是每次需要它们时都计算它们。

【讨论】:

  • 我同意你的看法。如果这将是现实生活中的问题。 :-) 但这是编程方面的学术竞争,您将源代码发送到某个代理,测试代理在某些“单元测试”上运行您的代码,并将结果与​​其数据库进行比较。这些单元测试有一些 TIMEOUTS,在 2/4 的情况下,会遇到 TIMEOUT。问题是我不知道它有多慢(我不认为它很慢,但是计算出的针对 TIMEOUT 的程序必须比我的解决方案更快地计算它)。感谢您的评论,我会在工作中按照您的方式进行。但不是在学校...
  • 这确实是您想要的答案......即使您在使用缓存时构建缓存。目前,您的应用程序不断丢弃它在“_list”变量中所做的工作。
【解决方案2】:
【解决方案3】:

您应该将素数缓存到_list,然后将其用于Factor 和PrimeOrd。此外,避免运算符 LINQ 运算符(如 TakeWhile)创建的值会被丢弃。

这是一个优化的版本:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

static class P
{
    private static List<int> _list = new List<int>();

    public static int Nth(int n)
    {
        if (_list.Count == 0 || _list.Count <= n)
        {
            GenerateNextPrimes().First(p => _list.Count >= n);            
        }

        return _list[n];
    }

    public static int PrimeOrd(int prime)
    {
        var primes = GrowPrimesTo(prime);
        return primes.IndexOf(prime);
    }

    public static List<int> Factor(int N)
    {
        List<int> ret = new List<int>();        
        GrowPrimesTo(N);

        for (int ixDivisor = 0; ixDivisor < _list.Count; ixDivisor++)
        {
            int currentDivisor = _list[ixDivisor];

            while (N % currentDivisor == 0)
            {
                N /= currentDivisor;
                ret.Add(currentDivisor);
            }

            if (N <= 1)
            {
                break;
            }
        }

        return ret;
    }

    private static List<int> GrowPrimesTo(int max)
    {
        if (_list.LastOrDefault() >= max)
        {
            return _list;
        }

        GenerateNextPrimes().First(prime => prime >= max);
        return _list;        
    }

    private static IEnumerable<int> GenerateNextPrimes()
    {
        if (_list.Count == 0)
        {
            _list.Add(2);
            yield return 2;
        }

        Func<int, bool> IsPrime =
            n =>
            {
                // cache upperBound
                int upperBound = (int)Math.Sqrt(n);
                for (int ixPrime = 0; ixPrime < _list.Count; ixPrime++)
                {
                    int currentDivisor = _list[ixPrime];
                    if (currentDivisor > upperBound)
                    {
                        return true;
                    }

                    if ((n % currentDivisor) == 0)
                    {
                        return false;
                    }
                }

                return true;
            };

        // Always start on next odd number
        int startNum = _list.Count == 1 ? 3 : _list[_list.Count - 1] + 2;
        for (int i = startNum; i < Int32.MaxValue; i += 2)
        {
            if (IsPrime(i))
            {
                _list.Add(i);
                yield return i;
            }
        }
    }

    public static string Convert(int n)
    {
        if (n == 0) return ".";
        if (n == 1) return "()";

        StringBuilder sb = new StringBuilder();
        var p = Factor(n);
        var max = PrimeOrd(p.Last());
        for (int i = 0; i <= max; i++)
        {
            var power = p.FindAll(x => x == Nth(i)).Count;
            sb.Append(Convert(power));
        }
        return "(" + sb.ToString() + ")";
    }
}

class Program
{
    static void Main(string[] args)
    {        
        string line = Console.ReadLine();
        int num;

        if(int.TryParse(line, out num))
        {   
            Console.WriteLine("{0}: '{1}'", num, P.Convert(num));             
        }
        else
        {
            Console.WriteLine("You didn't entered number!");
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多