• ベストアンサー

除算を使わずに10で割りたい。

加算、減算、シフト、論理演算、ループ、等を使って 除算を使わずに10で割る方法は無いものでしょうか? また、近似値を求めてから誤差を修正する方法でも構いません。 ただし、ループで10を引き続けてカウントする方法は除外させてください。 言語はCでお願いします。

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

  • ベストアンサー
  • mtaka2
  • ベストアンサー率73% (867/1179)
回答No.16

ANo.15 は「引き戻し法」ですね。いわゆる普通の「割り算の筆算」をそのまま2進数ベースで実装したものです。 (10進の割り算の場合は、各桁で「1倍~9倍のどこまで引けるか」を計算しますが、2進数なので、「引ける(その桁は1)か引けない(その桁は0)か」の2択の判定になります。 それをもうちょっと進めた(計算量を減らした)方法に「引き放し法」というのもあります。「引けるかどうか」チェックしてから「引く」のは二度手間なので、「引いてしまってから、結果によって次の処理を変える(負になったら、次のステップでは足すようにする)」というものです。 でも、この手の処理は「CPUの内部でハードウェアで実装されている」機能ですから、それをソフトウェアで実装するのは遅いだけでメリットはありません。 多倍長演算が例に挙げられてますけど、多倍長の2進数で実装する場合でも、 個々の演算は通常の加減乗除の組合せで実装するのが普通です。 例えば、32bitCPUで256bitの数値演算をしたいのであれば、 「4294967296進数で8桁の数値」を扱うようにすればいいんです。 簡単な例ですが、以下、64bitの数値を16bit×4桁と考えて10で割るコードです。除数の方も多倍長になるとやることは格段に複雑になりますが、演算の基本方針は同じです。 #include <stdio.h> int main(int argc, char *argv[]) { union { unsigned long long ulonglong; unsigned short ushort[4]; } x, y; unsigned int div, mod; x.ulonglong = 9876543210LL; printf("%lld = %d * (1<<48) + %d * (1<<32) + %d * (1<<16) + %d\n", x.ulonglong, x.ushort[3], x.ushort[2], x.ushort[1], x.ushort[0]); /* x86 CPUは Little Endian なので、ushort[3]が上位でushort[0]が下位 */ div = x.ushort[3] / 10; mod = x.ushort[3] % 10; y.ushort[3] = div; div = (mod * 65536 + x.ushort[2]) / 10; mod = (mod * 65536 + x.ushort[2]) % 10; y.ushort[2] = div; div = (mod * 65536 + x.ushort[1]) / 10; mod = (mod * 65536 + x.ushort[1]) % 10; y.ushort[1] = div; div = (mod * 65536 + x.ushort[0]) / 10; mod = (mod * 65536 + x.ushort[0]) % 10; y.ushort[0] = div; printf("%lld / 10 = %lld mod %d\n", x.ulonglong, y.ulonglong, mod); }

kenji_aki
質問者

お礼

回答ありがとうございます。 「引き戻し法」「引き放し法」覚えておきます。 >多倍長演算が例に挙げられてますけど、多倍長の2進数で実装する場合でも、 >個々の演算は通常の加減乗除の組合せで実装するのが普通です。 なるほど、私は初めから多倍長演算になると普通の乗除算は使えないと勝手に考えてしまい、このような質問をすることになっていました。 このような考え方があったのですね。 教えていただき、ありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (15)

  • Tasuke22
  • ベストアンサー率33% (1799/5383)
回答No.5

取合えず回答1 10のビットを反転して、掛けます。

全文を見る
すると、全ての回答が全文表示されます。
  • jacta
  • ベストアンサー率26% (845/3158)
回答No.4

> ただし、ループで10を引き続けてカウントする方法は除外させてください。 ループで10を足し続けて、被除数を越える直前の値が商。

kenji_aki
質問者

お礼

ウィットの利いた回答ありがとうございます。

全文を見る
すると、全ての回答が全文表示されます。
  • ts3m-ickw
  • ベストアンサー率43% (1248/2897)
回答No.3

学生さんの宿題ですかねぇ。除算がダメなら0.1を乗算すればいいのでは、とか詭弁を使ってみたりして。 冗談はさておき、除算にはいくつかのアルゴリズムがありますが、復元法なら簡単だと思います。2で割る部分はシフトで求めます。 詳しいアルゴリズムはこんなところで。

参考URL:
http://www.elc.ees.saitama-u.ac.jp/ITO/Ex4/divide.html
kenji_aki
質問者

お礼

回答ありがとうございます。 恥ずかしながら理解するのに時間が掛かりました。 実のところ、ループも使わずに出来ないかと思うのですが お手数ですが他の方法をご存知であればご教示ください。 今回の回答に不満があるというわけではありません。 実際プログラムを組んでみて、例えば数kBの数値を除算するのにどれほどの時間が掛かるか試して見る必要があります。 マルチバイトの比較やシフトなんかも組まないといけないので 今実際に試すことができません。 回答には大変感謝しております。 ありがとうございました。 また、他の回答も随時受け付けております。

全文を見る
すると、全ての回答が全文表示されます。
  • saru1234
  • ベストアンサー率37% (223/593)
回答No.2

課題じゃないんですか? だと、そのまま質問するのはルール違反なんですけど。 こういうのはヒントになるでしょうか。(全然役に立たないかも知れませんが。) 論理演算可能な数値らしいので、浮動小数点とかではないですよね。 ・乗算せずに10倍する方法。  ・3bitシフトして8倍の値と、1bitシフトして2倍の値を得る。  ・それらを加算すると10倍の値を得られる。

kenji_aki
質問者

お礼

回答ありがとうございます。 申し訳ありませんが、乗算に関しては自分でいろいろやって、お書きになった方法に関してもよく理解しているつもりです。 しかしながら、除算になると事が違ってきます。 単純に、2で割ったものと8で割ったものを引いても足しても意味がありません。 2進数では1/10が循環小数になってしまうのです。 いくつか近似値を求める方法は試したのですが、うまく誤差の修正がいきません。 200弱くらいまでしか正しい結果を得られませんでした。 これをマルチバイトに適応するとなるともっと効率のいい方法が必要になると感じています。 情報が少なくて申し訳ありませんでした。 ありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。
  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.1

素直に除算を使用して10で割るのが、自然だとおもうのですが、 どうして、除算を使用してはいけないのでしょうか。(コンパイラが除算をサポートしていないのでしょうか) その辺の事情を書かれると、良い回答が得られるかもしれません。

kenji_aki
質問者

補足

そうですね、いろいろ用途があります。 例えば、32ビットを超える多倍長のバイナリを10進数表記にしたり それを使って、2進化10進数への変換を行ったり 方法によっては多倍長演算にも使えそうですかね。 多倍長演算に関しては、数値を文字列に変換して行うのが基本だと思うのですが バイナリで行いたいと常々感じていました。 言語によっては初めからサポートされてるものもあるようですが 実際に使った事は無いので結果がバイナリで出力されるのかどうかわかりません。 もちろんC言語ではサポートされていないので実装したいとも思っています。 多倍長のバイナリ16進数から10進数に変換する方法だけでもいいです。 たぶん、そのほうが手っ取り早いです。 うまく説明できているかどうかわかりませんが、問題解決に協力していただきたいです。 友人に説明したところ、何言ってるかわからないと言われました。すみません。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • 加算と減算で乗算と除算を表現したい

    C言語の勉強をしている者です。 現在、Cを使って簡易電卓を作ろうと取り組んでいる最中なのですが、 テキストの中で乗算と除算を「*」、「/」を使わずに表現しろとの記載がありました。 乗算はループで加算を繰り返すことで理解できているのですが、除算の方法について浮かびません。 どうぞ知恵をお貸しください。

  • 情報処理の質問です

    加算演算のみで、減算・乗算・除算する方法を詳しく説明するとしたら、どのように答えますか? よろしくお願いします。

  • [2進数 シフト演算 除算について]

    [2進数 シフト演算 除算について] シフト演算について勉強中です。ご協力お願い出来たら幸いです。 乗算について例えば『1010』(符号ビットを考えず)を2倍 4倍 8倍(2のn乗)した場合 ビットを2倍であれば1つ、4倍であれば2つ・・・左に シフトすれば良いというのは理解しました。 また3倍 5倍などのケースも、 3倍であれば1ケタ左にシフトした数+1010で求まる事も理解しました。 問題は除算です。他の質問を探ってみたのですが、考え方は一緒という回答で・・・詰まっています 除算は右シフトとの事ですが 先ほどの例である『1010』(10)ですがこれを1/2、つまり2で割ると 1つ右にシフトし1010→0101 となり 1010を1/4する場合右に2ビットシフトし 1010→0010.10 となり理解は出来ます。 しかし1/3 、1/5といった場合の計算の仕方が分かりません。 余りを出さないという考えで(近似値になると思いますが) 解き方をご教授願えたらと思います。

  • コンピュータにおける負数について

     次の問題を教えてください! 「コンピュータで負数を表すのに補数を用いている理由として正しいのはどれか??」 (1)加算を減算で処理することができる。 (2)減算を加算で処理することができる。 (3)乗算を加算とけたシフトで処理することができる。 (4)除算を減算とけたシフトで処理することができる。  どなたかお詳しい方,簡単で結構ですので理由も添えて お教えください。  ちなみに負数は「マイナス」ですよね?では,補数って何ですか??これも教えて下さい。  宜しくお願い致します。

  • 剰余演算を論理演算と加減算に置き換える方法

    剰余(割算の余り)を求める演算を論理演算と加減算とビットシフトのみで行う方法がありましたら教えてください。 言語はC/C++ではなくても大丈夫です(ロジックだけでも)。

  • 16ビットCPUで32ビットの計算方法

    16ビットのCPUを持つシーケンサ(PLC )で32ビットの四則演算(加算、減算、乗算、除算)をさせたいのですが、命令語にダブルワードを処理できるものがないので、演算がオーバーフローした情報から何かしら自分でプログラムを組まなければなりません。 16ビットのレジスタを使った32ビット演算の考え方を教えてください。

  • 基本情報技術者過去問

    1)負数を2の補数で表す8ビットの数値がある。この値を10進数で表現すると-100である。この値を符号なしの数値として解釈すると、10進数で幾らか? ア)28 イ)100 ウ)156 エ)228 2) 多くのコンピュータが、演算回路を簡単にするために補数を用いている理由はどれですか。 ア)加算を減算で処理できる イ)減算を加算で処理できる ウ)乗算を加算の組み合わせで処理できる エ)除算を減算の組み合わせで処理できる

  • 10進のマイナスの計算について

    10進のマイナスを2進にする方法 10進のマイナスで少数のものを2進にする方法 を教えてください 方法にも減算、加算、除算、乗算とありますが 一番分かりやすいものをお願いします いろいろと調べているのですが どうしてもわかりません 例をだしていただけるとありがたいです 

  • Javascriptで算術演算子を作っているのですがわかりません・・・

    あの、JavaScriptの課題で、算術演算子つくり、加算、減算、乗算、除算、整数の除算の商と余りが求めれるように、a bにそれぞれ数値を代入して計算開始というのを作りました。それで、数値以外のたとえば、アルファベットなどを代入した場合、それは数値ではありません、数値を代入してくださいというような数値の入力を促すようになるようにしたいのですが、エラーばかりでます。どのようにソースを打ったら良いのかさっぱりわかりません。教えてください!!よろしくおねがいします。

  • 配列128桁の加算、減算について。

    現在C言語で四則演算について勉強しています。 128桁の配列をもつ整数についてa,b,各桁を加算、減算するプログラムを書きたいのですが分からなくて困ってます。できればCのソースを教えて欲しいですおねがいします。  s = 65536 a[128],b[128],c[128]   i = -1 とする。  i <128 である限り、演算を実行。 i >127なら終わり。(++1) c(i) = a(i) - b(i)という演算を行う。 c(i) < 0 の場合 s を借りてくる。 c(i)に s を加算し、上の桁から1を引く。