如何在不使用*和+运算符的情况下编写用于乘法的C程序?


68

是否可以编写一个将两个数字相乘而不使用乘法和加法运算符的C程序?

在Stack Overflow上找到了这个。请帮助这个可怜的程序员解决他的问题。请不要给出答案一样c = a/(1/((float)b)),这是完全一样的c = a*b。(并且已经给出了答案。)

2014年1月19日投票最多的答案将获胜。

注意:这是一个询问问题。请不要认真对待问题和/或答案。有关更多信息,请参见代码拖曳


2
@PaulR发挥您的幻想
John Dvorak

26
Code-golf.SE不应成为您嘲笑在StackOverflow上看到的问题的地方。
Gareth 2014年

17
@Gareth,您确定吗?在这第一线表明,这可能是比较合适的。
达伦·斯通

5
我正在等待有人编写基于睡眠的算法
kb_sou 2014年

21
这个问题听起来并不荒谬。实际的计算机硬件(晶体管)没有乘法和加法运算-它们具有诸如NOT,AND,OR,XOR之类的基本逻辑运算。弄清楚如何回答这个问题,可以使您深入了解计算机在逻辑门级的工作原理。
加布2014年

Answers:


147

始终使用递归

挽回是正确的方法!

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:一个用于最终递归,一个用于??::不带括号,一个用于在不尝试调整规则的情况下解决问题;)
2014年

10
如果毕加索是一名程序员...
R休斯

4
@SargeBorsch但哪儿的乐趣在
Oberon 2014年

3
@HC_ inc函数测试其参数以查看最低位是否为1; 如果是这样,它将在参数的其余高位上调用自身,并返回与被设置为相同的低位的结果0,而如果没有(即最低位是0),则将其替换0为a 1并返回结果。此过程与您要手动添加值(逐位二进制数)的过程非常相似。
JAB

2
增量函数是否不会进入-1的无限循环?(0xFFFF)双烯酮显示(-1 >> 1)== -1。
分隔符2014年

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
将其放在结构中,不需要内存。
本杰克逊

4
哈哈哈!
Almo 2014年

1
使用"%zu"格式字符串。
Grijesh Chauhan 2014年

5
只会sizeof(char[A][B])起作用(除非A <= 0或B <= 0或A * B溢出,在这种情况下,您应该会遇到“错误类型”错误)
greggo 2014年

3
@DavidRicherby-我可以简化代码main(){return sizeof(char[A][B]);},您可以使用cc -DA=6 -DB=7 a.c; ./a.out; echo $?
Mark Lakata 2014年

47

如果您不太确定,但可以使用Monte Carlo方法

#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用于其算术的工具。但是我希望在没有两个++运算符实例的情况下看到它。
达伦·斯通

1
@DarrenStone-= -1
Timtech

20
@Timtech |= 1(将100%的时间处理50%的数字)
Darren Stone

2
+1,但要注意它可能太慢,您可以添加多线程支持,并仔细锁定'count ++':-)
greggo 2014年

1
总有printf增加:printf("%*cc%n\n", count, &count, 'c');(打印“C” count次,然后又“C”,并存储在写回的字符数count
MSalters

45

由于您没有指定数字的大小,因此我假设您是指两个一位数字。

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

如果想要最大效率的实现,请使用以下微型实现:

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

请注意,即使类型是隐式整数,它仍然只接受位-它需要较少的代码,因此效率更高。(是的,它确实可以编译。)


8
真好 对问题的故意误解:-)
John Dvorak 2014年

6
您可以对此进行优化return a && b;。它更短,因此更快。
Ry-

1
@minitech:我决定反对这样做,以使代码稍差一些。如果我想进一步发展,那就做吧return a&b;
Cel Skeggs 2014年

1
C必须#include<stdbool.h>定义truefalse
leewz 2014年

1
是啊,#include<stdbool.h>似乎只是三个#defines表示你可以做自己(truefalsebool,一个标志,用来标记,它的被激活)。您还可以从其他答案之一中获得技巧,并将隐式int用于“简短”版本。
leewz 2014年

31

这是一个简单的shell脚本:

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
我无法确定哪个更糟糕。您正在将计算外包给搜索引擎,或者您选择的搜索引擎是必应。不幸的是,我不认为这会为我们的happless OP,谁需要C.什么工作
AmeliaBR

5
感谢您接受监督。仅供参考,我之所以使用Bing,是因为Google发出这样的请求变得更加复杂-您必须添加标头才能说服Google您的请求确实来自浏览器。
Vroo 2014年

2
@abarnert嗯... Bing懂“时间”吗?沃尔夫拉姆·阿尔法可能会这样做。
约翰·德沃夏克

2
@JanDvorak:是的,Wolfram工作。(请注意%20,以免使用任何+符号。)但是,您仍然需要解析输出(以C表示)以获取输出值。这将特别棘手,因为输出似乎是图像而不是文本。HTML解析加上OCR可能是此问题的最佳解决方案。
2014年

3
@JanDvorak:那没意思。我期待有人编写没有加法或乘法的简单OCR库…
abarnert 2014年

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

附注:它将很高兴带有一些值。;)


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;

然后取每个论点的符号和大小。要对二进制补码中的数字求反,请将所有位取反,然后加一个。

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

要使两个正整数相乘,我们可以使用乘法的几何含义:

// 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的幂,因此从技术上应该不允许这样做。
  • 无用图是无用的。同样,它可以被转置以节省一行。
  • 重复移位-1不是找到符号位的最佳方法。即使没有内置常数,也可以将逻辑右移-1,然后将所有位取反。
  • XOR -1不是反转所有位的最佳方法。
  • 整个带有符号大小表示的伪装都是不必要的。只需将其强制转换为无符号,然后模块化算术即可完成其余工作。
  • 由于MIN_INT(AKA signBit)的绝对值为负,因此该值将中断。幸运的是,它在一半情况下仍然有效,因为MIN_INT * [even number] 应该为零。此外,plusOne中断for时-1,结果溢出时都会引起无限循环。 plusOne任何值都可以正常工作。对困惑感到抱歉。

实际代码拖尾+1:看起来应该可以工作,但是很有可能会在OP上崩溃,并且他/她将不知道为什么。
凯文(Kevin)

1
只需使用shift,XOR和AND,就可以在没有任何加法运算符的情况下进行加法运算。所有这些++都使我感到头疼-带进位的一位加法运算是(x ^ y)| (((x&y)<< 1)(对在此cr脚的小文本框中键入引起的所有错误进行模运算。)
Julie in Austin

@JulieinAustin是的。该算法的效率甚至比需要的低。我应该修改巨魔名单吗?:-)
John Dvorak 2014年

1
@JulieinAustin (x ^ y) | ((x & y) << 1)不相当的工作,也不会传播时携带X或Y和携带在相同的位置都为真:)
霍布斯

@hobbs解决方案:如果进位非零,则递归地添加它们而不是ORing。
约翰·德沃夏克

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集合论的基础上构建von Neumann序数,然后使用Peano公理

假设您具有可以包含其他集合的集合类型,这自然会转换为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)启动。但是,正如克罗内克(Kroenecker)所说的那样,上帝创造了自然数。所有其他一切都是人类的工作,那么,为什么要麻烦呢?


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-实际上使用查找表进行加法运算的计算机...

关于使用表机制“加速”实际上可以在一条指令中完成的操作的某种满足。

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

呃,表查找使用加法--(a [i])与(*(a + i))相同。
朱莉在奥斯丁

@JulieinAustin我提到了。通过合并字段(如IBM 1620中所示,请参见链接),可以在不添加表的情况下完成表查找,但是在C中进行设置很麻烦-您需要将表对齐到适当的地址,以便索引可以刚刚进行或运算英寸
greggo

8

我不确定这些“代码巨魔”帖子中的“作弊”是什么构成的,但这在运行时将2个任意整数相乘,没有*或没有+使用标准库(C99)的运算符。

#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很好地执行进位评估。我喜欢您的代码:)
2014年

@BЈовић:我的错,我以为拖钓与谅解无关。更改名称并添加注释。
Matthias

抱歉。我误解了那个标签是什么,以及Q的真正含义。你应该恢复它
BЈовић

在这种情况下,@ Matthias很有用,以了解其工作原理,以便我们了解会聚操作的扭曲程度。在实际的代码
拖曳

我想指出的是,如果您想添加位反转的数字(带有高位以携带道具)并且您没有“ bitrev”指令,那么这可能是一种非常合理的方法(将c>更改为> = 1,当然)
greggo,2014年

7

这里有很多很好的答案,但是看起来很多人没有利用现代计算机真正强大的事实。大多数CPU中有多个处理单元,那么为什么只使用一个呢?我们可以利用它来获得出色的性能结果。

#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循环的每个部分划分为一个不同的执行单元,因此我们要进行并行乘法!

请注意,您必须使用该-fopenmp标志来告诉编译器使用OpenMP。


巨魔零件:

  1. 对并行编程的使用产生误导。
  2. 对负数(或大数)无效。
  3. 实际上并没有划分for循环的各个部分-每个线程都运行循环。
  4. 恼人的变量名和变量重用。
  5. 比赛条件微妙answer--。大多数情况下,它不会显示,但偶尔会导致结果不准确。

2
为什么不将其与Paul R的SIMD答案结合使用,以使您可以以32x的速度而不是8x的速度运行?尽管确实如此,但您希望让GPU和内核参与其中。那就真的杀出。:)
abarnert 2014年

2
还可以使用OpenMPI在几台计算机上并行运行它。
millinon 2014年

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为负来确保至少一个参数()为正(并且不,我拒绝将否定视为一种加法或乘法运算)。然后while (a)循环b为中的每个设置位将的移位副本添加到结果中a。该do循环实现r += x使用和,异或x运算以及移入一组明显的半加法器,并将进位进位,直到不再有进位为止(实际的CPU将使用全加法器,效率更高,但是C不会)没有您需要的操作员,除非您算上+操作员)。


4
询问者没有拖钓。应该巨魔。
约翰·德沃夏克

2
这是一个隐形巨魔!秘密故障发生在a == INT_MIN上。
詹德(Jander)2014年

1
@Jander嗯。是的,那是一个很好的选择。我猜测(在普通的二进制补码系统上)取反的结果仍然是负数,并且while(a)循环永远不会终止。
hobbs

@hobbs是的,这对我来说很正确。否则,一个非常漂亮的答案。
詹德(Jander)2014年

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
失败用于= 2,B = 2,C = 5
BЈовић

@BЈовић: while(C/A != B || C%A)
2014年

2
请注意,这实际上是一种尝试与Deep Thought的继任者相同的事情,但对于所有可能的Universe而言,而不仅仅是答案为42的那种。如果不是针对bug的话,这将是非常令人印象深刻的。并且在Vogons的情况下缺乏错误处理。
2014年

1
需要多个线程。您知道,要使其高效。
greggo,2014年

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完全没有用处。

– […]目的是用懒惰的OP认为可以接受的语言来做作业,但仍然使他感到沮丧。


2
“不使用乘法和加法运算符”。很好地修改规则-这对于提问者来说绝对是没有用的:-)
John Dvorak 2014年

2
这实际上不是C解决方案。另外,它无法在我的ARM9上编译。
abarnert 2014年

1
@abarnert:无法将您的陈述视为相关论点。
Runium 2014年

@Sukminder:问题是“是否可以编写C程序……?” 内联汇编不是C。某些C编译器也可以进行内联汇编这一事实并没有改变,这比某些C编译器也可以执行C ++或ObjC的事实更使C ++或ObjC算作C代码。
abarnert 2014年

2
@abarnert:它是在C程序中广泛使用的嵌入式代码。即使它是杂种,也可以说它是C程序。甚至有可能OP会将其识别为C代码。显然不是python,还是?
Runium 2014年

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

是否可以编写一个将两个数字相乘而不使用乘法和加法运算符的C程序?

当然:

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

但是,那当然是作弊;显然他希望能够提供两个数字,对吗?

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

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简单地用两个参数调用它。
也适用于负数。


负面的a,是的,负面的b我不这么认为。但这可以通过许多创造性的方法来解决。最简单的将是sign_a ^ = sign_b,sign_b = 0
MSalters

@MSalters,已测试并且可用于所有符号组合(使用Linux / gcc)。
ugoren 2014年

3

C#

我认为不允许相减和取反...无论如何:

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

1
这正是我所想到的解决方案……但是晚点参加聚会我知道这是一个向下滚动的问题,直到我发现有人已经写过为止。不过,您还是从我这里得到-(-1)。
弗洛里斯2014年

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个并行乘法,而无需执行*+在需要时执行。


我不认为这是在拖钓...
John Dvorak

真的吗 我认为SIMD的无意义,免费和特定于体系结构的使用将使它有资格进行代码拖曳?
Paul 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,当然也可以将%n代替strn等)
  • 打印'*'的a * b字符

现在正在等待“图灵机仿真”解决方案。
greggo,2014年

1
while strlen(cg) != a是消除--(使其成为O(N * N))的一种非常拖钓的方法。
MSalters 2014年

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
gh 这不是拖钓。这是一种完全合理的方法。
John Dvorak 2014年

1
这太简单了,因为它太快了:-)
Timtech

3

该Haskell版本仅适用于非负整数,但是它以孩子第一次学习它的方式进行乘法。也就是说,3x4是3组,每组4件事。在这种情况下,被计数的“事物”是指棒上的缺口(“ |”)。

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


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
天哪,充满了*
Paul R

1
@PaulR :)但它们不是运算符
SQB

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