Saturday, December 26, 2015

Semafor

posix semaphore ile ilgili görsel sonucu
Bu yazıda prosesler arası kaynak paylaşımı ve eş zamanlama çözümü için kullanılan semafor çözümlerini inceleyeceğiz. İlk olarak, Unix’deki Inter Process Communication (IPC) alt yapısını kullanarak semafor programlama yapacağız. Daha sonra sırasıyla C++11’de ve Java platformundaki semafor çözümlerini çalışılacağız.
Birden fazla kaynağı iplikler ya da prosesler arasında paylaştırmak gerektiğinde semafor çözümü kullanılır. Her proses semafordan ihtiyaç duyduğu kaynak kadar istekte bulunur. Semafor tam sayı değer saklayan bir nesne olarak düşünülebilir. Bu tam sayının başlangıç değeri kaynak sayısıdır. Semafor üzerinde temel olarak iki işlem tanımlıdır:

  • Azaltma: Semaforun değeri, alınan kaynak sayısı kadar azaltılır. Eğer semaforun değeri, negatif bir değere ulaşırsa, çağrıyı yapan proses ya da iplik istekte bulunduğu sayı kadar kaynak hazır olana kadar kuyrukta bekler.
  • Artırma: Kaynaklar geri verildiğinde semaforun değeri, geri verilen kaynak sayısı kadar arttırılır. Bekleyen proseslerden, kaynak sayısı karşılananlar proses uyandırılır.
Unix işletim sisteminde, çekirdek tüm kaynaklar için tekil bir anahtar kullanır. Proses arası iletişim yapısı için kullanılan kaynaklar için de tekil bir anahtar üretilmesi gerekir. Bunun için ftok() fonksiyonu kullanılır. ftok() fonksiyonuna parametre olarak sistemdeki bir dosyanın tam yolu verilir:
  1 #include <sys/ipc.h>
  2 #include <sys/msg.h>
  3 #include <stdio.h>
  4 
  5 int main(){
  6     key_t key;
  7     int id;
  8     key= ftok("/home/student/keyfile",1);
  9     int flag = (IPC_CREAT | IPC_EXCL | 0400) ;
 10     id= msgget(key,flag);
 11     printf("Queue ID: %d\n",id);
 12     id= shmget(key,4*sizeof(int),flag);
 13     printf("Shared Memory ID: %d\n",id);
 14     id= semget(key,3,flag);
 15     printf("Semaphore ID: %d\n",id);
 16 } 
Bu kodu aşağıdaki gibi derleyip çalıştırıyoruz:
[student@godel]$ cc -o ftok ftok.c
[student@godel]$ ./ftok
Queue ID: 196608
Shared Memory ID: 88276993
Semaphore ID: 32768
Bize ürettiği tekil anahtarın değeri mesaj kuyruğu için 196608, paylaşılan bellek için 88276993 ve semafor için ise 32768’dir. Üretilen tekil anahtarları, kaynak türlerine göre listelemek için ipcs komutundan yararlanıyoruz:
[student@godel]$ ipcs

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status     
0x00000000 1703936    student    600        393216     2          dest        
0x010159a1 88276993   student    400        16         0                      

------ Semaphore Arrays --------
key        semid      owner      perms      nsems    
0x010159a1 32768      student    400        3        

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages   
0x010159a1 196608     student    400        0            0 
Tekil anahtar üretirken her üç kaynak türü için de aynı dosya yolunu kullandığımıza dikkat edin. Normalde farklı kaynak türleri farklı dosya yolu kullanılır. Anahtarı silmek için ise ipcrm komutunu kullanıyoruz. Komuta parametre olarak kaynağın türünü ve anahtar kimliğini veriyoruz:
[student@godel]$ ipcrm -s 32768
[student@godel]$ ipcrm -m 88276993
[student@godel]$ ipcrm -q 196608
[student@godel]$ ipcs

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00000000 1703936    student    600        393216     2          dest        

------ Semaphore Arrays --------
key        semid      owner      perms      nsems    

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages
Mesaj kuyruğunu silmek için –q, semafor silmek için –s ve paylaşılan bellek için -m seçeneğini kullanıyoruz.
Üç farklı kaynağın her birinden sırasıyla 3, 5 ve 10 adet bulunan durum için semaforu, POSIX kütüphanesindeki semget ve semctl çağrılarını kullanarak aşağıdaki şekilde yaratıyoruz:

#define NUM_SEMS_IN_GROUP 3
#define RESOURCE1 0
#define RESOURCE2 1
#define RESOURCE3 2

int semid;

int numResource1 = 3;
int numResource2 = 5;
int numResource3 = 10;

semid = semget(
     IPC_PRIVATE,
     NUM_SEMS_IN_GROUP,
     IPC_CREAT | 0600
);

semctl(semid, RESOURCE1, SETVAL, &numResource1);
semctl(semid, RESOURCE2, SETVAL, &numResource2);
semctl(semid, RESOURCE3, SETVAL, &numResource3);

Bu üç farklı kaynaktan sırayla 2, 3 ve 1 adet kaynak almak için ise semop çağrısını kullanıyoruz:

struct sembuf ops[NUM_SEMS_IN_GROUP];
ops[0].sem_num = RESOURCE1;  
ops[0].sem_op = 2;
ops[1].sem_num = RESOURCE2;  
ops[1].sem_op = 3;
ops[2].sem_num = RESOURCE3;  
ops[2].sem_op = 1;

ops[0].sem_flg = ops[1].sem_flg = ops[2].sem_flg = WAIT;
semop(semid, ops, NUM_SEMS_IN_GROUP);

Şimdi POSIX semaforları kullanarak örnek bir problemi çözelim. Ev taşıma hizmeti veren bir firmanın 5 aracı, 12 taşıyıcısı ve 1000 TL’ye kadar sigortalanacak taşıma kapasitesi olsun. Kendisine gelen farklı taşıma istekleri için bu kaynakların paylaşımını semafor kullanarak çözelim:  
Araç 
Sayısı
Taşıyıcı Sayısı
Sigortalama 
Değeri
4
5
250
1
2
500
3
5
1000
2
8
250
Çözümün kaynak kodunu aşağıda bulabilirsiniz:
#include <sys/types.h> 
#include <sys/ipc.h>
#include <sys/sem.h>
#include <pthread.h>
#include <stdlib.h> 
#include <stdio.h>

#include "utils.h"

#define NUM_THREADS 10
#define TIME_BTWN_NEW_THREADS 0.5
#define RUNTIME_RANGE 5.0

#define NUM_SEMS_IN_GROUP 3
#define TRUCK_SEM 0
#define MOVER_SEM 1
#define INSUR_SEM 2

#define NUM_TRUCKS 5
#define NUM_MOVERS 12
#define AMT_INSUR 1000

#define WAIT 0

#define STRING_SIZE 80

#define FALSE 0
#define TRUE (!FALSE)

#define STDOUT_FD 1

struct job {
    int numTrucks;
    int numMovers;
    int amtInsurance;
} jobTable[] = {
    { 4, 5, 250},
    { 1, 2, 500},
    { 3, 5, 1000},
    { 2, 8, 250},
};

int numJobs = sizeof (jobTable) / sizeof (struct job);
int semid;
extern int errno;
void *threadMain(void *);

main() {
    pthread_t threads[NUM_THREADS]; 

    int numTrucks = NUM_TRUCKS;
    int numMovers = NUM_MOVERS;
    int amtInsur = AMT_INSUR;

    int count;

    if ((semid = semget(IPC_PRIVATE, NUM_SEMS_IN_GROUP, IPC_CREAT | 0600)) == -1) {
        perror("semget");
        exit(errno);
    }

    if ((semctl(semid, TRUCK_SEM, SETVAL, &numTrucks)) ||
        (semctl(semid, MOVER_SEM, SETVAL, &numMovers)) ||
        (semctl(semid, INSUR_SEM, SETVAL, &amtInsur))) {
        perror("Error initializing semaphores");
        goto cleanup;
    }

    srand48(time(NULL));

    for (count = 0; count < NUM_THREADS; count++) {
        if (pthread_create(&threads[count], NULL, threadMain, (void *) (count % numJobs))){
            perror("Error starting reader threads");
            goto cleanup;
        }
        fractSleep(TIME_BTWN_NEW_THREADS);
    }

    for (count = 0; count < NUM_THREADS; count++) {
        pthread_join(threads[count], (void **) NULL);
    }

cleanup:
    if (semctl(semid, 0, IPC_RMID, NULL)) {
        perror("semctl IPC_RMID:");
    }
}

void *threadMain(void * arg) {
    int jobNum = (int) arg;
    char string[STRING_SIZE];

    sprintf(string,
            "Job # %d requesting %d trucks, %d people, $%d000 insurance...\n",
            jobNum, jobTable[jobNum].numTrucks, jobTable[jobNum].numMovers,
            jobTable[jobNum].amtInsurance);
    printWithTime(string);

    if (reserve(semid, jobTable[jobNum])) {
        perror("reserve");
        return (NULL);
    }

    sprintf(string,
            "Job # %d got %d trucks, %d people, %d000 insurance and is running...\n",
            jobNum, jobTable[jobNum].numTrucks, jobTable[jobNum].numMovers,
            jobTable[jobNum].amtInsurance);
    printWithTime(string);

    fractSleep(drand48() * RUNTIME_RANGE);

    sprintf(string,
            "Job # %d done;  returning %d trucks, %d people, %d000 insurance...\n",
            jobNum, jobTable[jobNum].numTrucks, jobTable[jobNum].numMovers,
            jobTable[jobNum].amtInsurance);
    printWithTime(string);

    if (release(semid, jobTable[jobNum])) {
        perror("release");
    }
}

int release(int semid, struct job thisJob) {
    return (playWithSemaphores(
            semid, thisJob.numTrucks, thisJob.numMovers, thisJob.amtInsurance));
}

int reserve(int semid, struct job thisJob) {
    return (playWithSemaphores(
            semid, -thisJob.numTrucks, -thisJob.numMovers, -thisJob.amtInsurance));
}

int playWithSemaphores(int semid, int numTrucks, int numMovers, int amtInsurance) {

    struct sembuf ops[NUM_SEMS_IN_GROUP];

    ops[0].sem_num = TRUCK_SEM;
    ops[0].sem_op = numTrucks;
    ops[1].sem_num = MOVER_SEM;
    ops[1].sem_op = numMovers;
    ops[2].sem_num = INSUR_SEM;
    ops[2].sem_op = amtInsurance;

    ops[0].sem_flg = ops[1].sem_flg = ops[2].sem_flg = WAIT;

    return (semop(semid, ops, NUM_SEMS_IN_GROUP));
}
C++11’de iplik programlama ve eş zamanlama ile ilgili hazır çözümler gelmiş olsa da semafor çözümünü içermez. Ancak semafor mekanizmasını mutex sınıfını kullanarak gerçekleştirebiliriz:
class semaphore {
  bool hasResource(initializer_list<int> values){
 int i=0;
 for (auto & value : values)
        if(resources[i++]<value) return false; 
 cerr << "Obtained the resources!" << endl ; 
 return true;  
  }
public:

  semaphore(initializer_list<int> inits) {
      int i=0;
      for (auto & init : inits)
          resources.push_back(init); 
  }

  void release(initializer_list<int> values){
    unique_lock<mutex> lck(mtx);
    int i=0;
    for (auto & value : values)
        resources[i++] += value;     
    cv.notify_one();
  }

  void acquire(initializer_list<int> values){
    unique_lock<mutex> lck(mtx);
 
    while(!hasResource(values)){
      cv.wait(lck);
    }
    int i=0;
    for (auto & value : values)
        resources[i++] -= value;     
  }

  mutex mtx;
  condition_variable cv;
  vector<int> resources;
};
POSIX semaforları kullanarak çözdüğümüz problemi şimdi yukarıda oluşturduğumuz semaphore sınıfını kullanarak çözmeye çalışalım:
int jobs[][3= {
{ 4, 5, 250 }, 
  { 1, 2, 500 }, 
  { 3, 5, 1000 },
  { 2, 8, 250 },
};

int main(){
  semaphore sem({5, 12, 1000});
  vector<thread> tasks;
  auto run= [&sem] (int i,int job[3] ) {
    sem.acquire({job[0],job[1],job[2]});
    sem.release({job[0],job[1],job[2]});
  };
  int i=0;
  for (auto &job : jobs){
    tasks.push_back({thread(run,i,job)});
    ++i;
  }
  for (auto& task: tasks)
    task.join();
  return 0;
}
Java’da semafor programlama için Java SE 5 ile gelen java.util.concurrent paketinde yer alan Semaphore sınıfını kullanıyoruz. Semaphore sınıfını kullanarak semaforu yaratırken kaynak sayısını veriyoruz. Semaphore sınıfında kaynak almak için acquire ve alınan kaynağı geri vermek için release metodları bulunuyor. acquire metodu eğer yeterli sayıda kaynak yok ise, çağrıyı yapan ipliği, diğer iplikler release metodu ile yeterli sayıda kaynak bırakıncaya kadar bir kuyrukta bloke eder. Yukarıda, önce POSIX semaforlarını, daha sonra C++11 kullanarak çözdüğümüz problemi, bu kez Java’daki Semaphore sınıfını kullanarak tekrar çözelim:
import java.util.Arrays;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class TransportationProblem {
   static int jobs[][] = { 
            { 4, 5, 250 }, 
            { 1, 2, 500 }, 
            { 3, 5, 1000 }, 
            { 2, 8, 250 } 
       };
   public static void main(String[] args) throws InterruptedException {
     Thread[] tasks = new Thread[jobs.length];
     MultiResource mr = new MultiResource(5, 12, 1000);
     for (int i = 0; i < tasks.length; ++i) {
      tasks[i] = new Thread(new Task(mr, jobs[i]),Arrays.toString(jobs[i]));
     }
     for (Thread task : tasks)
        task.start();
     for (Thread task : tasks)
        task.join();
  }

}

class Task implements Runnable {
   int[] job;
   MultiResource mr;

   public Task(MultiResource mr, int[] job) {
      this.mr = mr;
      this.job = job;
   }

   @Override
   public void run() {
     try {
        mr.acquire(job);
        System.err.println(Thread.currentThread().getName() 
               + " is using the resource " + Arrays.toString(job) + "...");
        mr.release(job);
        System.err.println(Thread.currentThread().getName() 
               + " has relased the resource " + Arrays.toString(job) + "!");
     } catch (InterruptedException e) {
       e.printStackTrace();
     }

  }

}
class MultiResource {
   private volatile Semaphore[] semaphores;

   public MultiResource(int... permits) {
      System.err.println("Initializing the semaphores with permits " 
                             + Arrays.toString(permits));
      semaphores = new Semaphore[permits.length];
      for (int i = 0; i < semaphores.length; ++i) {
        semaphores[i] = new Semaphore(permits[i], true);
      }
   }

   public void acquire(int... permits) throws InterruptedException {
      System.err.println(Thread.currentThread().getName() 
              + " is acquiring the resources " + Arrays.toString(permits));
      for (int i = 0; i < permits.length; ++i) {
          System.err.println(Thread.currentThread().getName() 
              + " acquired the resource(" + (i + 1) + ") " + permits[i]);
          semaphores[i].acquire(permits[i]);
      }
      System.err.println(Thread.currentThread().getName() 
              + " acquired the resources " + Arrays.toString(permits)
       + "...finally!");
   }

   public void release(int... permits) throws InterruptedException {
      System.err.println(Thread.currentThread().getName() 
                + " is releasing " + Arrays.toString(permits) + "...");
      for (int i = 0; i < permits.length; ++i) {
          semaphores[i].release(permits[i]);
      }
      System.err.println(Thread.currentThread().getName() + 
             " is releasing " + Arrays.toString(permits) + "...done.");
   }
}

Wednesday, December 9, 2015

Java SE 9'da Temel Tipler Üzerinde Çalışan Akımlar (=Stream)

Java Programlama Dili, Java SE 8 ile birlikte yeni bir paradigmayı daha destekliyor: Fonksiyonel Programlama. Java SE 8 ile birlikte gelen λ ifadeleri ise fonksiyonel programlama yapmamıza olanak sağlıyor. λ ifadeleri sayesinde fonksiyonlar artık dilin birinci sınıf vatandaşı olarak işlem görecek. Fonksiyon tipinden bir değişken tanımlayabilecek ve fonksiyona parametre olarak başka bir fonksiyonu geçirebileceğiz. Java SE 8 öncesinde, LambdaJ, Functional Java, Guava gibi çeşitli kütüphaneler aracılığı ile fonksiyonel programlama yapabiliyorduk. Ama şimdi λ ifadeleri hem dilin bir parçası haline geldi hem de yüksek başarımla çalışıyorlar. Java'da fonksiyonel programlama ile esas olarak amaçlanan çok çekirdekli programlamadır.
Java 8'de bakış açımızı da değiştirmemiz gerekiyor. Fonksiyonel programlama ile bildirimsel programlamaya (=declarative programming) geçiş yapıyoruz. Bunu basit bir örnek üzerinde anlatmak istiyorum:
for (int i=1;i<10;++i)
    System.out.println(i);
Yukarıdaki kodda 9 defa dönen basit bir for döngüsü oluşturuyoruz. Döngüyü oluştururken işlemciye adım adım neler yapması gerektiğini söylüyoruz:
1. adım: i bir tamsayıdır
2. adım: i'nin başlangıç değeri 1'dir.
3. adım: i'nin değeri 10'dan küçükse ekrana i'nin değerini yaz, aksi halde 5. adıma git
4. adım: i'nin değerini bir artır.
5. adım: Dur
Aynı problemin çözümünü, Java 8'i ile gelen Stream API'nin yeteneklerini kullanarak kodlamaya çalışalım:
IntStream.range(1,10).forEach(System.out::println);
Burada döngü kurmakla ilgili detaylarla ilgilenmedik. Sadece ne istediğimizi söyledik. Bu bildirimsel programlama olarak adlandırılır. Şimdi ise her iki yaklaşımla ama bu kez dişe dokunur bir iş yapalım, [1-2147483646] aralığındaki tam sayıların toplamını hesaplayalım:
package com.example.study;

import java.util.stream.LongStream;

public class Exercise {
 static final int RUN = 15;

 public static void main(String[] args) {
  long metricParallelStream = 0, metricForLoop = 0;
  for (int i = 0; i < RUN; ++i) {
   metricForLoop += sumWithForLoop();
  }
  for (int i = 0; i < RUN; ++i) {
   metricParallelStream += sumWithLongStream();
   System.gc();
  }
  System.out.println(String.format("For Loop   : %-16d", metricForLoop));
  System.out.println(String.format("LongStream : %-16d", metricParallelStream));
  System.out.println(String.format("Speedup    : %-2.3f", 
                                              (double) metricForLoop / metricParallelStream));
 }

 private static long sumWithLongStream() {
  long start = System.nanoTime();
  long sum = LongStream.range(1, Integer.MAX_VALUE).parallel().sum();
  long stop = System.nanoTime();
  printPerformance("LongStream", sum, start, stop);
  return stop - start;
 }

 private static void printPerformance(String method, long sum, long start, long stop) {
  System.out.println(String.format("%-16d (%-12s) @ %-16d", 
                                                 sum, method, stop - start));
 }

 private static long sumWithForLoop() {
  long sum = 0;
  long start = System.nanoTime();
  for (long i = 1; i < Integer.MAX_VALUE; sum += i, ++i)
   ;
  long stop = System.nanoTime();
  printPerformance("For-loop", sum, start, stop);
  return stop - start;
 }
}
Bu problemi hem for döngüsü hem de LongStream sınıfını kullanarak çözdük:
for (long i = 1; i < Integer.MAX_VALUE; sum += i, ++i);
LongStream.range(1, Integer.MAX_VALUE).parallel().sum();
LongStream ile elde ettiğimiz çözümün iki önemli kazanımı bulunuyor:
  • Bildirimsel programlama yaptığımız için yanlış yapmanız neredeyse imkansız.
  • parallel() çağrısı ile hiç paralel programlama bilmemiz gerekmeden çok çekirdekli sistemlerde sonuca hızlı ulaşmamızı sağlayacak şekilde paralel çalışacak bir çözüm elde ettik.
Yukarıdaki kodu 2 fiziksel çekirdekli, 4 sanal işlemcili bir dizüstü bilgisayarda çalıştırıldığında aşağıdaki sonuca ulaştık:
2305843005992468481 (For-loop    ) @ 1309016611      
2305843005992468481 (For-loop    ) @ 1307834288      
2305843005992468481 (For-loop    ) @ 1321886282      
2305843005992468481 (For-loop    ) @ 1336129993      
2305843005992468481 (For-loop    ) @ 1341218910      
2305843005992468481 (For-loop    ) @ 1308587198      
2305843005992468481 (For-loop    ) @ 1320821780      
2305843005992468481 (For-loop    ) @ 1450435201      
2305843005992468481 (For-loop    ) @ 1367910679      
2305843005992468481 (For-loop    ) @ 1310250661      
2305843005992468481 (For-loop    ) @ 1314651941      
2305843005992468481 (For-loop    ) @ 1366452480      
2305843005992468481 (For-loop    ) @ 1320181355      
2305843005992468481 (For-loop    ) @ 1313093162      
2305843005992468481 (For-loop    ) @ 1313353438      
2305843005992468481 (LongStream  ) @ 991360829       
2305843005992468481 (LongStream  ) @ 822089904       
2305843005992468481 (LongStream  ) @ 841850713       
2305843005992468481 (LongStream  ) @ 819578699       
2305843005992468481 (LongStream  ) @ 822906446       
2305843005992468481 (LongStream  ) @ 828978169       
2305843005992468481 (LongStream  ) @ 835416084       
2305843005992468481 (LongStream  ) @ 874176581       
2305843005992468481 (LongStream  ) @ 815826464       
2305843005992468481 (LongStream  ) @ 839485656       
2305843005992468481 (LongStream  ) @ 815087102       
2305843005992468481 (LongStream  ) @ 825911518       
2305843005992468481 (LongStream  ) @ 842565855       
2305843005992468481 (LongStream  ) @ 845280683       
2305843005992468481 (LongStream  ) @ 875872887       
For Loop   : 20001823979     
LongStream : 12696387590     
Speedup    : 1.575
LongStream sınıfının kullanıldığı çözümde yaklaşık 1.5 katlık bir hızlanma elde edildiği görülüyor. parallel() çağrısı kullanılmadığı durumda LongStream ile elde ettiğimiz çözümün for döngüsü ile ettiğimiz çözüme göre bir miktar daha yavaş olduğunu belirtmeliyim.
3n+1 Problemi
Matematikte 3n+1 problemi olarak bilinen bir problem vardır: 
Hangi sayıdan başlarsanız başlayın yukarıdaki kurala göre dizinin elemanlarını hesapladığınızda 1 değerine  ulaşırsınız. Örnek olarak 17'den başlayalım ve yukarıdaki kurala göre dizinin elemanlarını sırayla hesaplayalım:
17 -> 52 -> 26 -> 13 -> 40 -> 20 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1
17'den başladık ve sonunda 1'e ulaştık. Dizinin 1'e gittiğini görüyoruz ama limitinin 1 olduğunu ispatlayamıyoruz. Bu yazıda ispatlamaya çalışmayacağız, merak etmeyin. Sadece farklı yaklaşımlarla  3n+1 problemini kodlayacağız. Önce problemi buyruksal programlama ile çözelim:
int n = 17;
while (n > 1) {
    n =  (n%2==1) ? 3 * n +1 : n / 2;
    System.out.println(n);
}
Şimdi de IntStream sınıfından yararlanarak Java SE 9'da bildirimsel programlama ile çözelim:
IntStream.iterate(17, i -> i % 2 == 1 ? 3 * i + 1 : i / 2)
        .takeWhile(i -> i > 1)
        .forEach(System.out::println);
takeWhile metodu Java 9'da geldi. Parametre olarak bir Predicate alıyor. Predicate fonksiyonu false üretene kadar akım kesilmiyor.
Asal Sayı Üretelim
Asal Sayılar, kendisi ve 1 dışında tam böleni olmayan sayılar olarak tanımlanırlar. 2,3,5,7,11 ilk asal sayılar. Tüm asal sayıları verecek genel bir formül yok. Kaç tane asal sayı var? Sonsuz sayıda! Ama ne kadar sonsuz? Az? Çok? Tüm asal sayıları verecek genel bir formül yok ama bir n verildiğinde n'ye kadar en fazla kaç tane asal sayı olduğunu söyleyebiliyoruz:
Şimdi ilk k asal sayıyı üretecek kodu Java 9'da yazalım:
package com.example.study;

import java.util.stream.IntStream;

/**
 *
 * @author Binnur Kurt (binnur.kurt@gmail.com)
 */
public class PrimeNumbers {

    public static void main(String[] args) {
        int k = 100;
        IntStream.iterate(3, i -> i + 2)
                .filter( n -> 
                    n==2 || 
                    (n % 2 == 0) || 
                    IntStream.iterate(3, i -> i + 2)
                            .filter(i -> (n % i) == 0)
                            .findFirst().getAsInt() == n
                )
                .limit(k)
                .forEach(System.err::println);
    }
}
Buyruksal programlama ile kodlamayı size bırakıyorum. Kolay gelsin!
Pi Sayısını Üretelim
Pi sayısı herhangi bir çemberin çevresinin çapına oranı olarak tanımlanır. Tanımı basit olsa da ölçmesi o kadar kolay değil! Eski Çinli matematikçiler 3 yaklaşık değerini kullanmışlar. Biraz işin kolayına kaçmışlar! Pi kesirli bir sayı değil: kesirli sayılarda bir periyotluk vardır. Pi sayısında bir periyotluk bulmak mümkün değil:
Biz de elimizden geldiğince Stream API kullanarak noktadan sonrasını hesaplamaya çalışalım:
package com.example.study;

import java.util.stream.LongStream;

public class ComputePi {

   public static void main(String[] args) {
        double pi= LongStream.iterate(1, i -> (i<0) ? (-i+2) : -(i+2) )
           .mapToDouble( i -> 4./i )
           .limit(1_000_000_000)
           .sum();
        System.out.println(pi);
   }

}
Ben bu kadarını yapabildim: 3.1415926525897935. Artık siz tam rakamı bulursunuz!