*、/、+、-、%演算子を使用せずに数値を3で割ります


684

どのように使用しなくても3で番号を分割するだろう*/+-%、演算子?

番号は、署名されている場合と、署名されていない場合があります。


13
@AlexandreC。-これらのテクニックは加算(+)を使用しています。
手斧-2012

19
これはオラクルだったので、オラクルのどの部分を使用できましたか?
ホーガン

8
識別された重複は重複ではありません。ここでのいくつかの回答は、ビットシフトや加算を使用していないことに注意してください。この質問は、これらの操作の解決策を制限していません。
マイケルバー

66
...そしてここに、PL / SQLが生まれる方法があります。
セダットカパノグル

22
この質問はSOとは無関係です。これはcodegolf.stackexchange.com
Kromster

回答:


548

これは、必要な操作を実行する単純な関数です。ただし、+演算子が必要なので、ビット演算子を使用して値を追加するだけです。

// replaces the + operator
int add(int x, int y)
{
    while (x) {
        int t = (x & y) << 1;
        y ^= x;
        x = t;
    }
    return y;
}

int divideby3(int num)
{
    int sum = 0;
    while (num > 3) {
        sum = add(num >> 2, sum);
        num = add(num >> 2, num & 3);
    }
    if (num == 3)
        sum = add(sum, 1);
    return sum; 
}

ジムがコメントしたように、これはうまくいきます:

  • n = 4 * a + b
  • n / 3 = a + (a + b) / 3
  • ですからsum += an = a + bおよび反復

  • ときa == 0 (n < 4)sum += floor(n / 3);すなわち1if n == 3, else 0


96
これはおそらく、Oracleが求めている答えです。+、-、*、および/演算子が実際にCPUにどのように実装されているかがわかります。単純なビット単位の演算です。
craig65535

21
これは、n = 4a + b、n / 3 = a +(a + b)/ 3であるため機能します。したがって、+ = a、n = a + bを合計して、繰り返します。a == 0(n <4)の場合、合計+ = floor(n / 3); すなわち、1の場合のn == 3、それ以外は0
ジムBalter

7
これが私が見つけたトリックで、私に同じような解決策をもたらしました。10進数1 / 3 = 0.333333では、、繰り返し数により、を使用してこれを簡単に計算できa / 3 = a/10*3 + a/100*3 + a/1000*3 + (..)ます。バイナリでは、ほとんど同じです:1 / 3 = 0.0101010101 (base 2)、につながりa / 3 = a/4 + a/16 + a/64 + (..)ます。4で割ると、ビットシフトが発生します。使用できるのは整数のみなので、num == 3の最後のチェックが必要です。
Yorick Sijsling 2012

4
ベース4ではさらに良くなりますa / 3 = a * 0.111111 (base 4) = a * 4^-1 + a * 4^-2 + a * 4^-3 + (..) = a >> 2 + a >> 4 + a >> 6 + (..)。ベース4は、最後に切り上げられるのは3つだけで、1と2は切り捨てられる理由についても説明しています。
ヨリックSijsling

2
@ while1:ビットごとのAND演算です。また、よく知られている事実はn == 2^k、次のことが当てはまることです。そのため、x % n == x & (n-1)ここでnum & 3は許可されていないnum % 4間に実行するために使用されます%
アプラビン2012

436

馬鹿げた条件は馬鹿げた解決策を要求します:

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

int main()
{
    FILE * fp=fopen("temp.dat","w+b");
    int number=12346;
    int divisor=3;
    char * buf = calloc(number,1);
    fwrite(buf,number,1,fp);
    rewind(fp);
    int result=fread(buf,divisor,number,fp);
    printf("%d / %d = %d", number, divisor, result);
    free(buf);
    fclose(fp);
    return 0;
}

小数部も必要な場合は、resultとして宣言しdouble、それにの結果を追加しfmod(number,divisor)ます。

仕組みの説明

  1. fwrite書き込みはnumber(数は上記の例では123456である)バイト。
  2. rewind ファイルポインタをファイルの先頭にリセットします。
  3. freadファイルから長さのある最大number「レコード」を読み取り、読み取ったdivisor要素の数を返します。

30バイトを書き込んでから3単位でファイルを読み戻すと、10の「単位」が得られます。30/3 = 10


13
@earlNameless:それらが内部で何を使用するかはわかりません。それらは「実装定義」のブラックボックスにあります。ビットワイズ演算子を使用することを止めるものは何もありません。とにかく、それらは私のコードのドメインの外にあるので、それは私の問題ではありません。:)
Matteo Italia

8
@IvoFlipseは私がきれいにすることができます、あなたは大きなものを手に入れ、それを3倍にも小さすぎるものに押し込み、それからどれだけの量がはまっているかを確認します。
Pureferret、2012

27
私たちの会社で最高のCプログラマー(そして最も社会的に扱いにくい人)にコードの説明を求めました。彼がやった後、私はそれがかなり独創的だったと言いました。彼は「このドレックは解決策ではない」と言って、私に彼の机を離れるように頼んだ
cvursache '30 / 07/30

6
@cvursache私の要点は、質問は脳死であり、脳死の答えが許されるということです。あなたの会社の「最高のCプログラマは、」そのdreckは、(適切な)問題『ではありません」同じように簡単に言ったかもしれない』。
JeremyP

17
@JeremyP:まさに。私のポイントは、実際に私が算術サポートなしのコンパイラーを与えられた場合、それらの条件での作業は意味をなさないので、賢明なことはより良いコンパイラーを求めることです。インタビュアーがビットごとの演算で除算を実装する方法について私の知識を確認したい場合、彼は単純明快で理論的な質問としてそれを尋ねることができます。この種の「トリック演習」は、このような答えを求めて叫びます。
Matteo Italia

306
log(pow(exp(number),0.33333333333333333333)) /* :-) */

2
これは、適切に丸められ、数値が大きすぎなければ実際に機能する可能性があります。
ミスティシャル2012

252
改善されたバージョン:log(pow(exp(number)、sin(atan2(1、sqrt(8)))))
アランカリー

@bitmask、数学関数は通常、asmに直接実装されます。
SingerOfTheFall

7
私はちょうど私のJSコンソールでそれを入力した、それは709よりも高い数(そのちょうど私のシステムであってもよい)で動作しないMath.log(Math.pow(Math.exp(709),0.33333333333333333333))Math.log(Math.pow(Math.exp(709),Math.sin(Math.atan2(1,Math.sqrt(8)))))
Shaheer

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

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

    int num = 1234567;
    int den = 3;
    div_t r = div(num,den); // div() is a standard C function.
    printf("%d\n", r.quot);

    return 0;
}

113

(プラットフォームに依存する)インラインアセンブリを使用できます。たとえば、x86の場合:(負の数でも機能します)

#include <stdio.h>

int main() {
  int dividend = -42, divisor = 5, quotient, remainder;

  __asm__ ( "cdq; idivl %%ebx;"
          : "=a" (quotient), "=d" (remainder)
          : "a"  (dividend), "b"  (divisor)
          : );

  printf("%i / %i = %i, remainder: %i\n", dividend, divisor, quotient, remainder);
  return 0;
}

2
@JeremyPは、Cで回答を記述できないという前提でコメントに失敗しませんか?結局、質問には「C」というタグが付けられます。
セスカーネギー

1
@SethCarnegie答えはCで書かれていないのが私のポイントです。x86アセンブラは標準の一部ではありません。
JeremyP 2012

1
@JeremyPはtrueですが、asmディレクティブはtrue です。インラインアセンブラを備えているのはCコンパイラだけではなく、Delphiにもあります。
セスカーネギー

7
@SethCarnegieこのasmディレクティブは、付録JのC99標準でのみ言及されています-一般的な拡張機能。
JeremyP 2012

2
arm-eabi-gccで失敗します。
Damian Yerrick

106

使用itoaはをベース3文字列に変換します。最後のトリットをドロップし、ベース10に変換します。

// Note: itoa is non-standard but actual implementations
// don't seem to handle negative when base != 10.
int div3(int i) {
    char str[42];
    sprintf(str, "%d", INT_MIN); // Put minus sign at str[0]
    if (i>0)                     // Remove sign if positive
        str[0] = ' ';
    itoa(abs(i), &str[1], 3);    // Put ternary absolute value starting at str[1]
    str[strlen(&str[1])] = '\0'; // Drop last digit
    return strtol(str, NULL, 3); // Read back result
}

4
@cshemby私は実際にそれitoaが任意のベースを使用できることを知りませんでした。itoa私が使用して完全に機能する実装を行う場合は、賛成票を投じます。
ミスティシャル2012

2
実装には/%次のものが含まれます... :-)
R .. GitHub ICEのHELPING STOP

2
@R ..同様に、printf10進数の結果を表示するための実装も行います。
Damian Yerrick 2016

57

(注:より良いバージョンについては、以下の編集2を参照してください!)

「[..] +[..] 演算子を使用せずに」と言ったので、これは見かけほど複雑ではありません。+キャラクターを一緒に使用することを禁止する場合は、以下を参照してください。

unsigned div_by(unsigned const x, unsigned const by) {
  unsigned floor = 0;
  for (unsigned cmp = 0, r = 0; cmp <= x;) {
    for (unsigned i = 0; i < by; i++)
      cmp++; // that's not the + operator!
    floor = r;
    r++; // neither is this.
  }
  return floor;
}

その後、ちょうど言うdiv_by(100,3)分割する100ことで3


編集:続けて++演算子を置き換えることもできます:

unsigned inc(unsigned x) {
  for (unsigned mask = 1; mask; mask <<= 1) {
    if (mask & x)
      x &= ~mask;
    else
      return x & mask;
  }
  return 0; // overflow (note that both x and mask are 0 here)
}

編集2:含まれている任意の演算子使用することなく、わずかに速いバージョン+-*/% 文字が

unsigned add(char const zero[], unsigned const x, unsigned const y) {
  // this exploits that &foo[bar] == foo+bar if foo is of type char*
  return (int)(uintptr_t)(&((&zero[x])[y]));
}

unsigned div_by(unsigned const x, unsigned const by) {
  unsigned floor = 0;
  for (unsigned cmp = 0, r = 0; cmp <= x;) {
    cmp = add(0,cmp,by);
    floor = r;
    r = add(0,r,1);
  }
  return floor;
}

add関数の最初の引数を使用しているの*は、構文type[]がと同じである関数パラメーターリストを除いて、文字を使用しないとポインターのタイプを示すことができないためですtype* const

FWIW、AndreyT0x55555556によって提案されたトリックを使用するための同様のトリックを使用して、乗算関数を簡単に実装できます。

int mul(int const x, int const y) {
  return sizeof(struct {
    char const ignore[y];
  }[x]);
}

5
Oracleについて言及されている場合でも、質問にはSQLではなくcというタグが付けられます。
ビットマスク

3
これは確かにSQLのようには見えません!
moooeeeep

64
使用できる場合++:なぜ単純に使用しないのです/=か?
qwertz 2012

5
@bitmask:++もショートカットですnum = num + 1
qwertz 2012

4
@bitmaskええ、でも+=ようやくのショートカットになりましたnum = num + 1
qwertz 2012

44

それは、Setunコンピュータで簡単に可能です

整数を3で除算するには、右に1桁シフトします。

このようなプラットフォームで準拠するCコンパイラを実装することが厳密に可能かどうかはわかりません。「少なくとも8ビット」を「少なくとも-128から+127の整数を保持できる」と解釈するなど、ルールを少し拡張する必要があるかもしれません。


8
問題は、Cに「1桁右シフト」演算子がないことです。>>演算子は「2 ^ nによる除算」演算子です。つまり、機械表現ではなく、算術の観点から指定されます。
R .. GitHub ICE HELPING ICEの停止

Setunコンピュータは、どんな意味でもバイナリではないので、命令セットは明確に異なっている必要があります。しかし、私はそのコンピューターの操作にまったく精通していないので、応答が本当に正しいかどうかは確認できません。+1
virolino


32

これが私の解決策です:

public static int div_by_3(long a) {
    a <<= 30;
    for(int i = 2; i <= 32 ; i <<= 1) {
        a = add(a, a >> i);
    }
    return (int) (a >> 32);
}

public static long add(long a, long b) {
    long carry = (a & b) << 1;
    long sum = (a ^ b);
    return carry == 0 ? sum : add(carry, sum);
}

最初に、

1/3 = 1/4 + 1/16 + 1/64 + ...

今、残りは簡単です!

a/3 = a * 1/3  
a/3 = a * (1/4 + 1/16 + 1/64 + ...)
a/3 = a/4 + a/16 + 1/64 + ...
a/3 = a >> 2 + a >> 4 + a >> 6 + ...

これで、ビットシフトされたaの値を加算するだけです。おっとっと!ただし、追加することはできません。そのため、ビット単位の演算子を使用して追加関数を作成する必要があります。ビット単位の演算子に精通している場合、私のソリューションはかなり単純に見えるはずです...でも、あなたがそうでない場合に備えて、最後に例を紹介します。

もう1つ注意すべき点は、最初に左に30シフトすることです。これは、端数が四捨五入されないようにするためです。

11 + 6

1011 + 0110  
sum = 1011 ^ 0110 = 1101  
carry = (1011 & 0110) << 1 = 0010 << 1 = 0100  
Now you recurse!

1101 + 0100  
sum = 1101 ^ 0100 = 1001  
carry = (1101 & 0100) << 1 = 0100 << 1 = 1000  
Again!

1001 + 1000  
sum = 1001 ^ 1000 = 0001  
carry = (1001 & 1000) << 1 = 1000 << 1 = 10000  
One last time!

0001 + 10000
sum = 0001 ^ 10000 = 10001 = 17  
carry = (0001 & 10000) << 1 = 0

Done!

それはあなたが子供の頃学んだ追加を単に運ぶだけです!

111
 1011
+0110
-----
10001

方程式のすべての項を追加できないため、この実装は失敗しました。

a / 3 = a/4 + a/4^2 + a/4^3 + ... + a/4^i + ... = f(a, i) + a * 1/3 * 1/4^i
f(a, i) = a/4 + a/4^2 + ... + a/4^i

div_by_3(a)= x のreslutを仮定しx <= floor(f(a, i)) < a / 3ます。ときa = 3k、私たちは間違った答えを得ます。


2
3の入力で機能しますか?1/4、1/16、...すべての3のリターン0、そう0に合計が、3/3 = 1です
斧- SOverflowで行わ

1
ロジックは良いですが、実装には問題があります。の系列近似n/3は常に未満です。n/3これはn=3k、結果がではk-1なくになることを意味しkます。
Xyand

@アルバート、これは私が試した最初のアプローチで、いくつかのバリエーションがありましたが、3で割り切れる特定の数値または2で割り切れる特定の数値(バリエーションによって異なります)はすべて失敗しました。だから私はもっと簡単なものを試しました。うまくいくこのアプローチの実装を見て、私がどこで失敗したのかを確認したいと思います。
手斧-2012

@hatchet、質問はクローズされているので新しい回答を投稿することはできませんが、アイデアはバイナリdivを実装することです。簡単に調べられるはずです。
Xyand


25

32ビットの数値を3で除算するには0x55555556、それを乗算してから、64ビットの結果の上位32ビットを取得します。

あとは、ビット演算とシフトを使用して乗算を実装するだけです...


1
これは、遅い除算を回避するための一般的なコンパイラトリックです。ただし、0x55555556 / 2 ** 32は正確に1/3ではないため、おそらくいくつかの修正を行う必要があります。
CodesInChaos

multiply it。それは禁止された*演算子を使用することを意味しませんか?
luiscubal 2012

8
@luiscubal:いいえ、ありません。これが私が言った理由です:「今やることはビット操作とシフトを使用して乗算を実装することです」
AnT

18

さらに別のソリューション。これは、ハードコードされた例外として処理する必要があるintのmin値を除くすべてのint(負のintを含む)を処理する必要があります。これは基本的に減算による除算を行いますが、ビット演算子(シフト、xor、&および補数)のみを使用します。速度を上げるには、3 *(2の累乗の減少)を減算します。C#では、1ミリ秒(1,000,000の除算では2.2秒)あたりこれらのDivideBy3呼び出しの約444を実行するので、ひどく遅くなることはありませんが、単純なx / 3ほど高速ではありません。比較すると、クーディーの優れたソリューションは、このソリューションよりも約5倍高速です。

public static int DivideBy3(int a) {
    bool negative = a < 0;
    if (negative) a = Negate(a);
    int result;
    int sub = 3 << 29;
    int threes = 1 << 29;
    result = 0;
    while (threes > 0) {
        if (a >= sub) {
            a = Add(a, Negate(sub));
            result = Add(result, threes);
        }
        sub >>= 1;
        threes >>= 1;
    }
    if (negative) result = Negate(result);
    return result;
}
public static int Negate(int a) {
    return Add(~a, 1);
}
public static int Add(int a, int b) {
    int x = 0;
    x = a ^ b;
    while ((a & b) != 0) {
        b = (a & b) << 1;
        a = x;
        x = a ^ b;
    }
    return x;
}

これはc#です。これは私が手にしたものですが、cとの違いはわずかです。


subを1回減算する必要があるのは、subを2回減算できた場合、現在の2倍の大きさのときに前回の反復を減算できたためです。
Neil、

(a >= sub)減算としてカウント?
ニール

@ニール、私はあなたが正しいかもしれないと思います。内側のwhileは単純なifで置き換えることができ、ループの2番目の反復からの不要な比較を保存します。> =については減算です...これを行うのは非常に難しくなるので、私はそうしないことを望みます!あなたの要点はわかりますが、> =は減算としてはカウントされないと言う側に寄りかかると思います。
手斧-2012

@ニール、私はその変更を行い、時間を半分に削減しました(不要なネゲートも節約しました)。
手斧-2012

16

とても簡単です。

if (number == 0) return 0;
if (number == 1) return 0;
if (number == 2) return 0;
if (number == 3) return 1;
if (number == 4) return 1;
if (number == 5) return 1;
if (number == 6) return 2;

(もちろん、簡潔にするために、一部のプログラムは省略しています。)プログラマーがこれをすべて入力するのに飽きた場合は、プログラマーが別のプログラムを作成して生成することができると確信しています。私はたまたま/彼の仕事を非常に簡単にする特定の演算子を知っています。


8
Dictionary<number, number>繰り返しif文の代わりにを使用して、O(1)時間を複雑にすることができます!
Peter Olson、

@EnesUnalいいえ、ifステートメントをより多くトラバースする必要があるため、時間は数値が増加するにつれて直線的に増加します。
Peter Olson

理論的には増加しません:)
12

@ PeterOlson、EresUnal、switchステートメントを使用した場合、O(1)になります:-)
thedayturns

または、配列を生成して、動的プログラミングを使用することもできます。x / 3 = yの場合、y << 2 + y = x-x%3。
lsiebert 2015

14

カウンターの使用は基本的なソリューションです。

int DivBy3(int num) {
    int result = 0;
    int counter = 0;
    while (1) {
        if (num == counter)       //Modulus 0
            return result;
        counter = abs(~counter);  //++counter

        if (num == counter)       //Modulus 1
            return result;
        counter = abs(~counter);  //++counter

        if (num == counter)       //Modulus 2
            return result;
        counter = abs(~counter);  //++counter

        result = abs(~result);    //++result
    }
}

また、係数関数を実行するのも簡単です。コメントを確認してください。


@Enes Unal:少数ではありません:)このアルゴリズムは非常に基本的です。
GJ。

すべての原始性には弱点が含まれます:)
2012

11

これは、base 2の古典的な除算アルゴリズムです。

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

int main()
{
  uint32_t mod3[6] = { 0,1,2,0,1,2 };
  uint32_t x = 1234567; // number to divide, and remainder at the end
  uint32_t y = 0; // result
  int bit = 31; // current bit
  printf("X=%u   X/3=%u\n",x,x/3); // the '/3' is for testing

  while (bit>0)
  {
    printf("BIT=%d  X=%u  Y=%u\n",bit,x,y);
    // decrement bit
    int h = 1; while (1) { bit ^= h; if ( bit&h ) h <<= 1; else break; }
    uint32_t r = x>>bit;  // current remainder in 0..5
    x ^= r<<bit;          // remove R bits from X
    if (r >= 3) y |= 1<<bit; // new output bit
    x |= mod3[r]<<bit;    // new remainder inserted in X
  }
  printf("Y=%u\n",y);
}

10

Pascalでプログラムを作成し、DIV演算子を使用します。

質問はタグ付けされているので 、おそらくPascalで関数を記述し、それをCプログラムから呼び出すことができます。そのための方法はシステム固有です。

しかし、これはFree Pascal fp-compilerパッケージがインストールされている私のUbuntuシステムで動作する例です。(私はこれを、見当違いの頑固さから行っています。これが有用であるとは主張していません。)

divide_by_3.pas

unit Divide_By_3;
interface
    function div_by_3(n: integer): integer; cdecl; export;
implementation
    function div_by_3(n: integer): integer; cdecl;
    begin
        div_by_3 := n div 3;
    end;
end.

main.c

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

extern int div_by_3(int n);

int main(void) {
    int n;
    fputs("Enter a number: ", stdout);
    fflush(stdout);
    scanf("%d", &n);
    printf("%d / 3 = %d\n", n, div_by_3(n));
    return 0;
}

ビルドするには:

fpc divide_by_3.pas && gcc divide_by_3.o main.c -o main

サンプル実行:

$ ./main
Enter a number: 100
100 / 3 = 33

8
int div3(int x)
{
  int reminder = abs(x);
  int result = 0;
  while(reminder >= 3)
  {
     result++;

     reminder--;
     reminder--;
     reminder--;
  }
  return result;
}

3
++および-演算子は、+および-演算子とは異なります!アセンブリ言語には2つの命令がADDありINC、それらは同じオペコードではありません。
アミールサニヤン

7

この回答がすでに公開されているかどうかをクロスチェックしませんでした。プログラムを浮動小数点数に拡張する必要がある場合は、数値に必要な精度の10 * numberを掛けてから、次のコードを再度適用できます。

#include <stdio.h>

int main()
{
    int aNumber = 500;
    int gResult = 0;

    int aLoop = 0;

    int i = 0;
    for(i = 0; i < aNumber; i++)
    {
        if(aLoop == 3)
        {
           gResult++;
           aLoop = 0;
        }  
        aLoop++;
    }

    printf("Reulst of %d / 3 = %d", aNumber, gResult);

    return 0;
}

7

これは、3だけでなく、どの除数でも機能するはずです。現在は署名なしのみですが、署名済みに拡張することはそれほど難しくありません。

#include <stdio.h>

unsigned sub(unsigned two, unsigned one);
unsigned bitdiv(unsigned top, unsigned bot);
unsigned sub(unsigned two, unsigned one)
{
unsigned bor;
bor = one;
do      {
        one = ~two & bor;
        two ^= bor;
        bor = one<<1;
        } while (one);
return two;
}

unsigned bitdiv(unsigned top, unsigned bot)
{
unsigned result, shift;

if (!bot || top < bot) return 0;

for(shift=1;top >= (bot<<=1); shift++) {;}
bot >>= 1;

for (result=0; shift--; bot >>= 1 ) {
        result <<=1;
        if (top >= bot) {
                top = sub(top,bot);
                result |= 1;
                }
        }
return result;
}

int main(void)
{
unsigned arg,val;

for (arg=2; arg < 40; arg++) {
        val = bitdiv(arg,3);
        printf("Arg=%u Val=%u\n", arg, val);
        }
return 0;
}

7

文字列連結/を使用evalして「舞台裏」で演算子を使用するのは不正行為でしょうか?

たとえば、Javacriptでは、次のことができます

function div3 (n) {
    var div = String.fromCharCode(47);
    return eval([n, div, 3].join(""));
}

7

使用BC数学の中でPHP

<?php
    $a = 12345;
    $b = bcdiv($a, 3);   
?>

MySQL(これはOracleからのインタビューです)

> SELECT 12345 DIV 3;

パスカル

a:= 12345;
b:= a div 3;

x86-64アセンブリ言語:

mov  r8, 3
xor  rdx, rdx   
mov  rax, 12345
idiv r8

1
クールなストーリー、これはCのタグが付けられており、初日からそうです。また、質問の要点を完全に把握することができません。
ランディン

6

最初に私が思いついた。

irb(main):101:0> div3 = -> n { s = '%0' + n.to_s + 's'; (s % '').gsub('   ', ' ').size }
=> #<Proc:0x0000000205ae90@(irb):101 (lambda)>
irb(main):102:0> div3[12]
=> 4
irb(main):103:0> div3[666]
=> 222

編集:申し訳ありませんが、タグに気づきませんでしたC。しかし、あなたは文字列のフォーマットについての考えを使うことができると思います...


5

次のスクリプトは、演算子を使用せずに問題を解決するCプログラムを生成します* / + - %

#!/usr/bin/env python3

print('''#include <stdint.h>
#include <stdio.h>
const int32_t div_by_3(const int32_t input)
{
''')

for i in range(-2**31, 2**31):
    print('    if(input == %d) return %d;' % (i, i / 3))


print(r'''
    return 42; // impossible
}
int main()
{
    const int32_t number = 8;
    printf("%d / 3 = %d\n", number, div_by_3(number));
}
''')


4

このアプローチ(c#)はどうですか?

private int dividedBy3(int n) {
        List<Object> a = new Object[n].ToList();
        List<Object> b = new List<object>();
        while (a.Count > 2) {
            a.RemoveRange(0, 3);
            b.Add(new Object());
        }
        return b.Count;
    }

これはCのタグが付けられ、初日からそうです。
ランディン

4

私は正しい答えは次のとおりだと思います:

基本的な演算子を使用して基本的な操作を行わないのはなぜですか?


彼らが知りたいのは、プロセッサが内部でどのように動作するかを知っているかどうかです...数学演算子を使用すると、最終的に上記の答えと非常によく似た操作が実行されます。
RaptorX

または、役に立たない問題を認識できるかどうかを知りたいと思っています。
グレゴワール2012年

1
@グレゴワール私は同意します、そのような実装を行う必要はありません、商業生活の中でのビット(オーカル)無駄な要求を満たすことを避けることが必要です:正解は「これはまったく意味をなさない、なぜお金を失うのか」そのためですか?」)
AlexWien

4

fma()ライブラリ関数を使用したソリューションは、任意の正の数で機能します

#include <stdio.h>
#include <math.h>

int main()
{
    int number = 8;//Any +ve no.
    int temp = 3, result = 0;
    while(temp <= number){
        temp = fma(temp, 1, 3); //fma(a, b, c) is a library function and returns (a*b) + c.
        result = fma(result, 1, 1);
    } 
    printf("\n\n%d divided by 3 = %d\n", number, result);
}

私の別の答えを見てください


ライブラリの素晴らしい使い方。なぜ結果++を直接使用しなかったのですか?
緑のゴブリン

すると人々は+が使われたと言うかもしれません。

3

OS XのAccelerateフレームワークの一部として含まれているcblasを使用します。

[02:31:59] [william@relativity ~]$ cat div3.c
#import <stdio.h>
#import <Accelerate/Accelerate.h>

int main() {
    float multiplicand = 123456.0;
    float multiplier = 0.333333;
    printf("%f * %f == ", multiplicand, multiplier);
    cblas_sscal(1, multiplier, &multiplicand, 1);
    printf("%f\n", multiplicand);
}

[02:32:07] [william@relativity ~]$ clang div3.c -framework Accelerate -o div3 && ./div3
123456.000000 * 0.333333 == 41151.957031

まあ、それは単なる実装の詳細だったので、0.333333の代わりに3.0 / 1.0と入力することもできましたが、ルールに従う必要があります。修繕!
wjl

私はもともとそれを3.0 / 1.0として持っていましたが、私のテストではそうでした。より高い精度の数値を使用することで、かなり正確な結果が得られます。gist.github.com/3401496
wjl

3

一般に、これに対する解決策は次のとおりです。

log(pow(exp(numerator),pow(denominator,-1)))


3

最初:

x/3 = (x/4) / (1-1/4)

次に、x /(1-y)を解く方法を理解します。

x/(1-1/y)
  = x * (1+y) / (1-y^2)
  = x * (1+y) * (1+y^2) / (1-y^4)
  = ...
  = x * (1+y) * (1+y^2) * (1+y^4) * ... * (1+y^(2^i)) / (1-y^(2^(i+i))
  = x * (1+y) * (1+y^2) * (1+y^4) * ... * (1+y^(2^i))

y = 1/4の場合:

int div3(int x) {
    x <<= 6;    // need more precise
    x += x>>2;  // x = x * (1+(1/2)^2)
    x += x>>4;  // x = x * (1+(1/2)^4)
    x += x>>8;  // x = x * (1+(1/2)^8)
    x += x>>16; // x = x * (1+(1/2)^16)
    return (x+1)>>8; // as (1-(1/2)^32) very near 1,
                     // we plus 1 instead of div (1-(1/2)^32)
}

を使用しています+が、誰かがすでにビットごとの演算でaddを実装しています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.