从Perl到Java
我试图解决一些在线难题,找到一个非常大的数的最大素因子(确切地说是739391333591914005052111110339491123405991919445111971)。在寻找解决方案的过程中,我偶然发现了以下Perl代码(): 但是我的结果总是不正确。。。而我的Perl对于对原始代码进行反向工程并不是很好。有人知道我遗漏了什么吗 ==更新:问题通过解决方法(在某种程度上)解决了来回答翻译问题。。。 您的Java翻译非常接近。它只有一个问题-您的从Perl到Java,java,perl,Java,Perl,我试图解决一些在线难题,找到一个非常大的数的最大素因子(确切地说是739391333591914005052111110339491123405991919445111971)。在寻找解决方案的过程中,我偶然发现了以下Perl代码(): 但是我的结果总是不正确。。。而我的Perl对于对原始代码进行反向工程并不是很好。有人知道我遗漏了什么吗 ==更新:问题通过解决方法(在某种程度上)解决了来回答翻译问题。。。 您的Java翻译非常接近。它只有一个问题-您的while循环条件应该是=0,而不是>0。
while
循环条件应该是=0
,而不是>0
。有了这项修正案,它将起作用。事实上,在某些情况下,它将输出第二大素因子
要显示这一点,请尝试使用1148487369611039
,它具有基本因子104717
,104723
,104729
。没有校正-它输出104723
,校正后,您会得到正确的答案:104729
算法评述
正如其他人在评论中所指出的,这不是一种特别快速的方式来做你想做的事情。事实上,这是一种轻描淡写的说法——它非常缓慢。在我的盒子里,找到正确答案花了3分钟(459905301806642105202622615174502491
)1,但要证明这个数是素数需要很长的时间(可能是500年,或者类似的顺序),只需简单地将每个奇数除以其平方根(这就是算法所做的)
你可以使用各种各样的技巧来加快速度,这取决于你对得到答案的把握程度。一种方法是预先测试任何候选素数-例如,使用biginger.isProbablePrime()
作为goAtIt()
中的测试插入一个测试,并在过程早期得到一个非常大的素数时提前返回。如果你不喜欢其中的概率因素,你可以自己动手。您还可以构建素数表,并且只能在任何试验划分和/或查找中使用这些素数表。你也可以考虑
1(我在while
循环goAtIt()
中的之后放置了一个输出,以检查它何时实际找到了解决方案)
关于Perl大数的注记
Perl的一个小问题是它不接受真正大的数字
我认为它比这更糟糕,因为如果您简单地替换
my $magic = <number>;
因此,它会给出错误的答案,而不是像上面演示的那样抛出错误。这相当令人讨厌,因为该算法适用于较小的数字,如果与较大的输入一起使用,可能会使粗心的用户产生错误的安全感…尽管这并不是您问题的答案:IMHO,您最好搜索其他素数分解算法,而不是尝试将此算法从Perl移植到Java。我想,对于这么大的数字来说,直接因子分解太慢了。作为一个提示:您是否也用较小的数字测试了重写的代码?如果它能工作,那么将数字增加,比如说,十次方左右,你就会看到计算是如何变慢的。perl代码使用浮点数,因此代码可能存在截断问题。您可能需要通过biginger.ONE在这里和那里轻推一个值。但这也没有真正起作用:-)我实际上觉得自己很愚蠢,我以前没有想到要寻找一个java示例来实现这一点。实际上,在stackoverflow上找到类似的解决方案并不难:。。。很抱歉,与使用递归相比,一种更快、占用内存更少的方法是,首先构建一个包含所有质数的列表,直到所讨论的数字。然后从大的数字开始倒转,寻找第一个等分的数字。
my $magic = <number>;
my $magic = Math::BigInt->new(' <number> ');
static final BigInteger two = new BigInteger( "2" );
public static void main( String[] args ) {
BigInteger number = new BigInteger( "<number>" );
System.out.println( goAtIt( number ) );
}
static BigInteger goAtIt( BigInteger prime ) {
if ( isEven( prime ) )
return goAtIt( prime.divide( two ).max( two ) );
BigInteger sqrt = sqrt( prime );
BigInteger comp = new BigInteger( "3" );
while (sqrt.compareTo( comp ) > 0) {
if ( prime.remainder( comp ).equals( BigInteger.ZERO ) )
break;
comp = comp.add( two );
}
if ( comp.compareTo( sqrt ) > 0 )
return prime;
return comp.max( goAtIt( prime.divide( comp ) ) );
}
static boolean isEven( BigInteger number ) {
return number.getLowestSetBit() != 0;
}
static BigInteger sqrt( BigInteger n ) {
BigInteger a = BigInteger.ONE;
BigInteger b = new BigInteger( n.shiftRight( 5 ).add( new BigInteger( "8" ) ).toString() );
while (b.compareTo( a ) >= 0) {
BigInteger mid = new BigInteger( a.add( b ).shiftRight( 1 ).toString() );
if ( mid.multiply( mid ).compareTo( n ) > 0 )
b = mid.subtract( BigInteger.ONE );
else
a = mid.add( BigInteger.ONE );
}
return a.subtract( BigInteger.ONE );
}
my $magic = <number>;
my $magic = 7393913335919140050521110339491123405991919445111971;