Sieve of Sundaram (สำหรับการค้นหาหมายเลขเฉพาะ)


13

ความท้าทาย

ใช้ตะแกรง Sundaramnสำหรับการหาตัวเลขที่สำคัญดังต่อไปนี้ ใช้เป็นจำนวนเต็มการป้อนข้อมูลและการส่งออกตัวเลขที่สำคัญดังต่อไปนี้n nคุณสามารถสันนิษฐานได้ว่าnจะน้อยกว่าหรือเท่ากับหนึ่งล้านเสมอ


กระชอน

  1. เริ่มต้นด้วยรายการของจำนวนเต็มจากไป1n

  2. ลบตัวเลขทั้งหมดที่อยู่ในรูปแบบi + j + 2ijที่:

    • iและน้อยกว่าj อยู่เสมอมากกว่าหรือเท่ากับซึ่งเป็นมากกว่าหรือเท่ากับnji1

    • i + j + 2ij น้อยกว่าหรือเท่ากับ n

  3. คูณจำนวนที่เหลือและเพิ่ม21

นี้จะให้ผลผลิตทั้งหมดตัวเลขที่สำคัญ (ยกเว้น2ซึ่งควรจะรวมอยู่ในการส่งออกของคุณ) 2n + 2น้อยกว่า


202นี่เป็นภาพเคลื่อนไหวของตะแกรงที่ถูกใช้ในการหาช่วงเวลาดังต่อไปนี้


เอาท์พุต

ผลลัพธ์ของคุณควรเป็นจำนวนเต็มทุกตัว≤ n(ตามลำดับจากน้อยไปหามาก) ตามด้วยบรรทัดใหม่:

2
3
5

ที่ไหนเป็นn5


ตัวอย่าง

> 10
2
3
5
7

> 30
2
3
5
7
11
13
17
19
23
29

>ปัจจัยการผลิตจะแสดงด้วย


ตัวอย่างของคุณที่มีn=30หายไป 29 ในผลลัพธ์
isaacg

5
ปัญหาของความท้าทายที่ขอให้ใช้วิธีการเฉพาะคือไม่ชัดเจนว่าการแก้ไขใดที่สามารถทำได้ ตัวอย่างเช่นคำอธิบายของคุณจะตรวจสอบ(i,j)ด้วยi<=jแต่ผลลัพธ์จะไม่เปลี่ยนแปลงหากเราเพิกเฉยต่อข้อกำหนดนี้ เราสามารถทำได้เพื่อบันทึกไบต์?
xnor

i <= jฉันไม่เคยบอกว่าคุณจะต้องตรวจสอบว่า มันเป็นเพียงส่วนหนึ่งของการทำงานของตะแกรง ใช่คุณสามารถละไว้i <= jในรหัสของคุณ @xnor
Zach Gates

2
เรามีระยะทางมากแค่ไหนที่นี่? ตะแกรงเท่ากับการเลือกตัวเลขคี่ทั้งหมด (เพราะผลลัพธ์เป็นแบบฟอร์ม2n+1) ซึ่งไม่ใช่แบบฟอร์ม2(i + j + 2ij)+1- เราสามารถทดสอบคุณสมบัตินี้โดยตรงกับช่วงเวลาที่เป็นไปได้หรือรหัสของเราต้องทำคูณ 2 บวก 1 ในบางจุด ?
Martin Ender

1
ฉันสับสนเล็กน้อยnกับสิ่งที่เกิดขึ้น 2 * n + 2ในรายละเอียดของวิธีการที่มันบอกว่ามันจะสร้างจำนวนเฉพาะทั้งหมดขึ้นอยู่กับ แต่ในรายละเอียดของอินพุต / เอาต์พุตก็บอกว่าใส่เป็นและการส่งออกจำนวนเฉพาะทั้งหมดขึ้นอยู่กับn nดังนั้นเราควรจะใช้วิธีการในการสร้างช่วงเวลาทั้งหมด2 * n + 2แล้วปล่อยสิ่งที่มีขนาดใหญ่กว่าnเอาท์พุท? หรือเราควรคำนวณnในคำอธิบายวิธีการจากอินพุตn?
Reto Koradi

คำตอบ:



3

Haskell, 93 90 ไบต์

import Data.List
g n=unlines[show$2*x+1|r<-[[1..n]],x<-2:(r\\[i+j+2*i*j|j<-r,i<-r]),2*x<n]

วิธีการทำงาน: [i+j+2*i*j|j<-r,i<-r]มีทั้งหมดi+j+2ijซึ่งจะถูกลบออก ( \\) [1..n]จาก ขยาย2x+1และเปลี่ยนเป็นสตริง ( show) เข้าร่วมกับ NL ( unlines)


1

สกาลา, 115 124 122 115 114 ไบต์

n=>{println(2);for{m<-1 to n;if !(for{j<-1 to n;i<-1 to j}yield i+j+2*i*j).contains(m);o=2*m+1;if o<=n}println(o)}

ฟังก์ชั่นที่ไม่ระบุชื่อ ใช้ n เป็นอาร์กิวเมนต์และพิมพ์ผลลัพธ์ไปที่ stdout


1

JavaScript (ES7), 107 105 ไบต์

ความเข้าใจในอาร์เรย์นั้นยอดเยี่ยมมาก! แต่ฉันสงสัยว่าทำไม JS ไม่มีไวยากรณ์ช่วง (เช่น[1..n]) ...

n=>{for(a=[i=1];i<n;a[i++]=i);for(i=0;i++<n;)for(j=0;j<n;a[i+j+++2*i*j]=0);return[for(i of a)if(i)i*2+1]}

สิ่งนี้ได้รับการทดสอบเรียบร้อยแล้วใน Firefox 40

n=>{
  for(a=[i=1];i<n;a[i++]=i); // fill a list with 1..n
  for(i=0;i++<n;)            // for each integer i in 0..n
    for(j=0;j<n;)            //   for each integer j in 0..n
      a[i+j+++2*i*j-1]=0;    //     set the corresponding item of the list to 0
  return[for(i of a)         // filter the list by:
          if(i)              //   item != 0 AND item != undefined
           i*2+1]            // and return each result * 2 + 1
}

ทางเลือกโซลูชันที่เป็นมิตรกับ ES6 (111 ไบต์):

n=>{for(a=[i=1];i<n;a[i++]=i);for(i=0;i++<n;)for(j=0;j<n;a[i+j+++2*i*j]=0);return a.filter(x=>x).map(x=>x*2+1)}

ยินดีต้อนรับข้อเสนอแนะ!


0

MATLAB, 98

n=1:input('');m=n;for p=m for i=1:p j=i:p;for k=i+j+2*i*j n(n==k)=[];end;end;end;disp(2*n'+1);

และในรูปแบบที่อ่านได้

n=1:input(''); %Ask for the input number (e.g. 100) and form a range
m=n; %Back up the range as we will be editing 'n', but need 'm' as a loop list
for p=m %For each number between 1 and n inclusive
    for i=1:p %'i' is all numbers greater than or equal to 1 up to p
        j=i:p; %'j' is all numbers greater than or equal to i up to p
        for k=i+j+2*i*j %Calculate the numbers to remove, and loop through them
            n(n==k)=[]; %Remove that value from the 'n' array
        end
    end
end
disp([2;2*n'+1]); %An display the list including the number 2 seperated by a new line.

0

Java8: 168 165 ไบต์

N->{int[]A=new int[N*N];int i=1,j;N=N/2;for(;i<N;i++)for(j=i;j<N;)A[i+j+2*i*j++]=1;System.out.println(N>1?2:\"\");for(i=1;i<N;i++)if(A[i]<1)System.out.println(2*i+1);}

สำหรับประเภทข้อมูลตัวเลขขนาดใหญ่ที่มีช่วงกว้างมากขึ้นสามารถใช้ เราไม่จำเป็นต้องทำซ้ำเพราะNดัชนีทั้งหมดN/2เพียงพอ

เพื่อให้เข้าใจอย่างถูกต้องต่อไปนี้เป็นวิธีการที่เทียบเท่า

static void findPrimeSundar(int N){
    int[] A = new int[N*N];
    int i=1,j;
    N=N/2;
    for(;i<N;i++)
      for(j=i;j<N;)
        A[i+j+2*i*j++]=1;
    System.out.println(N>1?2:"");
    for(i=1;i<N;i++)
        if(A[i]<1)System.out.println(2*i+ 1);
}

1
N>=2-> N>1? A[i]==0-> A[i]<1?
lirtosiast

@ThomasKwa ใช่คุณพูดถูก ขอบคุณ
CoderCroc

0

CJam, 35 ไบต์

2li:V,:)__2m*{_:+\:*2*+}%m2f*:)&+N*

ลองออนไลน์

ดูเหมือนว่าจะค่อนข้างยาวเมื่อเทียบกับวิธี Pyth ของ isaacg แต่มันคือ ... สิ่งที่ฉันมี

คำอธิบาย:

2       Push a 2, will be part of final output.
li      Get input and convert to integer n.
:V      Save in variable V for later use.
,       Generate list [0 ... n-1].
:)      Increment list elements to get list [1 ... n].
__      Create two copies, one for sieve, and for clamping results.
2m*     Cartesian power, generating all i,k pairs.
{       Loop over all i,j pairs.
  _     Copy pair.
  :+    Calculate sum i + j.
  \     Swap copy of pair to top.
  :*    Calculate product i * j.
  2*    Multiply by 2, to get 2 * i * j.
  +     Add both values, to get i + j + 2 * i * j.
}%      End loop over all i,j pairs.
m       Sieve operation, remove the calculated values from the list of all values.
2f*     Multiply the remaining values by 2...
:)      ... and add 1 to the. We now have the list of all primes up to 2 * n + 2.
&       Intersect with [1 ... n] list, because output is only values <= n.
+       Concatenate with the 2 we pushed at the start.
N*      Join with newlines.

0

Perl 6 , 96 ไบต์

หากฉันปฏิบัติตามคำอธิบายอย่างเคร่งครัดสั้นที่สุดที่ฉันจัดการเพื่อรับคือ 96 ไบต์

->\n {$_=@=1..n;for 1..n {for $^i..n {.[$i+$^j+2*$i*$j-1]=0}};2,|.[0..n].map(* *2+1).grep(3..n)}
->\n {
  $_=@=1..n; # initialize array
  for 1..n { # $i
    for $^i..n { # $j
      .[$i+$^j+2*$i*$j-1]=0 # remove value
    }
  };
  2,|.[0..n].map(* *2+1).grep(3..n)
}

ถ้าฉันสามารถทำ2n + 1ในการเริ่มต้นของอาร์เรย์ก่อนแทรก2และ จำกัด ที่เพียงค่าน้อยกว่าหรือเท่ากับn; สามารถลดได้ถึง 84 ไบต์

->\n {$_=@=2,{++$*2+1}...^*>n;for 1..n {for $^i..n {.[$i+$^j+2*$i*$j]=$}};.grep(?*)}

หากฉันยังเพิกเฉยที่jควรจะเป็นอย่างน้อยiฉันก็สามารถลดได้ถึง 82 ไบต์

->\n {$_=@=2,{++$*2+1}...^*>n;for 1..n X 1..n ->(\i,\j){.[i+j+2*i*j]=$};.grep(?*)}

ตัวอย่างการใช้งาน:

my $code = ->\n {...} # insert one of the lambdas from above

say $code(30).join(',');
# 2,3,5,7,11,13,17,19,23,29

my &code = $code;
say code 11;
# (2 3 5 7 11)


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.