Как я могу вычесть два целых числа в C без оператора -
?
Вычитание без знака минус в C
Ответы (16)
int a = 34;
int b = 50;
Вы можете преобразовать b в отрицательное значение, используя отрицание и добавив 1:
int c = a + (~b + 1);
printf("%d\n", c);
-16
Это отрицание знака дополнения до двух. Процессор делает это, когда вы используете оператор '-', когда вы хотите отрицать значение или вычитать его.
Преобразование float проще. Просто отмените первый бит (Shoosh дал вам пример, как это сделать).
РЕДАКТИРОВАТЬ:
Хорошо, парни. Я сдаюсь. Вот моя версия, независимая от компилятора:
#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 бит).
Понтус прав, дополнение 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 будет зависеть от ширины (количества «битов значения») интересующего вас типа целого числа; если не указано иное, у вас есть еще работа, чтобы выяснить это!
minusone
: minusone = ((~1 << 1) >> 1);
- person tomlogic; 09.06.2010
~1<<1
приводит к неопределенному поведению (целочисленное переполнение со знаком), а последующий >>1
имеет поведение, определяемое реализацией.
- person R.. GitHub STOP HELPING ICE; 13.08.2010
#define minusone (~1+1==0 ? ~1 : ~1+2==0 ? ~0 : ~(INT_MAX/2*2))
- person R.. GitHub STOP HELPING ICE; 13.08.2010
- + Без установки битов
- + Независимость от языка
- + Может быть настроен для разных типов чисел (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
minusone_int
. Вероятно, вы можете вызвать его напрямую, если знаете псевдоним.
- person Phil H; 10.06.2010
asin(1.0)
, поскольку он включает только точные аргументы.
- person R.. GitHub STOP HELPING ICE; 13.08.2010
-
.
- person S.S. Anne; 02.04.2020
a - b = c
ограничиваясь числовым пространством 0 ‹= c‹ (a + b):
(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, тогда это сработает.
Учитывая, что кодирование целых чисел для поддержки дополнения до двух не является обязательным в C, итерация выполняется до тех пор, пока не будет выполнено. Если они хотят, чтобы вы прыгали через пылающие обручи, не нужно действовать эффективно!
int subtract(int a, int b)
{
if ( b < 0 )
return a+abs(b);
while (b-- > 0)
--a;
return a;
}
Глупый вопрос ... наверное глупое интервью!
Если вы хотите сделать это для чисел с плавающей запятой, начните с положительного числа и измените его бит знака следующим образом:
float f = 3;
*(int*)&f |= 0x80000000;
// now f is -3.
float m = 4 + f;
// m = 1
Вы также можете сделать это для удвоений, используя соответствующее 64-битное целое число. в визуальной студии это, например, __int64.
Для вычитания в C двух целых чисел вам понадобится:
int subtract(int a, int b)
{
return a + (~b) + 1;
}
Я не верю, что есть простое и элегантное решение для чисел с плавающей запятой или двойных чисел, таких как целые числа. Таким образом, вы можете преобразовать свои числа с плавающей запятой в массивы и применить алгоритм, аналогичный смоделированному здесь
Я полагаю это
b - a = ~( a + ~b)
Тип сборки (аккумулятора):
int result = a;
result -= b;
Поскольку вопрос задан для целых чисел, а не int
s, вы можете реализовать небольшой интерпретатор, который использует церковные числа.
Создайте таблицу поиска для всех возможных случаев int-int!
Не испытано. Без использования дополнения до 2:
#include <stdlib.h>
#include <stdio.h>
int sillyNegate(int x) {
if (x <= 0)
return abs(x);
else {
// setlocale(LC_ALL, "C"); // if necessary.
char buffer[256];
snprintf(buffer, 255, "%c%d", 0x2d, x);
sscanf(buffer, "%d", &x);
return x;
}
}
Предполагая, что длина int
намного меньше 255, и передача snprintf / sscanf туда и обратно не приведет к неопределенному поведению (верно? Верно?).
Вычитание можно вычислить с помощью a - b == a + (-b).
Альтернатива:
#include <math.h>
int moreSillyNegate(int x) {
return x * ilogb(0.5); // ilogb(0.5) == -1;
}
Это будет работать с использованием целочисленного переполнения:
#include<limits.h>
int subtractWithoutMinusSign(int a, int b){
return a + (b * (INT_MAX + INT_MAX + 1));
}
Это также работает для поплавков (при условии, что вы создаете версию с плавающей запятой…)
return a + b * (INT_MIN + INT_MAX);
;-)
- person R.. GitHub STOP HELPING ICE; 13.08.2010
Для максимального диапазона любого типа данных дополнение до единицы обеспечивает отрицательное значение, уменьшенное на 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]. Спасибо ..... Может это вам поможет
Iff:
- Minuend больше или равно
0
, или - Вычитаемое больше или равно
0
, или - Вычитаемое и Минус меньше
0
умножьте Minuend на -1
и добавьте результат к Subtrahend:
SUB + (MIN * -1)
В противном случае умножьте Minuend на 1
и добавьте результат к Subtrahend.
SUB + (MIN * 1)
Пример (Попробуйте онлайн):
#include <stdio.h>
int subtract (int a, int b)
{
if ( a >= 0 || b >= 0 || ( a < 0 && b < 0 ) )
{
return a + (b * -1);
}
return a + (b * 1);
}
int main (void)
{
int x = -1;
int y = -5;
printf("%d - %d = %d", x, y, subtract(x, y) );
}
Вывод:
-1 - -5 = 4
-
, так что вряд ли это вообще решение!
- person Clifford; 09.06.2010
-
. Название немного вводит в заблуждение. - person RobertS supports Monica Cellio   schedule 30.05.2020