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?
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.
Tout le monde oublie l'évidence. Aucune multiplication n'est impliquée:
10^(log10(A) + log10(B))
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);
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.
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!
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.
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.
C'est la même chose que x*8-x = x*(8-1) = x*7
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
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.
b
3 fois.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<>
.
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;
}
@ 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.
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!
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;
}
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));
}
}
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
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;
}
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();
}
C'est la solution C99/C11 la plus simple pour les nombres positifs:
unsigned multiply(unsigned x, unsigned y) { return sizeof(char[x][y]); }
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());
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;
}
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
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);
}
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.
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;
}
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;
}
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;
}
}