質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

Q&A

解決済

3回答

4232閲覧

分数で計算する方法が解からない

aaaaaaaa

総合スコア501

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

0グッド

1クリップ

投稿2016/08/25 11:12

下記のソースは、整数、小数点の二進数を十進数に変換する関数です。
しかし小数点の二進数を十進数に変換するときに問題が発生してしまいます。

小数点の二進数は、まず整数の部分と小数点以下の部分にわけて計算し、整数には2^xを、小数点以下の値には2^-xを乗算し、算出した値を配列にいれ一つずつ加算していき十進数を算出しようとしているのですが、この小数点以下の値には2^-xを乗算するときに分数、例えば2^-1ならば1/2、2^-3なら1/8のように分数で計算したいのです。しかしphpだと小数になってしまい、上手く十進数にすることができません。

どうすると下記のソースで、小数の二進数を十進数に変換することができるのでしょうか。

php

1//問題点(②1-3)…小数点が存在した時の計算が上手くいかない。分数で計算できれば上手くいく。 2function henkan($nisinsu) { 3 4 print "どこで文字列型になったのか:".gettype($nisinsu)."(".$nisinsu.")";//まだ、henkan関数に引数として受け取られたころは、仮引数が小数点であればdouble(倍精度浮動小数点数)型だ。 5 6 //----------------------------------------------▼修正中---------------------------------------------- 7 // 8 //処理の順番 ①…受け取った仮引数を一つ一つに分割し配列$resultに代入。代入後すぐに、分割した配列の数を取得。 9 // ②…上記の処理後、同じく受け取った仮引数に小数点が無いか調べる。小数点が存在する場合は、②-1。なければ②-2。 10 // ②-1(if)…受け取った引数に小数点があったときの処理。小数点以下"全て"をいったん取り除き、取り除いた部分を$syosutenに代入。つでに切り取った部分の数も取得($sakuzyo_mozi)。 11 // ②-1-1…小数点より上、つまり上一けた目から小数点の一つ前までを分割して取得する。 12 // ②-1-2…$syosutenに代入された値のうち、ドットつまり小数点の部分だけを削除。小数点が存在した場合、10進数にするときの処理には、必要ないので消す。 13 // ②-1-3…分割し、小数点を排除した数字に対して負数の指数(2^-x)を掛けていく。同じ要領で、分割し、小数点より上の数字(整数部分)に対して指数を掛けていく。しかし前者が上手くいかない! 14 // ②-1-4…数点以下の値其々($zyusinsu_syosuten)に、負の指数を、小数点より上の値其々($zyusinsu)に、正の指数を乗算した。それによって算出された値を加算することで小数点の2進数を10進数に変換する。 15 // 16 // ②-2(else)…受け取った引数に小数点が無かった時の処理。適宜、変換に必要な計算を行い二進数を十進数に変換する。 17 18 19 //① 20 //二進数を受け取ったら、数字を一つ一つ分解し、2^x乗の計算をする。 21 //マッチした部分を境に区切るのがpreg_splitなので数値と数値の間の"位置"にマッチするよう作る。 22 //$resultには、分割された2進数が入っている。 23 $result = preg_split("//", $nisinsu,-1,PREG_SPLIT_NO_EMPTY);//分割の結果、空になった配列だけを排除する定数。 24 //正規表現に何も指定していないものの、文字列の先頭と末尾と文字間にマッチしてくれるのだ。「101.1」で例えると|1|0|1|.|1|となる。 25 //ただこのままだと、最初と最後に空文字が生まれてしまうのでPREG_SPLIT_NO_EMPTYで空文字を削除する。 26 //preg_splitによって分割された配列の数を取得 27 $kazu = count($result); 28 print "<p>preg_splitによって分割された配列の数".$kazu."</p>"; 29 30 //②仮引数に小数点があったときの処理 31 //②-1 32 if(($dot_iti = mb_strpos($nisinsu,".")) !== false){//特定の文字列が含まれているか調べ、存在したらその文字の位置を数値で返してくれるので$dotで保存する。小数点が存在しなければfalseを返す。 33 print "<p>ドットは、何文字目にあったのか?:".$dot_iti."</p>"; 34 35 //小数点が存在している位置から後端までを$resultから取り出し、$syosutenに代入。 36 $syosuten = array_slice($result,$dot_iti,$kazu-$dot_iti);//第二引数が取り除く開始位置、第三引数が何文字取り除くかである。$kazu(配列の値の数) - $dot_iti(仮引数($nisinsu)内の小数点の位置)分取り除く。 37 //二進数を構成する数字を一つ一つに分解し、その分解した数を代入した$kazuから、小数点が存在する位置を引いた数を$sakuzyo_moziに代入。算出した値は、小数点から文字の終端までの数となる。 38 $sakuzyo_mozi =$kazu - $dot_iti; 39 print "<p>小数点も含めた取り除く文字の数:".$sakuzyo_mozi."</p>"; 40 print_r($syosuten); 41 42 //②-1-1 43 //小数点より上、つまり上一けた目から小数点の一つ前までを取得。第三引数は、分割された要素の数 - 小数点から文字の終端までの数だ。1.111なら、5(1)-4(.111)で、1となり、この1は、小数点より上の数字の数を意味する。 44 $seisu = array_slice($result,0,$seisu_kazu = $kazu-count($syosuten)); 45 print "いいい".$seisu_kazu."あああ"; 46 print_r($seisu); 47 48 //②-1-2 49 //$syosutenに代入された値のうち、ドットつまり小数点の部分だけを削除。 50 //小数点が存在した場合、10進数にするときの処理には、必要ないので消す。 51 //ちょんぎる配列、取り除く範囲の開始位置、開始位置から何文字取り除くかが引数の意味となる。 52 $dot = array_splice($syosuten,0,1); 53 print "<p>「".$dot[0]."」をちょんぎった</p>"; 54 print_r($syosuten); 55 print "<p>↑ちょん切った後の配列</p>"; 56 57 //小数点を削除した後の$syosutenの配列の数を取得。 58 $syosuten_kazu = count($syosuten); 59 60 //②-1-3 61 //分割し、小数点を排除した数字に対して負数の指数を掛けていく。 62 for($i=0,$sinsu = pow(2,-($kazu-1));$i<$syosuten_kazu;$i++) { 63 64 if($i !== 0) { 65 $sinsu = $sinsu/2; 66 } 67 print "●syosutenに掛けるべき数".$sinsu."<br>"; 68 print"●syosuten:".$syosuten[$i]."<hr>"; 69 70 //2進数を10進数にする計算。乗算部分。$zyusinsu_syosutenは、小数点以下の数字に負の指数で乗算した値が入っている配列だ。 71 //▼①phpの仕様なのか小数点で計算するので、ここで躓いてしまう。 72 $zyusinsu_syosuten[] = $sinsu * $syosuten[$i]; 73 } 74 //配列の数値を表示。 75 print_r($zyusinsu_syosuten); 76 77 //分割し、小数点より上の数字に対して指数を掛けていく。 78 for($i=0,$sisuu = pow(2,$seisu_kazu-1);$seisu_kazu > $i;$i++){ 79 80 //for文の増加式にいれると計算してくれないのでここでする。$iが0のとき、つまりループ初回のときは、計算を行わない。 81 if($i !== 0) {//$iが0でなければ、つまりループが二回目以降であれば、for文の初期化式でpow関数を利用し算出した指数($kazuが四個であれば2~3(8))を、条件式である$kazu>$iの条件に従って2で割っていく。 82 //2進数の一桁一けたに乗算するために必要な2の乗数の指数を算出。 83 $sisuu = $sisuu/2; 84 } 85 print "●seisuに掛けるべき数".$sisuu."<br>"; 86 print"●seisu:".$seisu[$i]."<hr>"; 87 88 //zyusinsuという配列に2進数を10進数に換算するのに必要な値を格納。 89 $zyusinsu[] = $sisuu*$seisu[$i]; 90 } 91 //配列の数値を表示。 92 //▼問題点…上一けたから順に$sisuuを乗算しているが何故か、全ての配列の値が1となってしまう。 93 print_r($zyusinsu); 94 95 //②-1-4 96 //小数点以下の値其々($zyusinsu_syosuten)に、負の指数を、小数点より上の値其々($zyusinsu)に、正の指数を乗算した。それによって算出された値を加算することで小数点の2進数を10進数に変換する。 97 //加算するためにまず配列の結合。 98 $seisuu_and_syosu = array_merge($zyusinsu,$zyusinsu_syosuten);// 99 print_r($seisuu_and_syosu); 100 101 //結合した配列の値同士を加算。 102 for($i=1;$i<count($seisuu_and_syosu);$i++) { 103 $seisuu_and_syosu[0] += $seisuu_and_syosu[$i]; 104 } 105 print "<hr>"; 106 return "<p>".$nisinsu."を十進数に変換すると…".$zyusinsu[0]."</p>"; 107 //②-2…小数点が無いときの2進数から10進数へ変換する処理 108 } else { 109 print "<p>小数点は無かった。:".$dot_iti."</p>"; 110 print "<p>どこで文字列型になったのか2:".gettype($result[1])."</p>";//▼なぜ、preg_splitすると文字列型になるのだろうか。 111 112 113 114 //2の$kazu-1乗が$sinsuに代入される。$kazuは、preg_splitで分割された文字の数が代入されている。 115 for($i=0,$sisuu = pow(2,$kazu-1);$kazu > $i;$i++){ 116 //また、$kazuに「-1」しないと、例えば、2進数の上一けた目(1010の1)に乗算される8(2^3)が16(2^4)になってしまう。 117 //例えば、2進数の1111(15)を10進数にするときに行う計算を例にすると、$kazuに「-1」という作業を行わなければ1*16+1*8+1*4*1*2という計算式が生まれてしまうのだ。 118 //本来は、1*8+1*4+1*2+1*1である。因みに答えは、8+4+2+1で15となる。この-1は、とても重要なのだ。 119 120 //for文の増加式にいれると計算してくれないのでここでする。$iが0のとき、つまりループ初回のときは、計算を行わない。 121 if($i !== 0) {//$iが0でなければ、つまりループが二回目以降であれば、for文の初期化式でpow関数を利用し算出した指数($kazuが四個であれば2~3(8))を、条件式である$kazu>$iの条件に従って2で割っていく。 122 //2進数の一桁一けたに乗算するために必要な2の乗数の指数を算出。 123 $sisuu = $sisuu/2; 124 } 125 print "●resultに掛けるべき数".$sisuu."<br>"; 126 print"●result:".$result[$i]."<hr>"; 127 //zyusinsuという配列に2進数を10進数に換算するのに必要な値を格納。例えば、$kazuが四個であれば、$zyusinsu内は、8,4,2,1の順番となる。最後にこれを加算することで十進数が出来上がる。 128 $zyusinsu[] = $sisuu*$result[$i]; 129 } 130 //配列の数値を表示。 131 print_r($zyusinsu); 132 //配列の数値を加算。 133 for($i=1;$i<count($zyusinsu);$i++) { 134 $zyusinsu[0] += $zyusinsu[$i]; 135 136 } 137 print "<hr>"; 138 return "<p>".$nisinsu."を十進数に変換すると…".$zyusinsu[0]."</p>"; 139 }//else 140}//kansu 141 142print henkan("1.111"); 143 144

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

全部は見てませんが、1/2 1/4 1/8 を作るところが変なのと、
解を表示してる変数名が違います

php

1//for($i=0,$sinsu = pow(2,-($kazu-1));$i<$syosuten_kazu;$i++) { 2 for($i=0,$sinsu = pow(2,-1);$i<$syosuten_kazu;$i++) {

php

1//return "<p>".$nisinsu."を十進数に変換すると…".$zyusinsu[0]."</p>"; 2 return "<p>".$nisinsu."を十進数に変換すると…".$seisuu_and_syosu[0]."</p>";

投稿2016/08/26 01:39

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

aaaaaaaa

2016/08/26 09:55

少々長いソースにもかかわらずご回答有難うございました。 二点の粗忽のせいで上手く計算ができないのでいたのですね。仰るとおりに修正したところ無事、1.875と10進数に変換することができました。
guest

0

オーバーフローとかは考えませんが、その分簡単な方法

小数点以下が何桁あるか数えます -> N
小数点がなかったものとして整数に変換します。すなわち、変換したい数の2^N倍を求めます。
求めた数を2^Nで割ります。

例)"1010.1100" (= 10.75)
N=4
b10101100 = d172
172/2^4 = 10.75

投稿2016/08/26 03:19

ozwk

総合スコア13512

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ざっとやるとこんな感じでは?

PHP

1function henkan($str){ 2 if(strpos($str,".")===false){ 3 $num=bindec($str); 4 }else{ 5 list($seisu,$shosu)=explode(".",$str); 6 $num=bindec($seisu); 7 for($i=0;$i<strlen($shosu);$i++){ 8 if(substr($shosu,$i,1)==="1"){ 9 $num+=pow(2,-1-$i); 10 } 11 } 12 } 13 return $num; 14} 15

投稿2016/08/25 11:44

yambejp

総合スコア114572

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問