【问题标题】:Divide a number by 3 without using *, /, +, -, % operators不使用 *、/、+、-、% 运算符将数字除以 3
【发布时间】:2012-07-26 12:43:12
【问题描述】:

如果不使用*/+-% 等运算符,您如何将一个数除以 3?

号码可能有符号或无符号。

【问题讨论】:

  • 识别出的重复不是重复。请注意,这里的几个答案既不使用移位也不使用加法,因为此问题并未限制这些操作的解决方案。
  • 顺便说一句:另一个问题是关于检查一个数字是否可以被3整除。这个问题是关于除以被3。
  • 也许面试官的意思是问“你如何在不使用 blah blah blah 的情况下除以 2”。这是一个大多数开发人员应该能够回答的理智问题。
  • x /= 3;不使用 / 运算符,/= 是不同的运算符。
  • 这个问题与 SO 无关。它属于codegolf.stackexchange.com

标签: c math division divide


【解决方案1】:

用 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

【讨论】:

    【解决方案2】:

    (注意:请参阅下面的编辑 2 以获得更好的版本!)

    这并不像听起来那么棘手,因为您说过“不使用 [..] + [..] operators”。如果您想禁止同时使用+ 字符,请参见下文。

    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,您可以使用与AndreyT 提出的0x55555556 技巧类似的技巧轻松实现乘法函数:

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

    【讨论】:

    • 这个问题被标记为c,而不是SQL,尽管提到了Oracle。
    • 这确实不像SQL!
    • 如果可以使用++:为什么不直接使用/=
    • @bitmask: ++ 也是一个快捷方式:对于num = num + 1
    • @bitmask 是的,但是+= 终于是num = num + 1 的快捷方式了。
    【解决方案3】:

    使用itoa 转换为base 3 字符串。删除最后一个 trit 并转换回基数 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
    }
    

    【讨论】:

    • @cshemby 我实际上不知道itoa 可以使用任意基数。如果您使用 itoa 完成完整的工作实施,我会投票。
    • 实现将包含/%... :-)
    • @R.. 用于显示十进制结果的printf 的实现也是如此。
    【解决方案4】:

    这是一个simple function,它执行所需的操作。但它需要+ 运算符,因此您剩下要做的就是使用位运算符添加值:

    // 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 &lt; 4)sum += floor(n / 3);即1、if n == 3, else 0

    【讨论】:

    • 这可能是 Oracle 正在寻找的答案。它向您展示了 +、-、* 和 / 运算符是如何在 CPU 上实际实现的:简单的按位运算。
    • 这是有效的,因为 n = 4a + b,n/3 = a + (a+b)/3,所以 sum += a,n = a + b,然后迭代。当 a == 0 (n
    • 这是我发现的一个技巧,它给了我一个类似的解决方案。十进制: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 进行最后一次检查,因为我们只能处理整数。
    • 在 base 4 中它变得更好:a / 3 = a * 0.111111 (base 4) = a * 4^-1 + a * 4^-2 + a * 4^-3 + (..) = a &gt;&gt; 2 + a &gt;&gt; 4 + a &gt;&gt; 6 + (..)。底数 4 也解释了为什么最后只有 3 向上舍入,而 1 和 2 可以向下舍入。
    • @while1:这是按位与运算。另外,一个众所周知的事实是,对于n == 2^k,以下是正确的:x % n == x &amp; (n-1),所以这里num &amp; 3 用于执行num % 4,而% 是不允许的。
    【解决方案5】:

    要将 32 位数字除以 3,可以将其乘以 0x55555556,然后取 64 位结果的高 32 位。

    现在剩下要做的就是使用位运算和移位来实现乘法...

    【讨论】:

    • 这是解决慢除法的常见编译器技巧。但是你可能需要做一些修正,因为 0x55555556/2**32 不完全是 1/3。
    • multiply it。这不是意味着使用被禁止的* 运算符吗?
    • @luiscubal:不,不会。这就是为什么我说:“现在剩下要做的就是使用位操作和移位实现乘法”
    【解决方案6】:
    log(pow(exp(number),0.33333333333333333333)) /* :-) */
    

    【讨论】:

    • 如果四舍五入并且数字不太大,这实际上可能有效。
    • 改进版:log(pow(exp(number),sin(atan2(1,sqrt(8)))))
    • @bitmask,数学函数通常直接在asm中实现。
    • 我只是在我的 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)))))
    【解决方案7】:

    愚蠢的情况需要愚蠢的解决方案:

    #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

    【讨论】:

    • @earlNameless:你不知道他们在里面用什么,他们在“实现定义”的黑匣子里。没有什么能阻止他们只使用按位运算符;无论如何,它们在我的代码域之外,所以这不是我的问题。 :)
    • @IvoFlipse from I can clean,你得到一个大的 something 并把它塞进小三倍的东西里,然后看看装了多少。大约是三分之一.
    • 请了我们公司最好的 C 程序员(也是最不擅长社交的)来解释代码。他做了之后,我说这很巧妙。他说“这不是解决办法”并让我离开他的办公桌
    • @cvursache 我认为关键是这个问题太脑残了,以至于允许脑死的答案。贵公司的“最好的 C 程序员”可以很容易地说“dreck 不是一个(正确的)问题”。
    • @JeremyP:完全正确。我的观点是,如果在现实生活中给我一个不支持算术的编译器唯一明智的做法就是要求一个更好的编译器,因为在这些条件下工作没有任何意义。如果面试官想检查我对如何使用按位运算实现除法的知识,他可以直截了当,将其作为理论问题提出;这些“技巧练习”只是为了这样的答案而尖叫。
    【解决方案8】:
    #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;
    }
    

    【讨论】:

      【解决方案9】:

      您可以使用(取决于平台的)内联汇编,例如,对于 x86:(also works for negative numbers)

      #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;
      }
      

      【讨论】:

      • @JeremyP 假设答案不能用 C 编写,您的评论不会失败吗?这个问题毕竟被标记为“C”。
      • @SethCarnegie 答案不是用 C 写的,这是我的观点。 x86 汇编器不是标准的一部分。
      • @JeremyP 这是真的,但 asm 指令是。我还要补充一点,C 编译器并不是唯一具有内联汇编器的编译器,Delphi 也有。
      • @SethCarnegie asm 指令仅在附录 J 下的 C99 标准中提及 - 通用扩展。
      • 在 arm-eabi-gcc 中失败。
      【解决方案10】:

      使用Hacker's Delight Magic number calculator

      int divideByThree(int num)
      {
        return (fma(num, 1431655766, 0) >> 32);
      }
      

      其中fmamath.h 标头中定义的标准库函数。

      【讨论】:

      • 这怎么不使用-*操作符?
      【解决方案11】:

      这是我的解决方案:

      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! 的位移位值加在一起!哎呀!但是我们不能加法,所以相反,我们必须使用按位运算符编写一个加法函数!如果您熟悉按位运算符,我的解决方案应该看起来相当简单......但万一您不熟悉,我将在最后介绍一个示例。

      另外需要注意的是,我首先左移了 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,那么x &lt;= floor(f(a, i)) &lt; a / 3。当a = 3k 时,我们得到错误的答案。

      【讨论】:

      • 对输入 3 有效吗? 1/4, 1/16, ... 3 都返回 0,所以总和为 0,但 3/3 = 1。
      • 逻辑不错,但实现有问题。 n/3 的级数近似值始终小于 n/3,这意味着对于任何 n=3k,结果将是 k-1 而不是 k
      • @Albert,这是我尝试的第一种方法,有几个变体,但它们都失败了某些数字可以被 3 整除或被 2 整除(取决于变化)。所以我尝试了一些更简单的方法。我希望看到这种方法的有效实施,看看我在哪里搞砸了。
      • @hatchet,问题已结束,所以我无法发布新答案,但想法是实现二进制 div。我应该很容易查到。
      【解决方案12】:

      另一种解决方案。这应该处理除 int 的最小值之外的所有整数(包括负整数),这需要作为硬编码异常处理。这基本上是通过减法进行除法,但仅使用位运算符(移位、异或、& 和补码)。为了更快的速度,它减去 3 *(2 的递减幂)。在 c# 中,它每毫秒执行大约 444 次这样的 DivideBy3 调用(1,000,000 次除法需要 2.2 秒),因此速度不会太慢,但速度远不及简单的 x/3。相比之下,Coodey 的好解决方案比这个快大约 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 一次,因为如果您可以减去两次,那么您可以在前一次迭代中减去它,此时它是现在的两倍。
      • (a &gt;= sub) 算不算减法?
      • @Neil,我想你可能是对的。内部的 while 可以用一个简单的 if 代替,从循环的第二次迭代中保存不需要的比较。关于 >= 减法...我希望不会,因为那样做会很困难!我明白你的意思,但我想我会倾向于说 >= 不算减法。
      • @Neil,我进行了更改,将时间缩短了一半(也节省了不需要的否定)。
      【解决方案13】:

      Setun computer 上很容易实现。

      要将整数除以 3,shift right by 1 place

      我不确定在这样的平台上实现符合标准的 C 编译器是否完全可行。我们可能需要稍微扩展一下规则,比如将“至少 8 位”解释为“至少能够保存从 -128 到 +127 的整数”。

      【讨论】:

      • 问题是你在 C 中没有“右移一位”运算符。&gt;&gt; 运算符是“除以 2^n”运算符,即在算术术语,而不是机器表示。
      • Setun 计算机在任何意义上都不是二进制的,所以指令集肯定是不同的。但是,我对那台计算机的操作完全不熟悉,所以我无法确认响应是否真的正确——但至少它是有道理的——并且是高度原创的。 +1
      【解决方案14】:

      我想出的第一个。

      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。但是你可以使用关于字符串格式化的想法,我猜......

      【讨论】:

        【解决方案15】:

        这是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);
        }
        

        【讨论】:

          【解决方案16】:

          使用cblas,作为 OS X Accelerate 框架的一部分。

          [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
          

          【讨论】:

          • 嗯,这只是一个实现细节,所以我可以将其输入为 3.0 / 1.0 而不是 0.333333,但我应该遵守规则。固定!
          • 我最初的版本是 3.0 / 1.0,在我的测试中也是如此。通过使用更高精度的数字,他们应该得到一个相当准确的结果。 gist.github.com/3401496
          【解决方案17】:

          没有交叉检查此答案是否已发布。如果程序需要扩展为浮点数,可以将数字乘以 10*所需的精度数,然后可以再次应用以下代码。

          #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;
          }
          

          【讨论】:

            【解决方案18】:

            这应该适用于任何除数,而不仅仅是三个。目前仅适用于未签名,但将其扩展到已签名应该没有那么困难。

            #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;
            }
            

            【讨论】:

              【解决方案19】:
              #!/bin/ruby
              
              def div_by_3(i)
                i.div 3        # always return int http://www.ruby-doc.org/core-1.9.3/Numeric.html#method-i-div
              end
              

              【讨论】:

              • OP 要求使用 C 而不是 Ruby 的解决方案
              • 问题中没有提到 C,只是标记。你没有被录用;)
              • 我很确定您可以使用 popen() 将 Ruby 调用包装为来自 C 的外部调用
              【解决方案20】:

              使用fma() library function 的解决方案,适用于任何正数:

              #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);
              }
              

              See my another answer.

              【讨论】:

              • 图书馆很好用。为什么不直接使用result++?
              • 那么人们可能会说 + 已经被使用了。
              【解决方案21】:

              在 Python 中,基本上是字符串比较和状态机。

              def divide_by_3(input):
                to_do = {}
                enque_index = 0
                zero_to_9 = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
                leave_over = 0
                for left_over in (0, 1, 2):
                  for digit in zero_to_9:
                    # left_over, digit => enque, leave_over
                    to_do[(left_over, digit)] = (zero_to_9[enque_index], leave_over)
                    if leave_over == 0:
                      leave_over = 1
                    elif leave_over == 1:
                      leave_over = 2
                    elif leave_over == 2 and enque_index != 9:
                      leave_over = 0
                      enque_index = (1, 2, 3, 4, 5, 6, 7, 8, 9)[enque_index]
                answer_q = []
                left_over = 0
                digits = list(str(input))
                if digits[0] == "-":
                  answer_q.append("-")
                digits = digits[1:]
                for digit in digits:
                  enque, left_over = to_do[(left_over, int(digit))]
                  if enque or len(answer_q):
                    answer_q.append(enque)
                answer = 0
                if len(answer_q):
                  answer = int("".join([str(a) for a in answer_q]))
                return answer
              

              【讨论】:

                【解决方案22】:

                PHP 中使用BC Math

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

                MySQL(来自甲骨文的采访)

                > SELECT 12345 DIV 3;
                

                Pascal:

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

                x86-64 汇编语言:

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

                【讨论】:

                • 很酷的故事,它被标记为 C,从第一天起就一直如此。另外,你完全没有把握问题的重点。
                【解决方案23】:
                int div3(int x)
                {
                  int reminder = abs(x);
                  int result = 0;
                  while(reminder >= 3)
                  {
                     result++;
                
                     reminder--;
                     reminder--;
                     reminder--;
                  }
                  return result;
                }
                

                【讨论】:

                • ++ 和 -- 运算符与 + 和 - 运算符不同!在汇编语言中有两条指令ADDINC,它们的操作码不同。
                【解决方案24】:

                使用计数器是一个基本的解决方案:

                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
                    }
                }
                

                执行模函数也很容易,检查 cmets。

                【讨论】:

                • @Enes Unal: 不适合小数字 :) 这个算法非常基础。
                • 每个原始性都包含弱点:)
                【解决方案25】:

                使用 Linux shell 脚本:

                #include <stdio.h>
                int main()
                {
                    int number = 30;
                    char command[25];
                    snprintf(command, 25, "echo $((%d %c 3)) ", number, 47);
                    system( command );
                    return 0;
                }
                

                See my another answer.

                【讨论】:

                  【解决方案26】:

                  以下脚本会生成一个 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));
                  }
                  ''')
                  

                  【讨论】:

                    【解决方案27】:

                    真的很简单。

                    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;
                    

                    (为了简洁起见,我当然省略了一些程序。)如果程序员厌倦了全部输入,我相信他或她可以编写一个单独的程序来为他生成它。我碰巧知道某个操作员/,这将极大地简化他的工作。

                    【讨论】:

                    • 您可以使用Dictionary&lt;number, number&gt; 而不是重复的if 语句,这样您就可以拥有O(1) 的时间复杂度!
                    • @EnesUnal 不,时间随着数量的增加而线性增加,因为它必须遍历越来越多的 if 语句。
                    • 理论上不会增加​​:)
                    • @PeterOlson, EresUnal 如果我使用 switch 语句,它会是 O(1) :-)
                    • 或者你可以生成一个数组,并使用动态编程。如果 x/3 = y,则 y
                    【解决方案28】:

                    通过使用eval 和字符串连接在“幕后”使用/ 运算符会作弊吗?

                    例如,在Javacript中,你可以这样做

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

                    【讨论】:

                      【解决方案29】:

                      好啊bc:

                      $ num=1337; printf "scale=5;${num}\x2F3;\n" | bc
                      445.66666
                      

                      【讨论】:

                        【解决方案30】:

                        如果我们认为__div__ 不是正字法/

                        def divBy3(n):
                            return n.__div__(3)
                        
                        print divBy3(9), 'or', 9//3
                        

                        【讨论】:

                          猜你喜欢
                          • 2012-12-02
                          • 1970-01-01
                          • 1970-01-01
                          • 2022-07-17
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2016-07-09
                          相关资源
                          最近更新 更多