我们毫无疑问地知道,ISO C标准(以及C++,我认为,虽然我对C方面更感兴趣)允许签名数字的三个基础表示:
维基百科的条目表明,60年代的IBM 7090使用了标志/幅度,PDP-1,CDC 160A和UNIVAC 1100使用的是补充,所有这些都可以追溯到60年代.
是否有其他任何具有这些替代表示的C(或底层硬件)实现,这些实现比五十年前更新了(它们是什么)?
对于不再存在的机器,保持某种标准似乎有点浪费.
我有一个关于Delphi中位移行为的问题(或者更可能是错误报告)(在Borland Delphi 7中测试过).
目标:使用任意数字向右执行"算术"按位移位.
这意味着必须扩展符号位 - 如果设置了一个数字的最高有效位,则将从左侧填充二进制数,而不是0.
因此,算术右移后的数字"-1"必须保持相同的数字(所有位= 1),但是"逻辑移位"(总是用零填充数字)必须给出最大正整数(最大正有符号整数) ,为了正确)
我只在32位系统上测试过它(Windows); 而且,我需要它以32位整数显式工作.
当源编号存储在变量中时,看起来Delphi中存在带有"shr"的内部错误.
我的示例代码:
program bug;
{$APPTYPE CONSOLE}
var
I:Integer;
C:Cardinal;
begin
I := -1; // we’ll need that later
C := $FFFFFFFF;
Run Code Online (Sandbox Code Playgroud)
(这只是开始).接下来,让我们尝试一些"shr":
Writeln('0) ', -1 shr 1 );
Writeln('1) ', $FFFFFFFF shr 1 );
Run Code Online (Sandbox Code Playgroud)
"-1"是等效于"$ FFFFFFFF"的签名.似乎"shr"行为(算术或逻辑)基于源号是签名还是不签名(整数或基数)的事实.
输出是:
0) -1
1) 2147483647
Run Code Online (Sandbox Code Playgroud)
非常正确.然后我需要尝试手动将这些数字转换为整数或基数:
Writeln('2) ', Integer(-1) shr 1 );
Writeln('3) ', Integer($FFFFFFFF) shr 1 );
Writeln('4) ', Cardinal(-1) shr 1 );
Writeln('5) ', Cardinal($FFFFFFFF) shr 1 ); …Run Code Online (Sandbox Code Playgroud) 我有下一个代码:
std::cout << (-10 >> 1) << std::endl;
std::cout << (-9 >> 1) << std::endl;
std::cout << (-8 >> 1) << std::endl;
std::cout << (-7 >> 1) << std::endl;
std::cout << (-6 >> 1) << std::endl;
std::cout << (-5 >> 1) << std::endl;
std::cout << (-4 >> 1) << std::endl;
std::cout << (-3 >> 1) << std::endl;
std::cout << (-2 >> 1) << std::endl;
std::cout << (-1 >> 1) << std::endl;
Run Code Online (Sandbox Code Playgroud)
结果是:
-5
-5
-4
-4
-3
-3
-2
-2 …Run Code Online (Sandbox Code Playgroud) 我试图找到一种方法来执行间接左移/右移操作而不实际使用变量移位操作或任何分支.
我正在研究的特定PowerPC处理器有一个怪癖,即按常数立即移位,就像
int ShiftByConstant( int x ) { return x << 3 ; }
Run Code Online (Sandbox Code Playgroud)
是快速的,单操作的,超标量的,而变量的变换,如
int ShiftByVar( int x, int y ) { return x << y ; }
Run Code Online (Sandbox Code Playgroud)
是一个微编码操作,需要7-11个周期才能执行,而管道的其余部分都停止运行.
我想要做的是弄清楚哪个非微码整数PPC操作sraw解码然后单独发出它们.这对sraw自身的延迟没有帮助- 它将用六个替换一个操作 - 但在这六个操作之间我可以将一些工作双重调度到其他执行单元并获得净增益.
我似乎无法找到μopssraw解码到的任何地方 - 有谁知道如何用一系列常量移位和基本整数运算替换变量位移?(for循环或开关或其中带有分支的任何东西都不会起作用,因为分支惩罚甚至比微码惩罚更大,即使对于正确预测的分支也是如此.)
这无需在装配中回答; 我希望学习算法而不是特定的代码,所以用C语言或高级语言甚至伪代码的答案都会非常有用.
编辑:我应该补充一些说明:
PPC具有条件移动,因此我们可以假设存在无分支内部函数
int isel(a, b, c) { return a >= 0 ? b : c; }
Run Code Online (Sandbox Code Playgroud)
(如果你写出一个做同样事情的三元组,我会明白你的意思)
sraw.:-(我使用Visual Studio,Ubuntu的GCC,英特尔编译器,MinGW测试了右移.所有移位的符号位.我猜Xcode的GCC也是如此.
我知道这种行为是特定于实现的,但看起来所有主要的桌面/服务器编译器都实现了算术移位.是否有任何广泛使用的编译器不会在符号位中移位?
谢谢.
我想知道什么是检查签署类型进行操作时右移是算术的最简便的方式(例如:是否-2 >> 1是-1)在编译时.
我的想法是在编译时以某种方式检查它并能够检测到这一点,因此我可以编译该函数的不同版本(取决于运算符>>是否真的是算术移位).
通过阅读主题 验证C/C++签名的右移是特定编译器的算术吗?我想到了初始化旗帜的想法
static const bool is_arithmetic_rs = (((signed int)-1)>>1) == ((signed int)-1));
Run Code Online (Sandbox Code Playgroud)
并在运行时测试它像这样:
if (is_arithmetic_rs) {
// some fast algorithm using arithmetic right shifts (using >> operator)
} else {
// the same algorithm without arithmetic right shifts (much slower)
}
Run Code Online (Sandbox Code Playgroud)
但是,我希望每次都尽可能避免这种分支.为简单起见,我们假设我想实现一个可移动的算术右移; 如果每次调用函数时都必须检查这个,这会对性能造成巨大影响,所以我想在编译时这样做,如果可能的话.
如果没有可行的方法来进行此检查,是否有办法通过检查尽力而为的方式来完成此操作,例如使用ifdef检查特定的编译器/平台?
c ×4
c++ ×3
assembly ×1
bit-shift ×1
compile-time ×1
delphi ×1
delphi-7 ×1
integer ×1
iso ×1
performance ×1
portability ×1
powerpc ×1