为什么 _mm_mulhrs_epi16() 总是进行有偏舍入到正无穷大?

2024-02-24

有谁知道为什么pmulhrsw指示或

_mm_mulhrs_epi16(x) := RoundDown((x * y + 16384) / 32768)

总是向正无穷大舍入?对我来说,这对负数有很大的偏差,因为像 -0.6, 0.6, -0.6, 0.6, ... 这样的序列平均起来不会等于 0。

这种行为是有意还是无意?如果是故意的,那有什么用呢?有没有一种简单的方法可以减少偏见?

对我来说幸运的是,我只需更改操作顺序即可获得偏差较小的结果(我的函数是带符号的几何平均值):

__m128i ChooseSign(x, sign)
{
  return _mm_sign_epi16(x, sign)
}
signsDifferent = _mm_srai_epi16(_mm_xor_si128(a, b), 15)   // (a ^ b) >> 15
sign = _mm_andnot_si128(signsDifferent, a)    // !signsDifferent & a
//result = ChooseSign(sqrt(a * b), sign) * fraction   // biased
result = ChooseSign(sqrt(a * b) * fraction, sign)

一个最严重的错误。我在 上问了同样的问题英特尔开发者论坛 https://software.intel.com/en-us/forums/topic/540117andysem 纠正了我,指出行为是四舍五入到最接近的整数。

我错误地认为这是有偏见的,因为来自MSDN的公式 https://learn.microsoft.com/en-us/previous-versions/bb513995(v=vs.120)

was (x * y + 16384) >> 15。这看起来非常相似int(x + 0.5)舍入方法,我知道这种方法对负数有偏见并且畏缩。但我没有意识到负数的右移与除法和转换为 int 不同。

另外,它与我的非 SIMD 参考实现不匹配,结果证明这是有偏差的,因为我正在计算int(sum / 9.0f),向零舍入。

在质疑硬件中实现的某些东西的行为之前,我应该有更多的怀疑,因为硬件会经过严格的审查,因为int(x + 0.5)将是一个非常昂贵的错误。

_mm_mulhrs_epi16()仍然有一些偏差,总是将 x.5 舍入到+infinity。但这对我的申请来说不是什么大问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 _mm_mulhrs_epi16() 总是进行有偏舍入到正无穷大? 的相关文章

  • C++ 错误:“_mm_sin_ps”未在此范围内声明

    我正在尝试对将函数应用于数组的不同方法进行基准测试 why is mm sin ps在我的范围内不知道但是 mm sqrt ps is 我怎样才能让它知道 并且编译没有错误 include
  • 使用乘法执行整数除法[重复]

    这个问题在这里已经有答案了 查看编译器生成的 x86 程序集 我注意到 无符号 整数除法有时会实现为整数乘法 这些优化似乎遵循以下形式 value n gt value 0xFFFFFFFF n 1 0x100000000 例如 除以 9
  • 如何使用 JavaScript 四舍五入到任意数量的有效数字?

    我尝试了下面的示例代码 function sigFigs n sig if n 0 return 0 var mult Math pow 10 sig Math floor Math log n lt 0 n n Math LN10 1 r
  • SSE、内在函数和对齐

    我使用大量 SSE 编译器内在函数编写了一个 3D 矢量类 一切都工作正常 直到我开始使用 new 来实例化具有 3D 向量作为成员的类 我在发布模式下经历了奇怪的崩溃 但在调试模式下却没有 反之亦然 因此 我阅读了一些文章 并认为我需要将
  • 排列 SSE __m128i 寄存器内的字节

    我有以下问题 In m128i寄存器有 16 个 8bit 值 顺序如下 1 5 9 13 2 6 10 14 3 7 11 15 4 8 12 16 我想要实现的是有效地洗牌字节以获得此排序 1 2 3 4 5 6 7 8 9 10 11
  • 优化数组压缩

    假设我有一个数组k 1 2 0 0 5 4 0 我可以按如下方式计算掩码m k gt 0 1 1 0 0 1 1 0 仅使用掩码 m 和以下操作 左移 右移 And Or 加 减 乘 我可以将 k 压缩为以下形式 1 2 5 4 以下是我目
  • 使用 AVX 内在函数代替 SSE 并不能提高速度 - 为什么?

    我已经使用 Intel 的 SSE 内在函数相当长一段时间了 并取得了良好的性能提升 因此 我希望 AVX 内在函数能够进一步加速我的程序 不幸的是 直到现在情况并非如此 可能我犯了一个愚蠢的错误 所以如果有人能帮助我 我将非常感激 我使用
  • Ruby - 乘法问题

    我的输出是这样的 ruby 1 9 2 p290 011 gt 2 32 3 gt 6 959999999999999 我记得有一天在另一台机器上我得到了它就像 2 32 3 6 我的错误是什么 非常感谢您阅读本文 如果您确实想向下舍入为整
  • Numpy 的舍入方式与 Python 不同

    The code import numpy as np a 5 92270987499999979065 print round a 8 print round np float64 a 8 gives 5 92270987 5 92270
  • C# 中四舍五入到偶数

    我没有看到 Math Round 的预期结果 return Math Round 99 96535789 2 MidpointRounding ToEven returning 99 97 据我了解 MidpointRounding ToE
  • 使用 (float&)int 进行类型双关可以正常工作,(float const&)int 会像 (float)int 一样转换吗?

    VS2019 发布 x86 template
  • Karasuba算法递归过多

    我正在尝试用 c 实现 Karasuba 乘法算法 但现在我只是想让它在 python 中工作 这是我的代码 def mult x y b m if max x y lt b return x y bm pow b m x0 x bm x1
  • 如何自定义舍入形式

    我的问题可能看起来很简单 但仍然无法得到有效的东西 我需要自定义 Math round 舍入格式或其他格式以使其工作如下 如果数字是 1 6 他应该四舍五入到 1 如果大于或等于 1 7 他应该四舍五入到 2 0 对于所有其他带有 6 的小
  • MS Access 中的舍入

    VBA Access 中舍入的最佳方法是什么 我目前的方法是利用Excel方法 Excel WorksheetFunction Round 但我正在寻找一种不依赖Excel的方法 请注意 VBA Round 函数使用 Banker 舍入 将
  • 将字段中的位扩展到掩码中所有(重叠+相邻)集位的最快方法?

    假设我有 2 个名为 IN 和 MASK 的二进制输入 实际字段大小可能是 32 到 256 位 具体取决于用于完成任务的指令集 每次调用时两个输入都会改变 Inputs IN 1100010010010100 MASK 000111101
  • _mm_max_ss 在 clang 和 gcc 之间有不同的行为

    我正在尝试使用 clang 和 gcc 交叉编译一个项目 但在使用时发现一些奇怪的差异 mm max ss e g m128 a mm set ss std numeric limits
  • R中舍入单位的舍入数字[重复]

    这个问题在这里已经有答案了 我正在尝试按舍入单位对数字进行舍入 例如 value lt c 8 21 1 76 6 42 1 94 10 38 如果舍入单位为 0 2 则结果为 8 2 1 8 6 4 2 0 10 4 我怎样才能在R中做到
  • 为什么 Sql Server 2000 上的 TSQL 对小数点的舍入不一致?

    我正在尝试计算美元金额的折扣百分比 在 50 的情况下 有时你会得到半分钱 我需要将其四舍五入到最接近的一分钱 在Sql中 我的计算如下 round retail 0 5 2 0 如果我采用以下值 我会得到不同的结果 4 39 2 49 不
  • 汇编语言程序中连续两次相乘

    我正在使用 8086 模拟器以及 DOSBOX 和 MASM 我知道当我们将 8 位与 8 位相乘时 答案将是 16 位 al 8 bit ax 当我们将 16 位与 16 位相乘时 答案将是 32 位 ax 16 bit dx ax 但如
  • 如何在 AVX/AVX2 中递增向量

    我想使用内在函数来增加 SIMD 向量的元素 最简单的方法似乎是为每个元素加 1 如下所示 note vec inc之前已设置为1 vec mm256 add epi16 vec vec inc 但是是否有任何特殊指令来增加向量 类似于in

随机推荐