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);
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);
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; } }
for (long i = 1; i < Integer.MAX_VALUE; sum += i, ++i);
LongStream.range(1, Integer.MAX_VALUE).parallel().sum();
- 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.
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
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); }
IntStream.iterate(17, i -> i % 2 == 1 ? 3 * i + 1 : i / 2) .takeWhile(i -> i > 1) .forEach(System.out::println);
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); } }
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:
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); } }
No comments:
Post a Comment