ソニーがソフトウェアスペシャリスト認定コンテストをやっている

広告

2/8追記:ライセンスについて

※回答はオープンソースソフトウェアとして公開してください。
その際、そのソフトウェアをOSDに準拠したライセンス(GPLライセンスやBSDライセンスなど)であることを明示して公開してください。

とあるので、ここのコードは修正BSDライセンスとして扱って下さい。普段は常識的な範囲でご自由にライセンスにしておくのだけど、OSSの世界ではそれは困るらしい。

ガンマ関数の計算に『C言語による最新アルゴリズム事典』からコードを借用しているけれど「ご利用についての制限はありません」とあるので、出典を明記しつつパクらせていただきます。

ソニーがソフトウェアスペシャリスト認定コンテストをやっている

詳しくは http://www.sony.co.jp/SonyInfo/Jobs/newgrads/sus/go_for_it.html 

<応募資格>

大学3年生以上最終学歴卒業後3年未満の方
※新卒採用広報活動の一環となるため、今回は応募資格を限らせていただきます。

おいらは一応応募可能。

<評価ポイント>
(略)
GO FOR ITでは、あなたのコードを実際の開発現場で働いているソフトウェアエンジニアが、様々な角度から見せていただきます。あなたの書いた成果物から伝わるエンジニアとしての実力や経験、ポテンシャルを評価し、ソニーのエンジニアがあなたと一緒にコードを書きたいかどうかを判定します。単に決まった「正解」が導き出せるかだけでなく、ソニーのエンジニアをうならせ、あなたと一緒に仕事をしたいと思わせるようなコードをお待ちしております。

うならせるという点が難しいのかな、問題そのものはそう難しくないのでベタな解答をすべきではないと言うことか。

<回答方法>

  1. 回答をネット上のあなたのblogなどにpostし、誰でもアクセスのできる状態にしてください。
  2. フォームを通じてそのURLと、下記項目を参考にしていただき、参考情報をPDFファイルで提出してください。

ブログに書くということは他のライバルのコードを参考にすることは問題ないわけだ。ということは、全問正解はそう難しいことではなくて、むしろディスカッションが本番と言うことになる。

では1つやってみようか。

2) 実数の階乗

ある検索サイトに5!と入力するとその計算結果である120が表示されます。その検索サイトに2.5!と入力するとなんと3.32335097と表示されます。さらにその検索サイトに(-1.9)!と入力すると-10.5705641と表示されます。きっとそれらの仕組みはとても難しくて企業秘密に違いないので是非ともこれらを実行するプログラムを作ってほしい。ただし、君のPCは古いのでネットワークや便利で高度な数学関数は入っていません。入っている数学関数はsin,cos,tan,log,pow,floorなどの初歩的な関数のみです、残念ながら。

  1. 入力された整数a(0<=a<=10)の階乗を求めるプログラムを作ってください。
  2. 入力された実数a(0<=a<=10)の階乗を求めるプログラムを作ってください。
  3. 入力された実数a(-1.9<=a<=-1.1)の階乗を求めるプログラムを作ってください。

階乗の一般化はガンマ関数であるとどこかで聞いたことがある人はガンマ関数の実装をすればいい。そうでなくてもWolfram Alphaに尋ねれば計算方法まで教えてくれる。

#include 
#include 
#include 
#include 
#include 
using namespace std;

const double e = 2.71828183;

double mygamma( double k )
{
    double x;
    double y;
    double tmp;
    double ser;
    
    static double cof[6] = {
        76.18009172947146,
        -86.50532032941677,
        24.01409824083091,
        -1.231739572450155,
        0.1208650973866179e-2,
        -0.5395239384953e-5
    };
    
    x = y = k;
    tmp = x + 5.5;
    tmp -= (x+0.5)*log(tmp);
    ser = 1.000000000190015;
    for( int i = 0; i < 6; i++ )
        ser += cof[i] / ++y;
    
    return pow( e, -tmp + log(2.5066282746310005 * ser / x) );
}

double kaijo( double k )
{
    return gamma( k + 1 );
}

int main()
{
    cout << kaijo(5) << endl;
    cout << kaijo(2.5) << endl;
    cout << kaijo(-1.9) << endl;

    cout << endl;
    cout << "i)入力された整数a(0<=a<=10)の階乗を求めるプログラムを作ってください。" << endl;
    for( int i = 0; i <= 10; i++ )
        cout << i << "の階乗は" << kaijo(i) << "です。" << endl;
        
    cout << endl;
    cout << "ii)入力された実数a(0<=a<=10)の階乗を求めるプログラムを作ってください。" << endl;
    for( double i = 0; i <= 10; i += 0.1 )
        cout << i << "の階乗は" << kaijo(i) << "です。" << endl;

    cout << endl;
    cout << "iii)入力された実数a(-1.9<=a<=-1.1)の階乗を求めるプログラムを作ってください。" << endl;
    for( double i = -1.9; i <= -1.0; i += 0.1 )
        cout << i << "の階乗は" << kaijo(i) << "です。" << endl;
}

面倒臭いから組み込み関数のgammaを使ったけど、条件から使えるのは初等関数だけということなのでmygammaも作ってみた。ただし、マイナスを入れると動作がおかしいので要改善だけど、あと30分で出かけるのでこの辺でおしまい。ガンマ関数の実装は

とか

あたりを見れば載っているはずだ。結果は

120
3.32335
-10.5706

i)入力された整数a(0<=a<=10)の階乗を求めるプログラムを作ってください。
0の階乗は1です。
1の階乗は1です。
2の階乗は2です。
3の階乗は6です。
4の階乗は24です。
5の階乗は120です。
6の階乗は720です。
7の階乗は5040です。
8の階乗は40320です。
9の階乗は362880です。
10の階乗は3.6288e+06です。

ii)入力された実数a(0<=a<=10)の階乗を求めるプログラムを作ってください。
0の階乗は1です。
0.1の階乗は0.951351です。
0.2の階乗は0.918169です。
0.3の階乗は0.897471です。
0.4の階乗は0.887264です。
0.5の階乗は0.886227です。
0.6の階乗は0.893515です。
0.7の階乗は0.908639です。
0.8の階乗は0.931384です。
0.9の階乗は0.961766です。
1の階乗は1です。
1.1の階乗は1.04649です。
1.2の階乗は1.1018です。
1.3の階乗は1.16671です。
1.4の階乗は1.24217です。
1.5の階乗は1.32934です。
1.6の階乗は1.42962です。
1.7の階乗は1.54469です。
1.8の階乗は1.67649です。
1.9の階乗は1.82736です。
2の階乗は2です。
2.1の階乗は2.19762です。
2.2の階乗は2.42397です。
2.3の階乗は2.68344です。
2.4の階乗は2.98121です。
2.5の階乗は3.32335です。
2.6の階乗は3.71702です。
2.7の階乗は4.17065です。
2.8の階乗は4.69417です。
2.9の階乗は5.29933です。
3の階乗は6です。
3.1の階乗は6.81262です。
3.2の階乗は7.75669です。
3.3の階乗は8.85534です。
3.4の階乗は10.1361です。
3.5の階乗は11.6317です。
3.6の階乗は13.3813です。
3.7の階乗は15.4314です。
3.8の階乗は17.8379です。
3.9の階乗は20.6674です。
4の階乗は24です。
4.1の階乗は27.9318です。
4.2の階乗は32.5781です。
4.3の階乗は38.078です。
4.4の階乗は44.5988です。
4.5の階乗は52.3428です。
4.6の階乗は61.5539です。
4.7の階乗は72.5276です。
4.8の階乗は85.6217です。
4.9の階乗は101.27です。
5の階乗は120です。
5.1の階乗は142.452です。
5.2の階乗は169.406です。
5.3の階乗は201.813です。
5.4の階乗は240.834です。
5.5の階乗は287.885です。
5.6の階乗は344.702です。
5.7の階乗は413.408です。
5.8の階乗は496.606です。
5.9の階乗は597.494です。
6の階乗は720です。
6.1の階乗は868.957です。
6.2の階乗は1050.32です。
6.3の階乗は1271.42です。
6.4の階乗は1541.34です。
6.5の階乗は1871.25です。
6.6の階乗は2275.03です。
6.7の階乗は2769.83です。
6.8の階乗は3376.92です。
6.9の階乗は4122.71です。
7の階乗は5040です。
7.1の階乗は6169.59です。
7.2の階乗は7562.29です。
7.3の階乗は9281.39です。
7.4の階乗は11405.9です。
7.5の階乗は14034.4です。
7.6の階乗は17290.2です。
7.7の階乗は21327.7です。
7.8の階乗は26340です。
7.9の階乗は32569.4です。
8の階乗は40320です。
8.1の階乗は49973.7です。
8.2の階乗は62010.8です。
8.3の階乗は77035.6です。
8.4の階乗は95809.5です。
8.5の階乗は119292です。
8.6の階乗は148696です。
8.7の階乗は185551です。
8.8の階乗は231792です。
8.9の階乗は289868です。
9の階乗は362880です。
9.1の階乗は454761です。
9.2の階乗は570499です。
9.3の階乗は716431です。
9.4の階乗は900609です。
9.5の階乗は1.13328e+06です。
9.6の階乗は1.42748e+06です。
9.7の階乗は1.79984e+06です。
9.8の階乗は2.27156e+06です。
9.9の階乗は2.86969e+06です。
10の階乗は3.6288e+06です。

iii)入力された実数a(-1.9<=a<=-1.1)の階乗を求めるプログラムを作ってください。
-1.9の階乗は-10.5706です。
-1.8の階乗は-5.73855です。
-1.7の階乗は-4.27367です。
-1.6の階乗は-3.69693です。
-1.5の階乗は-3.54491です。
-1.4の階乗は-3.72298です。
-1.3の階乗は-4.32685です。
-1.2の階乗は-5.82115です。
-1.1の階乗は-10.6863です。

というところ。

追記1

C言語による最新アルゴリズム事典』のソースコードはここで公開されている。

============================================================
    『C言語による最新アルゴリズム事典』全ソースコード
------------------------------------------------------------
  ・『C言語による最新アルゴリズム事典』掲載の全ソースコード
    です。
    本に載せたものと違って,できるかぎりテスト用の main() を
    補ってあります。本に載っていないソースコードやテストデー
    タも若干ですが含まれています。
------------------------------------------------------------
  ご利用についての制限はありません。ただしバグによる損害の賠
償などには応じかねますのでご了承ください。
  バグを発見されたらお知らせいただければ幸いです.
------------------------------------------------------------

とあるので、出典を明示しておけば利用しても問題ないだろう。

これを利用したところコードは

#include < cmath>
#include < ctime>
#include < iostream>
#include < string>
#include < vector>
using namespace std;

const double e = 2.71828183;


#define PI      3.14159265358979324  /* $¥pi$ */
#define LOG_2PI 1.83787706640934548  /* $¥log 2¥pi$ */
#define N       8

#define B0  1                 /* 以下はBernoulli数 */
#define B1  (-1.0 / 2.0)
#define B2  ( 1.0 / 6.0)
#define B4  (-1.0 / 30.0)
#define B6  ( 1.0 / 42.0)
#define B8  (-1.0 / 30.0)
#define B10 ( 5.0 / 66.0)
#define B12 (-691.0 / 2730.0)
#define B14 ( 7.0 / 6.0)
#define B16 (-3617.0 / 510.0)

double loggamma(double x)  /* ガンマ関数の対数 */
{
	double v, w;

	v = 1;
	while (x <  N) {  v *= x;  x++;  }
	w = 1 / (x * x);
	return ((((((((B16 / (16 * 15))  * w + (B14 / (14 * 13))) * w
	            + (B12 / (12 * 11))) * w + (B10 / (10 *  9))) * w
	            + (B8  / ( 8 *  7))) * w + (B6  / ( 6 *  5))) * w
	            + (B4  / ( 4 *  3))) * w + (B2  / ( 2 *  1))) / x
	            + 0.5 * LOG_2PI - log(v) - x + (x - 0.5) * log(x);
}

double gamma_(double x)  /* ガンマ関数 */
{
	if (x <  0)
		return PI / (sin(PI * x) * exp(loggamma(1 - x)));
	return exp(loggamma(x));
}


double kaijo( double k )
{
    return gamma_( k + 1 );
}

int main()
{
    cout < < kaijo(5) < < endl;
    cout < < kaijo(2.5) < < endl;
    cout < < kaijo(-1.9) < < endl;

    cout < < endl;
    cout < < "i)入力された整数a(0<=a<=10)の階乗を求めるプログラムを作ってください。" < < endl;
    for( int i = 0; i < = 10; i++ )
        cout < < i < < "の階乗は" < < kaijo(i) < < "です。" < < endl;
        
    cout < < endl;
    cout < < "ii)入力された実数a(0<=a<=10)の階乗を求めるプログラムを作ってください。" < < endl;
    for( double i = 0; i < = 10; i += 0.1 )
        cout < < i < < "の階乗は" < < kaijo(i) < < "です。" < < endl;

    cout < < endl;
    cout < < "iii)入力された実数a(-1.9<=a<=-1.1)の階乗を求めるプログラムを作ってください。" < < endl;
    for( double i = -1.9; i < = -1.0; i += 0.1 )
        cout < < i < < "の階乗は" < < kaijo(i) < < "です。" < < endl;
}

となった。実行結果は

120
3.32335
-10.5706

i)入力された整数a(0<=a<=10)の階乗を求めるプログラムを作ってください。
0の階乗は1です。
1の階乗は1です。
2の階乗は2です。
3の階乗は6です。
4の階乗は24です。
5の階乗は120です。
6の階乗は720です。
7の階乗は5040です。
8の階乗は40320です。
9の階乗は362880です。
10の階乗は3.6288e+06です。

ii)入力された実数a(0<=a<=10)の階乗を求めるプログラムを作ってください。
0の階乗は1です。
0.1の階乗は0.951351です。
0.2の階乗は0.918169です。
0.3の階乗は0.897471です。
0.4の階乗は0.887264です。
0.5の階乗は0.886227です。
0.6の階乗は0.893515です。
0.7の階乗は0.908639です。
0.8の階乗は0.931384です。
0.9の階乗は0.961766です。
1の階乗は1です。
1.1の階乗は1.04649です。
1.2の階乗は1.1018です。
1.3の階乗は1.16671です。
1.4の階乗は1.24217です。
1.5の階乗は1.32934です。
1.6の階乗は1.42962です。
1.7の階乗は1.54469です。
1.8の階乗は1.67649です。
1.9の階乗は1.82736です。
2の階乗は2です。
2.1の階乗は2.19762です。
2.2の階乗は2.42397です。
2.3の階乗は2.68344です。
2.4の階乗は2.98121です。
2.5の階乗は3.32335です。
2.6の階乗は3.71702です。
2.7の階乗は4.17065です。
2.8の階乗は4.69417です。
2.9の階乗は5.29933です。
3の階乗は6です。
3.1の階乗は6.81262です。
3.2の階乗は7.75669です。
3.3の階乗は8.85534です。
3.4の階乗は10.1361です。
3.5の階乗は11.6317です。
3.6の階乗は13.3813です。
3.7の階乗は15.4314です。
3.8の階乗は17.8379です。
3.9の階乗は20.6674です。
4の階乗は24です。
4.1の階乗は27.9318です。
4.2の階乗は32.5781です。
4.3の階乗は38.078です。
4.4の階乗は44.5988です。
4.5の階乗は52.3428です。
4.6の階乗は61.5539です。
4.7の階乗は72.5276です。
4.8の階乗は85.6217です。
4.9の階乗は101.27です。
5の階乗は120です。
5.1の階乗は142.452です。
5.2の階乗は169.406です。
5.3の階乗は201.813です。
5.4の階乗は240.834です。
5.5の階乗は287.885です。
5.6の階乗は344.702です。
5.7の階乗は413.408です。
5.8の階乗は496.606です。
5.9の階乗は597.494です。
6の階乗は720です。
6.1の階乗は868.957です。
6.2の階乗は1050.32です。
6.3の階乗は1271.42です。
6.4の階乗は1541.34です。
6.5の階乗は1871.25です。
6.6の階乗は2275.03です。
6.7の階乗は2769.83です。
6.8の階乗は3376.92です。
6.9の階乗は4122.71です。
7の階乗は5040です。
7.1の階乗は6169.59です。
7.2の階乗は7562.29です。
7.3の階乗は9281.39です。
7.4の階乗は11405.9です。
7.5の階乗は14034.4です。
7.6の階乗は17290.2です。
7.7の階乗は21327.7です。
7.8の階乗は26340です。
7.9の階乗は32569.4です。
8の階乗は40320です。
8.1の階乗は49973.7です。
8.2の階乗は62010.8です。
8.3の階乗は77035.6です。
8.4の階乗は95809.5です。
8.5の階乗は119292です。
8.6の階乗は148696です。
8.7の階乗は185551です。
8.8の階乗は231792です。
8.9の階乗は289868です。
9の階乗は362880です。
9.1の階乗は454761です。
9.2の階乗は570499です。
9.3の階乗は716431です。
9.4の階乗は900609です。
9.5の階乗は1.13328e+06です。
9.6の階乗は1.42748e+06です。
9.7の階乗は1.79984e+06です。
9.8の階乗は2.27156e+06です。
9.9の階乗は2.86969e+06です。
10の階乗は3.6288e+06です。

iii)入力された実数a(-1.9<=a<=-1.1)の階乗を求めるプログラムを作ってください。
-1.9の階乗は-10.5706です。
-1.8の階乗は-5.73855です。
-1.7の階乗は-4.27367です。
-1.6の階乗は-3.69693です。
-1.5の階乗は-3.54491です。
-1.4の階乗は-3.72298です。
-1.3の階乗は-4.32685です。
-1.2の階乗は-5.82115です。
-1.1の階乗は-10.6863です。

と正しい結果になっているようだ。