самый быстрый способ отрицать число

Сегодня утром я думал о том, что будет самым быстрым способом изменить число положительного на отрицательное и с отрицательного на положительное, конечно, самый простой способ может быть:

int a = 10;
a = a*(-1);

или же

int a = 10;
a = -a;

Но потом, я подумал, я так и сделаю, используя команды shift и указатели …
Что, действительно, можно было бы изменить знак значения, используя операторы сдвига и память?

29

Решение

Первый производит:

    .file   "optimum.c".def    ___main;    .scl    2;  .type   32; .endef
.text
.globl _main
.def    _main;  .scl    2;  .type   32; .endef
_main:
pushl   %ebp
movl    %esp, %ebp
andl    $-16, %esp
subl    $16, %esp
call    ___main
movl    $10, 12(%esp) ;i = 10
negl    12(%esp)      ;i = -i
movl    $0, %eax
leave
ret

Второй производит:

    .file   "optimum.c".def    ___main;    .scl    2;  .type   32; .endef
.text
.globl _main
.def    _main;  .scl    2;  .type   32; .endef
_main:
pushl   %ebp
movl    %esp, %ebp
andl    $-16, %esp
subl    $16, %esp
call    ___main
movl    $10, 12(%esp)   ;i = 10
negl    12(%esp)        ;i = -i
movl    $0, %eax
leave
ret

Тот же вывод! Никакой разницы в коде сборки не производится.

—————————РЕДАКТИРОВАТЬ, ОП ОТВЕТЫ, ИСПОЛЬЗУЕТ VC ++ 2012, INTEL ARCH ——————-

Скомпилировано с использованием cl optimum.c /Fa optimum.asm

; Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.30319.01

TITLE   C:\Users\Dell\Downloads\TTH\TTH\TTH\optimum.c
.686P
.XMM
include listing.inc
.model  flat

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC  _main
; Function compile flags: /Odtp
_TEXT   SEGMENT
_a$ = -4                        ; size = 4
_argc$ = 8                      ; size = 4
_argv$ = 12                     ; size = 4
_main   PROC
; File c:\users\dell\downloads\tth\tth\tth\optimum.c
; Line 4
push    ebp
mov ebp, esp
push    ecx
; Line 5
mov DWORD PTR _a$[ebp], 10          ; 0000000aH
; Line 6
mov eax, DWORD PTR _a$[ebp]
neg eax ;1 machine cycle!
mov DWORD PTR _a$[ebp], eax
; Line 7
xor eax, eax
; Line 8
mov esp, ebp
pop ebp
ret 0
_main   ENDP
_TEXT   ENDS
END

и со вторым подходом (а = а * -1)

; Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.30319.01

TITLE   C:\Users\Dell\Downloads\TTH\TTH\TTH\optimum.c
.686P
.XMM
include listing.inc
.model  flat

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC  _main
; Function compile flags: /Odtp
_TEXT   SEGMENT
_a$ = -4                        ; size = 4
_argc$ = 8                      ; size = 4
_argv$ = 12                     ; size = 4
_main   PROC
; File c:\users\dell\downloads\tth\tth\tth\optimum.c
; Line 4
push    ebp
mov ebp, esp
push    ecx
; Line 5
mov DWORD PTR _a$[ebp], 10          ; 0000000aH
; Line 6
mov eax, DWORD PTR _a$[ebp]
imul    eax, -1 ;1 instruction, 3 machine/cycles :|
mov DWORD PTR _a$[ebp], eax
; Line 7
xor eax, eax
; Line 8
mov esp, ebp
pop ebp
ret 0
_main   ENDP
_TEXT   ENDS
END
21

Другие решения

Используйте что-нибудь читаемое, например

a *= -1;

или же

a = -a;

Оставьте остальное оптимизатору.

37

Другие ответы правильно указали, что читабельность важнее:

  • Вы должны забыть о скорости и выбрать идиому, которая вам наиболее удобна для чтения.
  • Почти все компиляторы (с включенной оптимизацией) понимают, что a = -a а также a *= -1 являются точно такими же и будут испускать любой ассм, который они решат, будет наиболее эффективным на целевом процессоре, независимо от того, как вы его напишите. (например. Godbolt проводник компилятора для x86 gcc / MSVC / clang и ARM gcc.)
    • Но хотя MSVS 2012 (только в режиме отладки) использует одну инструкцию для каждой, они принимают 1 цикл для = -a и 3 для *= -1 на последних процессорах Intel, используя фактический imul инструкция.
  • Любая попытка сделать его быстрее сделает его менее читаемым и может сделать его медленнее.
  • Если вам нужно оптимизировать, вы должны начать с анализа сгенерированного кода и производительности.

Однако есть практическое преимущество к *= -1 идиома: вам нужно написать левую часть только один раз, она оценивается только один раз, а читатель должен прочитать ее только один раз! Это актуально, когда LHS длинный, сложный или дорогой или может иметь побочные эффекты:

(valid ? a : b)[prime_after(i++)] *= -1;
*look_up (input) *= -1;  // Where look_up may have side-effects
parity[state][(unsigned int)getc(stdin)] *= -1;
variable_with_a_long_explanatory_name *= -1;

И как только человек принял идиому, он склонен придерживаться ее в других ситуациях.

5

Предполагая, что процессор, по крайней мере, несколько компетентен и имеет sizeof(int) == sizeof(Cpu_register)тогда «сделать это число отрицательным» будет одна инструкция (обычно называется neg) [ну, может понадобиться и загрузка и сохранение значения, но если вы используете переменную для чего-то еще, она может остаться после загрузки и сохраниться только после одной …]

Умножение на -1 скорее всего медленнее чем a = -a;, но большинство компетентных компиляторов должны быть в состоянии сделать оба этих эквивалента.

Итак, просто напишите код четко, а остальное должно позаботиться о себе. Отрицание числа не является сложной операцией в большинстве процессоров. Если вы используете какой-то необычный обработчик, посмотрите на вывод компилятора и посмотрите, что он делает.

3

Также 0 — n

Gcc выдает команду «neg» для всех четырех случаев: -n, 0 — n, n * -1 и ~ n + 1

3

Решение с использованием языка высокого уровня

Подобные вопросы популярны в интервью и в мире конкурентного программирования.

Я приземлился здесь, исследуя больше решений для отрицания числа без использования оператора — или +.

За это :

  1. дополнить число с помощью оператора ~
  2. Затем добавьте 1 к числу, полученному на шаге 1, используя логику Half adder:
> int addNumbers(int x, int y)
>       {
>                    if(y==0)  return x; // carry is 0
>                    return addNumbers(x^y,(x&y)<<1);
>         }

Здесь x ^ y выполняет сложение битов и x&у ручки несут операцию

1

Ты можешь попробовать

int a = 10;
a= ~a+1;

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

-2
По вопросам рекламы [email protected]