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

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

      (x << 3) - x;

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

45
задан Peter Mortensen 29 November 2015 в 11:30
поделиться

19 ответов

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

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

2
ответ дан 26 November 2019 в 20:47
поделиться

Нет хорошего способа сделать это. Инструменты построены не с учетом этого. Вместо этого, вы должны объединить свои проекты как можно больше. Даже если это тот же объем кода, сборки будут работать в разы быстрее.

Вам придется переосмыслить идею о том, что для хорошей абстракции требуются отдельные проекты. Это кажется очень чистым способом добиться разделения. Но это не стоит цены с этой цепочкой инструментов. Вместо этого используйте языковые функции; классы, пространства имен и т. д.

-121--2257092-

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

Здесь - для очистки типов входных/выходных параметров только для считывателя , поскольку при условии, что все работает так, как ожидалось, это просто бесполезно для самого питона .

-121--4998528-

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

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 + регистрацией _ 2 (а) раз. Может быть быстрее, если поменять местами a и b, когда a > b.

2
ответ дан 26 November 2019 в 20:47
поделиться

С делегатами один объект может быть делегатом многих других объектов. Например, экземпляр MyController может быть делегатом NSTableView, NSTextField, NSWindow и любых других объектов, составляющих интерфейс. Это дает компактное место для размещения всего кода пользовательского интерфейса, связанного с одним разделом пользовательского интерфейса.

Если бы вы сделали это с подклассированием, вам пришлось бы создать один подкласс для каждого объекта, из которого вы хотели выполнить обратный вызов.

Также, это классический наследование против композиции вопрос

-121--4268575-

Возможно, вы слышали выражение «шесть сигм».

Это относится к плюс и минус 3 сигма (т.е. стандартные отклонения) вокруг среднего значения.

Все, что выходит за пределы диапазона «шесть сигм», может рассматриваться как отклонение.

Размышляя, я думаю, что 'шесть сигм' слишком широк.

В этой статье описывается, как это означает «3,4 дефектных деталей на миллион возможностей».

Это кажется довольно строгим требованием для целей сертификации. Только ты можешь решить, устраивает ли это тебя.

-121--2898879-

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

#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-разрядные результаты невозможны). Он должен работать даже с отрицательными числами при условии, что входные данные соответствующим образом интерпретируют заново _ приводят < > .

4
ответ дан 26 November 2019 в 20:47
поделиться

Когда дело доходит до него, умножение позитивным целым числом можно сделать подобное:

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). Левый Shift 3 - 8, который составляет> 7;
  • Добавить b 3 раза.
5
ответ дан 26 November 2019 в 20:47
поделиться

Несмотря на свое имя, getc возвращает int , а не char , чтобы он мог представлять все возможные значения символов и, кроме того, EOF (конец файла). Если getc возвращает char , не будет путь указать конец файла без использования одного из значений, которое может быть в файле.

Поэтому для исправления кода необходимо сначала изменить объявление char c; на int c; , чтобы оно могло удерживать маркер EOF при возврате. Затем необходимо изменить условие while loop для проверки EOF вместо NULL .

Также можно вызвать feof (fr) , чтобы проверить конец файла отдельно от чтения символа. Если вы сделали это, вы могли бы оставить c в качестве char , но вам пришлось бы вызвать feof () после того, как вы прочитали символ, но прежде, чем распечатать его, и использовать break , чтобы выйти из цикла.

-121--4213604-

Согласно документам , ни TCPServer, ни BaseRequestHandler не закрывают сокет, если не выдан соответствующий запрос. Реализации по умолчанию для handle () и finish () ничего не делают.

Может произойти несколько вещей:

  • Вы закрываете сам сокет или запрос, который его оборачивает, или вызываете сервер _ закрываете где-то.
  • Тайм-аут сокета мог быть сбит, и вы внедрили обработчик тайм-аута, который закрывает сокет.
  • Возможно, клиент закрывает сокет. Код действительно помог бы разобраться в этом.

Однако мое тестирование подтверждает ваши результаты. Как только вы вернетесь из дескриптора на сервере, будь то подключение через telnet или модуль сокета Python , ваше соединение будет закрыто удаленным хостом. Обработка активности сокета в петле внутри ручки, кажется, работает:

def handle(self):
    while 1:
        try:
            data = self.request.recv(1024)
            print self.client_address, "sent", data
        except:
            pass

Краткий поиск кода Google подтверждает, что это типичный способ обработки запроса: 1 2 3 4 . Честно говоря, для Python доступно множество других сетевых библиотек, на которые я мог бы посмотреть, если бы я столкнулся с отключением между абстракцией SocketServer и моими ожиданиями.

Образец кода, который я использовал для тестирования:

from SocketServer import BaseRequestHandler, TCPServer

class TestRequestHandler(BaseRequestHandler):
    def handle(self):
        data = self.request.recv(1024)
        print self.client_address, "sent", data
        self.request.send(data)

class TestServer(TCPServer):
    def __init__(self, server_address, handler_class=TestRequestHandler):
        TCPServer.__init__(self, server_address, handler_class)

if __name__ == "__main__":
    import socket

    address = ('localhost', 7734)
    server = TestServer(address)
    server.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-121--3090712-

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

19
ответ дан 26 November 2019 в 20:47
поделиться

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

     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
7
ответ дан 26 November 2019 в 20:47
поделиться

Другое мышление - снаружи ответа:

BigDecimal a = new BigDecimal(123);
BigDecimal b = new BigDecimal(2);
BigDecimal result = a.multiply(b);
System.out.println(result.intValue());
0
ответ дан 26 November 2019 в 20:47
поделиться

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

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 был блестящий и новый код, как это видел реальное использование.

12
ответ дан 26 November 2019 в 20:47
поделиться
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;
}

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

17
ответ дан 26 November 2019 в 20:47
поделиться

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

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

Как выглядит умножение в двоичной системе?

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

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

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

59
ответ дан 26 November 2019 в 20:47
поделиться

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

Умножьте номер на 7 без использования * Оператор

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

 number / (1 / 7) 

Редактировать:
Это компилирует и работает нормально в C:

 int number,result;
 number = 8;
 result = number / (1. / 7);
 printf("result is %d\n",result);
20
ответ дан 26 November 2019 в 20:47
поделиться

Каждый уходит с видом на очевидное. Умлипликация не участвует:

10^(log10(A) + log10(B))
25
ответ дан 26 November 2019 в 20:47
поделиться

Он такой же, как x*8-x = x*(8-1) = x*7

8
ответ дан 26 November 2019 в 20:47
поделиться
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
ответ дан 26 November 2019 в 20:47
поделиться

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

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

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

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

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

10
ответ дан 26 November 2019 в 20:47
поделиться

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

Псевдокод:

total = 0
multiply = 34

loop while i < 7

    total = total + multiply

endloop
0
ответ дан 26 November 2019 в 20:47
поделиться

В 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
ответ дан 26 November 2019 в 20:47
поделиться

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

-1
ответ дан 26 November 2019 в 20:47
поделиться

Уродливые и медленные и непрозрачные, но ...

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's complement
        rv -= b<<31;
    }
    return rv;
}
-3
ответ дан 26 November 2019 в 20:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: