Подтвердить что ты не робот

Как я могу выполнить умножение без оператора '*'?

Я просто изучал некоторые основные вещи, поскольку я изучаю C. Я наткнулся на вопрос, чтобы умножить число на 7 без использования оператора *. В основном это похоже на

      (x << 3) - x;

Теперь я знаю об основных операциях манипулирования битами, но я не могу понять, как вы умножаете число на любое другое нечетное число без использования оператора *? Есть ли общий алгоритм для этого?

4b9b3361

Ответ 1

Подумайте, как вы умножаете десятичное число с помощью карандаша и бумаги:

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

Что такое умножение в двоичном формате?

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

Заметьте что-нибудь? В отличие от умножения в десятичном значении, когда вам нужно запомнить "таблицу раз" при умножении в двоичном формате, вы всегда умножаете одно из условий на 0 или 1, прежде чем записывать их в списках. Нет необходимости в таблице раз. Если цифра второго слагаемого равна 1, вы добавляете в первый член. Если это 0, вы этого не сделаете. Также обратите внимание, как слагаемые постепенно смещаются влево.

Если вы не уверены в этом, сделайте несколько бинарных умножений на бумаге. Когда вы закончите, верните результат обратно в десятичный и посмотрите, правильно ли он. После того, как вы сделали несколько, я думаю, вы поймете, как двоичное умножение может быть реализовано с помощью сдвигов и добавлений.

Ответ 2

Все игнорируют очевидное. Не используется умножение:

10^(log10(A) + log10(B))

Ответ 3

Целый левый сдвиг умножается на 2, если он не переполняется. Просто добавьте или вычтите по мере необходимости, как только вы приблизитесь.

Ответ 4

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

Вы хотели размножаться без *, вы получили его, приятель!

Ответ 5

В вопросе говорится:

умножьте число на 7 без использования * operator

Это не использует *:

 number / (1 / 7) 

Edit:
Это компилируется и отлично работает в C:

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

Ответ 6

Легко избежать оператора '*':

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

Нет '*' в поле зрения. Конечно, если вы хотели вникать в это, вы могли бы также использовать надежную старую смену и добавить алгоритм:

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

Конечно, с современными процессорами все (?) имеют инструкции умножения, но назад, когда PDP-11 был блестящим и новым, такой код видел реальное использование.

Ответ 7

Математически умножение распределяется по сложениям. По сути, это означает:

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

Любое действительное число (в вашем случае 7) может быть представлено в виде серии дополнений (например, 8 + (-1), так как вычитание действительно просто происходит неправильно). Это позволяет представить любой оператор умножения как эквивалентную последовательность операторов умножения, которая будет иметь тот же результат:

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

Оператор побитового сдвига по существу просто умножает или делит число на мощность 2. Пока ваше уравнение имеет дело только с такими значениями, смещение битов может использоваться для замены всего возникновения оператор умножения.

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

Аналогичная стратегия может быть использована для любого другого целого числа, и не имеет значения, является ли это нечетным или четным.

Ответ 8

Это то же самое, что и x*8-x = x*(8-1) = x*7

Ответ 9

Любое число, нечетное или четное, может быть выражено как сумма степеней двух. Например,

     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

Итак, вы можете умножить x на любое число, выполнив правильный набор сдвигов и добавив.

 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

Ответ 10

Когда дело доходит до этого, умножение на положительное целое можно сделать следующим образом:

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

Эффективное? Едва. Но он правильный (факторинг в пределах по ints и т.д.).

Таким образом, использование сдвига влево - это просто ярлык для умножения на 2. Но как только вы дойдете до наивысшей мощности-2 в b, просто добавьте a необходимое количество раз, поэтому:

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

или что-то близкое к этому.

Иными словами, умножить на 7.

  • Сдвиг влево на 2 (раз 4). Левый сдвиг 3 равен 8, который равен > 7;
  • Добавить b 3 раза.

Ответ 11

Однажды вечером я обнаружил, что мне очень скучно, и приготовил это:

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

Приведенный выше код должен быть совершенно понятным, поскольку я старался максимально упростить его. Он должен работать, более или менее, способом, которым процессор может выполнять эти операции. Единственная ошибка, о которой я знаю, заключается в том, что a не разрешается превышать 32 767, а b не допускается достаточно большим для переполнения a (то есть переполнение переполнения не обрабатывается, поэтому 64- битные результаты невозможны). Он должен работать даже с отрицательными числами, если входы соответствуют reinterpret_cast<>.

Ответ 12

O (log (b)) метод

public int multiply_optimal(int a, int b) {

    if (a == 0 || b == 0)
        return 0;
    if (b == 1)
        return a;
    if ((b & 1) == 0)
        return multiply_optimal(a + a, b >> 1);
    else
        return a + multiply_optimal(a + a, b >> 1);

}

Ресурсный код работает следующим образом:
Базовый блок:
если любое из чисел 0, произведение равно 0.
если b = 1, product = a.

Если b четно:
ab можно записать как 2a (b/2)
2a (b/2) = (a + a) (b/2) = (a + a) (b → 1) где ' → ' арифметический оператор правого сдвига в java.

Если b нечетно:
ab может быть записано как a + a (b-1)
а + а (б-1) = а + 2а (B-1)/2 = а + (а + а) (б-1)/2 = а + (а + а) ((б-1) → 1)
Так как b нечетно (b-1)/2 = b/2 = b → 1
Итак, ab = a + (2a * (b → 1))
ПРИМЕЧАНИЕ: каждый рекурсивный вызов b уменьшается наполовину = > O (log (b))

Ответ 13

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

Ответ 14

@Wang, это хорошее обобщение. Но вот немного более быстрая версия. Но он не предполагает переполнения и a неотрицателен.

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

Он будет занимать не более 1 + log_2 (a) раз. Может быть быстрее, если вы замените a и b, когда a > b.

Ответ 15

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

Я избегал знакового бита, потому что это не тема поста. Это реализация того, что сказал Уэйн Конрад. Еще одна проблема заключается в том, что вы хотите попробовать более низкие математические операции. Project Euler - это классно!

Ответ 16

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

Ответ 17

Сдвиг и добавление не работают (даже с расширением знака), когда мультипликация отрицательна. Подписанное умножение должно быть выполнено с помощью Бут-кодировка:

Начиная с LSB, изменение от 0 до 1 равно -1; изменение от 1 до 0 равно 1, в противном случае 0. Существует также неявный дополнительный бит 0 ниже LSB.

Например, номер 5 (0101) будет кодироваться как: (1) (- 1) (1) (- 1). Вы можете убедиться, что это правильно:

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

Этот алгоритм также работает с отрицательными числами в 2 форме дополнения:

-1 в 4-битном дополнении - 1111. Используя алгоритм Бута: (1) (0) (0) (0) (- 1), где нет места для самого левого бита 1, получаем: (0) (0) (0) (-1), которая равна -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;
}

Приведенный выше код не проверяет переполнение. Ниже приведена небольшая версия, которая умножает два 16-разрядных номера и возвращает 32-битное число, поэтому оно никогда не переполняется:

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

Ответ 18

Если вы можете использовать функцию журнала:

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

Если вы не можете использовать функцию журнала:

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

Я нашел это более эффективным:

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

и еще один способ.

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

Ответ 19

JAVA:. Учитывая тот факт, что каждое число можно разделить на степени двух:

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

Мы хотим получить x где:
x = n * m

Поэтому мы можем добиться этого, выполнив следующие шаги:

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

Пример реализации с использованием рекурсии:

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

Я получил этот вопрос на последнем собеседовании, и этот ответ был принят. EDIT: решение для положительных чисел

Ответ 20

Это простейшее решение C99/C11 для положительных чисел:

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

Ответ 21

Другой ответ на вопрос:

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

Ответ 22

В С#:

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

Ответ 23

Завершить его. Запустите цикл семь раз и итерации по числу, которое вы умножаете на семь.

псевдокод:

total = 0
multiply = 34

loop while i < 7

    total = total + multiply

endloop

Ответ 24

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

Ответ 25

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

Ответ 26

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

Ответ 27

Пусть N - число, которое мы хотим умножить на 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

Как мы знаем, левое смещение любого числа на один бит умножает его на 2. Следовательно, умножение любого числа на 8 эквивалентно праву, смещающему его на 3 бита

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

Я нашел это описание здесь http://www.techcrashcourse.com/2016/02/c-program-to-multiply-number-by-7-bitwise-operator.html

Надеюсь, это поможет.

Ответ 28

Очень просто, приятель... Каждый раз, когда вы оставляете сдвиг числа, это означает, что вы умножаете число на 2, что означает, что ответ равен (x < 3) -x.

Ответ 29

Чтобы умножить два числа без оператора *:

int mul(int a,int b) {
    int result = 0;
    if(b > 0) {
        for(int i=1;i<=b;i++){
            result += a;
        }
    }
    return result;
}

Ответ 30

Уродливый, медленный и непроверенный, но...

int mult(a,b){
    int i, rv=0;
    for(i=0; i < 31; ++i){
        if(a & 1<<i){
            rv += b << i;
        }
    }
    if(a & 1<<31){ // two complement
        rv -= b<<31;
    }
    return rv;
}