SSブログ
プログラミング ブログトップ

JavaScriptで並べ替えに "クイックソート" アルゴリズムを使用してみました。 [プログラミング]

データの並べ替えを高速に行う必要がある時、一般的に、最適なアルゴリズムと言えば " Quicksort " (クイックソート) アルゴリズムだそうです。

私はHTML5のCanvas要素とWeb Audio APIで簡易なミュージック プレイヤーを作ってみたのですが、音楽ファイルを含む多数のフォルダーがあるディレクトリーを読み込んだ後に、楽曲リストを名前順に並べ替える必要がございました。
そこで威力を発揮したのがクイックソートです。
数千曲のリストも素早く並べ替えられます。

専用ブログの記事: ウェブ音楽プレイヤー
URL: https://applicationprogram.blog.so-net.ne.jp/2019-07-03-1

以下に私の使用したコードを掲載致しますが、このコードは書き方として冗長なものとなっております。
また、始めに基準値を設定する為の複数個のサンプル データの中央の値を取る為にバブル ソートを行っておりますが、これについても実はもっと簡単に、サンプル数を3つに固定して単純な条件分岐だけで中央の値を取得する事も出来ます。

var data = [2,6,1,4,9,23,11,41,35,26,14,19,55,38,17,25,18,40,31,45,34,5,10,7,3,8,12,22];
var data2 = ['abc','aaaaaa','xy','ABC','123','12','5678','98','11F'];


// クイックソートを行う関数の宣言。
function quicksort( arrayOfData, boundaryOfLeft, boundaryOfRight )
{
 if( boundaryOfLeft < boundaryOfRight )
 // 区間内に複数個のデータがあるならば処理を行う。
 {
  // 奇数個のデータの中央の値を基準値として設定する。
  var sampleData = [];
  var pivot = 0;
  var randomNumber = 0;
  var numberOfSample = 3;
  var i = 0;
  var j = 0;

  // ランダムにサンプル データを抽出する。
  for( i = 0; i < numberOfSample; i++ )
  {
   randomNumber = Math.floor( Math.random() * (boundaryOfRight + 1 - boundaryOfLeft) + boundaryOfLeft );
   sampleData[i] = arrayOfData[randomNumber];
  }

  // バブル ソートを行う。
  for( i = 0; i < sampleData.length - 1; i++ )
  {
   for( j = sampleData.length - 1; j > i; j-- )
   {
    if( sampleData[j] < sampleData[j - 1] )
    {
     temporaryData = sampleData[j - 1];
     sampleData[j - 1] = sampleData[j];
     sampleData[j] = temporaryData;
    }
   }
  }

  // 中央の値を取る。
  pivot = sampleData[(numberOfSample - 1) / 2];

  i = boundaryOfLeft;
  j = boundaryOfRight;
  var temporaryData = null;
  while( true )
  {
   while( arrayOfData[i] < pivot )
   // 基準以上の値に出会うまで移動する。
   {
    i++;
   }

   while( arrayOfData[j] > pivot )
   // 基準以下の値に出会うまで移動する。
   {
    j--;
   }

   if( i >= j )
   // もし左右の注目位置が一致または交差したならば処理を抜ける。
   {
    break;
   }else
   // 左右の注目位置が未だ離れているならばその位置の値を交換する。
   {
    temporaryData = arrayOfData[i];
    arrayOfData[i] = arrayOfData[j];
    arrayOfData[j] = temporaryData;
    i++;
    j--;
   }
  }

  if( boundaryOfLeft < i - 1 )
  // 未だ左側の区間内に複数のデータがあるならば処理を繰り返す。
  {
   arrayOfData = quicksort( arrayOfData, boundaryOfLeft, i - 1 );
  }

  if( j + 1 < boundaryOfRight )
  // 未だ右側の区間内に複数のデータがあるならば処理を繰り返す。
  {
   arrayOfData = quicksort( arrayOfData, j + 1, boundaryOfRight );
  }
 }
 return( arrayOfData );
}


// クイックソートを実行する。
data = quicksort( data, 0, data.length - 1 );
data2 = quicksort( data2, 0, data2.length - 1 );

console.log( data ); // 1,2,3,4,5,6,7,8,9,10,11,12,14,17,18,19,22,23,25,26,31,34,35,38,40,41,45,55
console.log( data2 ); // 11F,12,123,5678,98,ABC,aaaaaa,abc,xy




Web APIでディレクトリーを読み込む機能を標準化して欲しい。 [プログラミング]

この度、自作のウェブ プログラム音楽ファイルを読み込んで音楽を再生出来るように致しました。

専用ブログの記事: ウェブ音楽プレイヤー
URL: https://applicationprogram.blog.so-net.ne.jp/2019-07-03-1

JS_Music Player_SS_(2017_06_28)_2_Cropped_1 ミュージック プレイヤーのスクリーンショット画像。 黒い背景の上に青色の二重の光る円環があり、円環の中心から青色の多数の輝く粒子が放出されている。 画面の下方には音楽のスペクトラム アナライザーのヴィジュアライザーが描画されており、垂直の青色のバーが多数横方向に並んで伸び縮みしている。 青色のバーは明るさと彩度と色相に微妙なグラデーションが掛かっている。
https://c1.staticflickr.com/5/4238/35410672282_f315bbd654_o.png

これは自作のHTML5 音楽再生ウェブ アプリケーション プログラムで音楽ファイルを再生させながらヴィジュアライザーを表示している状態のスクリーンショット画像です。

音楽ファイルの読み込みには " HTMLInputElement " を利用しております。

ファイル入力の標準化された方法と致しまして、HTMLの " input " 要素で " type="file" " 、 " multiple " 属性を設定する事でウェブ ブラウザーの標準のファイル選択用のボタンが画面に表示され、それを押すとファイルを1つまたは複数選択して参照する事が出来ます。
私は以前作成した " HTML5 インタラクティヴ ジェネレーティヴ ディジタル アート " ではこの方法を利用致しました。

ですが私が新たに作成した " 音楽再生ウェブ アプリケーション " では、非標準の " HTMLInputElement.webkitdirectory " を利用して音楽ファイルが入っているフォルダーのあるディレクトリーを読み込むように致しました。

そして、読み込んだファイルの相対パスとファイル名に基づいてファイルの順序をクイックソート アルゴリズムで並べ替えてから " window.URL.createObjectURL( fileList[i] ) " で選択したファイル毎のURLを生成させ、音楽再生時に " XMLHttpRequest " でURLからデータを取得し、 " audioContext.decodeAudioData() " で音楽データをデコードして、バッファーにデータを入れて出力させます。

選択したフォルダー以下にある全てのフォルダーと音楽ファイルを読み込んでリストにして再生出来ます。

現状では、セキュリティ上の配慮からディレクトリーへのアクセスが可能な " HTMLInputElement.webkitdirectory " はWeb標準化されておりません。
その為、ヴェンダー プリフィクスが付いており、仕様が固まっていない上、将来標準化されるかどうかも不透明です。
一応、現在主流のブラウザーは対応しているようです。

この機能は非常に利用価値が高いものですので、是非とも標準化して心置き無く使用出来るようになって欲しいところです。

"MDN" (Mozilla Developer Network)の "HTMLInputElement.webkitdirectory" のページのURL:
https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/webkitdirectory

JavaScriptでのループ処理速度を計測して比較してみました。 [プログラミング]

私は自作のHTML5 ディジタル インタラクティヴ アート プログラムのコードを書いている中で、処理速度を向上させる為に試行錯誤しております。

例えば、複数の種類の図形を大量に同時に動かすアニメーションの処理を軽量化する為に次の様な方法を用いております。
まず、レイヤーとして使用する為に、小さなCanvas Contextを図形の種類の数だけ配列に格納して準備致します。
図形を予めそれらのレイヤーに種類毎に1つずつ描画しておきます。
図形が描かれたレイヤーを、インターヴァル タイマーなどで定期的に呼び出した関数内で位置と縮尺を変えながら画面表示用のCanvasに大量に転写させます。

この方法は前述のプログラムの中では、煌めく粒子が大量に放出されて別々の方向へ飛んで行くアニメーションの為に使用しております。
粒子が放出される度に、粒子の画像に色が異なる円形のグラデーションを適用しており、個々の粒子毎に大きさも飛んで行く方向も異なるので、それら個々の粒子毎に描画し直していては処理が追いつかないのです。


また、物理計算などに於いては同様の処理を大量に繰り返す、ループ処理が多用されます。
ループ処理の繰り返し回数が膨大であると、プログラムの処理待ち時間が長くなり、ユーザーは苛々してしまいます。

私はギターの弦の振動をシミュレートして音を出す機能を前述のプログラムに組み込んでありますが、この計算の中では長い時間が掛かる繰り返しの計算処理を回数に制限を掛けて分割し、制限の回数に達した時点で、 " setTimeout(); " 関数で待ち時間を " 0 " [ms]として計算処理を行う関数を再び呼び出して続きの処理を行うという流れを繰り返し、既定の処理が全て完了した時点で、同様にしてその後の処理を行う関数を呼び出すようにしております。
この様にすることで、 " setTimeout(); " 関数が呼ばれた瞬間に処理が一旦解放され、処理待ちのキューに溜まっていた別の処理を実行する事が可能となり、プログラム全体の動きが止まってしまう事を避けることが出来ます。


ここからが本題ですが、ループ処理そのものの速度を上げるにはどうしたら良いでしょうか。
ウェブ上には様々な情報がございますが、環境やウェブ ブラウザーのヴァージョンなどにより結果は異なるようです。
私は2016年12月17日現在の私の環境での複数種類のループ処理の速度を実測してみることに致しました。

尚、私の環境は次の通りです。
・CPU: Intel Core i7-3770T ( 22[nm], TDP 45[W], Base Clock Frequency 2.50[GHz], Turbo Boost Clock Frequency 3.70[GHz], 4 Cores, 8 Threads )
・Main memory: CFD ELIXIR W3U1600HQ-8G ( DDR3 SDRAM PC3-12800 8GB*4 )
・Video Card: Palit GeForce GTX 750 KalmX (Fanless)
・OS: Ubuntu 16.04 LTS
・Linux kernel: 4.4.0
・Web browser: Firefox 50.1.0

まず、計測する際に使用したコードの例を掲載致します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>JS_Speed_Test</title>
</head>
<body>

<script type = "text/javascript">

var startTime = 0;
var endTime = 0;
var elapsedTime = 0;

var startTime2 = 0;
var endTime2 = 0;
var elapsedTime2 = 0;

var v = 0;
var w = 0;
var x = 0;
var y = 0;
var z = 2147483647;

for( var i = 0; i < 4; i++ )
{
 // [インクリメント評価方式]
 v = 0;
 startTime = Date.now();
 for( w = 0; w < z; w++ )
 {
  v += w;
  if( v > 1000000)
  {
   v = 0;
  }
 }
 endTime = Date.now();
 elapsedTime += (endTime - startTime);

 // [デクリメント評価方式]
 v = 0;
 startTime2 = Date.now();
 for( x = z, y = 0; x--; y++ )
 {
  v += y;
  if( v > 1000000)
  {
   v = 0;
  }
 }
 endTime2 = Date.now();
 elapsedTime2 += (endTime2 - startTime2);
}
alert( elapsedTime + "milliseconds\n" + elapsedTime2 + "milliseconds" );

</script>
</body>
</html>

形式としては、まず比較対象の2種類のループ処理を一括で逐次実行する形とし、それらを纏めてループ処理で4回計測してそれぞれのループ処理の合計の処理時間を計測するものと致しました。
尚、実行順による処理時間の差が出ますので、2回目は順序を入れ替えて計測致しました。
この記事の中では上記コード内の2つのfor文を便宜的に、 " インクリメント評価方式 " 、 " デクリメント評価方式 " と呼ばせて頂きます。

私の環境では、有意な速度差が計測出来ました。

ループ回数が " 符号付き32 bit整数型 " の最大値である " 2147483647 " (2^31)以下の場合は、上のコードにある、 " インクリメント評価方式 " の方が " デクリメント評価方式 " よりも高速でした。
・インクリメント評価方式: 14680[ms](1回目の合計値), 15778[ms](2回目の合計値)
・デクリメント評価方式: 17808[ms](1回目の合計値), 17280[ms](2回目の合計値)

逆に、ループ回数が " 符号付き64 bit整数型 " の範囲となる " 2147483648 " (2^31 + 1)以上の場合は、上のコードにある、 " デクリメント評価方式 " の方が " インクリメント評価方式 " よりも高速でした。
・インクリメント評価方式: 23440[ms](1回目の合計値), 23450[ms](2回目の合計値)
・デクリメント評価方式: 21488[ms](1回目の合計値), 21345[ms](2回目の合計値)


推測ですが、 " デクリメント評価方式 " ではループ回数が " 符号付き32 bit整数型 " の範囲内では、条件式の中の2つの数値の比較の処理コストは大きくなく、一方で、計数の為のデクリメントされて行く変数と、ループ内の処理で使用する為のインクリメントされて行く変数の2つの変数を使用していることによる処理のコストが大きくなるのかもしれません。

一方、ループ回数が " 符号付き64 bit整数型 " の範囲となると、大きなデータ型同士の比較を毎回繰り返さなくてはならない " インクリメント評価方式 " に比べて、 " デクリメント評価方式 " では条件式の評価の仕方が " 0か非0か " だけなので、処理コストが小さくなったのかもしれません。

尚、 " デクリメント評価方式 " で私が何故カウント ダウン用の変数と、インクリメント用の変数の2つの変数を用いているのかと申しますと、ループ処理内で頻繁に利用される配列を用いた処理をする際、配列に後ろから前に向かって値を入れて行くと桁違いに処理が遅くなってしまうので、配列の要素番号は昇順で使用すべきだからです。


一方、別の計測で、 " for文 " と " while文 " の実行速度を比較致しましたが、その速度差は誤差程度しかございませんでした。
また、前置インクリメント後置インクリメントにも速度差は誤差程度しかございませんでした。

結論と致しましては、 " 2147483648 " 回にも達するような繰り返し計算をするならば途中で処理を分割するべきですので、通常の繰り返し回数内で明らかに高速である、上記コード内の " インクリメント評価方式 " を使用したいと思います。
また、ループ処理の中で使用する変数は1つでも少ない方が高速な処理が可能です。

ところで、この結果はあくまで私の計測した環境上でのものですので、環境が異なれば結果は違ったものとなります。
また、私の理解が間違っている可能性もございますが、御容赦下さいませ。

シグモイド関数が凄く便利です。 [プログラミング]

Sigmoid Function_SS_(2016_11_03)_1_resized_1 2つのシグモイド関数の和を表したグラフ。 表計算ソフトウェアのLibreOffice Calcのスクリーンショット画像である。 グラフの左寄りの一部が縦軸方向で0近くまで窪んでいる。
https://c2.staticflickr.com/6/5744/30743914875_63e44f7b51_o.png
これはオープン ソースで無償の表計算ソフトウェアである " LibreOffece Calc " で作成した、2つの " シグモイド関数 " の和のグラフのスクリーンショット画像です。

->->
[2016年11月16日追記]
記事内容を更新致しました。
<-<-

私がブログに掲載している、 " HTML5 インタラクティヴ アート " の中で、80[Hz]付近の低周波数領域の音だけ音の終わりの方で徐々に周波数を下げて行く処理が施してあります。
その際、特定の領域にだけ左右非対称な形の滑らかな曲線による重み付けをする為の係数を計算させる必要がございました。

ブログ記事: リズム演奏機能を追加致しました。
http://crater.blog.so-net.ne.jp/2016-11-16

大抵の場合、滑らかな曲線による重み付けの為の係数は、sine関数などの三角関数で事足りるのですが、今回はグラフが左右非対称の形状かつ、1箇所の窪んだ領域以外はほぼ一定の値にする必要があり、これを周期関数である三角関数で記述しようとすると条件分岐で定義域を区切ったり周波数を計算したりと煩雑になってしまいます。
ところが、これをシグモイド関数で求めると非常に簡単に出来るのです。

yの値が0から1までに収まり、80[Hz]付近が窪んだ形になるxの関数として次のような式を使用致しました。
(後日、プログラム中で使用する式の形は変更致しました。)
y =
 (1 / (1 + Math.pow( Math.E, - 0.08 * (x - 160))))
 + (1 / (1 + Math.pow( Math.E, - 0.2 * (40 - x))));

ここで、 " Math.E " は自然対数の底でもあるネイピア数を返します。
冪乗は " Math.pow( base, exponent ) " となります。

独立変数xについてのシグモイド関数yはゲインをaとすると次の式で表されます。
y = (1 / (1 + Math.pow( Math.E, - a * x)));


私はこの曲線に1を加えて、更に係数を乗じた上で、これの逆数を時刻を表す変数に掛け合わせました。
そしてその値を各時刻毎に正弦波を表す関数内の時刻の値から減算する事により、一部の低周波数領域に於いて時間経過と共に周波数が下がって行く処理を実装致しました。

皆様も是非、シグモイド関数を御活用なさってみて下さい。

オンライン百科事典 "Wikipedia" の "シグモイド関数" のページのURL:
https://ja.wikipedia.org/wiki/シグモイド関数

オンライン百科事典 "Wikipedia" の "ロジスティック方程式" のページのURL:
https://ja.wikipedia.org/wiki/ロジスティック方程式

->->
[2016年11月4日追記]
シグモイド関数も含めて様々な曲線を持つ、プログラミングに役立つ関数を紹介してくれているウェブページへのリンクを掲載させて頂きます。

"東京工業大学 ロボット技術研究会" の記事 "簡単・便利な関数" のURL:
http://titech-ssr.blog.jp/archives/1046417061.html
<-<-

JavaScriptで "Cubic Hermite Spline補間関数" を作りました。 [プログラミング]

現在も制作中の、インタラクティヴ ディジタル アート作品の為に、JavaScript三次補間関数を作成致しました。
この関数に補間対象の1次元のデータ配列と拡大倍率の値を渡すと、 " 三次Hermite スプライン補間法 " (Cubic Hermite Spline Interpolator / キュービック エルミート スプライン補間法)でデータの内挿を行い、渡された値の間を滑らかに繋ぐ新たな値を生成して、1次元の新たなデータ配列を返却します。

Cubic Hermite Spline Interpolation_SS_(2016_08_01)_1_Cropped_1 黒い背景に水色の角ばった線と橙色の滑らかな曲線が重なりあったグラフとして描かれている。左上には白く光る丸とそこから緑色の曲線が放射されている模様が描かれている。
https://c1.staticflickr.com/9/8752/28065573983_d53a4c160a_o.png
これはグラフをHTML5のCanvas要素内に描画した際のスクリーンショット画像です。
水色の角ばった線が与えたデータを表しております。
橙色の曲線が補間されたデータを表しております。
与えたデータの点を通り、滑らかな曲線を描いております。
このグラフのデータの補間による拡大倍率は12倍です。

オーヴァーシュートとアンダーシュートが出ますので、値域に関しては適切な処理が必要です。

->->
[2016年8月2日追記]
" 三次Hermite スプライン補間関数 " のオプションを追加致しました。
与えられたデータ配列の最初の要素の値と最後の要素の値が滑らかに繋がり、循環するように指定出来ます。
Cubic Hermite Spline Interpolation_SS_(2016_08_02)_1_Cropped_1 黒い背景に青緑色のぐにゃぐにゃに歪んだ滑らかな曲線の円3つ描かれている。右上の歪んだ円の中央には白く光る丸が描かれ、そこから放射状に青色と紫色のリボンの様な曲線が伸びている模様が描かれている。
https://c1.staticflickr.com/9/8654/28701035475_245787f389_o.png
このスクリーンショット画像に描かれている歪んだ円環は、乱数による一様なノイズを複数回、スケールを変えながら滑らかにデータ補間しつつ合成して行ったものを円形に繋いだ曲線です。
円の始点と終点が滑らかに繋がるようにする為に、データ補間のオプションで、ノイズの最初のデータの値と最後のデータの値が循環するように指定したものです。
<-<-
->->
[2017年5月22日追記]
データを循環させる場合の繋げ方が適切でなかったので修正致しました。
データの最初と最後が補間により滑らかに繋がります。
<-<-

私のこのプログラムは行列計算などにはしていないので処理速度は速くはない筈ですが、綺麗に補間出来ます。
また、このコードはもしかすると間違っているかもしれません。

私のブログ記事: とても美しいディジタル アートになりました。
http://crater.blog.so-net.ne.jp/2016-07-26

私のブログ記事: HTML5のCamvasと "JavaScript" で音声処理と画像描画。
http://crater.blog.so-net.ne.jp/2016-06-30

私のブログ記事: "JavaScript" で音と画像を生成するプログラムのソースコード。
http://crater.blog.so-net.ne.jp/2016-06-30-1

この関数の作成の為にWikipediaなどを参照させて頂きました。

"Wikipedia" (English)の "Cubic Hermite spline" のページのURL:
https://en.wikipedia.org/wiki/Cubic_Hermite_spline

以下に自作のソース コードを掲載致します。
自己責任の上で御自由にお使い下さいませ。
当ソース コードには間違いがあるかもしれません。
もし当ソース コードを使用した事による如何なる問題につきましても、私は責任を取る事が出来ません。
御了承下さいませ。

引数は、以下のものと致します。

dataArray:
補間対象の1次元データ配列。

dataArrayLength:
データ配列の最初の要素から数えての補間対象とするデータの要素数。
dataArray[0]からdataArray[15]までを対象とする場合、16という数値を渡す。

scaleFactor:
拡大倍率。
8倍に拡大したい場合、8という数値を渡す。

isDataLoop:
データの最初と最後を循環させる場合、trueを渡し、循環させない場合、falseを渡す。

// 三次Hermite スプライン補間関数を関数式により定義する。
var cubicHermiteSplineInterpolation = function( dataArray, dataArrayLength, scaleFactor, isDataLoop )
{
 var interpolatedDataArray = [];
 var startingTangent = 0;
 var endingTangent = 0;

 if( isDataLoop === true )
 // データを循環させる場合は以下の処理を行う。
 {
  // データの要素を1つ分だけ後ろへ移動する。
  var i = dataArrayLength;
  for( ; i > 0; i-- )
  {
   dataArray[i] = dataArray[i - 1];
  }

  dataArray[0] = dataArray[dataArrayLength]; // 元のデータの最後の要素の値を先頭の要素に複製する。
  dataArray[dataArrayLength + 1] = dataArray[1]; // 元のデータの最初の要素の値を最後の要素の1つ後に複製する。
  dataArray[dataArrayLength + 2] = dataArray[2]; // 元のデータの最初から2番目の要素の値を最後の要素の2つ後に複製する。
  dataArray[dataArrayLength + 3] = dataArray[3]; // 元のデータの最初から3番目の要素の値を最後の要素の3つ後に複製する。

  var j = 0;
  var k = 0;
  for( i = 1; i < dataArrayLength + 2; i++ )
  {
   // 区間の正接の計算を行う。
   startingTangent = 0.5 * (dataArray[i + 1] - dataArray[i - 1]);
   endingTangent = 0.5 * (dataArray[i + 2] - dataArray[i]);

   // 内挿を行う。
   for( j = 0; j < scaleFactor; j++, k++ )
   {
    var x = j / scaleFactor;
    interpolatedDataArray[k] =
     ((1 + 2 * x) * (1 - x) * (1 - x)) * dataArray[i]
     + (x * (1 - x) * (1 - x)) * startingTangent
     + (x * x * (3 - 2 * x)) * dataArray[i + 1]
     + (x * x * (x - 1)) * endingTangent;
   }
  }

  // 最後部の不要になった要素を削除する。
  for( i = dataArrayLength * scaleFactor; i < (dataArrayLength + 1) * scaleFactor; i++ )
  {
   interpolatedDataArray.pop();
  }

  // 返却される配列の要素数は、 'dataArrayLength * scaleFactor' となる。
 }else
 // データを循環させない場合は以下の処理を行う。
 {
  var i = 0;
  var j = 0;
  var k = 0;
  for( ; i < dataArrayLength - 1; i++ )
  {
   if( i === 0 )
   // 最初の区間の設定を行う。
   {
    startingTangent = (dataArray[i + 1] - dataArray[i]);
    endingTangent = 0.5 * (dataArray[i + 2] - dataArray[i]);
   }else if( i === dataArrayLength - 2 )
   // 最後の区間の設定を行う。
   {
    startingTangent = 0.5 * (dataArray[i + 1] - dataArray[i - 1]);
    endingTangent = (dataArray[i + 1] - dataArray[i]);
   }else
   // 最初と最後以外の区間の設定を行う。
   {
    startingTangent = 0.5 * (dataArray[i + 1] - dataArray[i - 1]);
    endingTangent = 0.5 * (dataArray[i + 2] - dataArray[i]);
   }

   // 内挿を行う。
   for( j = 0; j < scaleFactor; j++, k++ )
   {
    var x = j / scaleFactor;
    interpolatedDataArray[k] =
     ((1 + 2 * x) * (1 - x) * (1 - x)) * dataArray[i]
     + (x * (1 - x) * (1 - x)) * startingTangent
     + (x * x * (3 - 2 * x)) * dataArray[i + 1]
     + (x * x * (x - 1)) * endingTangent;
   }
  }
  interpolatedDataArray[(dataArrayLength - 1) * scaleFactor] = dataArray[dataArrayLength - 1]; // 最後の要素の値を代入する。

  // 返却される配列の要素数は、 '(dataArrayLength - 1) * scaleFactor + 1' となる。
 }
 return( interpolatedDataArray ); // 補間された新たな1次元のデータ配列を返却する。
};

改善、改善、さらに改善! [プログラミング]

仕事で長い事取り組んでいるプログラミングで、幾つもの改善、改良を重ね、仕様追加に対応してきました。

本日は、各種測定データ ログを一定時間毎にCSV ファイルに書き出しているのですが、時間間隔の計測にWin32APIのSleep( 1000 );のwhile( 1 ){}を行うスレッドで変数をインクリメントしていたので、僅かな誤差が在りました。
24時間試験を行うと、大きな差になってしまう事が問題となりましたので、これを改善しました。

DWORD time_thread( void *p )
{
  previous_time = systime.wSecond;
  while( 1 )
  {
    Sleep( 1 );
    GetLocalTime( &systime );
    if( systime.wSecond != previous_time )
    {
      previous_time = systime.wSecond;
      time++;
    }
  }
  return( 0 );
}

確かこのような感じで書いたと思います。
このタイマーはその他様々に使用しております。

データ ログ ファイルには、データ番号、日付、時刻、多数のデータなどを書き込みます。

この時間間隔や時刻情報が他の測定機材の時刻とずれてはまずい訳です。


ところで、私はプログラマーではございません。
回路設計技術者を志しております。
病気に倒れる前、回路設計CAD, プリント基板設計CADを使いました。
昨日と今日はAutoCADを使ってみております。
Blenderの方が使い易いじゃないかと思う部分も在りました。
ですが、もちろん目的が異なり、機能も異なっているので文句は言えません。
次はSpiceで回路シミュレーションを覚えなければなりませんね。



ああ、ロッテリアの絶品チーズバーガーを食べたいなぁ。。。

プログラミング ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。