• ベストアンサー

2の補数の計算について

C言語のプログラム中で得られた10進数の値を,固定長16ビットの2進数に変換したいと考えています. しかしながら,得られた10進数の値が負数であった場合,それを負数と判断し,2の補数として出力したいのですが,なかなかいい方法が思いつきません… 例えば処理中で -1.915098 といったような10進数の値を2進数に変換し,先頭の1ビットが正負符号の2の補数として表現するためにはどのように記述すればよいでしょうか? 簡単で構いませんので,記述例も書いていただけると助かります…

質問者が選んだベストアンサー

  • ベストアンサー
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.4

Q13 でいいなら, 端数処理の問題はあるけどおそらく考えすぎ. 元の数を x とすると (int)(x * (1 << 13)) でだいたいうまくいくはず. 負の数のときに問題になりえるんだけど, そのときには負の浮動小数点数を整数に変換するときに丸めが「0 への丸め」じゃないということなので (x < 0) ? (int)(x * (1 << 13)) : ~(int)(-x * (1 << 13)) + 1 でいいような気がする. もちろん Q13 でいいかどうかは私にはわからんので確認しといてください.

ohkohkun
質問者

お礼

>Tacosanさん ご回答,ありがとうございます. 書いて頂いたように記述してみたところ,うまく表示させることができました! Q13の件についても確認したのですが,やはり固定小数点数で正しかったようです. 本当にありがとうございましたm(__)m

その他の回答 (4)

回答No.5

浮動小数点であれば単純な2の補数では表現不可能です。 下記の様にfloat型をそのまま表示しちゃ駄目なのかな? float型もlong型も32bitの処理系とします。 float f; long *l; f = -1.915098; l = (long *)&f; printf("%04x\n",*l); float型 bit[31] 符号ビット bit[30:21] 指数部 bit[22:0] 可数部 floatの値 = (-1)*符号 * 2^(指数部-127) * 1.仮数部 16進数で出力してますが、2進数には簡単に直せますよね? また固定小数点なら2の補数で表現可能です。入力範囲とビット幅を決定しなければいけません。 ビット数を32ビットとし 入力範囲を((2^31)-1)/(2^30)=1.999... ~ -(2^31)/(2^30)=-2 とするなら。 float f; long l; f = -1.915098; l = f * (float)(1<<30); printf("%04x\n",l); で良いのでは? 入力範囲を超えるならクリップ処理を入れたほうが良いかも。

ohkohkun
質問者

お礼

>ICE_FALCONさん ご回答,ありがとうございます. お礼が遅くなってしまい,申し訳ありませんでした… 宣言まで丁寧に書いて頂き,非常に理解しやすかったです. 結果的には,固定小数点数でうまく表示させることができました. また,ご指摘の通り入力範囲を超える値もありましたので,自分なりにクリップ処理も追加してみました. この度は,本当にありがとうございました. また何かありましたら,よろしくお願い致しますm(__)m

回答No.3

No.1です。 「浮動小数点」の認識が、私とは違っているようです。 私の認識では >「4.125」のように小数部がいわゆる2^(-n)で表現できるような値に関しましては(以下略) 浮動小数点としての表記は(()内は指数)、 4.125=4.125*2(0) =0.4125*2(1) となるため、この時点で丸めが発生していますよ。 質問者さんの行っていることは、0.0001を1bitの規定として扱った場合の処理です。 >#また,最終的には小数点を用いずに出力しなければなりません >(「1.915098」を13ビット(2^13=8192)を基準として表現?できるように,とのことなのですが, ここが不明瞭です。 「13bit」は少数部のことでしょうか? であれば、「固定16bit」だと「符号部1bit、指数部2bit」しか領域がとれませんよ? それとも、No.2氏の書かれている通り、固定小数点でしょうか? どちらにしろ丸めが発生するのは避けられませんが。 質問の >10進数の値を,固定長16ビットの2進数に変換したいと考えています. に対して、具体的な結果としてどのような値としたいのかをいくつかの例を教えていただけませんか?

ohkohkun
質問者

補足

>SilverThawさん 度々ありがとうございます.ご指摘,大変感謝しています. まず, >10進数の値を,固定長16ビットの2進数に変換したいと考えています. に関してですが,結果として以下のように,複数の小数点や負数を含む数値に対して,それぞれ16ビットの2進数に変換できることを目的としています. 1.915098(10) → xxxx xxxx xxxx xxxx(2) -3.055348(10) → xxxx xxxx xxxx xxxx(2) … 2の補数表現 0.540523(10) → xxxx xxxx xxxx xxxx(2) このとき,xxxx xxxx xxxx xxxx(2)は小数点を含まないように表現したいと考えています. この点から,ご指摘のように「0.0001を1bitの規定として扱った場合の処理」をすることで,小数点を含まず2進数に変換できるのではないかと理解しました… >#また,最終的には小数点を用いずに出力しなければなりません >(「1.915098」を13ビット(2^13=8192)を基準として表現?できるように,とのことなのですが, この件に関しましては,Tacosanさんの言われている通り,固定小数点のQ13表記のことだと思われます. Q13表記で,上の例を表現しますと, 1.915098(10) → 0011 1101 0100 1000(2) (1.915098 * 8192 = 15688.48282, 小数点以下切り捨てで15688→0011110101001000) -3.055348(10) → 1001 1110 0011 1011(2) … 2の補数表現 (-3.055348 * 8192 = -25029.41082, 小数点以下切り捨てで25029→0110000111000101, 2の補数表示で1001111000111011) 0.540523(10) → 0001 0001 0100 1011(2) (0.540523 * 8192 = 4427.964416, 小数点以下切り捨てで4427→0001000101001011) という結果になり,目的としていた表示となっていたため,固定小数点ではないかと考えました. 不明瞭にしてしまっていた点に関しましては,私なりに上記のように理解したのですが,おかしい点などがありましたら,ご指摘頂けるとうれしく思います…

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

たとえば 1.915098 なんかだと変換するときに端数が出るんだけど, その処理はどうするんですか? 切り上げ/切り捨て/四捨五入/最近値のどれにするかによって処理が変わるのでそこは決めておく必要があります. 「13ビット(2^13=8192)を基準として表現」の意味が分からんけどいわゆる Q13 (小数点以下が 13ビットの固定小数) のことなのかなぁ?

ohkohkun
質問者

補足

>Tacosanさん 回答ありがとうございますm(__)m 端数の件は考えていませんでした…しかし,おそらく切り捨てで処理すればいいのではないかと考えています. Q表記という名称に関しましては,正直知りませんでした… そこで調べさせて頂いたのですが,「13ビット(2^13=8192)を基準として表現」はQ13という意味のような気がしてきました. 例えば 1.915098 の場合ですと,2^13=8192ですので 1.915098(10) * 8192(10) = 15688.48282(10) となり,ここで15688.48282(10)の小数部分以下を切り捨てたとして,15688(10)を2進数に変換すると 15688.48282(10) = 0011110101001000(2) となりました.この上式で得られた2進表記がQ13であり,下位から13ビット目と14ビット目の間に小数点があることを表している,と理解しているのですが,ここまでは正しいでしょうか…? また,001.1110101001000(2)に対して10進数に変換したところ 001.1110101001000(2) = 1.915039...(10) となりました. #おそらく,許容される誤差の範囲内だと思います.

回答No.1

単純な「2の補数」ではなく「浮動少数点」の理解が必要なようですが、この部分は理解されていますか? 少なくとも、「-1.915098」といった小数点付を扱うにはその知識が必要ですが、マイナスがつかない場合の変換はできますか?

ohkohkun
質問者

補足

>SilverThawさん 早速の回答,ありがとうございますm(__)m 「浮動小数点」に関しましては,概要が多少分かる程度であり,正規化などについては正しく理解できていません… マイナスが付かない場合の変換に関してですが,ある程度までは出来る形になっています. 例として挙げさせていただいた「1.915098」のような小数部が長い場合の変換はうまく出来ていないのですが,「4.125」のように小数部がいわゆる2^(-n)で表現できるような値に関しましては, 4.125 * 256(=2^8) を行い, 4.125 * 256 = 1056 として,整数にしてから 1056(10) = 0000010000100000(2) 上のように求めています. #本来ならば,さらに8ビットシフトが必要かと思いますが,その辺りはまだ… #また,最終的には小数点を用いずに出力しなければなりません(「1.915098」を13ビット(2^13=8192)を基準として表現?できるように,とのことなのですが,ここはまだ理解できていません…) しかしながら,この方法では「1.915098」のような値をうまく求めることができず,どうしたものかというのが現状です. 乱文で申し訳ありませんが,よろしくお願い致します…

関連するQ&A