"signbit"与乘法检测到的符号变化,并将其与零进行比较
Sign change detected by `signbit` vs multiplication and comparizon with zero
我正在做一些实验,研究检测两个数字之间符号变化的方法。给定两个数字x
,y
,比如double
,我们想知道它们是否有不同的符号。我一直在模仿我通常看到的
x*y > 0
但这读起来并不完全像人们通常会做的那样。它读起来像是将两个数字相乘并检查结果的符号。然而,我们真正要做的是检查每个数字的符号,并根据通常的规则决定符号的变化。这与相似
signbit(x) ^ signbit(y)
我很好奇,看看必须将数字相乘是否会对表演产生一些影响。我本以为会有负面影响。
比较性能时,前者的计算速度更快。
我不明白为什么。是因为编译器能够用signbit(x) ^ signbit(y)
的语义替换x*y > 0
,即x
和y
的符号位的xor吗?解释是什么?
注意:signbit(x) ^ signbit(y)
不是要取代x*y
,而是整个x*y > 0
。
使用的代码:(在Visual Studio中编译)
#include <iostream>
#include <math.h>
#include <string>
#include <chrono>
using namespace std;
using namespace std::chrono;
#define N 1000000
int main() {
double x, y;
cout << "x = ";
cin >> x;
cout << "y = ";
cin >> y;
bool answer;
high_resolution_clock::time_point t1 = high_resolution_clock::now();
for (auto i = 0; i < N; ++i) {
answer = signbit(x) ^ signbit(y);
}
high_resolution_clock::time_point t2 = high_resolution_clock::now();
auto diffBit = std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count();
high_resolution_clock::time_point t3 = high_resolution_clock::now();
for (auto i = 0; i < N; ++i) {
answer = (x*y > 0);
}
high_resolution_clock::time_point t4 = high_resolution_clock::now();
auto diffMult = std::chrono::duration_cast<std::chrono::nanoseconds>(t4 - t3).count();
cout << "Bit function lasted = " << diffBit << endl;
cout << "Multiplication lasted = " << diffMult << endl;
}
您的测试并没有达到您想象的效果。
简化以删除尽可能多的代码:
#include <math.h>
#include <string>
#include <chrono>
#include <utility>
#include <tuple>
using namespace std;
using namespace std::chrono;
#define N 1000000
std::pair<double, double> getxy();
template<class T> void out(T t);
int main() {
double x, y;
std::tie(x,y) = getxy();
bool answer;
high_resolution_clock::time_point t1 = high_resolution_clock::now();
for (auto i = 0; i < N; ++i) {
answer = signbit(x) ^ signbit(y);
}
high_resolution_clock::time_point t2 = high_resolution_clock::now();
auto diffBit = std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count();
high_resolution_clock::time_point t3 = high_resolution_clock::now();
for (auto i = 0; i < N; ++i) {
answer = (x*y > 0);
}
high_resolution_clock::time_point t4 = high_resolution_clock::now();
auto diffMult = std::chrono::duration_cast<std::chrono::nanoseconds>(t4 - t3).count();
out(diffBit);
out(diffMult);
}
然后使用带有-O2的gcc5.3进行编译,生成以下汇编程序:
main:
pushq %rbp
pushq %rbx
subq $8, %rsp
call getxy()
call std::chrono::_V2::system_clock::now()
movq %rax, %rbx
movl $1000000, %eax
.L2:
subl $1, %eax
jne .L2
call std::chrono::_V2::system_clock::now()
subq %rbx, %rax
movq %rax, %rbp
call std::chrono::_V2::system_clock::now()
movq %rax, %rbx
call std::chrono::_V2::system_clock::now()
subq %rbx, %rax
movq %rbp, %rdi
movq %rax, %rbx
call void out<long>(long)
movq %rbx, %rdi
call void out<long>(long)
addq $8, %rsp
xorl %eax, %eax
popq %rbx
popq %rbp
ret
请注意,所有的计算都被忽略了,因为它们没有实质性的副作用。
第二个循环被完全忽略了。
编译时是否进行了优化?在C++11中,signbit是一个重载函数,因此除非它是内联的,否则会调用函数调用开销。
在任何情况下,表达式(x*y>0)都将比signbit从双精度中提取符号的操作简单得多,因此即使signbit是内联的,它也会产生比(x*y>0)更多的代码。我一点也不惊讶,更简单的表达更有效!
要深入了解发生了什么,请查看为每个表达式生成的代码的汇编。
相关文章:
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- 为什么比较运算符如此快速
- 我可以使用 g++ 进行三种比较 (<=>) 吗?
- 比较字符数组
- 将模板化的类型与C++中的某些类/类型进行比较
- C++自定义比较函数
- 如何比较自定义类的std::变体
- 多个If语句与使用逻辑运算符计算条件的单个语句的比较
- std::设置自定义比较器
- 布尔比较运算符是如何在C++中工作的
- C++将目录中的所有文件与::filesystem进行比较
- shell排序中的交换和比较
- 如何在C++中比较两个char数组
- catch框架有没有办法比较流或文件
- 从文件中读取多个字节,并将它们存储在C++中进行比较
- 智能指针作为无序映射键,并通过引用进行比较
- 比较if语句中的数组值和int值
- 对于循环变体比较
- 使用自定义比较函数使用std::sort()对矢量字符串进行排序时出现问题
- 比较两个大小不等的映射c++