【问题标题】:Create a class PrimeRandomGenerator that extends class RandomGenerator创建一个扩展类 RandomGenerator 的 PrimeRandomGenerator 类
【发布时间】:2015-12-20 11:55:46
【问题描述】:

我必须创建一个扩展 RandomGenerator 的类,并在每次用户在主程序中输入一个区间时生成一个随机素数。

我已经创建了构造函数和isPrime 方法,但我不知道下一步该做什么。

这就是我得到的。我确信这其中有错误,但我就是看不到它们。

public class RandomGeneratorImproved extends RandomGenerator {
    public RandomGeneratorImproved(int prime) {
        int startp=0;
        int tillp=prime-1;

    }


    public RandomGeneratorImproved(int lowp,int upperp) {
        int startp=lowp;
        int tillp=upperp;

    }


    public boolean isPrime(int startp,int tillp) {
        int prime=rgen.nextInt(startp,tillp);
        int n=0;
        if (prime<=1) {
            return false;
        } else if (prime<=3) {
            return true;
        } else if (prime%2==0 || prime%3==0){
            return false;
        }
        for (int i=5;i<(prime/i);i+=6) {
            if (prime%i==0) {
                return false;
            }
        }
        return true;
    }


    private RandomGenerator rgen= RandomGenerator.getInstance();
}

注意事项:

  • 如果用户只输入一个数字(比如说:x),那么间隔将为 (0,x)。换句话说,我们必须创建两个方法或两个构造函数。
    例如:
    public int nextPrime(int n)public int nextPrime(int low,int high)

  • 我不允许使用数组(或其他使问题变得更容易的现成方法)。

  • 我搜索了所有涉及随机素数生成器的内容,但找不到与此类似的内容。

【问题讨论】:

  • 发布MCVE。请务必将您的代码复制粘贴到新项目,并确保在将其发布到此处之前编译并运行。
  • 我的代码无法运行,这就是我在这里发帖的原因。它还没有完成,我无法编译它,我只能发布完成的部分。我应该吗?
  • 是的,不过只是与您的问题相关的部分。
  • 好的,完成。感谢您的反馈!
  • 不知道 acm.jar 是什么,它不是 SE 库的一部分。此外,这些变量没有在那里声明,它们只是被赋值。正如我所说,将这个类复制粘贴到一个新项目中,看看它是否编译。然后我会指导你如何使用它。

标签: java class random primes


【解决方案1】:

关于如何改进和使用课程的一些建议。

我必须创建一个扩展 RandomGenerator 的类,并在每次用户在主程序中输入一个区间时生成一个随机素数。

这告诉我,您的类的实例在创建时与范围无关。该范围仅根据用户生成素数的需求给出。因此,我会

  • 创建一个空的构造函数并在那里进行任何初始化。
  • 添加重载方法public int generatePrime(int high)public int generatePrime(int low, int high)。通常,具有较少参数(较少数据)的重载方法应该只通过完成所需数据来调用最具体的方法(参见下面的代码)。
  • 方法名称isPrime 表明它应该检查一个给定的int 是否是素数。我会做到boolean isPrime(int primeQ)

剩下的唯一步骤是从指定的范围内找出ints 给isPrime 的内容。由于超类有一个在范围内生成随机int 的方法,您可以将其传递给isPrime 以检查它是否为素数。如果是,请将其退回,否则重试。请注意,这效率极低,但由于缺乏工具和信息,这是我能找到的最简单的桥梁。

代码如下:

public class RandomGeneratorImproved extends RandomGenerator {

    private RandomGenerator rgen;

    public RandomGeneratorImproved() {

        rgen = RandomGenerator.getInstance();
    }

    public int generatePrime(int prime) {

        return generatePrime(0, prime - 1);
    }

    public int generatePrime(int lowp, int upperp) {

        int prime = rgen.nextInt(lowp, upperp);
        while (!isPrime(prime))
            prime = rgen.nextInt(lowp, upperp);
        return prime;
    }

    public boolean isPrime(int prime) {

        int n = 0; // <------ this is not used
        if (prime <= 1) {
            return false;
        }
        else if (prime <= 3) {
            return true;
        }
        else if (prime % 2 == 0 || prime % 3 == 0) {
            return false;
        }
        for (int i = 5; i < (prime / i); i += 6) {
            if (prime % i == 0) {
                return false;// "random number"+prime+"is not a prime number";
            }
        }
        return true;// "random number"+prime+"is a prime number";
    }
}

请注意,int n = 0; 行会发出警告,指出从未使用过 n。您可能想要删除它。

用法是:

RandomGeneratorImproved rpg = new RandomGeneratorImproved();
int generatedPrime = rpg.generatePrime(6, 30);
int generatedPrime2 = rpg.generatePrime(30); // same as rpg.generatePrime(1, 30)

【讨论】:

  • 谢谢您,先生,我真的很高兴。但是,如果在这些区间之一中不存在素数怎么办?我认为while 循环永远不会结束......
  • @George.K 非常正确,但实现的细节取决于您以及您可以使用的任何工具。例如,如果您能够使用数组,则可以存储您尝试过的所有整数,以便不再重复它们,一旦不再尝试,只需返回 -1 之类的东西以表示那里没有素数。如果您正在阅读一本书,它应该会指导您。我只是帮助了类结构和 OO 设计思想和约定。
  • 我不能用 for 循环来做到这一点吗?例如:for(int i=0;i&lt;=(upperp-lowp);i++) { if (!isPrime(prime) { prime =rgen.nextInt(lowp,upperp) }else { prime=-1 } return prime; 并在主程序中检查素数是否为 -1。 (抱歉打字不好)
  • @George.K 你在循环什么? i 不在循环内使用。而且您仍然在每次迭代的范围内生成一个随机的int。您只是在限制迭代次数。
  • 哎呀,是的,很抱歉,这绝对不是真的。没关系,我会弄清楚的,谢谢你的帮助!
【解决方案2】:

拒绝方法 - 在感兴趣的范围内生成一个随机数,检查它是否满足目标标准,如果不满足则返回它,重复该过程 - 具有产生完全无偏结果的优点。它的缺点是性能(或缺乏)。

此外,试除法几乎是人类已知的最慢的素性测试方法。根据“随机素数”的使用,不同的方法是可能的。它们都要求以某种形式提供直到范围上限的平方根的主要因素,但审判部门也是如此。

替代方案 1:埃拉托色尼的窥视孔

鉴于目标范围似乎仅限于小整数,以下方法是可行的:绘制一个随机数 k,使用 Eratosthenes 的窗口筛法筛选范围 [max(2, k - 335), k] 并返回该范围内的最高素数。之所以可行,是因为素数之间的间距最大为 4,302,407,359 不超过 336。因此,小窗口(“窥视孔”)必须包含一个素数。

缺点:由此产生的素数分布是不均匀的(有偏差的)。例如,仅当 k == 2 时才会返回数字 2,因为下一个更高的素数 (3) 就在它旁边。相比之下,数字 3,842,610,773 后面跟着 335 个非素数,因此它被绘制的概率是数字 2 的 336 倍。但是,通过查看输出来证明偏差并不容易,而且对于自动化测试人员应该几乎是不可能的。

警告:在这种情况下,筛选总是需要处理直到 k 的平方根的所有素数因子,这涉及每个素数的模除以计算窗口内的起始偏移量。相比之下,仅根据前十几个素数,审判部门就可以拒绝超过 85% 的所有复合材料。因此,窥视孔实际上可能没有任何情况比审判部门有优势。

替代方案 2:惰性分段埃拉托色尼

筛选前 2^31 个数字需要相当多的 CPU 时间(在 C++ 中大约需要 1 CPU 秒,在 Java 中更多),除非大量需要随机素数,否则很多努力都白费了,数以百万计的曲调。如果只需要一小部分随机素数,那么试除法确实是要走的路,但如果需要更多,那么分段筛分的惰性方法会有所帮助。

选择一个不超过 L1 缓存大小的段大小,并创建一个覆盖整个目标范围的段缓存数组。绘制一个随机 k 后,从缓存中检索对应段的引用;如果为 nil,则筛选段并将引用存储在适当的缓存槽中。然后你在任何情况下都有一个段引用,所以你可以通过检查段中的位 (k &gt;&gt; 1) % segment_size 来测试 k 的素数,假设只有赔率的筛子。

段应该是表示奇数的打包位图,如果段大小是 2 的幂,则可以通过掩码计算% segment_size。这样您总是可以快速得到答案,而无需长时间等待将整个范围筛选为一个去。当您需要它时(即当您绘制大量随机素数时)效率会提高,因为缓存会自行填满,导致越来越多的素数查询由已经存在的段来满足。

与窥视孔方法不同,这给出了一个完全无偏的分布(这很明显,因为它只替代了素数测试,而不是绘制素数的实际方法)。

post on Code Review 中有更多信息讨论了绘制 100 个随机素数的挑战。

【讨论】:

  • 我已经搜索了您所说的所有内容,但我想不出一种算法来实现这一点。另外,我只想要一个不管速度如何都能运行的算法(我知道这很愚蠢,但在我的水平上,我想要的只是运行程序)。无论如何感谢您的评论!
  • 不用担心,对于少量的查询和/或交互速度,试用部门绝对是要走的路。我忽略了您的问题描述中的“交互式”位,(“每次用户输入......”)这就是为什么我考虑如何快速获得孤立查询的答案,甚至更快地响应批量查询(例如 Lazy Eratosthenes) . IOW,在批量查询需要时获得筛子的性能,而无需在程序启动时等待其完全初始化(这在测试时会变得非常烦人)。窥视孔更像是一种跳出框框思考的练习。
  • 是的,我同意最后一个。我会考虑的,我希望我能找到一种方法,因为试用部门确实让我的程序真的很慢。你真的很有帮助,我会考虑你的话!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-08-15
  • 1970-01-01
  • 1970-01-01
  • 2015-06-08
  • 2013-04-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多