SlideShare a Scribd company logo
+ 
ProjectEuler92 
ICPC AOJ Meeting 2014/11/10
+ 
Problem 
 A number chain is created by continuously adding the square of 
the digits in a number to form a new number until it has been 
seen before. 
 For example, 
 44 → 32 → 13 → 10 → 1 → 1 
85 → 89 → 145 → 42 → 20 → 4 → 16 → 37 → 58 → 89 
 Therefore any chain that arrives at 1 or 89 will become stuck in 
an endless loop. What is most amazing is that EVERY starting 
number will eventually arrive at 1 or 89. 
 How many starting numbers below ten million will arrive at 89? 
https://projecteuler.net/problem=92
+ 
Problem 
 各桁の2乗を足し合わせて新たな数を作ることを, 同じ数が現れ 
るまで繰り返す. 
 例えば 
 44 → 32 → 13 → 10 → 1 → 1 
85 → 89 → 145 → 42 → 20 → 4 → 16 → 37 → 58 → 89 
 のような列である. どちらも1か89で無限ループに陥っている. 
驚くことに, どの数から始めても最終的に1か89に到達する. 
 では, 10,000,000より小さい数で89に到達する数はいくつある 
か.
+ 
SourceCode 
class Execution{ 
private boolean[] boolData; 
public Execution(int limit){ 
boolData = new boolean[limit]; 
calculation(); 
} 
private void calculation(){ 
IntStream.range(0,boolData.length).forEach(e->boolData[e]=validNum(e)); 
} 
private boolean validNum(int num){ 
for(int i=0;i<1000;i++) { 
num=genNextNum(num); 
if(num==89){ 
return true; 
} 
} 
return false; 
} 
全体はこちらにあります 
http://ideone.com/aytcpH
+ 
private int genNextNum(int num){ 
int sum=0; 
while(num!=0){ 
sum+=Math.pow(num%10,2); 
num/=10; 
} 
return sum; 
} 
public int getCount(){ 
int count=0; 
for(boolean b:boolData){ 
if(b){ 
count++; 
} 
} 
return count; 
} 
}
+ 
Answer 
8581146
+ 
脱線 
脱線します
+ 
高速化しよう 
 Java8で導入されたlambda式を使ってCPUをマルチスレッドで 
動作させる 
 AMDが作成したAparapiというOpenCLライブラリを使用して 
GPUで動作させる
+ 
GPUを使用する制約 
 GPUで動作する部分では 
 多次元配列が使えない(1次元配列は使える) 
 Javaのクラスが使えない(Math.~はGPU向けに移植された物を使う) 
 フィールド読み書き不可 
 適当なクラスにcom.amd.Kernelを継承させればKernelを継承した 
クラスのフィールドに限りアクセスできる 
 メソッドも同様 
再帰関数不可 
Kernelの中で使える変数は4つまで 
break文不可(ただし、returnで抜けることはできる)
+ 
ハードウエアによる違い 
 AMDのGPUではdoubleが普通に使えるがIntelのGPUでは 
doubleが使えない。 
 floatでもIntelGPUでは値が壊れることがある 
 IntelGPUでまともに使えるのはint[]だけ
+ 
SourceCode(lambda) 
private void calculation(){ 
IntStream.range(0,boolData.length) 
.parallel().forEach(e->boolData[e]=validNum(e)); 
}
+ 
SourceCode(GPU) 
class GPUExecution extends Kernel{ 
private boolean[] boolData; 
public GPUExecution(int limit){ 
boolData = new boolean[limit]; 
} 
public void run(){ 
int index = getGlobalId(); 
boolData[index]=validNum(index); 
} 
private boolean validNum(int num){ 
for(int i=0;i<1000;i++) { 
num=genNextNum(num); 
if(num==89){ 
return true; 
} 
} 
return false; 
}
+ 
private int genNextNum(int num){ 
int sum=0; 
while(num!=0){ 
sum+=pow(num%10,2); 
num/=10; 
} 
return sum; 
} 
public int getCount(){ 
int count=0; 
for(boolean b:boolData){ 
if(b){ 
count++; 
} 
} 
return count; 
} 
} 
呼び出し元 
GPUExecution kernel = new 
GPUExecution(i); 
kernel.execute(Range.create(i)); 
System.out.println(kernel.getCount());
+ 
200000 
180000 
160000 
140000 
120000 
100000 
80000 
60000 
40000 
20000 
0 
1 2 3 4 5 6 7 
for-loop 
lambda 
GPU 
@MacBookAir2013 IntelCorei5 IntelHDGraphics4000
+ 
300000 
250000 
200000 
150000 
100000 
50000 
0 
1 2 3 4 5 6 7 
for-loop 
lambda 
GPU 
@ThinkPadE525 AMD A8-4500M RadeonHD8570M
+ 
for-loop lambda GPU 
60 8 342 
6 3 39 
25 15 25 
184 61 42 
1812 605 174 
18114 5952 989 
180843 57232 5046 
for-loop lambda GPU 
104 485 2224 
6 7 199 
30 43 175 
255 75 177 
2622 810 206 
25891 7484 426 
258544 74647 2331 
MacBookAir ThinkPadE525
+ 
for-loop(mac) lambda(mac) GPU(mac) 
Time 180843 57232 5046 
x35.83 
for-loop(win) lambda(win) GPU(win) 
Time 258544 74647 2331 
x110.92

More Related Content

More from nullzine

Meeting10
Meeting10Meeting10
Meeting10
nullzine
 
Meeting9
Meeting9Meeting9
Meeting9
nullzine
 
Meeting7
Meeting7Meeting7
Meeting7
nullzine
 
Meeting6
Meeting6Meeting6
Meeting6
nullzine
 
Meeting5
Meeting5Meeting5
Meeting5
nullzine
 
Meeting4
Meeting4Meeting4
Meeting4
nullzine
 
Meeting1
Meeting1Meeting1
Meeting1
nullzine
 

More from nullzine (7)

Meeting10
Meeting10Meeting10
Meeting10
 
Meeting9
Meeting9Meeting9
Meeting9
 
Meeting7
Meeting7Meeting7
Meeting7
 
Meeting6
Meeting6Meeting6
Meeting6
 
Meeting5
Meeting5Meeting5
Meeting5
 
Meeting4
Meeting4Meeting4
Meeting4
 
Meeting1
Meeting1Meeting1
Meeting1
 

Meeting11

  • 1. + ProjectEuler92 ICPC AOJ Meeting 2014/11/10
  • 2. + Problem  A number chain is created by continuously adding the square of the digits in a number to form a new number until it has been seen before.  For example,  44 → 32 → 13 → 10 → 1 → 1 85 → 89 → 145 → 42 → 20 → 4 → 16 → 37 → 58 → 89  Therefore any chain that arrives at 1 or 89 will become stuck in an endless loop. What is most amazing is that EVERY starting number will eventually arrive at 1 or 89.  How many starting numbers below ten million will arrive at 89? https://projecteuler.net/problem=92
  • 3. + Problem  各桁の2乗を足し合わせて新たな数を作ることを, 同じ数が現れ るまで繰り返す.  例えば  44 → 32 → 13 → 10 → 1 → 1 85 → 89 → 145 → 42 → 20 → 4 → 16 → 37 → 58 → 89  のような列である. どちらも1か89で無限ループに陥っている. 驚くことに, どの数から始めても最終的に1か89に到達する.  では, 10,000,000より小さい数で89に到達する数はいくつある か.
  • 4. + SourceCode class Execution{ private boolean[] boolData; public Execution(int limit){ boolData = new boolean[limit]; calculation(); } private void calculation(){ IntStream.range(0,boolData.length).forEach(e->boolData[e]=validNum(e)); } private boolean validNum(int num){ for(int i=0;i<1000;i++) { num=genNextNum(num); if(num==89){ return true; } } return false; } 全体はこちらにあります http://ideone.com/aytcpH
  • 5. + private int genNextNum(int num){ int sum=0; while(num!=0){ sum+=Math.pow(num%10,2); num/=10; } return sum; } public int getCount(){ int count=0; for(boolean b:boolData){ if(b){ count++; } } return count; } }
  • 8. + 高速化しよう  Java8で導入されたlambda式を使ってCPUをマルチスレッドで 動作させる  AMDが作成したAparapiというOpenCLライブラリを使用して GPUで動作させる
  • 9. + GPUを使用する制約  GPUで動作する部分では  多次元配列が使えない(1次元配列は使える)  Javaのクラスが使えない(Math.~はGPU向けに移植された物を使う)  フィールド読み書き不可  適当なクラスにcom.amd.Kernelを継承させればKernelを継承した クラスのフィールドに限りアクセスできる  メソッドも同様 再帰関数不可 Kernelの中で使える変数は4つまで break文不可(ただし、returnで抜けることはできる)
  • 10. + ハードウエアによる違い  AMDのGPUではdoubleが普通に使えるがIntelのGPUでは doubleが使えない。  floatでもIntelGPUでは値が壊れることがある  IntelGPUでまともに使えるのはint[]だけ
  • 11. + SourceCode(lambda) private void calculation(){ IntStream.range(0,boolData.length) .parallel().forEach(e->boolData[e]=validNum(e)); }
  • 12. + SourceCode(GPU) class GPUExecution extends Kernel{ private boolean[] boolData; public GPUExecution(int limit){ boolData = new boolean[limit]; } public void run(){ int index = getGlobalId(); boolData[index]=validNum(index); } private boolean validNum(int num){ for(int i=0;i<1000;i++) { num=genNextNum(num); if(num==89){ return true; } } return false; }
  • 13. + private int genNextNum(int num){ int sum=0; while(num!=0){ sum+=pow(num%10,2); num/=10; } return sum; } public int getCount(){ int count=0; for(boolean b:boolData){ if(b){ count++; } } return count; } } 呼び出し元 GPUExecution kernel = new GPUExecution(i); kernel.execute(Range.create(i)); System.out.println(kernel.getCount());
  • 14. + 200000 180000 160000 140000 120000 100000 80000 60000 40000 20000 0 1 2 3 4 5 6 7 for-loop lambda GPU @MacBookAir2013 IntelCorei5 IntelHDGraphics4000
  • 15. + 300000 250000 200000 150000 100000 50000 0 1 2 3 4 5 6 7 for-loop lambda GPU @ThinkPadE525 AMD A8-4500M RadeonHD8570M
  • 16. + for-loop lambda GPU 60 8 342 6 3 39 25 15 25 184 61 42 1812 605 174 18114 5952 989 180843 57232 5046 for-loop lambda GPU 104 485 2224 6 7 199 30 43 175 255 75 177 2622 810 206 25891 7484 426 258544 74647 2331 MacBookAir ThinkPadE525
  • 17. + for-loop(mac) lambda(mac) GPU(mac) Time 180843 57232 5046 x35.83 for-loop(win) lambda(win) GPU(win) Time 258544 74647 2331 x110.92