在线组装;浮点数上的按位运算;这里出了什么问题?
Inline assembly; Bitwise operation on float; What's going awry here?
这段简单的代码就是我的问题:
扩展asm(gcc(;英特尔语法(-masm=英特尔(;平台-x86
它应该做的是:返回一个长度为1、符号(+-(与x相同的浮点值。
float signf(float x)
{
float r = 1;
asm volatile (
"and %1,0x80000000;"
"or %0,%1;"
:"=r"(r):"r"(x));
return r;
}
用公平掷骰子选择的任意随机数调用它可以得到:
signf of -1352353.3253: -5.60519e-045
内联asm的实际问题是您仅将r
声明为输出,因此编译器将优化初始化。您应该使用"+r"
约束而不是"=r"
约束,它应该可以工作。
一个更好的优化版本可能看起来像:
float signf(float x)
{
float r;
__asm__ __volatile__ (
"and %0, 0x80000000;"
"or %0, 0x3f800000;"
:"=r"(r):"0"(x));
return r;
}
请注意,此函数涉及float->int->float转换(通过内存(,这可能会影响性能。
上述代码的C版本是:
float signf(float x)
{
union { float f; int i; } tmp, res;
tmp.f = x;
res.f = 1;
res.i |= tmp.i & 0x80000000;
return res.f;
}
这为我生成了相同的代码(使用gcc 4.4.5(
简单的C方法return x < 0 ? -1 : 1;
生成完整的FPU代码,无需转换或内存访问(加载操作数除外(,因此可能会执行得更好。如果可用,它还使用fcmov
来避免分支。需要一些基准测试。
在C++11中有两个C++函数:
bool std::signbit (x);
http://en.cppreference.com/w/cpp/numeric/math/signbit
或者,
float f = std::copysign (1.0f, x);
http://en.cppreference.com/w/cpp/numeric/math/copysign
这似乎工作得很好(AT&T语法(:
float signf(float x)
{
float r = 1;
asm ("andl $0x80000000, %1n"
"torl %1, %0n"
:"+r"(r):"r"(x));
return r;
}
TBH,我会按照其他人的建议使用copysignf()
。您尝试执行的操作是不可移植的,因为它仅与能够执行此asm()
语句的IA-32平台和C++编译器绑定。
编辑1
顺便说一句,下面的版本工作原理相同(生成的指令与上面的asm()
语句几乎相同(,并且没有不可移植的东西和类型别名问题(与其他人建议的基于union
或基于reinterpret_cast<>
的版本不同(。
float signf3(float x)
{
unsigned u;
std::memcpy(&u, &x, sizeof (u)) ;
float r = 1.f;
unsigned uone;
std::memcpy(&uone, &r, sizeof (uone));
uone |= u & 0x80000000;
std::memcpy(&r, &uone, sizeof (r));
return r;
}
这个问题被标记为C++,所以我将提供两个C++建议,您可以让编译器优化:
return x < 0.0f ? -1.0f : 1.0f;
return x / std::abs(x); // I believe self-division shouldn't cause 'almost 1.0' numbers to be genereated
您不需要为此使用asm。下面是你试图做的事情(甚至是-0.0f的正确结果(
float signf(float x) {
bool sign=(0!=(*(reinterpret_cast<uint32_t *>(&x)) & 0x80000000));
return sign? -1.0f : 1.0f;
}
- 警告处理为错误这里有什么问题
- 努力将整数转换为链表。不知道我在这里做错了什么
- 我可以在这里替换什么,因为我不能在 C# 中使用隐式变量的 lambda 函数?
- 当我从下面的代码中删除关键字 virtual 时,它可以正常工作,否则会出现错误。在这里"virtual"字的意义是什么?
- 这里的 = 运算符有什么用法?
- 这里的字符串函数是什么意思
- 我正在尝试使用 while 循环从字符串中删除字母,直到没有字母。我在这里做错了什么?
- 我的C++合并排序代码不起作用。我在这里错过了什么?
- 这里的以下 OOP 结构是什么?
- reinterpret_cast和static_cast - 这里有什么区别?
- istringstream,num1 和 num2 在这里发生了什么?
- 编译器在这里做什么,允许在很少进行实际比较的情况下比较许多值
- C++ - *(int**) 地址?这里发生了什么?
- 使用大括号实例化 - 它是什么,为什么在这里使用它?
- & 符号在这里做什么?
- 我做错了什么?C++新手在这里
- 这里的矢量数组发生了什么?
- 新手在这里,到底什么是 acquireLock(),它的目的是什么?
- 这里(无效)first2++有什么意义?
- 类介绍 (c++) 项目希望我们创建两个构造函数,但它们都不需要任何参数 - 我应该在这里做什么?