从Perl到Java
我正在尝试解决一些在线难题,找到一个非常大的数字的最大素数因子(准确地说是7393913335919140050521110339491123405991919445111971).在我寻找解决方案时,我偶然发现了这个Perl代码(
from here):
use strict; use warnings; my $magic = <number>; sub largestprimef($); sub max($$); print largestprimef($magic); sub largestprimef($) { my $n = shift; my $i; return largestprimef(max(2,$n/2)) if($n % 2 == 0); my $sn = int( sqrt($n) ); for ( $i = 3 ; $i <= $sn ; $i += 2 ) { if ( $n % $i == 0 ) { last; } } if ( $i > $sn ) #loop ran over,means the number is prime { return $n; } else { return max( $i,largestprimef( $n / $i ) ); } } sub max($$) { return ( sort { $a <=> $b } (@_) )[1]; } 现在该算法似乎有效! Perl的一个小问题是它不接受真正的大数字.所以我改写了 my $magic = <number>; 至 my $magic = Math::BigInt->new(' <number> '); 但这只是运行了很多年龄.所以我把它重写为Java(我更熟悉),这导致了这个: 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 ); } 但是我的结果总是关闭……而且我的Perl对原始代码进行逆向工程并不是那么好.有没有人知道我错过了什么? ==更新:问题(某种程度上)通过解决方法解决 解决方法
要回答翻译问题……
您的Java翻译非常接近.它只有一个问题 – 你的while循环条件应该是> = 0,而不是> 0.通过该修订,它将起作用.实际上 – 在某些情况下它会输出第二大的素因子. 为了证明这一点 – 试试1148487369611039 – 它有素数因子104717,104723&没有修正 – 它输出104723,通过修正,你得到正确答案:104729 评论算法 正如其他人在评论中所指出的那样 – 这并不是一种特别快速的方式来做你想要的.事实上,这是轻描淡写 – 这是非常缓慢的.在我的盒子上花了3分钟才找到正确的答案(459905301806642105202622615174502491)1,但需要很长时间(可能是500年,或者那种顺序),通过简单的试验划分每个奇数来证明这个数字是素数数字到它的平方根(这是算法的作用). 您可以使用各种技巧来加快速度,具体取决于您希望获得答案的确定程度.一个是预先测试任何候选人的素数 – 例如使用BigInteger.isProbablePrime()以高确定性插入测试作为goAtIt()中的测试,如果在此过程的早期获得非常大的素数,则提前返回.如果你不喜欢它的概率元素,你可以滚动你自己的Miller-Rabin primality deterministic test.你也可以构建素数表,并且只在任何试验分区和/或查找中使用它们.您可能还会考虑Pollard-Strassen algorithm 1(我在goAtIt()中的while循环之后输出一个输出,以检查它何时实际找到了解决方案) 关于Perl大数字的注释
我认为它比这更糟糕,因为如果你只是替换,Perl会暗含turn the large integer into a double precision floating point my $magic = <number>; 同 my $magic = 7393913335919140050521110339491123405991919445111971; 所以 – 它会给出错误的答案而不是抛出错误,如ideone here所示.相当讨厌,因为算法适用于小数字,并且如果用于较大的输入,可能会使不警惕的用户陷入虚假的安全感…… (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |