番号Xがあり、SQL-Serverを使用してIsPrime(X) = true/false
と言いたい場合、最善のアプローチは何ですか?
素数のテーブルをインポートするだけですか、それとも小さい素数に対してかなり効率的なアルゴリズムがありますか?
注:私は約よりも大きい数には興味がありません。千万。
以下を使用することになりました:
CREATE FUNCTION [dbo].[isPrime]
(
@number INT
)
RETURNS VARCHAR(10)
BEGIN
DECLARE @retVal VARCHAR(10) = 'TRUE';
DECLARE @x INT = 1;
DECLARE @y INT = 0;
WHILE (@x <= @number )
BEGIN
IF (( @number % @x) = 0 )
BEGIN
SET @y = @y + 1;
END
IF (@y > 2 )
BEGIN
SET @retVal = 'FALSE'
BREAK
END
SET @x = @x + 1
END
RETURN @retVal
END
これは多くの人に起こっていないのではないかと思いますが、チェックする必要があるのは、新しい数がそれぞれ前の素数で割り切れるかどうかだけです...
create table prime (primeno bigint)
declare @counter bigint
set @counter = 2
while @counter < 1000000
begin
if not exists(select top 1 primeno from prime where @counter % primeno = 0 )
-上記で、ANDプライム<@counter/2などを追加すると、チェックのオーバーヘッドがさらに削減されます。
insert into prime select @counter
set @counter = @counter + 1
end
select * from prime order by 1
怠惰なコーディングですが、私の隣のような遅い仮想PCでも、数分で最大100万個のすべてを手に入れることができます。何かを見落としていない限り、78,498個にします(1を数えない場合)。
CREATE proc prime
@no int
as
declare @counter int
set @counter =2
begin
while(@counter)<@no
begin
if(@no%@counter=0)
begin
select 'Not prime'
return
end
set @counter=@counter+1
end
select 'prime'
return
end
--exec prime 10
シーケンス生成 に基づいて、関数や反復プロセス(while
)なしで素数を生成する興味深い方法があります。基本的には2 .. @max
シーケンスが生成され、シーケンス内に他にないすべての番号をcurrent%other = 0
:
declare @max INT = 10000
;WITH all_numbers(n) AS
(
SELECT 2
UNION ALL
SELECT n+1 FROM all_numbers WHERE n < @max
)
select all1.n as prime
from all_numbers all1
where not exists (select 1 from all_numbers all2 where all2.n < all1.n AND all1.n % all2.n = 0)
order by all1.n
-- beware, 0 means no limit. Otherwise 32767 can be the max specified
OPTION (MAXRECURSION 0)
このソリューションの主な欠点はパフォーマンスです(たとえば、20000まですべての素数を生成するのに約17秒かかりました)。
これはうまく機能する簡単なスクリプトです。必要に応じて@numを調整します。
declare @nonprimes table (number int)
declare @primes table (number int)
declare @num int = 2
declare @divisor int = 1
while @num<10000
begin
while @divisor>1
begin
if @num % @divisor=0
insert @nonprimes
select @num
if @@rowcount>0 goto A
set @divisor=@divisor-1
end
insert @primes
select @num
A: set @num=@num+1
set @divisor=@num-1
end
select sum(number) from @primes