web-dev-qa-db-fra.com

Comment puis-je effectuer une multiplication sans l'opérateur '*'?

J'étais en train de parcourir quelques éléments de base pendant que j'apprenais le C. J'ai eu la question de multiplier un nombre par 7 sans utiliser l'opérateur *. En gros c'est comme ça

      (x << 3) - x;

Maintenant, je connais les opérations de manipulation de bits de base, mais je ne peux pas comprendre comment multiplier un nombre par un autre nombre impair sans utiliser l'opérateur *. Existe-t-il un algorithme général pour cela?

45
Race

Pensez à la façon dont vous vous multipliez en décimal à l'aide d'un crayon et d'un papier:

  12
x 26
----
  72
 24
----
 312

A quoi ressemble la multiplication en binaire?

   0111
x  0101
-------
   0111
  0000
 0111
-------
 100011

Remarquez quelque chose? Contrairement à la multiplication en décimal, où vous devez mémoriser le "tableau des temps", lors de la multiplication en binaire, vous multipliez toujours l'un des termes par 0 ou 1 avant de l'écrire dans les ajouts à la liste. Il n'y a pas besoin de table de temps. Si le chiffre du second terme est 1, vous ajoutez le premier terme. Si c'est 0, vous ne le faites pas. Notez également comment les ajouts sont progressivement décalés vers la gauche.

Si vous n'êtes pas sûr de cela, effectuez quelques multiplications binaires sur papier. Lorsque vous avez terminé, convertissez le résultat en décimal et vérifiez s'il est correct. Après en avoir fait quelques-unes, je pense que vous aurez une idée de la façon dont la multiplication binaire peut être implémentée à l’aide de décalages et d’ajouts.

59
Wayne Conrad

Tout le monde oublie l'évidence. Aucune multiplication n'est impliquée:

10^(log10(A) + log10(B))
25
Jim C

La question dit:

multiplier un nombre par 7 sans utiliser * opérateur

Ceci n'utilise pas *:

 number / (1 / 7) 

Modifier:
Ceci compile et fonctionne bien en C:

 int number,result;
 number = 8;
 result = number / (1. / 7);
 printf("result is %d\n",result);
19
Carlos Gutiérrez

Un décalage gauche entier est multiplié par 2, à condition qu'il ne déborde pas. Il suffit d’ajouter ou de soustraire une fois que vous vous en approchez.

19
int multiply(int multiplicand, int factor)
{
    if (factor == 0) return 0;

    int product = multiplicand;
    for (int ii = 1; ii < abs(factor); ++ii) {
        product += multiplicand;
    }

    return factor >= 0 ? product : -product;
}

Tu voulais multiplier sans *, tu l'as compris, mon pote!

17
user123456

Il est facile d'éviter l'opérateur '*':

mov eax, 1234h
mov edx, 5678h
imul edx

Aucun '*' en vue. Bien sûr, si vous voulez entrer dans l'esprit du jeu, vous pouvez également utiliser le vieux changement fidèle et ajouter un algorithme:

mult proc
; Multiplies eax by ebx and places result in edx:ecx
    xor ecx, ecx
    xor edx, edx
mul1:
    test ebx, 1
    jz  mul2
    add ecx, eax
    adc edx, 0
mul2:
    shr ebx, 1
    shl eax, 1
    test ebx, ebx
    jnz  mul1
done:
    ret
mult endp

Bien sûr, avec les processeurs modernes, tous (?) Ont des instructions de multiplication, mais lorsque le PDP-11 était brillant et nouveau, un code comme celui-ci a vu une réelle utilisation.

12
Jerry Coffin

Mathématiquement, multiplication distribue par addition. Cela signifie essentiellement:

x * (a + b + c ...) = (x * a) + (x * b) + (x * c) ...

Tout nombre réel (dans votre cas, 7), peut être présenté sous la forme d’une série d’additions (telle que 8 + (-1), car la soustraction n’est en réalité qu’une addition qui va dans le mauvais sens). Cela vous permet de représenter n'importe quelle instruction de multiplication comme une série équivalente d'instructions de multiplication, qui aboutira au même résultat:

x * 7
= x * (8 + (-1))
= (x * 8) + (x * (-1))
= (x * 8) - (x * 1)
= (x * 8) - x

L'opérateur décalage au niveau du bit ne fait que multiplier ou diviser un nombre par une puissance de 2. Tant que votre équation ne traite que de telles valeurs, le décalage de bits peut être utilisé pour remplacer toutes les occurrences de l'opérateur de multiplication.

(x * 8) - x = (x * 23) - x = (x << 3) - x

Une stratégie similaire peut être utilisée sur n’importe quel autre nombre entier, qu’il soit impair ou pair.

10
goldPseudo

C'est la même chose que x*8-x = x*(8-1) = x*7

8
Igor Zevaka

Tout nombre, pair ou impair, peut être exprimé par une somme de puissances de deux. Par exemple,

     1   2   4   8
------------------
 1 = 1
 2 = 0 + 2
 3 = 1 + 2
 4 = 0 + 0 + 4
 5 = 1 + 0 + 4
 6 = 0 + 2 + 4
 7 = 1 + 2 + 4
 8 = 0 + 0 + 0 + 8
11 = 1 + 2 + 0 + 8

Ainsi, vous pouvez multiplier x par n’importe quel nombre en effectuant le bon ensemble de décalages et d’ajouts.

 1x = x
 2x = 0 + x<<1
 3x = x + x<<1
 4x = 0 +  0   + x<<2
 5x = x +  0   + x<<2
11x = x + x<<1 +   0  + x<<3
7
benzado

Au bout du compte, la multiplication par un entier positif peut se faire comme suit:

int multiply(int a, int b) {
  int ret = 0;
  for (int i=0; i<b; i++) {
    ret += b;
  }
  return ret;
}

Efficace? À peine. Mais c'est correct (en tenant compte des limites sur les ints, etc.).

Donc, utiliser un décalage à gauche n'est qu'un raccourci pour multiplier par 2. Mais une fois que vous avez atteint la puissance maximale de 2 sous b, vous ajoutez simplement a le nombre de fois nécessaire, alors:

int multiply(int a, int b) {
  int ret = a;
  int mult = 1;
  while (mult <= b) {
    ret <<= 1;
    mult <<= 1;
  }
  while (mult < b) {
    ret += a;
  }
  return ret;
}

ou quelque chose proche de cela.

En d'autres termes, multiplier par 7.

  • Décalage gauche de 2 (fois 4). Le décalage gauche 3 est 8 ce qui est> 7;
  • Ajouter b 3 fois.
5
cletus

Un soir, je me suis rendu compte que je m'ennuyais énormément et je l'ai préparé:

#include <iostream>

typedef unsigned int uint32;

uint32 add(uint32 a, uint32 b) {
    do {
        uint32 s = a ^ b;
        uint32 c = a & b;
        a = s;
        b = c << 1;
    } while (a & b)
    return (a | b)
}

uint32 mul(uint32 a, uint32 b) {
    uint32 total = 0;
    do {
        uint32 s1 = a & (-(b & 1))
        b >>= 1; a <<= 1;
        total = add(s1, total)
    } while (b)
    return total;
}

int main(void) {
    using namespace std;
    uint32 a, b;

    cout << "Enter two numbers to be multiplied: ";
    cin >> a >> b;

    cout << "Total: " << mul(a,b) << endl;
    return 0;
}

Le code ci-dessus devrait être assez explicite, car j'ai essayé de le garder aussi simple que possible. Cela devrait fonctionner, plus ou moins, comme un processeur peut effectuer ces opérations. Le seul problème que je connaisse est que a n'est pas autorisé à être supérieur à 32 767 et que b n'est pas autorisé à être assez grand pour déborder a (c'est-à-dire que plusieurs débordements ne sont pas gérés, donc des résultats 64 bits ne sont pas possibles) . Il devrait même fonctionner avec des nombres négatifs, à condition que les entrées soient correctement reinterpret_cast<>.

4
greyfade
unsigned int Multiply(unsigned int m1, unsigned int m2)
{
    unsigned int numBits = sizeof(unsigned int) * 8; // Not part of the core algorithm
    unsigned int product = 0;
    unsigned int mask = 1;
    for(int i =0; i < numBits; ++i, mask = mask << 1)
    {
        if(m1 & mask)
        {
            product += (m2 << i);
        }
    }
    return product;
}
3
Andrew Shepherd

@ Wang, c'est une bonne généralisation. Mais voici une version légèrement plus rapide. Mais cela ne suppose pas de débordement et est non négatif.

int mult(int a, int b){
    int p=1;
    int rv=0;
    for(int i=0; a >= p && i < 31; i++){
        if(a & p){
            rv += b;
        }
        p = p << 1;
        b = b << 1;
    }

    return rv;
}

Il boucle au plus 1 + log_2 (a) fois. Pourrait être plus rapide si vous échangez a et b quand a> b. 

2
Apprentice Queue
unsigned int Multiply( unsigned int a, unsigned int b )
{
    int ret = 0;
    // For each bit in b
    for (int i=0; i<32; i++) {

        // If that bit is not equal to zero
        if (( b & (1 << i)) != 0) {

            // Add it to our return value
            ret += a << i;
        }
    }
    return ret;
}

J'ai évité le signe, parce que ce n'est pas le sujet du post. Ceci est une mise en œuvre de ce que Wayne Conrad a dit fondamentalement. Voici un autre problème si vous souhaitez essayer davantage d'opérations mathématiques de bas niveau.Project Euler est cool!

2
Buttink

Décaler et ajouter ne fonctionne pas (même avec une extension de signe) lorsque le multiplicande est négatif. La multiplication signée doit être faite en utilisant Codage de la cabine :

En partant de LSB , le passage de 0 à 1 correspond à -1; un passage de 1 à 0 vaut 1, sinon 0. Il existe également un bit supplémentaire implicite 0 en dessous du LSB.

Par exemple, le nombre 5 (0101) sera codé comme suit: (1) (- 1) (1) (- 1). Vous pouvez vérifier que c'est correct:

5 = 2 ^ 3 - 2 ^ 2 + 2 -1

Cet algorithme fonctionne également avec les nombres négatifs sous forme de complément à 2:

-1 dans le complément à 4 bits 2 est 1111. En utilisant l'algorithme de Booth: (1) (0) (0) (0) (- 1), où il n'y a pas d'espace pour le bit 1 le plus à gauche, on obtient: (0) (0) (- 1) qui est -1.

/* Multiply two signed integers using the Booth algorithm */
int booth(int x, int y)
{
    int prev_bit = 0;
    int result = 0;

    while (x != 0) {
        int current_bit = x & 0x1;
        if (prev_bit & ~current_bit) {
            result += y;
        } else if (~prev_bit & current_bit) {
            result -= y;
        }

        prev_bit = current_bit;

        x = static_cast<unsigned>(x) >> 1;
        y <<= 1;
    }

    if (prev_bit)
        result += y;

    return result;
}

Le code ci-dessus ne vérifie pas le débordement. Vous trouverez ci-dessous une version légèrement modifiée qui multiplie deux nombres de 16 bits et renvoie un nombre de 32 bits afin qu’elle ne déborde jamais:

/* Multiply two 16-bit signed integers using the Booth algorithm */
/* Returns a 32-bit signed integer */
int32_t booth(int16_t x, int16_t y)
{
    int16_t prev_bit = 0;
    int16_t sign_bit = (x >> 16) & 0x1;
    int32_t result = 0;
    int32_t y1 = static_cast<int32_t>(y);

    while (x != 0) {
        int16_t current_bit = x & 0x1;
        if (prev_bit & ~current_bit) {
            result += y1;
        } else if (~prev_bit & current_bit) {
            result -= y1;
        }

        prev_bit = current_bit;

        x = static_cast<uint16_t>(x) >> 1;
        y1 <<= 1;
    }

    if (prev_bit & ~sign_bit)
        result += y1;

    return result;
}
2
user3225538
import Java.math.BigInteger;

public class MultiplyTest {
    public static void main(String[] args) {
        BigInteger bigInt1 = new BigInteger("5");
        BigInteger bigInt2 = new BigInteger("8");
        System.out.println(bigInt1.multiply(bigInt2));
    }
}
2
lordstriker24

Java:
Considérant le fait que chaque nombre peut être scindé en deux:

1 = 2 ^ 0
2 = 2 ^ 1
3 = 2 ^ 1 + 2 ^ 0
...

Nous voulons obtenir x où:
x = n * m

Pour y parvenir, procédez comme suit:

1.   while m is greater or equal to 2^pow:
     1.1  get the biggest number pow, such as 2^pow is lower or equal to m
     1.2  multiply n*2^pow and decrease m to m-2^pow
2.   sum the results

Exemple d'implémentation utilisant la récursivité:

long multiply(int n, int m) {
    int pow = 0;
    while (m >= (1 << ++pow)) ;
    pow--;
    if (m == 1 << pow) return (n << pow);
    return (n << pow) + multiply(n, m - (1 << pow));
}

J'ai eu cette question lors du dernier entretien d'embauche et cette réponse a été acceptée.

EDIT: solution pour les nombres positifs

1
Michał Szewczyk

Si vous pouvez utiliser la fonction de journalisation:

public static final long multiplyUsingShift(int a, int b) {
    int absA = Math.abs(a);
    int absB = Math.abs(b);

    //Find the 2^b which is larger than "a" which turns out to be the 
    //ceiling of (Log base 2 of b) == numbers of digits to shift
    double logBase2 = Math.log(absB) / Math.log(2);
    long bits = (long)Math.ceil(logBase2);

    //Get the value of 2^bits
    long biggerInteger = (int)Math.pow(2, bits);

    //Find the difference of the bigger integer and "b"
    long difference = biggerInteger - absB;

    //Shift "bits" places to the left
    long result = absA<<bits;

    //Subtract the "difference" "a" times
    int diffLoop = Math.abs(a);
    while (diffLoop>0) {
        result -= difference;
        diffLoop--;
    }

    return (a>0&&b>0 || a<0&&b<0)?result:-result;
}

Si vous ne pouvez pas utiliser la fonction de journalisation:

public static final long multiplyUsingShift(int a, int b) {
    int absA = Math.abs(a);
    int absB = Math.abs(b);

    //Get the number of bits for a 2^(b+1) larger number
    int bits = 0;
    int bitInteger = absB;
    while (bitInteger>0) {
        bitInteger /= 2;
        bits++;
    }

    //Get the value of 2^bit
    long biggerInteger = (int)Math.pow(2, bits);

    //Find the difference of the bigger integer and "b"
    long difference = biggerInteger - absB;

    //Shift "bits" places to the left
    long result = absA<<bits;

    //Subtract the "difference" "a" times
    int diffLoop = absA;
    while (diffLoop>0) {
        result -= difference;
        diffLoop--;
    }

    return (a>0&&b>0 || a<0&&b<0)?result:-result;
}

J'ai trouvé cela plus efficace:

public static final long multiplyUsingShift(int a, int b) {
    int absA = Math.abs(a);
    int absB = Math.abs(b);

    long result = 0L;
    while (absA>0) {
        if ((absA&1)>0) result += absB; //Is odd
        absA >>= 1;
        absB <<= 1;
    }

    return (a>0&&b>0 || a<0&&b<0)?result:-result;
}

et encore une autre façon.

public static final long multiplyUsingLogs(int a, int b) {
    int absA = Math.abs(a);
    int absB = Math.abs(b);
    long result = Math.round(Math.pow(10, (Math.log10(absA)+Math.log10(absB))));
    return (a>0&&b>0 || a<0&&b<0)?result:-result;
}
1
Justin

En C #:

private static string Multi(int a, int b)
{
    if (a == 0 || b == 0)
        return "0";

    bool isnegative = false;

    if (a < 0 || b < 0)
    {
        isnegative = true;

        a = Math.Abs(a);

        b = Math.Abs(b);
    }

    int sum = 0;

    if (a > b)
    {
        for (int i = 1; i <= b; i++)
        {
            sum += a;
        }
    }
    else
    {
        for (int i = 1; i <= a; i++)
        {
            sum += b;
        }
    }

    if (isnegative == true)
        return "-" + sum.ToString();
    else
        return sum.ToString();
}
1
user270004

C'est la solution C99/C11 la plus simple pour les nombres positifs:

unsigned multiply(unsigned x, unsigned y) { return sizeof(char[x][y]); }
1
chqrlie

Une autre réponse hors du commun:

BigDecimal a = new BigDecimal(123);
BigDecimal b = new BigDecimal(2);
BigDecimal result = a.multiply(b);
System.out.println(result.intValue());
0
Igor Nadj

En utilisant la récursivité, nous pouvons multiplier deux entiers avec les contraintes données.

Pour multiplier x et y, ajoutez récursivement x fois y.

     #include<stdio.h>
     /* function to multiply two numbers x and y*/
     int multiply(int x, int y)
     {
        /* multiplied with anything gives */
        if(y == 0)
        return 0;

        /* Add x one by one */
        if(y > 0 )
        return (x + multiply(x, y-1));

        /* the case where y is negative */
        if(y < 0 )
        return -multiply(x, -y);
     }

     int main()
     {
       printf("\n %d", multiply(5, -11));
       getchar();
       return 0;
     }
0
Vikash VK

Boucle ça. Exécuter une boucle sept fois et itérer par le nombre que vous multipliez par sept.

Pseudocode:

total = 0
multiply = 34

loop while i < 7

    total = total + multiply

endloop
0
Thomas Winsnes
public static void main(String[] args) {
    System.out.print("Enter value of A -> ");
    Scanner s=new Scanner(System.in);
    double j=s.nextInt();
    System.out.print("Enter value of B -> ");
    Scanner p=new Scanner(System.in);
    double k=p.nextInt();
    double m=(1/k);
    double l=(j/m);
    System.out.print("Multiplication of A & B=> "+l);
}
0
aashish041090

Soit N le nombre que nous voulons multiplier par 7. 

N x 7 = N + N + N + N + N + N + N
N x 7 = N + N + N + N + N + N + N + (N - N)
N x 7 = (N + N + N + N + N + N + N + N) - N
N x 7 = 8xN - N

Comme nous le savons, le décalage à gauche d’un nombre par un, multipliez-le par 2. Par conséquent, multiplier un nombre par 8 équivaut à un décalage à droite par 3 bits.

N x 7 = (N << 3) - N 

J'ai trouvé cette description ici http://www.techcrashcourse.com/2016/02/c-program-to-multiply-number-by-7-bitwise-operator.html

J'espère que ça aide. 

0
Arun Kumar

Une approche JavaScript pour les nombres positifs 

function recursiveMultiply(num1, num2){
    const bigger = num1 > num2 ? num1 : num2; 
    const smaller = num1 <= num2 ? num1 : num2; 
    const indexIncrement = 1;
    const resultIncrement = bigger;

    return recursiveMultiplyHelper(bigger, smaller, 0, indexIncrement, resultIncrement)
}

function recursiveMultiplyHelper(num1, num2, index, indexIncrement, resultIncrement){
    let result = 0;
    if (index === num2){
        return result;
    } 

    if ((index+indexIncrement+indexIncrement) >= num2){
        indexIncrement = 1;
        resultIncrement = num1;
    } else{
        indexIncrement += indexIncrement;
        resultIncrement += resultIncrement;
    }

    result = recursiveMultiplyHelper(num1, num2, (index+indexIncrement), indexIncrement, resultIncrement);
    result += resultIncrement;
    console.log(num1, num2, index, result);

    return result;
}
0
Eli Silver
public static int multiply(int a, int b) 
{
    int temp = 0;
    if (b == 0) return 0;
    for (int ii = 0; ii < abs(b); ++ii) {
        temp = temp + a;
    }

    return b >= 0 ? temp : -temp;
}

public static int abs(int val) {

    return val>=0 ? val : -val;
}
0
Srinivas Kootikanti
package com.amit.string;

// Here I am passing two values, 7 and 3 and method getResult() will
// return 21 without use of any operator except the increment operator, ++.
//
public class MultiplyTwoNumber {

    public static void main(String[] args) {
        int a = 7;
        int b = 3;
        System.out.println(new MultiplyTwoNumber().getResult(a, b));
    }

    public int getResult(int i, int j) {
        int result = 0;

        // Check for loop logic it is key thing it will go 21 times
        for (int k = 0; k < i; k++) {
            for (int p = 0; p < j; p++) {
                result++;
            }
        }
        return result;
    }
}
0
Amit Sinha