正如评论所说,在这个例子中,你可以把它变成一个带比较的蒙面减法。+
andpd
. 只要从返回到所需的范围中减去一个以上,这就有效。
喜欢
const __m128d v2pi = _mm_set1_pd(TWOPI);
__m128d needs_range_reduction = _mm_cmpge_pd(vphase, v2pi);
__m128d offset = _mm_and_pd(needs_range_reduction, v2pi); // 0.0 or 2*Pi
vphase = _mm_sub_pd(vphase, offset);
实现一个实际的(缓慢的)
fmod
在不太担心最后几点意义的情况下,你会这样做的。
integer_quotient = floor(x/y)
(或者)
rint(x/y)
或
ceil
)
x - y * integer_quotient
.
floor
/
rint
/
塞尔
SSE4.1便宜
_mm_round_pd
或
_mm_floor_pd()
. 这将给出余数,它可以是负数,就像整数除法一样。
我相信有一些数值技术可以更好地避免在灾难性的取消之前从两个附近的数字中减去舍入误差。如果你关心精度,去检查一下。(使用)
double
向量当你不太关心精确性的时候是有点愚蠢的;不妨使用
float
得到每个向量两倍的工作量)。如果输入比模大得多,则会不可避免地损失精度,而最小化临时舍入误差可能非常重要。但否则,除非您关心结果中非常接近零的相对误差,否则精度只会是一个问题。
x
几乎是
y
. (接近零的结果,只剩下有效位的底端几位用于精确。)
如果没有SSE4.1,有一些技巧,比如加上然后减去一个足够大的数字。转换为整数和后整数对于
pd
因为压缩的转换指令也会解码为一些无序的UOP。更不用说32位整数不能覆盖
双重的
但是,如果你的输入量那么大,你就无法获得精确的减程。
如果你有
FMA
,可以避免
y * integer_quotient
乘法和Sub的一部分。
_mm_fmsub_pd
.