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

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

ただいまの
回答率

88.58%

算術演算子を使わずに乗算する方法

解決済

回答 9

投稿

  • 評価
  • クリップ 1
  • VIEW 2,745

kazu-.

score 34

 演算子を使わない方法が思いつかない

どういう考えで算術演算子を使わずに乗算すればいいかわかりません。
考えたのですが、全然思いつきませんアドバイスでいいので助けてください。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • mather

    2018/11/03 22:48

    なぜ「算術演算子を使わずに乗算」する必要があるのですか?学校の課題などでしょうか?

    キャンセル

  • dice142

    2018/11/04 02:56

    過去の質問から察するに学校の課題ですよね?何かしら参考資料が提示されてるのではないですか?

    キャンセル

回答 9

+2

論理演算とシフトである程度出来ます。・・・全部は思いつかない;;

論理演算と算術演算

a=(1|(1<<2))→5とか・・・

5×3だと・・(5<<1)+5なんだが・・・“+”をどうするか??
・・・例が悪かった^^; 1010|101→1111→15・・出来ちゃたw
ビットが重ならなければor('|')でなんとかなるが・・・8×3は・・(8<<1)|8で出来る

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/03 20:15

    リンク先に書いてありますね。
    bitだったら、 and すれば、繰り上がりが分かるって。
    Xor かと思ったが、大差無い? 複数bitはもう一ひねり必要か。

    キャンセル

+2

論理演算子は既に出ているので別の方法で。

本来何を解決したいかわからないので検討違いならすみません。

BigDecimal two = new BigDecimal("2.00");
BigDecimal three = new BigDecimal("3.00");

BigDecimal multiply = two.multiply(three);
System.out.println("結果: " + multiply);

 以下追記

C言語でしたね、見落としていましたすみません。
GMPという多倍長計算を非常に高速に行うライブラリがあるのでそれを使いました。

#include <stdio.h>
#include "gmp.h"

int main(int argc, char **argv)
{
    mpz_t a, b, x;
    mpz_init(x);
    mpz_init_set_str(a, "2", 10);
    mpz_init_set_str(b, "3", 10);

    mpz_mul(x, a, b);

    mpz_out_str(stdout, 10, x);

    mpz_clear(a);
    mpz_clear(b);
    mpz_clear(x);
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/05 00:11

    この質問はCについてなので、オブジェクト指向のJavaは違う気がしますがどうなんでしょう。

    キャンセル

  • 2018/11/05 01:16

    はい、ご指摘の通りでした・・・Cでの回答を追記しておきました。

    キャンセル

+2

インクリメントとデクリメントだけで四則演算を全て実装してみました。算術演算子禁止として、Arithmetic operators - cppreference.comにある全ての演算子を使用しないようにしました。また、whileforおよびgotoを用いたループも禁止しました。

/**
 * Implementation of arithmetic operators without using arithmetic operators.
 * https://en.cppreference.com/w/c/language/operator_arithmetic
 */

#define NDEBUG
#include <assert.h>
#include <stdio.h>

int plu(int a);    // +a
int min(int a);    // -a
int add(int a, int b); // a + b
int sub(int a, int b); // a - b
int pro(int a, int b); // a * b
int div(int a, int b); // a / b
int mod(int a, int b); // a % b

int plu(int a) { return a; }

static inline int min_inc_r(int a, int b)
{
    if (a == 0) return b;
    assert(a < 0);
    return min_inc_r(++a, ++b);
}

static inline int min_dec_r(int a, int b)
{
    if (a == 0) return b;
    assert(a > 0);
    return min_dec_r(--a, --b);
}

int min(int a)
{
    if (a == 0) return 0;
    if (a < 0) return min_inc_r(a, 0);
    return min_dec_r(a, 0);
}

static inline int add_r(int a, int b)
{
    if (b == 0) return a;
    assert(b > 0);
    return add_r(++a, --b);
}

int add(int a, int b)
{
    if (b < 0) return min(add(min(a), min(b)));
    return add_r(a, b);
}

int sub(int a, int b) { return add(a, min(b)); }

static inline int pro_r(int a, int b, int r)
{
    if (b == 0) return r;
    assert(b > 0);
    return pro_r(a, --b, add(r, a));
}

int pro(int a, int b)
{
    if (b == 0) return 0;
    if (b < 0) return pro(min(a), min(b));
    return pro_r(a, b, 0);
}

static inline int div_r(int a, int b, int r)
{
    assert(b > 0);
    if (a == 0) return r;
    if (a < 0) return --r;
    return div_r(sub(a, b), b, ++r);
}

int div(int a, int b)
{
    if (b == 0) return 0; // or error
    if (b < 0) return min(div(a, min(b)));
    if (a < 0) return min(div(min(a), b));
    return div_r(a, b, 0);
}

int mod(int a, int b) { return sub(a, pro(div(a, b), b)); }

int main(void)
{
    printf("+42 = %d\n", plu(42));
    printf("-42 = %d\n", min(42));
    printf("7 + 6 = %d\n", add(7, 6));
    printf("7 - 6 = %d\n", sub(7, 6));
    printf("7 * 6 = %d\n", pro(7, 6));
    printf("7 / 6 = %d\n", div(7, 6));
    printf("7 %% 6 = %d\n", mod(7, 6));
}

div()は、0除算でエラーにならない事を除き、標準の/と動作を合わせたつもりです、たぶん。速度は全く考慮に入れていません。インクリメントのオーバーフローやデクリメントのアンダーフローは考慮していませんが、末尾再帰になっていますので、適当に最適化オプションを付けていればスタックオーバーフローは起きないはずです。assert()を有効にしたい場合は#define NDEBUGをコメントアウトしてください。ビット演算子やシフト演算子の実装については力尽きましたので、誰かがやってくれることでしょう。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+2

算術演算を論理演算で代用したいという目的であるという前提で検討しました。

考え方を以下に示します。
まず掛け算の前に2つの整数の和を、論理演算子で記述する方法を考えます。
①2つの整数の排他的論理和を取ります。これは繰り上がりがない場合の足し算の結果に等しいです。
②2つの整数の論理積を取ります。bitが1となっている桁は繰り上がりが発生する桁を意味します。
③上記の②の結果を1bitシフトしたものと①の結果について、再び排他的論理和と論理積を取ります。
④上記の③を排他的論理和または論理積が0になるまで繰り返します。これは繰り上がりがなくなることを意味します。
⑤最終的に算出された排他的論理和と論理積の論理和(一方は0なので排他的論理和でもよい)が2数の和になります。
掛け算の場合は、2数が同じ数値という前提で、繰り返す回数を指定すればよいです。

2数の和の計算を論理演算子のみで実現するコードは以下です。

int bitSum(int numA, int numB){
    int result;
    int bitAND;
    int bitANDOld;
    int bitEXOR;
    int bitEXOROld;

    bitANDOld = numA;
    bitEXOROld = numB;
    while(bitEXOROld !=0 && bitANDOld !=0){
        bitAND = (bitANDOld & bitEXOROld) << 1;
        bitEXOR = bitANDOld ^ bitEXOROld;
        bitANDOld = bitAND;
        bitEXOROld = bitEXOR;
    }
    result = bitANDOld | bitEXOROld;

    return result;        
}

掛け算の場合は以下のコードで実現できます。
*for文中の++はご容赦ください。

int bitProduct(int num, int multiple){
    int result = num;
    int bitAND;
    int bitANDOld;
    int bitEXOR;
    int bitEXOROld;

    for(int i = 0; i<multiple -1;i++){
    bitANDOld = num;
    bitEXOROld = result;
    while(bitEXOROld !=0 && bitANDOld !=0){
        bitAND = (bitANDOld & bitEXOROld) << 1;
        bitEXOR = bitANDOld ^ bitEXOROld;
        bitANDOld = bitAND;
        bitEXOROld = bitEXOR;
    }
    result = bitANDOld | bitEXOROld;
    }
    return result;        
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

シフト演算すれば
i*2 = i<<1
という感じで乗算できますよ。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

とりあえずコードだけ。

#include <stdio.h>

int add(int n, int m)
{
    if (n & m){
        return add(n ^ m, (n & m) << 1);
    }

    return n | m;
}

int mul(int n, int m)
{
    int result = 0;

    for ( ; n && m; n >>= 1, m <<= 1){
        if (n & 1){
            result = add(result, m);
        }
    }

    return result;
}

int main()
{
    int n = -100;
    int m = -10;

    printf("%d * %d = %d\n", n, m, mul(n, m));

    return 0;
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/04 11:30

    そうそう!
    私がやりたかったのは正にこれです。
    やはり再帰は素晴らしいですね。

    キャンセル

checkベストアンサー

0

shsh_さんが再帰を使った方法を載せてますが、再帰を使わない場合は次のようになります。(addの部分だけ)

int add(int a, int b)
{
    while (b != 0)
    {
        int c = (a & b) << 1;
        a ^= b;
        b = c;
    }
    return a;
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

具体的なコードはしめしませんが、つぎのような方針は如何でしょう?

  1. 九九の表(一桁の数同士の乗算)と 一桁同士の足し算の表を用意する。
  2. 筆算と同様の方法で 上の2つの表を引きながら計算をしていく。

筆算は普通は 10 進でおこないますが、2進数で筆算処理をするなら、小さな表を用意するだけで済ますことができます。
(2進数 <-> 10進の表記変換にいろいろ演算が必要になりますが,それもこの方法で対処できるでしょう)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

「乗算器」とかで検索したらどうか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 88.58%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る