*および+演算子を使用せずに乗算用のCプログラムを作成する方法は?


68

乗算演算子と加算演算子を使用せずに2つの数値を乗算するCプログラムを作成することは可能ですか?

Stack Overflowでこれを見つけました。この貧しいプログラマーの問題を助けてください。そしてc = a/(1/((float)b))、のような答えを与えないでくださいc = a*b。(そして、答えとして既に与えられています。)

2014年1月19日に最も賛成票を投じた回答が勝利します。

注:これは質問です。質問や回答を真剣に受け取らないでください。詳細については、コードトローリングを参照してください


2
@PaulRはあなたのファンタジーを使用します
ジョンドヴォルザーク14年

26
Code-golf.SEは、StackOverflowで見た質問を模擬する場所ではありません。
ガレス14年

17
@ガレス、よろしいですか?この最初の行は、これが非常に適切であることを示唆しています。
ダレンストーン14年

5
睡眠に基づくアルゴリズムを記述し、誰かを待っている-私
kb_sou

21
この質問は、見かけほどばかげていません。実際のコンピューターハードウェア(トランジスター)には、乗算および加算演算がありません。NOT、AND、OR、XORなどの基本的な論理演算があります。この質問に答える方法を理解することにより、論理ゲートのレベルでコンピューターが実際にどのように機能するかについて優れた洞察を得ることができます。
ゲイブ14年

回答:


147

常に再帰を使用する

Recusionは正しい方法です!

int inc(int x) {
    return x&1?inc(x>>1)<<1:x|1;
}

int dec(int x) {
    return x&1?x^1:dec(x>>1)<<1|1;
}

int add(int x, int y) {
    return x?add(dec(x),inc(y)):y;
}

int mul(int x, int y) {
    return x?x^1?add(y,mul(dec(x),y)):y:0;
}

int main() {
    int a, b;
    scanf("%i\n%i", &a, &b);
    printf("%i", mul(a,b));
}

8
私ができる場合、私は3を与えるだろう:究極の再帰のための1つの、のための1つの??::括弧なしで、ルールを微調整しようとせずに問題を解決するための一つ;)
よ」

10
ピカソは、プログラマ...だった場合
R・ヒューズ

4
@SargeBorschしかし、そのどこが面白かったのでしょうか?
オベロン14年

3
@HC_このinc関数は引数をテストして、最下位ビットが1; かどうかを確認します。もしそうなら、それは引数の残りの上位ビットに自分自身を呼び出し、に設定されてチェックされた同じ低ビットとの結果を返す0、(すなわち、最下位ビットがない場合ながら0)、それが置き換わる01、その結果を返します。このプロセスは、値を手動で、2進数を2進数で追加する場合の処理​​と非常に似ています。
JAB

2
増分関数は-1の無限ループに入りませんか?(0xFFFF)イデオンは(-1 >> 1)== -1を示します
区切り記号14年

87

毎回プログラムをコンパイルする必要がありますが、CまたはC ++のどのバージョンでも正確に正の整数の乗算を行います。

 #define A 45  // first number
 #define B 315 // second number

 typedef char buffer[A][B];

 main() {
    printf("%d\n",sizeof(buffer));
 }

4
構造内に配置すれば、メモリは必要ありません。
ベンジャクソン14年

4
はははーすごい!!
アルモ14年

1
"%zu"フォーマット文字列を使用します。
グリジェシュチャウハン

5
ちょうどsizeof(char[A][B])(あなたがエラーの「悪いタイプ」の並べ替えを取得する必要があり、その場合には<= 0またはB <= 0または* Bのオーバーフロー、しない限り)動作します
greggo

3
@DavidRicherby -私は、コードを簡略化することができmain(){return sizeof(char[A][B]);}、あなたが使用してコンパイルcc -DA=6 -DB=7 a.c; ./a.out; echo $?
マークLakata

47

少し不正確でも問題ない場合は、モンテカルロ法を使用できます。

#include <stdlib.h>
#include <stdio.h>

unsigned int mul(unsigned short a, unsigned short b) {
  const int totalBits = 24;
  const int total = (1 << totalBits);
  const int maxNumBits = 10;
  const int mask = (1 << maxNumBits) - 1;
  int count = 0, i;
  unsigned short x, y;
  for(i = 0; i < total; i++) {
    x = random() & mask;
    y = random() & mask;
    if ((x < a) && (y < b))
      count++;
  }
  return ((long)count) >> (totalBits - (maxNumBits << 1));
}

void main(int argc, char *argv[]) {
  unsigned short a = atoi(argv[1]);
  unsigned short b = atoi(argv[2]);
  printf("%hd * %hd = %d\n", a, b, mul(a, b));
}

例:

$ ./mul 300 250
300 * 250 = 74954

これで十分だと思う;)


3
あなたは私の賛成票を持っています。モンテカルロは、NASAが算術演算に使用するものだと聞きました。しかし、私は++演算子の2つのインスタンスなしでこれを見たいです。
ダレンストーン14年

1
@DarrenStone-= -1
ティム

20
@Timtech |= 1(数字の50%、時間の100%で動作します)
ダレンストーン14年

2
1、しかし、それは遅すぎるかもしれない、とあなたは慎重に「数++」:-)ロック、マルチスレッドのサポートを追加することができることに注目
greggo

1
常にprintfインクリメントがあります:(printf("%*cc%n\n", count, &count, 'c');「c」カウント回数、次に「c」を印刷し、書き戻された文字数を保存しcountます。
MSalters14年

45

数値のサイズを指定しなかったため、2つの1ビット数値を意味すると想定します。

#include <stdbool.h>
bool mul(bool a, bool b) {
    if (a && b) {
        return true;
    } else {
        return false;
    }
}

最大限に効率的な実装が必要な場合は、次の小さな実装を使用してください。

m(a,b){return a&b;}

型が暗黙的なintであるにもかかわらず、ビットのみを受け入れることに注意してください。コードの量が少ないため、より効率的です。(そして、はい、コンパイルします。)


8
いいね 質問の意図的な誤解:
ジョンドヴォルザーク

6
これをに最適化できreturn a && b;ます。短いので高速です。
Ry- 14年

1
@minitech:コードを少し悪くするために、私はそれに反対しました。それをさらに進めたい場合は、それを作成しreturn a&b;ます。
セルスケッグス14年

1
Cはと#include<stdbool.h>を定義する必要がtrueありfalseます。
leewz

1
うん、#include<stdbool.h>ちょうど3つのようです#define(あなたが自分で行うことができ、S truefalsebool、およびフラグは、それが起動されていますことをマークします)。また、他の回答の1つからトリックを取りint、「ショート」バージョンに暗黙的に使用することもできます。
leewz

31

これを行う簡単なシェルスクリプトを次に示します。

curl "http://www.bing.com/search?q=$1%2A$2&go=&qs=n&form=QBLH&pq=$1%2A$2" -s \
| sed -e "s/[<>]/\n/g" \
| grep "^[0-9 *]*=[0-9 ]*$"

更新:もちろん、Cでそれを行うには、単にそれをラップしexec("bash", "-c", ...)ます。(ありがとう、AmeliaBR)


41
私はどちらがよりひどいのか判断できません。計算を検索エンジンにアウトソーシングしていること、または選択した検索エンジンがBingであること。残念ながら、私はこれはCで何かを必要と私たちのhappless OP、のために働くだろうとは思わない
AmeliaBR

5
その見落としに気付いてくれてありがとう。参考までに、Bingを使用しているのは、Googleがこのようなリクエストを発行することをより複雑にしているためです。
Vroo 14年

2
@abarnertうーん... Bingは「時間」を理解していますか?しかし、Wolfram Alphaはそうかもしれません。
ジョンドヴォルザーク

2
@JanDvorak:ええ、Wolframは動作します。(記号%20を使用しないように注意してください+。)ただし、値を取得するには、出力を(Cで)解析する必要があります。出力はテキストではなく画像であるため、特に注意が必要です。HTML解析とOCRにより、この問題に対する最善の答えが得られる可能性があります。
アバーナート14年

3
@JanDvorak:それは面白くない。私は...加算や乗算なしでシンプルなOCRライブラリを書いて誰かを楽しみにしていた
abarnert

27

なぜ、INT64_MINとINT64_MAXの間で再帰的な半分の検索を行いましょう!

#include <stdio.h>
#include <stdint.h>

int64_t mul_finder(int32_t a, int32_t b, int64_t low, int64_t high)
{
    int64_t result = (low - (0 - high)) / 2;
    if (result / a == b && result % a == 0)
        return result;
    else
        return result / a < b ?
            mul_finder(a, b, result, high) :
            mul_finder(a, b, low, result);
}

int64_t mul(int32_t a, int32_t b)
{
    return a == 0 ? 0 : mul_finder(a, b, INT64_MIN, INT64_MAX);
}

void main(int argc, char* argv[])
{
    int32_t a, b;
    sscanf(argv[1], "%d", &a);
    sscanf(argv[2], "%d", &b);
    printf("%d * %d = %ld\n", a, b, mul(a, b));
}

PSそれは幸いにもいくつかの値でsigsegvになります。;)


18

残念ながら、これは整数に対してのみ機能します。

加算は許可されていないため、最初にインクリメント演算子を作成しましょう。

int plusOne(int arg){
  int onMask = 1;
  int offMask = -1;
  while (arg & onMask){
    onMask <<= 1;
    offMask <<= 1;
  }
  return(arg & offMask | onMask);
}

次に、サインを処理する必要があります。まず、符号ビットを見つけます:

int signBit = -1;
while(signBit << 1) signBit <<=1;

次に、各引数の符号と大きさを取得します。2の補数の数を否定するには、すべてのビットを反転させて1を追加します。

int signA = a & signBit;
if(signA) a = plusOne(-1 ^ a);
int signB = b & signBit;
if(signB) b = plusOne(-1 ^ b);
int signRes = signA ^ signB;

2つの正の整数を乗算するには、乗算の幾何学的な意味を使用できます。

// 3x4
//
// ooo
// ooo
// ooo
// ooo

int res = 0;
for(int i = 0; i < a; i = plusOne(i))
  for(int j = 1; j < b; j = plusOne(j))
    res = plusOne(res);

if(signRes) res = plusOne(-1 ^ res);

トロル:

  • 加算は許可されていませa++んが、実際には加算としてカウントされますか?先生はそれを許可するつもりだったに違いない。
  • 2の補数に依存しますが、これは実装定義の動作であり、ターゲットプラットフォームは指定されていません。
  • 同様に、減算と除算も同様に許可されていないと仮定します。
  • << 実際には2の累乗で乗算されるため、技術的には許可されません。
  • 不要な図は不要です。また、1行を節約するために転置することもできます。
  • 繰り返しシフトする-1ことは、符号ビットを見つける最良の方法ではありません。組み込み定数がない場合でも、-1の論理右シフトを実行してから、すべてのビットを反転できます。
  • XOR -1は、すべてのビットを反転させる最良の方法ではありません。
  • 符号の大きさの表現を持つ全体のシャレードは不必要です。符号なしのモジュラー算術演算にキャストするだけで残りは処理されます。
  • MIN_INT(AKA signBit)の絶対値は負であるため、これはその値に対して壊れます。幸いなことに、ゼロでMIN_INT * [even number] なければならないので、それはまだ半分のケースで機能します。また、plusOneforがブレークする-1と、結果がオーバーフローするたびに無限ループが発生します。 plusOneどんな値でもうまく機能します。混乱させて申し訳ありません。

実際のコードトロールの+1:動作するはずですが、OPで爆発する可能性が高く、その理由はわかりません。
ケビン14年

1
シフト、XOR、およびANDを使用するだけで、任意の加算演算子なしで加算を行うことができます。これらすべての++は頭を痛めています-キャリー付きのシングルビットADDは(x ^ y)| ((x&y)<< 1)(このくだらない小さなテキストボックスに入力することによって引き起こされるエラーを修正します。)
ジュリーインオースティン

@JulieinAustinうん。このアルゴリズムは、必要以上に非効率です。トロールリストを修正する必要がありますか?:-)
ジョンドヴォルザーク

1
@JulieinAustin (x ^ y) | ((x & y) << 1)はまったく機能せず、同じ位置でxまたはyとキャリーの両方がtrueの場合、キャリーを伝搬しません:)
hobbs

@hobbsソリューション:キャリーがゼロ以外の場合、ORingの代わりに再帰的に追加します。
ジョンドヴォルザーク14年

14

浮動小数点数でも機能します:

float mul(float a, float b){
  return std::exp(std::log(a) - std::log(1.0 / b));
}

11

PythonはCよりも使いやすいことを誰もが知っています。Pythonには、演算子を使用できない場合のために、すべての演算子に対応する関数があります。まさに私たちの問題定義ですよね?そう:

#include <Python.h>

void multiply(int a, int b) {
    PyObject *operator_name, *operator, *mul, *pa, *pb, *args, *result;
    int result;

    operator_name = PyString_FromString("operator");
    operator = PyImport_Import(operator_name);
    Py_DECREF(operator_name);
    mul = PyObject_GetAttrString(operator, "__mul__");
    pa = PyLong_FromLong((long)a);
    pb = PyLong_FromLong((long)b);
    args = PyTuple_New(2);
    PyTuple_SetItem(args, 0, pa);
    PyTuple_SetItem(args, 1, pb);
    presult = PyObject_CallObject(mul, args);
    Py_DECREF(args);
    Py_DECREF(mul);
    Py_DECREF(operator);
    result = (int)PyLong_AsLong(presult);
    Py_DECREF(presult);
    return result;
}

int main(int argc, char *argv[]) {
    int c;
    Py_Initialize();
    c = multiply(2, 3);
    printf("2 * 3 = %d\n", c);
    Py_Finalize();
}

10

他の答えはどれも理論的に正しいものではありません。質問に対する最初のコメントは次のとおりです。

「数字」についてより具体的にしてください

答えが可能になる前に、乗算と数値を定義する必要があります。実行すると、問題は簡単になります。

数学論理を開始する際にこれを行う最も一般的な方法は、ZF集合理論の上にフォンノイマン序数構築しペアノ公理を使用することです。

これは、他のセットを含むことができるセットタイプがあると仮定すると、自然にCに変換されます。それは何も含まれている必要はありませんが、(そのキャストのどれも些細行うものではありませんセット、void*ほとんどのセットライブラリにナンセンスを)ので、私は読者の練習として実装を残しておきます。

だから、最初に:

/* The empty set is 0. */
set_t zero() {
    return set_new();
}

/* The successor of n is n U {n}. */
set_t successor(set_t n) {
    set_t result = set_copy(n);
    set_t set_of_n = set_new();
    set_add(set_of_n, n);
    set_union(result, set_of_n);
    set_free(set_of_n);
    return result;
}

/* It is an error to call this on 0, which will be reported by
   running out of memory. */
set_t predecessor(set_t n) {
    set_t pred = zero();
    while (1) {
        set_t next = successor(pred);
        if (set_equal(next, n)) {
            set_free(next);
            return pred;
        }
        set_free(pred);
    }
}        

set_t add(set_t a, set_t b) {
    if (set_empty(b)) {
        /* a + 0 = a */
        return a;
    } else {
        /* a + successor(b) = successor(a+b) */
        set_t pred_b = predecessor(b)
        set_t pred_ab = add(a, pred_b);
        set_t result = successor(pred_ab);
        set_free(pred_b);
        set_free(pred_ab);
        return result;
    }
}

set_t multiply(set_t a, set_t b) {
    if (set_empty(b)) {
        /* a * 0 = 0 */
        return b;
    } else {
        /* a * successor(b) = a + (a * b) */
        set_t pred_b = predecessor(b)
        set_t pred_ab = mul(a, pred_b);
        set_t result = successor(pred_ab);
        set_free(pred_b);
        set_free(pred_ab);
        return result;
    }
}

これを整数、有理数、実数、シュールなどに拡張する場合は、無限の精度で(無限のメモリとCPUがあると仮定して)ブートすることができます。しかし、クローネッカーが有名に言ったように、神は自然数を作った。他のすべては人間の仕事なので、本当に、なぜわざわざ?


1
ワオ。あなたは私よりも遅いです。
ジョンドヴォルザーク

10
unsigned add( unsigned a, unsigned b )
{
    return (unsigned)&((char*)a)[b];  // ignore compiler warnings
       // (if pointers are bigger than unsigned). it still works.
}
unsigned umul( unsigned a, unsigned b )
{
    unsigned res = 0;
    while( a != 0 ){
        if( a & 1) res = add( res, b );
        b <<= 1;
        a >>= 1;
    }
    return res;
}

int mul( int a, int b ){
    return (int)umul( (unsigned)a, (unsigned)b );
}

a [b]ハックが不正行為であると考える場合(実際には追加であるため)、これは代わりに機能します。ただし、テーブル検索にはポインターの追加も含まれます。

http://en.wikipedia.org/wiki/IBM_1620-ルックアップテーブルを使用して実際に追加を行ったコンピューターを参照してください ...

テーブルメカニズムを使用して実際に1つの命令で実行できる操作を「高速化」することで満足できるもの。

static unsigned sumtab[17][16]= {
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15},
{ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16},
{ 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17},
{ 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18},
{ 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19},
{ 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20},
{ 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21},
{ 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22},
{ 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23},
{ 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24},
{10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25},
{11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26},
{12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27},
{13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28},
{14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29},
{15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30},
{16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31}
};

unsigned add( unsigned a, unsigned b )
{
   static const int add4hack[8] =  {4,8,12,16,20,24,28,32};
   unsigned carry = 0;
   unsigned (*sumtab0)[16] = &sumtab[0];
   unsigned (*sumtab1)[16] = &sumtab[1];
   unsigned result = 0;
   int nshift = 0;
   while( (a|b) != 0 ){
      unsigned psum = (carry?sumtab1:sumtab0)[ a & 0xF ][ b & 0xF ];
      result = result | ((psum & 0xF)<<nshift);
      carry = psum >> 4;
      a = a >> 4
      b = b >> 4;
      nshift= add4hack[nshift>>2];  // add 4 to nshift.
   }
   return result;
}

おっと、*char があります(乗算ではありませんが)
Sarge Borsch

ええと、テーブルルックアップは加算を使用します-(a [i])は(*(a + i))と同じです。
オースティンのジュリー14年

@JulieinAustin私はそれについて言及しました。テーブルの検索は、フィールドをマージすることで追加なしで実行できます(IBM 1620で説明されているように、リンクを参照)が、Cで設定するのは面倒です-インデックスができるように、テーブルを適切なアドレスに揃える必要がある。ただで論理和
greggo

8

これらの「コードトロール」投稿の「不正」を構成するものはわかりませんが、これは、実行時に2つの任意の整数を乗算します。標準ライブラリ(C99)を使用する*or +演算子はありません。

#include <math.h>
main()
{
  int a = 6;
  int b = 7;
  return fma(a,b,0);
}

8

私のトロールソリューションunsigned int

#include<stdio.h>

unsigned int add(unsigned int x, unsigned int y)
{
  /* An addition of one bit corresponds to the both following logical operations
     for bit result and carry:
        r     = x xor y xor c_in
        c_out = (x and y) or (x and c_in) or (y and c_in)
     However, since we dealing not with bits but words, we have to loop till
     the carry word is stable
  */
  unsigned int t,c=0;
  do {
    t = c;
    c = (x & y) | (x & c) | (y & c);
    c <<= 1;
  } while (c!=t);
  return x^y^c;
}

unsigned int mult(unsigned int x,unsigned int y)
{
  /* Paper and pencil method for binary positional notation:
     multiply a factor by one (=copy) or zero
     depending on others factor actual digit at position, and  shift 
     through each position; adding up */
  unsigned int r=0;
  while (y != 0) {
    if (y & 1) r = add(r,x);
    y>>=1;
    x<<=1;
  }
  return r;
}

int main(int c, char** param)
{
  unsigned int x,y;
  if (c!=3) {
     printf("Fuck!\n");
     return 1;
  }
  sscanf(param[1],"%ud",&x);
  sscanf(param[2],"%ud",&y);
  printf("%d\n", mult(x,y));
  return 0;
}

1
+1キャリー評価の素晴らしい実装。私はあなたのコードが好きです:)
yo

@BЈовић:私のせい、私はトローリングは理解についてではないと思った。名前を変更し、コメントを追加しました。
マティアス

ごめんなさい。私はそのタグが何であり、Qが本当に何であるかを誤解しました。あなたはそれを元に戻す必要があります
BЈовић

この場合の@Matthiasは、それがどのように機能するかを理解しておくと、収束キャリー操作がいかにねじれているかを理解するのに役立ちます。実際のコードトロールの状況では、コメントを編集できます:
greggo

私は、ビット反転した数字を追​​加したい(キャリープロップが高いから)、「bitrev」命令がない場合、これはおそらく完全に合理的なアプローチであることを指摘したいと思います(c>に変更した後)もちろん> = 1)
greggo

7

ここには多くの良い答えがありますが、それらの多くが現代のコンピューターが本当に強力であるという事実を利用しているようには見えません。ほとんどのCPUには複数の処理ユニットがありますが、なぜ1つだけを使用するのですか?これを活用して、優れたパフォーマンス結果を得ることができます。

#include <stdio.h>
#include <limits.h>
#include "omp.h"

int mult(int a, int b);

void main(){
        int first;
        int second;
        scanf("%i %i", &first, &second);
        printf("%i x %i = %i\n", first, second, mult(first,second));
}

int mult(int second, int first){
        int answer = INT_MAX;
        omp_set_num_threads(second);
        #pragma omp parallel
        for(second = first; second > 0; second--) answer--;
        return INT_MAX - answer;
}

その使用例を次に示します。

$ ./multiply
5 6
5 x 6 = 30

この#pragma omp parallelディレクティブは、OpenMPがforループの各部分を異なる実行ユニットに分割するようにするため、並列に乗算します!

-fopenmpOpenMPを使用するようコンパイラーに指示するには、フラグを使用する必要があることに注意してください。


トロール部品:

  1. 並列プログラミングの使用について誤解を招く。
  2. 負の(または大きな)数値では機能しません。
  3. 実際にはforループの部分を分割しません-各スレッドがループを実行します。
  4. 迷惑な変数名と変数の再利用。
  5. に微妙な競合状態がありanswer--ます。ほとんどの場合、表示されませんが、不正確な結果が生じることがあります。

2
これをPaul RのSIMDの回答と組み合わせて、8倍ではなく32倍の速度で実行できるのはなぜですか。本当に、GPUとコアを関係させたいと思っています。それは本当に燃えるでしょう。:)
アバーナート14年

2
OpenMPIを使用して、いくつかのマシンで並行して実行することもできます。
ミリノン14年

6

残念ながら、乗算はコンピューターサイエンスでは非常に難しい問題です。最良の解決策は、代わりに除算を使用することです:

#include <stdio.h>
#include <limits.h>
int multiply(int x, int y) {
    int a;
    for (a=INT_MAX; a>1; a--) {
        if (a/x == y) {
            return a;
        }
    }
    for (a=-1; a>INT_MIN; a--) {
        if (a/x == y) {
            return a;
        }
    }
    return 0;
}
main (int argc, char **argv) {
    int a, b;
    if (argc > 1) a = atoi(argv[1]);
    else a = 42;
    if (argc > 2) b = atoi(argv[2]);
    else b = 13;
    printf("%d * %d is %d\n", a, b, multiply(a,b));
}

6

実生活では、私は通常、トローリングに知識で対応しているので、ここでは答えがまったくありません。int私が見る限り、すべての値に対して機能します。

int multiply (int a, int b) {
  int r = 0;
  if (a < 0) { a = -a; b = -b }

  while (a) {
    if (a&1) {
      int x = b;
      do { int y = x&r; r ^= x; x = y<<1 } while (x);
    }
    a>>=1; b<<=1;
  }
  return r;
}

これは、私の知る限り、CPUが実際に整数乗算を行う方法に非常によく似ています。最初に、負のa場合aは両方の符号を反転することで、引数の少なくとも1つ()が正であることを確認します(否定、否定を一種の加算または乗算としてカウントすることを拒否します)。次に、while (a)ループは、のbすべての設定ビットの結果にのシフトされたコピーを追加しaます。doループが実装r += xキャリービットがバックに供給して、使用して、XOR、及び明らかに半加算器のセット何にシフトx実際のCPUがより効率的であり、全加算器を使用する(複数が、C」はdoesnの何がなくなるまで演算子を数えない限り、これに必要な演算子があります+)。


4
質問者はトロールしませんでした。あなたはトロールすることになっています。
ジョンドヴォルザーク14年

2
それはステルストロールです!秘密の障害はa == INT_MINにあります。
ジャンダー

1
@Janderうーん。ええ、それは良いものです。私は(通常の2の補数システムで)aを否定した結果が依然として負であり、while(a)ループが終了しないと推測しています。
ホッブズ

@hobbsええ、それは私には正しいように聞こえます。それ以外の場合は非常にきれいな答え。
ジャンダー

6
 int bogomul(int A, int B)
{
    int C = 0;
    while(C/A != B)
    {

        print("Answer isn't: %d", C);
        C = rand();

    }
    return C;
}

1
結果がオーバーフローすると、これは恐ろしく失敗します。いいね!ただし、印刷しないでください。
ジョンドヴォルザーク

2
a = 2、b = 2、c = 5で失敗
B –овић 14年

@BЈовић: while(C/A != B || C%A)
アバーナート14年

2
これは本当に深い思想の後継者と同じことを行うための試みですが、ことに注意してくださいためのすべての可能性の宇宙、代わりに答えが、それはバグがなければ非常に印象的になり42で一つだけの。そして、Vogonsの場合のエラー処理の欠如。
アバーナート14年

1
複数のスレッドが必要です。効率的にするために。
グレゴ

6

これをミックスに投入する:

#include <stdio.h>
#include <stdlib.h>

int mul(int a, int b)
{
        asm ("mul %2"
            : "=a" (a)
            : "%0" (a), "r" (b) : "cc"
        );
        return a;
}

int main(int argc, char *argv[])
{
        int a, b;

        a = (argc > 1) ? atoi(argv[1]) : 0;
        b = (argc > 2) ? atoi(argv[2]) : 0;

        return printf("%d x %d = %d\n", a, b, mul(a, b)) < 1;
}

情報ページから

–すべてを捨てずに削除できないコードに非常に許容できない、または不合理な何かを導入し、OPにとって答えがまったく役に立たないようにします。

– […]意図は、怠zyなOPが容認できると思う言語で宿題をすることですが、それでも彼を苛立たせます。


2
「乗算および加算演算子を使用せずに」。規則の良い曲げ-これは質問者にとって絶対に役に立たないでしょう:
ジョンドヴォルザーク

2
これは実際にはCのソリューションではありません。さらに、ARM9ではコンパイルできません。
アバーナート14年

1
@abarnert:ステートメントを関連する引数として認識できません。
ルニウム14年

@Sukminder:質問は「Cプログラムを書くことは可能ですか?」です。インラインアセンブリはCではありません。一部のCコンパイラもインラインアセンブリを実行できるという事実は、一部のCコンパイラがC ++またはObjCを実行できるという事実だけでなく、C ++またはObjCをCコードとしてカウントします。
アバーナート14年

2
@abarnert:Cプログラムで広く使用されている埋め込みコードです。異種交配ですが、Cプログラムであると主張できます。OPがそれをCコードとして認識することはもっともらしいです。明らかにPythonではありませんか?
ルニウム14年

5
#include <stdio.h>
#include <stdlib.h>

int mult (int n1, int n2);
int add (int n1, int n2 );
int main (int argc, char** argv)
{
        int a,b;
        a = atoi(argv[1]);
        b = atoi(argv[2]);

        printf ("\n%i times %i is %i\n",a,b,mult(a,b));
        return 0;
}

int add (int n1, int n2 )
{
        return n1 - -n2;
}

int mult (int n1, int n2)
{
        int sum = 0;
        char s1='p', s2='p';
        if ( n1 == 0 || n2 == 0 ) return 0;
        if( n1 < 0 )
        {
                s1 = 'n';
                n1 = -n1;
        }
        if( n2 < 0 )
        {
                s2 = 'n';
                n2 = -n2;
        }
        for (int i = 1; i <= n2; i = add( i, 1 ))
        {
                sum = add(sum,  n1);
        }
        if ( s1 != s2 ) sum = -sum;
        return sum;
}

5

乗算演算子と加算演算子を使用せずに2つの数値を乗算するCプログラムを作成することは可能ですか?

承知しました:

void multiply() {
    printf("6 times 7 is 42\n");
}

しかし、もちろんそれは不正行為です。明らかに彼は2つの数字を_供給できるようにしたいですよね?

void multiply(int a, int b) {
    int answer = 42;
    if (answer / b != a || answer % b) {
        printf("The answer is 42, so that's the wrong question.\n");
    } else {
        printf("The answer is 42, but that's probably not the right question anyway.\n");
    }
}

なぜ、それは私にはまったく明らかではなかったのです!
leewz

4

ポインター演算のような演算はありません。

int f(int a, int b) {
        char x[1][b];
        return x[a] - x[0];
}

int
main(int ac, char **av) {
        printf("%d\n", f(atoi(av[1]),atoi(av[2])));
        return 0;
}

この関数fは乗算を実装します。main単に2つの引数で呼び出します。
負の数でも機能します。


否定a、はい、否定b私はそうは思わない。しかし、それは多くの創造的な方法で修正可能です。最も単純なのはsign_a ^ = sign_b、sign_b = 0になります
MSalters

@MSalters、テストされ、すべての記号の組み合わせで動作します(Linux / gccを使用)
ウゴレン14年

3

C#

減算と否定は許可されていないと思います...とにかく:

int mul(int a, int b)
{
    int t = 0;
    for (int i = b; i >= 1; i--) t -= -a;
    return t;
}

1
これはまさに私が考えた解決策です...しかし、パーティーに遅れて来たのは、誰かがすでにそれを書いていることがわかるまでスクロールダウンすることだとわかっていました。それでも、あなたは私から-(-1)を受け取ります。
フローリス14年

3

SSE組み込み関数を使用したC(すべてがSIMDの方が優れているため):

#include <stdio.h>
#include <stdlib.h>
#include <xmmintrin.h>

static float mul(float a, float b)
{
    float c;

    __m128 va = _mm_set1_ps(a);
    __m128 vb = _mm_set1_ps(b);
    __m128 vc = _mm_mul_ps(va, vb);
    _mm_store_ss(&c, vc);
    return c;
}

int main(int argc, char *argv[])
{
    if (argc > 2)
    {
        float a = atof(argv[1]);
        float b = atof(argv[2]);
        float c = mul(a, b);
        printf("%g * %g = %g\n", a, b, c);
    }
    return 0;
}

この実装の大きな利点は、必要なしに、*または+必要に応じて4つの並列乗算を実行するように簡単に適応できることです。


私は、これは...トローリングされるとは思わない
ジョン・ドヴォルザーク

本当に ?SIMDの無意味で、無償で、アーキテクチャ固有の使用は、コードトローリングの資格があると思いましたか?
ポールR

うーん...本当。これがアーキテクチャ固有であることを理解していませんでした。
ジョン・ドヴォルザーク

3
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define INF 1000000

char cg[INF];

int main()
{
    int a, b;

    char bg[INF];
    memset(bg, '*', INF);

    scanf("%d%d", &a, &b);

    bg[b] = 0;

    while(a--)  
        strcat(cg, bg);

    int result;
    printf("%s%n",cg,&result);
    printf("%d\n", result);

    return 0;
}
  • 乗算結果<1 000 000に対してのみ動作します
  • これまでのところ、取り除くことはできません-演算子、おそらくここで強化
  • printfで%n書式指定子を使用して、印刷された文字数をカウントします(主にCに存在する%nを思い出させるために、これを投稿しています。
  • '*'のa * b文字を出力します

「チューリングマシンエミュレーション」ソリューションを待っています。
グレゴ

1
while strlen(cg) != aは排除するための非常にトローリングな方法です--(O(N * N)にします)。
MSalters

3

おそらく速すぎる:-(

   unsigned int add(unsigned int a, unsigned int b)
    {
        unsigned int carry;

        for (; b != 0; b = carry << 1) {
            carry = a & b;
            a ^= b;
        }
        return a;
    }

    unsigned int mul(unsigned int a, unsigned int b)
    {
        unsigned int prod = 0;

        for (; b != 0;  a <<= 1, b >>= 1) {
            if (b & 1)
                prod = add(prod, a);
        }
        return prod;
    }

1
うん これはトローリングではありません。これは、これを行うための完全に合理的な方法です。
ジョンドヴォルザーク

1
速すぎるのでトロリーです:
ティムテック14年

3

このHaskellバージョンは非負の整数でのみ動作しますが、子供が最初に学習した方法で乗算を行います。すなわち、3x4は4つのものの3つのグループです。この場合、カウントされる「もの」はスティック上のノッチ( '|')です。

mult n m = length . concat . replicate n . replicate m $ '|'

3
int multiply(int a, int b) {
    return sizeof(char[a][b]);
}

天候が適切で、コンパイラが未定義のナンセンスをサポートしている場合、これはC99で機能する可能性があります。


3

OPはCを要求しなかったのでこれ(Oracle)SQLにあります!

WITH
   aa AS (
      SELECT LEVEL AS lvl 
      FROM dual
      CONNECT BY LEVEL <= &a
   ),
   bb AS (
      SELECT LEVEL AS lvl
      FROM dual
      CONNECT BY LEVEL <= &b
   )
SELECT COUNT(*) AS addition
FROM (SELECT * FROM aa UNION ALL SELECT * FROM bb);

WITH
   aa AS (
      SELECT LEVEL AS lvl 
      FROM dual
      CONNECT BY LEVEL <= &a
   ),
   bb AS (
      SELECT LEVEL AS lvl
      FROM dual
      CONNECT BY LEVEL <= &b
   )
SELECT COUNT(*) AS multiplication
FROM aa CROSS JOIN bb;

1
なんてこった*
ポールR

1
@PaulR :)しかし、それらは演算子ではありません。
SQB 14年

2
int add(int a, int b) {
    return 0 - ((0 - a) - b);
}

int mul(int a, int b) {
    int m = 0;
    for (int count = b; count > 0; m = add(m, a), count = add(count, 0 - 1)) { }
    return m;
}

UDの痕跡が含まれる場合があります。


2
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
  int x = atoi(argv[1]);
  int y = atoi(argv[2]);
  FILE *f = fopen("m","wb");
  char *b = calloc(x, y);
  if (!f || !b || fwrite(b, x, y, f) != y) {
    puts("503 multiplication service is down for maintenance");
    return EXIT_FAILURE;
  }
  printf("%ld\n", ftell(f));
  fclose(f);
  remove("m");
  return 0;
}

テスト走行:

$ ./a.out 1 0
0
$ ./a.out 1 1
1
$ ./a.out 2 2
4
$ ./a.out 3 2
6
$ ./a.out 12 12
144
$ ./a.out 1234 1234
1522756
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.