Basic 情報処理試験(ソフトウェア開発技術者)カンニングペーパー
package com.example;
public class ErlangSheet {
// 打ち切り誤差
private static double PRECISION = 0.00001;
public static void main(String[] args){
for(double line=1;line <10.0;line++){
System.out.print(erlang(0.01,line)+"\t");
System.out.print(erlang(0.05,line)+"\t");
System.out.print(erlang(0.10,line)+"\t");
System.out.print(erlang(0.15,line)+"\t");
System.out.print(erlang(0.20,line)+"\n");
}
}
/**
* 回線数と呼損率から収容できる呼量を求める.
* @param lossRate 呼損率
* @param line 回線数
* @return 呼量
*/
public static double erlang(double lossRate,double line){
double upperErlan = 1.0;
double lowerErlan = Double.MIN_VALUE;
// 少なくとも指定された呼損率(lossRate)以上になる呼量を求める
while(lossRate > lossRate(line,upperErlan)){
upperErlan *= 10.0;
}
// 呼損率と呼量の関係は単調増加なので、二分法で呼損率から呼量を求める。
// 10000回処理を行っても所定の精度に収束しないときには、10000回時点の
// 値を返す。
//
// Low Mid Ans Up
// ----+---------------------+-----*-----------------+---
// | |
// Low Ans Mid Up
// -+-----*------+----------+-
// | |
// Low Ans Up
// -+-----*------+-
for(int cnt=0 ; cnt<10000 ; cnt++){
// 所定の精度がでていたら終了
if( upperErlan - lowerErlan < PRECISION ){
break;
}
double middle = (upperErlan+lowerErlan)/2.0;
if( lossRate > lossRate(line,middle)){
lowerErlan = middle;
}else{
upperErlan = middle;
}
}
return (upperErlan+lowerErlan)/2.0;
}
/**
* 回線数と呼量から呼損率を求める.
* lossRate = P(line,erlang) / ( 1 + P(1,erlang) + P(2,erlang) + ... + P(line,erlang) )
*/
public static double lossRate(double line,double erlang){
double denominator = lossRateParts(line,erlang);
double numerator = 1;
for(double cnt=1.0;cnt<=line;cnt++){
numerator += lossRateParts(cnt,erlang);
}
return denominator/numerator;
}
/**
* アーランの公式の一部分.
* P(n,a) = a^n / n!
*/
public static double lossRateParts(double n,double a){
return Math.pow(a,n) / factorial(n);
}
/**
* x の階乗
*/
public static double factorial(double x){
double ret = 1;
for(double cnt=1.0;cnt<=x;cnt++){
ret *= cnt;
}
return ret;
}
}