コードチャレンジ:最も近いプライム


8

チャレンジ

このタスクでは、整数Nが与えられます。整数に最も近い素数を出力する必要があります。

数値が素数の場合は、数値を出力します。

入力Nは1行で指定され、入力はEOFで終了します。入力の数は10000の値を超えません。

課題は、最速のソリューションを実装して、最大10000の値を可能な限り速く処理できるようにすることです。

入力

 299246598
 211571591
 71266182
 645367642
 924278231

出力

 299246587
 211571573
 71266183
 645367673
 924278233

制約

  • Nが2 ^ 64未満
  • ソリューションでは、指が4096バイトを超えないように注意してください。
  • 素数のための組み込みのものを使用していない限り、任意の言語を使用できます。
  • 最速のソリューション、最も効率的な時間の複雑さの勝利

追加:

これは、同じ問題の簡単なバージョン(N <2 ^ 31)なので、実際の問題を解決する前に、小さなケースでアプローチを確認してみてください。


2
あなたが要求している基本的な計算は、ほんの数日前のcodegolf.stackexchange.com/q/1977/78のサブパートでした。個人的に(つまり、モデレーターの帽子をかぶっていない)、そのような繰り返しは退屈だと思います。
dmckee ---元モデレーターの子猫

確率的素数検定を使用できますか?
キースランドール

2
どのように最速で審査する予定ですか?固定ハードウェアでの実行速度によって?または提出の複雑さを分析することによって?どういうわけか、異なる言語での運用コストを正規化しますか?-最後に、この課題は簡単すぎるようです。ここには革新の余地は本当にありません。
MtnViewMark 2011

1
@gnibbler:すべての2 ^ 64値のルックアップテーブルを使用すると、4096バイトウィンドウ全体(ソリューション)を
絞り込める

2
@Debanjan、時間の複雑さを述べる際の一般化されたリーマン仮説を仮定できるでしょうか?
Peter Taylor、

回答:


6

パイソン

import sys,random

# Miller-Rabin primality test, error rate 2^-200.                                                                                                                           
def prime(N):
  if N<3:return N==2
  s=0
  d=N-1
  while (d&1)==0:s+=1;d>>=1
  for i in xrange(100):
    a=random.randrange(1,N)
    if pow(a,d,N)!=1 and all(pow(a,d<<r,N)!=N-1 for r in xrange(s)):return 0
  return 1

for N in map(int,sys.stdin):
  d=0
  while 1:
    if prime(N+d):print N+d;break
    if prime(N-d):print N-d;break
    d+=1

ミラー・ラビン素数検定は無条件に決定論的ではないことに注意すべきです。en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test
mbomb007

2

パリGP

a(n)=x=[precprime(n),nextprime(n)];print(if(x[1]-n<n-x[2],x[1],x[2]))
while(1,print(a(input())))

私は、Mathematicaは似たものになるだろうとし、それはだNextPrime[n]厳密に上記の動作しますnので、3条件....
st0le

0

ハスケル

import Data.Numbers.Primes

-- Assuming, we are on x64
nearestPrime :: Int -> Int
nearestPrime n | n - s < l - n = s
               | otherwise     = l where
  l = head $ dropWhile (not . isPrime) [n..]
  s = head $ dropWhile (not . isPrime) [n,n-1..]

main = readLine >>= print . nearestPrime . read

かなり速いはずです。primeshackageから入手可能なパッケージが必要です。


申し訳ありませんが、これは許可されていません。これはコードの問題であり、この問題の短いバージョンでも機能しないはずです。
Quixotic

あなたが言ったように、コードのインポートは残念です。あなた自身よりも、別の規格で他人を判断しない限り
ベリサリウス博士は

@belisariusあなたは間違っている。これはコードゴルフではないので、コードサイズはオプションではありません。ただし、解決しようとしたタスクはコードゴルフでした。
FUZxxl 2012

1
組み込みの素数を使用することは、これはコードゴルフではなく、全体的なポイントは高速なアプローチを実装することであるため、良い選択ではありません。この答えは、明らかに-1に値します。でも、投票の気分は味わえません。
belisarius博士、

@belisariusなんらかの「復讐」が必要な場合は、私に投票してください。これで問題ありません。それにもかかわらず、それは悪いスタイルです。
FUZxxl 2012

0

ルビー

require 'prime'
gets(p).split.each{|n|
    a=b=n.to_i
    a,b = a-1,b+1 while !a.prime?  and !b.prime?
    p a.prime? ? a : b
}

組み込みの素数を使用するのは良い選択ではありません。これはコードゴルフではなく、全体的なポイントは高速なアプローチを実装することです。ベストスコアの決定はソリューションの複雑さに基づいて行われるため、これは許可されません。申し訳ありません。
Quixotic

0

ジャワ

これは、numが10 ^ 8より大きくなるまで1秒未満かかります。2 ^ 64は約1.8 * 10 ^ 19であることを考えると、十分に効率的ではありません。(6分前に10 ^ 15に開始され、まだD:を実行しています)

import java.util.*;

class ClosestPrime {

    public static double closest(double num) {
        double returnme = 0;
        if (isPrime(num)){returnme = num;}
        for (double i = 0; i < num / 2; i++) { //checks each side of num
            if (isPrime(num - i)) {returnme = num - i;
                break;}
            if (isPrime(num + i)) {returnme = num + i;
                break;}
        }
        return returnme;
    }

    private static boolean isPrime(double num) {
        long sqrtnum = (long) Math.sqrt(num); //no need to check for factors above sqrt(num)
        List<Double> primes = new LinkedList<Double>();
        primes.add((double) 2);
        for (double i = 3; i < sqrtnum; i+=2) {primes.add(i);} //fill list with odd numbers

        for (long i = 2; i <= sqrtnum; i++) {
            if (num / i % 1 == 0) {return false;}   
            ListIterator<Double> iter = primes.listIterator();
            while (iter.hasNext()) {if ((iter.next()) / i % 1 == 0){iter.remove();}} //sieving by Eratosthenes
        }
        return true;
    }
}

確率的アルゴリズムを使用しないため、毎回確実な答えが得られますが、効率の面でその代償が大きくなります。10^ 18は、リストに500万以上の素数があり、ふるい分け前にさらに多くなります。より良いふるいアルゴリズムでいつかこれを改善するかもしれません。これが他のどれよりも優れているとは思わない:)


0

ハスケル

これはかなり高速で、大きな制限までは非決定的です。また、私の最初のHaskell :)。wc903bはコンパイルされていません。

編集:誰かが時間の複雑さを推定したい場合は、私のゲストになってください...

import System.Environment
import Math.NumberTheory.Moduli -- arithmoi
import Data.List.Ordered -- data-ordlist

main :: IO ()
main = interact processInputStrings

processInputStrings :: String -> String
processInputStrings input = unlines $ map show $ getClosestMembers $ map read $ lines $ input 

isPrime :: Integer -> Bool
{- Implement the Miller–Rabin test with basis valid up to somewhere > 2^64 -}
isPrime 2 = True
isPrime 3 = True
isPrime t =  let
        factor :: (Integer, Integer) -> (Integer, Integer)
        factor (d,s) = if even d then factor (d `div` 2, s+1) else (d,s)
        (d,s) = factor (t-1, 0)
    in 
        and $ map (\a ->
            or [(powerMod a d t) == 1, or [(powerMod a (2^r * d) t) == t-1 | r <- [0..s-1]]]
        ) $ filter (<t) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]


getClosestMembers :: [Integer] -> [Integer]
getClosestMembers inputs = map (\i -> head [n | n <- concat [[i-d, i+d] | d <- [0..]], isPrime n]) inputs
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.