假设我们有两个寄存器长度2有符号1整数,例如a
和
b
。我们想要计算值,向上、向下、接近零或远离零,无论哪种方式更容易(即,我们不关心取整方向)。
结果是另一个寄存器长度有符号整数(很明显,平均值必须在寄存器长度有符号整数的范围内)。
执行此计算的最快方法是什么?
您可以选择两个整数最初在哪个寄存器中,以及平均值最终在哪个寄存器中。
脚注1:对于无符号整数,我们可以在两条指令中完成。这可能是最快的方式,尽管在Intel CPU上通过进位旋转的速度超过1 uop。但是只有一对,当计数只有1时。一个问题的答案
add rdi, rsi
rcr rdi, 1
这两个数字从rdi和rsi开始,平均值以rdi结束。但对于有符号数字,
-13将设置CF,并将a旋转到符号位。没有给出正确答案。
脚注2:我指定了寄存器长度有符号整数,因此我们不能简单地使用
movsxd
或cdqe
指令对扩展整数进行签名。
我找到的最接近解决方案使用了四条指令,其中一条是rcr,在Intel上是3个UOP,在AMD Zen上是1个(https://uops.info/):
add rdi, rsi
setge al
sub al, 1
rcr rdi, 1
我认为更短的解决方案可能在于以某种方式组合中间的两条指令,即执行
CF←SF≠OF
。
我见过这个问题,但这不是x86特有的,而且没有一个答案像我的解决方案那样好。
作为外部答案,考虑pavg指令系列。
我说“外面”,因为这可能是你不能接受的。它假设值是无符号8位或16位,并且在SSE寄存器中,这当然也需要SSE。我之所以提到它,主要是因为它是x86的涂油等效于其他ISA中的平均指令。
在它的辩护中,SSE现在无处不在,甚至在x86-64上也有保证。此外,该指令是1个周期,如果您愿意,实际上可以同时执行4个周期。最重要的是,与原始解决方案不同,它还可以正确处理溢出问题。
请注意,可以使用无符号例程来实现有符号例程,尽管通常正确解释溢出问题是一场噩梦。然而,你目前的解决方案似乎已经在这方面被打破了。
根据我们如何解释您宽松的舍入要求,以下内容可能是可以接受的:
sar rdi, 1
sar rsi, 1
adc rdi, rsi
试戴锁销
这有效地将两个输入除以2,添加结果,如果rsi
是奇数,则再添加1。(请记住,sar
根据移出的最后一位设置进位标志。)
由于sar
舍入为负无穷大,因此该算法的结果是:
>
如果rdi和rsi都是偶数或奇数,则完全正确
如果rdi为奇数,rsi为偶数,则向下舍入(朝向负无穷大)
如果rdi是偶数而rsi是奇数,则向上舍入(朝向加无穷大)
另外,对于随机输入,平均舍入误差为零。
一个典型的CPU上应该有3个UOP,延迟为2个周期,因为两个sar是独立的。
存在一个“3个长整数的平均值”问题,该问题特别涉及三个有符号整数的平均值的有效计算。 然而,使用无符号整数允许进行不适用于前一个问题中所述场景的额外优化。这个问题是关于三个无符号整数的平均值的有效计算,其中平均值向零舍入,也就是说,用我想要计算的数学术语⌊ (a b c)/3⌋. 计算该平均值的简单方法是 首先,现代优化编译器将除法转换为带倒数加移位的乘法,模运算转换为反乘法和减法,其中反乘法可以
我有3个非常大的有符号整数。 我想计算它们的截断平均值。预期平均值是,即。 不可能计算为: 注:我读了所有关于2个数字的平均值的问题,但我不知道该技术如何应用于3个数字的平均值。 使用BigInteger将非常容易,但假设我不能使用它。 如果我转换为双精度,那么,当然,我会失去精度: 如果我转换为,它可以工作,但也让我们假设我不能使用它。 问题:有没有一种方法可以仅使用长类型来计算3个非常大整数的
我阅读了Kip IRVINE的《x86处理器的汇编语言》一书,他写道: 将较小的值复制到较大的值 虽然MOV不能直接将数据从较小的操作数复制到较大的操作数,但程序员可以创建变通方法。假设计数(无符号,16位)必须移动到ECX(32位)。我们可以将ECX设置为零,并将计数移动到CX: 如果我们用一个等于-16的有符号整数尝试相同的方法,会发生什么? ECX(65,520)中的值与-16完全不同。另一
问题内容: 我想要一种计算Java中任意两个整数x,y的方法。如果x + y> Integer.MAX_VALUE或<Integer.MIN_VALUE,那么幼稚的方法就会遇到问题。 番石榴 使用此技术: …但这朝着负无穷大方向舍入,这意味着例程与{-1,-2}之类的天真方式不同(给出-2而不是-1)。 是否有任何相应的例程截断为0? “仅使用”不是我想要的答案,因为我也想要一种适用于长时间输入的
给出了一个由N个整数组成的非空零索引数组。一对整数(P,Q),如0≤ P 包含以下示例片段: 切片(1,2),其平均值为(2 2)/2=2 目标是找到平均值最小的切片的起始位置。 写一个函数: 即,给定一个由N个整数组成的非空零索引数组A,返回具有最小平均值的切片的起始位置。如果有多个具有最小平均值的切片,您应该返回这样一个切片的最小起始位置。 例如,给定数组A,这样: 如上所述,函数应该返回1。
希望这对你来说是有意义的,我很乐意更详细地解释这个问题。