Вычитание без знака минус - PullRequest
11 голосов
/ 31 марта 2009

Как вычесть два целых числа в C без оператора -?

Ответы [ 16 ]

16 голосов
/ 31 марта 2009
int a = 34;
int b = 50;

Вы можете преобразовать b в отрицательное значение, используя отрицание и добавив 1:

int c = a + (~b + 1);

printf("%d\n", c);

-16

Это отрицание знака дополнения до двух. Процессор делает это, когда вы используете оператор «-», когда хотите отменить значение или вычесть его.

Конвертировать поплавок проще. Просто отрицать первый бит (шош привел тебе пример, как это сделать).

EDIT:

Хорошо, ребята. Я сдаюсь. Вот моя независимая от компилятора версия:

#include <stdio.h>

unsigned int adder(unsigned int a, unsigned int b) {
    unsigned int loop = 1;
    unsigned int sum  = 0;
    unsigned int ai, bi, ci;

    while (loop) {
        ai = a & loop;
        bi = b & loop;
        ci = sum & loop;
        sum = sum ^ ai ^ bi;      // add i-th bit of a and b, and add carry bit stored in sum i-th bit
        loop = loop << 1;
        if ((ai&bi)|(ci&ai)|(ci&bi)) sum = sum^loop; // add carry bit
    }

    return sum;
}

unsigned int sub(unsigned int a, unsigned int b) {
    return adder(a, adder(~b, 1));    // add negation + 1 (two's complement here)
}


int main() {
    unsigned int a = 35;
    unsigned int b = 40;

    printf("%u - %u = %d\n", a, b, sub(a, b)); // printf function isn't compiler independent here

    return 0;
}

Я использую unsigned int, чтобы любой компилятор относился к нему одинаково.

Если вы хотите вычесть отрицательные значения, сделайте это так:

 unsgined int negative15 = adder(~15, 1);

Теперь мы полностью независимы от соглашений о подписанных значениях. В моем подходе результат все целые будут храниться как два дополнения - так что вы должны быть осторожны с большими (они должны начинаться с 0 бит).

12 голосов
/ 31 марта 2009

Pontus прав, дополнение 2 не предписано стандартом C (даже если это де-факто аппаратный стандарт). +1 за творческие ответы Фила; Вот другой подход к получению -1 без использования стандартной библиотеки или оператора -.

C требует трех возможных представлений, так что вы можете прослушать, что находится в действии, и получить разные -1 для каждого:

negation= ~1;
if (negation+1==0)                 /* one's complement arithmetic */
    minusone= ~1;
else if (negation+2==0)            /* two's complement arithmetic */
    minusone= ~0;
else                               /* sign-and-magnitude arithmetic */
    minusone= ~0x7FFFFFFE;

r= a+b*minusone;

Значение 0x7FFFFFFFE будет зависеть от ширины (числа «значений битов») типа целого числа, которое вас интересует; если не указано, у вас есть больше работы, чтобы выяснить это!

7 голосов
/ 31 марта 2009
  • + Без настройки бита
  • + Не зависит от языка
  • + Можно настроить для различных типов чисел (int, float и т.д.)
  • - Почти наверняка не ваш домашний ответ на C (который, вероятно, будет о битах)

Развернуть a-b:

a-b = a + (-b)
    = a + (-1).b

Производство -1:

float:             pi = asin(1.0);
(with    minusone_flt = sin(3.0/2.0*pi);
math.h)           or  = cos(pi)
                  or  = log10(0.1)
complex: minusone_cpx = (0,1)**2; // i squared
integer: minusone_int = 0; minusone_int--; // or convert one of the floats above
4 голосов
/ 31 марта 2009

Учитывая, что кодирование целых чисел для поддержки дополнения до двух не требуется в C, выполняйте итерацию до завершения. Если они хотят, чтобы вы прыгали через горящие обручи, не нужно быть эффективным!

int subtract(int a, int b)
{
  if ( b < 0 )
    return a+abs(b);
  while (b-- > 0)
    --a;
  return a;
}

Глупый вопрос ... возможно, глупое интервью!

3 голосов
/ 31 марта 2009

+ Без настройки бита + Не зависит от языка + Независимо от типа номера (int, float и т. Д.) - Требуется a> b (т.е. положительный результат) - Почти наверняка не ваш домашний ответ на C (который, вероятно, будет о битах)
a - b = c

ограничивая себя пространством чисел 0 <= c <(a + b): </p>

       (a - b) mod(a+b) = c mod(a+b)
a mod(a+b) - b mod(a+b) = c mod(a+b)

упрощение второго члена:

(-b).mod(a+b) = (a+b-b).mod(a+b)
              = a.mod(a+b)

замещающий:

a.mod(a+b) + a.mod(a+b) = c.mod(a+b)
2a.mod(a+b) = c.mod(a+b)

если b> a, то b-a> 0, поэтому:

c.mod(a+b) = c
c = 2a.mod(a+b)

Итак, если a всегда больше, чем b, то это сработает.

3 голосов
/ 31 марта 2009

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

float f = 3;
*(int*)&f |= 0x80000000;
// now f is -3.
float m = 4 + f; 
// m = 1

Вы также можете сделать это для двойников, используя соответствующее 64-битное целое число. в визуальной студии это, например, __int64.

1 голос
/ 31 марта 2009

Сборка (аккумулятор) стиль:

int result = a;
result -= b;
1 голос
/ 31 марта 2009

Полагаю, это

b - a = ~ (a + ~ b)

1 голос
/ 31 марта 2009

Для вычитания в С двух целых чисел вам нужно только:

int subtract(int a, int b)
{
    return a + (~b) + 1;
}

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

0 голосов
/ 06 марта 2017

Для максимального диапазона любого типа данных одно дополнение обеспечивает отрицательное значение, уменьшенное на 1, до любого соответствующего значения. например:
~ 1 --------> -2
~ 2 ---------> -3
и так далее ... Я покажу вам это наблюдение, используя небольшой фрагмент кода

#include<stdio.h>
int main()
{
   int a , b;
   a=10;
   b=~a; // b-----> -11    
   printf("%d\n",a+~b+1);// equivalent to a-b
   return 0;
}

Выход: 0
Примечание. Это действительно только для диапазона типов данных. означает, что для типа данных int это правило будет применяться только для значений диапазона [от -2 147 483 648 до 2 147 483 647]. Спасибо ..... может это вам поможет

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...