조건부 부정 대신 abs() 또는 fabs()를 사용하는 이유는 무엇입니까?
왜C/C++, ",abs()
★★★★★★★★★★★★★★★★★」fabs()
다음 코드를 사용하지 않고 변수의 절대값을 찾을 수 있습니까?
int absoluteValue = value < 0 ? -value : value;
더 낮은 수준의 지시사항이 적은 것과 관련이 있나요?
이 제안하는 '복근'은'조건부 복근'과 하지 않습니다.std::abs
(오류)fabs
부동 소수점 번호에 대해서는, 예를 참조해 주세요.
#include <iostream>
#include <cmath>
int main () {
double d = -0.0;
double a = d < 0 ? -d : d;
std::cout << d << ' ' << a << ' ' << std::abs(d);
}
출력:
-0 -0 0
의 「」-0.0
★★★★★★★★★★★★★★★★★」0.0
는 동일한 실수 '0'을 나타냅니다. 이 차이는 결과가 어떻게 사용되는지에 따라 중요하거나 중요하지 않을 수 있습니다.0으로 하며, abs는 됩니다.-0.0
저는 개인적으로 어떤 "절대값"을 계산하기 위해 사용되는 모든 것이 이 행동과 일치해야 한다고 생각합니다.
정수의 경우 두 변형 모두 실행 시 및 동작에서 동일합니다.(실시간 예)
지.........std::abs
(또는 적합 C 등가물)은 정확하고 읽기 쉽다고 알려져 있으므로 항상 이러한 것을 선호해야 합니다.
가장 먼저 떠오르는 것은 가독성입니다.
다음 두 줄의 코드를 비교합니다.
int x = something, y = something, z = something;
// Compare
int absall = (x > 0 ? x : -x) + (y > 0 ? y : -y) + (z > 0 ? z : -z);
int absall = abs(x) + abs(y) + abs(z);
컴파일러는 하위 계층에서도 같은 작업을 수행할 수 있습니다.최소한 최신의 컴파일러를 사용할 수 있습니다.
그러나 적어도 부동 소수점에서는 무한대, NaN(not-a-number), 마이너스 0 등의 모든 특수한 경우를 처리하려면 수십 개의 줄을 쓰게 됩니다.
읽기만 아니라 읽기도 쉬워요.abs
경우 을 취하는 입니다.보다 작으면 부정한다고 읽는 것보다 절대값을 취하는 것이다.
인 는, 「stupid」라고 하는 코드에 대해서는, 보다 .a = (a < 0)?-a:a
으로 「」를 붙이기 if
) 그 수 ).
Clang(6.0 프리 릴리즈)과 gcc(4.9.2)는 모두 두 번째 케이스에 대해 더 나쁜 코드를 생성합니다.
제가 쓴 샘플은 다음과 같습니다.
#include <cmath>
#include <cstdlib>
extern int intval;
extern float floatval;
void func1()
{
int a = std::abs(intval);
float f = std::abs(floatval);
intval = a;
floatval = f;
}
void func2()
{
int a = intval < 0?-intval:intval;
float f = floatval < 0?-floatval:floatval;
intval = a;
floatval = f;
}
clang은 func1을 위해 다음 코드를 만듭니다.
_Z5func1v: # @_Z5func1v
movl intval(%rip), %eax
movl %eax, %ecx
negl %ecx
cmovll %eax, %ecx
movss floatval(%rip), %xmm0 # xmm0 = mem[0],zero,zero,zero
andps .LCPI0_0(%rip), %xmm0
movl %ecx, intval(%rip)
movss %xmm0, floatval(%rip)
retq
_Z5func2v: # @_Z5func2v
movl intval(%rip), %eax
movl %eax, %ecx
negl %ecx
cmovll %eax, %ecx
movss floatval(%rip), %xmm0
movaps .LCPI1_0(%rip), %xmm1
xorps %xmm0, %xmm1
xorps %xmm2, %xmm2
movaps %xmm0, %xmm3
cmpltss %xmm2, %xmm3
movaps %xmm3, %xmm2
andnps %xmm0, %xmm2
andps %xmm1, %xmm3
orps %xmm2, %xmm3
movl %ecx, intval(%rip)
movss %xmm3, floatval(%rip)
retq
g++ func1:
_Z5func1v:
movss .LC0(%rip), %xmm1
movl intval(%rip), %eax
movss floatval(%rip), %xmm0
andps %xmm1, %xmm0
sarl $31, %eax
xorl %eax, intval(%rip)
subl %eax, intval(%rip)
movss %xmm0, floatval(%rip)
ret
g++ func2:
_Z5func2v:
movl intval(%rip), %eax
movl intval(%rip), %edx
pxor %xmm1, %xmm1
movss floatval(%rip), %xmm0
sarl $31, %eax
xorl %eax, %edx
subl %eax, %edx
ucomiss %xmm0, %xmm1
jbe .L3
movss .LC3(%rip), %xmm1
xorps %xmm1, %xmm0
.L3:
movl %edx, intval(%rip)
movss %xmm0, floatval(%rip)
ret
두 번째 형태에서는 두 가지 케이스가 더 복잡하며, gcc의 경우 브랜치를 사용합니다.Clang은 더 많은 명령을 사용하지만 분기는 사용하지 않습니다.어떤 프로세서 모델이 더 빠른지 모르겠지만 명령을 더 많이 하는 것이 더 나은 경우는 거의 없습니다.
조건부 부정 대신 abs() 또는 fabs()를 사용하는 이유는 무엇입니까?
다양한 이유가 이미 언급되었지만 조건부 코드 이점을 고려하십시오.abs(INT_MIN)
피해야 합니다.
대신 조건부 코드를 사용하는 데는 충분한 이유가 있습니다.abs()
정수의 음의 절대값이 요구될 때
// Negative absolute value
int nabs(int value) {
return -abs(value); // abs(INT_MIN) is undefined behavior.
}
int nabs(int value) {
return value < 0 ? value : -value; // well defined for all `int`
}
양의 절대 함수가 필요한 경우value == INT_MIN
진짜 가능성이 있어요.abs()
매우 명확하고 속도도 뛰어나지만 코너 케이스에 실패하였습니다.다양한 대안
unsigned absoluteValue = value < 0 ? (0u - value) : (0u + value);
특정 아키텍처에서 조건부 브랜치보다 더 효율적인 로우 레벨 구현이 있을 수 있습니다.예를 들어, CPU는abs
명령 또는 분기 오버헤드 없이 부호 비트를 추출하는 방법.산술적 우측 시프트를 가정하면 레지스터 r이 음의 경우 -1로 채워지고 양의 경우 0으로 채워질 수 있습니다.abs x
될 수 있다(x+r)^r
(그리고 Mats Peterson의 답변을 보면 g++는 실제로 x86에서 이 작업을 수행합니다).
IEEE 부동소수점 상황에 대한 다른 답변이 있습니다.
라이브러리를 신뢰하지 않고 조건부 분기를 실행하도록 컴파일러에 지시하는 것은 시기상조일 수 있습니다.
...그리고 매크로로 만들 수 있다면, 원하지 않는 여러 가지 평가(측면 효과)를 받을 수 있습니다.고려사항:
#define ABS(a) ((a)<0?-(a):(a))
및 용도:
f= 5.0;
f=ABS(f=fmul(f,b));
로 확장될 것이다.
f=((f=fmul(f,b)<0?-(f=fmul(f,b)):(f=fmul(f,b)));
함수 호출은 의도하지 않은 부작용을 일으키지 않습니다.
복잡한 표현을 입력해 주세요.abs()
로 코드화하면expr > 0 ? expr : -expr
전체 표현을 세 번 반복해야 되고, 두 번 평가됩니다.
또한 두 결과(대장 전후)가 다른 유형(예:signed int
/unsigned int
return 스테이트먼트에서의 사용을 디세블로 합니다.물론 임시 변수를 추가할 수도 있지만, 이 경우 일부만 해결되며 어떤 방식으로도 더 나은 것은 아닙니다.
abs()의 배후에 있는 의도는 "(무조건) 이 숫자의 부호를 양수로 설정하는 것입니다.현재 숫자의 상태에 근거해 조건부로 실장할 필요가 있다고 해도, 보다 복잡한 「이…이…이…이…이」가 아니라, 단순한 「이」라고 생각할 수 있는 것이 도움이 될 것입니다.
컴파일러가 abs()와 조건부 부정이 모두 같은 목표를 달성하려고 시도하고 있다고 판단할 수 없다고 가정하면 조건부 부정은 비교 명령, 조건부 점프 명령 및 이동 명령으로 컴파일되는 반면 abs()는 실제 절대값 명령 집합으로 컴파일됩니다.t 그런 것, 혹은 조금 현명하고, 기호 비트를 제외하고 모든 것을 동일하게 유지합니다.위의 명령어는 보통 1사이클이기 때문에 abs()를 사용하는 것은 적어도 조건부 부정보다 빠를 수 있습니다(컴파일러는 조건부정을 사용할 때 절대값을 계산하려고 하는 것을 인식하고 절대값 명령을 생성할 수 있기 때문입니다).컴파일된 코드에 변경이 없는 경우에도 조건부정보다 abs()가 읽기 쉬워집니다.
언급URL : https://stackoverflow.com/questions/48608993/why-use-abs-or-fabs-instead-of-conditional-negation
'source' 카테고리의 다른 글
대형 프로젝트에서 선호하는 C/C++ 헤더 정책은 무엇입니까? (0) | 2022.07.31 |
---|---|
Eclipse의 Import된 Maven 프로젝트가 기본적으로 Java 1.6 대신 Java 1.5를 사용하는 이유는 무엇이며, 어떻게 하면 그렇지 않은지 확인할 수 있습니까? (0) | 2022.07.31 |
문자열을 분할하고 구분 기호를 유지하는 방법 (0) | 2022.07.31 |
Vue.js 데이터 테이블이 첫 번째 열에 데이터만 표시됨 (0) | 2022.07.31 |
vuex와 socketio를 사용하여 실시간 크러드를 만드는 방법 (0) | 2022.07.31 |