Meeting112. +
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[]だけ
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