不使用*,/,+,-,%运算符将数字除以3


684

你会如何除以3为数字,没有使用*/+-%,运营商?

该数字可以签名也可以不签名。


13
@AlexandreC。-这些技术虽然使用加法(+)。
柴刀-由SOverflow完成,2012年

19
这是甲骨文,所以您允许使用甲骨文的哪些部分?
霍根2012年

8
所标识的重复项不是重复项。请注意,这里的几个答案都不使用移位或加法,因为此问题并不将解决方案限于这些操作。
Michael Burr 2012年

66
...这就是PL / SQL的诞生方式。
塞达特·卡帕诺格鲁

22
这个问题是SO的题外话。它属于codegolf.stackexchange.com
Kromster 2014年

Answers:


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

正如Jim所说的,这是可行的,因为

  • n = 4 * a + b
  • n / 3 = a + (a + b) / 3
  • 所以sum += an = a + b和迭代

  • a == 0 (n < 4)sum += floor(n / 3);即1时if n == 3, else 0


96
这可能是Oracle寻找的答案。它显示了您知道如何在CPU上实际实现+,-,*和/运算符:简单的按位运算。
craig65535 2012年

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。
吉姆巴尔特

7
这是我发现的一个技巧,也为我提供了类似的解决方案。以小数点表示: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

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进行四舍五入的原因。
Yorick Sijsling

2
@ while1:按位与运算。另外,一个众所周知的事实是,对于n == 2^k符合下列条件:x % n == x & (n-1),所以这里num & 3被用来执行num % 4,同时%是不允许的。
aplavin

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

如果还需要小数部分,只需将resultas 声明为double并将其结果添加到fmod(number,divisor)

解释如何运作

  1. fwrite写入number字节(数目在上面的例子中为123456)。
  2. rewind 将文件指针重置为文件的开头。
  3. fread从文件中读取最大长度的number“记录” divisor,并返回其读取的元素数。

如果写入30个字节,然后以3为单位读回文件,则将得到10个“单位”。30/3 = 10


13
@earlNameless:您不知道它们在内部使用什么,它们在“实现定义”的黑框中。没有什么阻止他们仅使用按位运算符。无论如何,它们不在我的代码范围内,所以这不是我的问题。:)
Matteo Italia 2012年

8
我可以清洁@IvoFlipse,您将得到一个大东西,然后将其推入太小三倍的东西中,然后查看其中的装配量。大约是三分之一。
Pureferret 2012年

27
让我们公司最好的C程序员(也是社交上最尴尬的人)解释代码。他做完之后,我说这很巧妙。他说“这不是解决办法”,请我离开他的书桌
cvursache

6
@cvursache我认为问题是脑筋急转弯,允许脑筋急转弯答案。“贵公司的最佳C程序员”可能也很容易说“
deck

17
@JeremyP:完全是。我的观点是,如果在现实生活中为我提供了不支持算术编译器,那么唯一明智的选择就是要求使用更好的编译器,因为在这些条件下工作没有任何意义。如果访调员想检查我的知识,如何用按位运算实现除法,他可能会很直接,就把它作为一个理论问题提出来。这类“技巧性练习”只是在呼喊这样的答案。
Matteo Italia

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

2
如果四舍五入并且数字不是太大,这实际上可能有效。
Mysticial

252
改进版本:log(pow(exp(number),sin(atan2(1,sqrt(8))))))
Alan Curry

@bitmask,数学函数通常直接在asm中实现。
SingerOfTheFall 2012年

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 2012年

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是正确的,但asm指令是。而且我要补充一点,C编译器并不是唯一具有内联汇编程序的编译器,Delphi也是如此。
塞斯·卡内基

7
@SethCarnegie该asm指令仅在C99标准的附录J-通用扩展名中提及。
JeremyP,2012年

2
在arm-eabi-gcc中失败。
达米安·耶里克

106

使用itoa转换为基数为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
}

4
@cshemby我实际上不知道itoa可以使用任意基数。如果您使用itoa我进行完整的实施,我会投票赞成。
Mysticial

2
该实现将包含/%... :-)
R .. GitHub STOP HELPING ICE 2012年

2
@R.。printf用于显示十进制结果的实现也是如此。
Damian Yerrick '16

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)来划分1003


编辑:您可以继续并替换++运算符:

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
这个问题被标记为c,而不是SQL,即使提到了Oracle。
bitmask

3
确实看起来不像SQL!
moooeeeep

64
如果可以使用++:为什么不简单使用/=
qwertz 2012年

5
@bitmask:++也是快捷方式:For num = num + 1
qwertz 2012年

4
@bitmask是的,但+=最终是的快捷方式num = num + 1
qwertz 2012年

44

Setun计算机上可以轻松实现。

要将整数除以3,请向右右移1位

我不确定在这种平台上是否完全可以实现符合标准的C编译器。我们可能需要稍微延长规则,例如将“至少8位”解释为“能够容纳至少从-128到+127的整数”。


8
问题是您在C中没有“右移一位”运算符。该>>运算符是“除以2 ^ n”运算符,即它是根据算术而不是机器表示法指定的。
R .. GitHub停止帮助ICE

Setun计算机在任何意义上都不是二进制的,因此指令集必须绝对不同。但是,我完全不熟悉该计算机的操作,因此我无法确认该响应是否确实正确-至少可以说是合理的-并且是非常原始的。+1
virolino '19


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的这些位移值相加!糟糕!但是,我们无法添加,因此,我们必须使用按位运算符编写一个add函数!如果您熟悉按位运算符,则我的解决方案应该看起来很简单...但是万一您不知道,我将在最后讲一个示例。

还要注意的另一件事是,我先左移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 <= 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 2012年

@Albert,这是我尝试的第一种方法,有几种变体,但是它们均无法成功地将某些数字均匀地除以3或均匀地除以2(取决于变体)。所以我尝试了一些更简单的方法。我希望看到这种方法的有效实施,看看我在哪里搞砸了。
柴刀-由SOverflow完成,2012年

@hatchet,问题已关闭,因此我无法发布新答案,但想法是实现二进制div。我应该很容易查找它。
Xyand 2012年


25

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

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


1
这是解决慢速除法的常见编译器技巧。但是您可能需要做一些修正,因为0x55555556 / 2 ** 32并非完全是1/3。
CodesInChaos

multiply it。那不是暗示使用禁止的*运算符吗?
luiscubal 2012年

8
@luiscubal:不,不会。这就是为什么我说:“现在剩下要做的就是使用位运算和移位来实现乘法”
AnT 2012年

18

另一个解决方案。这应该处理除整数的最小值以外的所有整数(包括负整数),这需要作为硬编码异常处理。这基本上是通过减法进行除法,但仅使用位运算符(移位,xor和&和补数)。为了获得更快的速度,它会减去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减去一次,因为如果您可以将sub减去两次,那么您可以在上一次迭代减去它的两倍时将其减去。
尼尔2012年

是否(a >= sub)算作一个减法?
尼尔

@尼尔,我想你可能是对的。内部的while可以用简单的if代替,从而节省了循环第二次迭代中不必要的比较。关于> =正在减法...我希望不要,因为这样做会很困难!我明白您的意思,但我认为我倾向于说> =不算作减法。
柴刀-由SOverflow完成,2012年

@Neil,我进行了更改,将时间缩短了一半(还节省了不需要的Negates)。
柴刀-由SOverflow完成,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
您可以使用a Dictionary<number, number>而不是重复的if语句,这样就可以节省O(1)时间!
彼得·奥尔森

@EnesUnal不,时间随着数量的增加而线性增加,因为它必须遍历越来越多的if语句。
彼得·奥尔森

从理论
上讲,

@ PeterOlson,EresUnal,如果我使用switch语句,它将是O(1):-)
dayturns

或者,您可以生成一个数组,然后使用动态编程。如果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

这是基础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程序中调用它;这样做的方法是特定于系统的。

但是,这是一个在我的Ubuntu系统上fp-compiler安装了Free Pascal 软件包的示例。(我这样做是出于固执的错位;我不声称这是有用的。)

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
++和-运算符与+和-运算符不同!在汇编语言中,有两条指令ADDINC并且它们没有相同的操作码。
阿米尔·萨尼扬

7

没有交叉检查该答案是否已经发布。如果程序需要扩展为浮点数,则可以将这些数字乘以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;
}

7

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

#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

/通过使用evaland字符串串联使用运算符“在幕后” 是否会作弊?

例如,在Javacript中,您可以执行

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

7

PHP中使用BC Math

<?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,从第一天开始就如此。此外,您完全无法把握问题的重点。
隆丁'18

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。
隆丁'18

4

我认为正确的答案是:

为什么不使用基本运算符进行基本运算?


因为他们想知道的是您是否知道处理器的内部工作原理...使用数学运算符最终将执行与上述答案非常相似的操作。
RaptorX

或者他们想知道您是否可以识别出无用的问题。
gregoire

1
@Gregoire我同意,没有必要做这样的实现,商业生活(Orcale)有点必要避免履行无用的要求:正确答案是:“这根本没有任何意义,为什么要放零钱为此吗?”)
AlexWien 2012年

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

看到我的另一个答案


很好地利用图书馆。您为什么不直接使用result ++?
绿色妖精

那么人们可能会说+已被使用。
2012年

3

使用cblas,它是OS X加速框架的一部分。

[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,但是我应该遵守规则。固定!
wjl 2012年

我最初将其设置为3.0 / 1.0,这在我的测试中已经实现。通过使用更高的精度数字,它们应该获得合理的精度结果。gist.github.com/3401496
2012年

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

尽管它使用了+,但是已经有人通过位运算器实现加法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.