相关疑难解决方法(0)

解释了将double转换为32位int的快速方法

在阅读Lua的源代码时,我注意到Lua使用a将a macro舍入double到32位int.我解压缩了macro,它看起来像这样:

union i_cast {double d; int i[2]};
#define double2int(i, d, t)  \
    {volatile union i_cast u; u.d = (d) + 6755399441055744.0; \
    (i) = (t)u.i[ENDIANLOC];}
Run Code Online (Sandbox Code Playgroud)

这里ENDIANLOC定义为endianness,0对于little endian,1对于big endian.Lua小心翼翼地处理字节序.t代表整数类型,如intunsigned int.

我做了一些研究,并且有一个更简单的格式macro使用相同的想法:

#define double2int(i, d) \
    {double t = ((d) + 6755399441055744.0); i = *((int *)(&t));}
Run Code Online (Sandbox Code Playgroud)

或者以C++风格:

inline int double2int(double d)
{
    d += 6755399441055744.0;
    return …
Run Code Online (Sandbox Code Playgroud)

c c++ floating-point performance

169
推荐指数
2
解决办法
1万
查看次数

我可以使用AVX FMA单元进行精确的52位整数乘法吗?

AXV2没有任何整数乘法,其源大于32位.它提供32 x 32 - > 32乘法,以及32 x 32 - > 64乘以1,但没有64位源.

假设我需要一个输入大于32位但小于或等于52位的无符号乘法 - 我可以简单地使用浮点DP乘法或FMA指令,并且当整数输入和输出时输出将是位精确的结果可以用52或更少的比特表示(即,在[0,2 ^ 52-1]范围内)?

如果我想要产品的所有104位更一般的情况怎么样?或整数乘积超过52位的情况(即,产品在位索引中的非零值> 52) - 但我只想要低52位?在后一种情况下,它MUL会给我更高的位并舍去一些低位(也许这就是IFMA帮助的?).

编辑:事实上,根据这个答案,也许它可以做任何高达2 ^ 53的事情- 我忘记了1在尾数之前隐含的领先有效地给了你一点.


1有趣的是,正如Mysticial 在评论中所解释的那样,64位产品PMULDQ操作的延迟是32位PMULLD版本的一半,吞吐量是32位版本的两倍.

floating-point x86 simd avx2 fma

14
推荐指数
1
解决办法
1278
查看次数

关于 uint64 到 double 的转换:为什么右移 1 后代码更简单?

为什么AsDouble1比 更简单AsDouble0

// AsDouble0(unsigned long):                          # @AsDouble0(unsigned long)
//         movq    xmm1, rdi
//         punpckldq       xmm1, xmmword ptr [rip + .LCPI0_0] # xmm1 = xmm1[0],mem[0],xmm1[1],mem[1]
//         subpd   xmm1, xmmword ptr [rip + .LCPI0_1]
//         movapd  xmm0, xmm1
//         unpckhpd        xmm0, xmm1                      # xmm0 = xmm0[1],xmm1[1]
//         addsd   xmm0, xmm1
//         addsd   xmm0, xmm0
//         ret
double AsDouble0(uint64_t x) { return x * 2.0; }

// AsDouble1(unsigned long):                          # @AsDouble1(unsigned long)
//         shr     rdi
//         cvtsi2sd        xmm0, rdi …
Run Code Online (Sandbox Code Playgroud)

c++ assembly sse x86-64 floating-point-conversion

9
推荐指数
2
解决办法
288
查看次数

如何使用SSE执行uint32/float转换?

在SSE中有一个函数_mm_cvtepi32_ps(__m128i input),它接受32位宽的有符号整数(int32_t)的输入向量并将它们转换为floats.

现在,我想将输入整数解释为未签名.但是没有功能_mm_cvtepu32_ps,我找不到一个实现.你知道我在哪里可以找到这样的功能,或者至少对实现有所暗示吗?为了说明结果的差异:

unsigned int a = 2480160505; // 10010011 11010100 00111110 11111001   
float a1 = a; // 01001111 00010011 11010100 00111111;  
float a2 = (signed int)a; // 11001110 11011000 01010111 10000010
Run Code Online (Sandbox Code Playgroud)

c x86 sse simd

7
推荐指数
2
解决办法
2057
查看次数

如何正确比较整数和浮点值?

如何以正确的方式比较整数和浮点值?

内置比较运算符在某些情况下会给出错误的结果,例如:

#include <iomanip>
#include <iostream>

int main()
{
    long long a = 999999984306749439;
    float     b = 999999984306749440.f; // This number can be represented exactly by a `float`.

    std::cout << std::setprecision(1000);
    std::cout << a << " < " << b << " = " << (a < b) << '\n';
    // Prints `999999984306749439 < 999999984306749440 = 0`, but it should be `1`.
}
Run Code Online (Sandbox Code Playgroud)

显然,比较运算符在实际比较它们之前将两个操作数都转换为相同类型。在这里,lhs转换为float,这会导致精度损失,并导致错误的结果。

即使我了解发生了什么,也不确定如何解决此问题。


免责声明:该示例使用floatlong long,但我正在寻找一种通用解决方案,该解决方案适用于整数类型和浮点类型的每种组合。

c++ floating-point

7
推荐指数
1
解决办法
314
查看次数

如何将VDT的双重版本的Pade Exp fast_ex()的标量代码转换成SSE2?

下面是我想要转换的代码:该double版本的VDT的帕德精通fast_ex()约(这里的老回购资源):

inline double fast_exp(double initial_x){
    double x = initial_x;
    double px=details::fpfloor(details::LOG2E * x +0.5);

    const int32_t n = int32_t(px);

    x -= px * 6.93145751953125E-1;
    x -= px * 1.42860682030941723212E-6;

    const double xx = x * x;

    // px = x * P(x**2).
    px = details::PX1exp;
    px *= xx;
    px += details::PX2exp;
    px *= xx;
    px += details::PX3exp;
    px *= x;

    // Evaluate Q(x**2).
    double qx = details::QX1exp;
    qx *= xx;
    qx += details::QX2exp;
    qx …
Run Code Online (Sandbox Code Playgroud)

c++ intrinsics sse2 exp

6
推荐指数
1
解决办法
159
查看次数

计算AVX2向量中每个元素的前导零位,模拟_mm256_lzcnt_epi32

使用AVX512,有一个internal函数_mm256_lzcnt_epi32,该函数返回一个向量,该向量对于8个32位元素中的每个元素,包含输入向量元素中前导零位的数量。

是否有仅使用AVX和AVX2指令来实现此目标的有效方法?

目前,我正在使用一个循环,该循环提取每个元素并应用该_lzcnt_u32函数。


相关:要对一个大位图进行位扫描,请参见__m256i字中的前导零计数,该字使用pmovmskb->位扫描以找到要执行标量位扫描的字节。

这个问题是关于当您实际上要使用全部8个结果而不仅仅是选择一个时,对8个单独的32位元素执行8个单独的lzcnts。

bit-manipulation simd avx avx2 avx512

6
推荐指数
1
解决办法
164
查看次数

如何在x86(32位)程序集中将无符号整数转换为浮点数?

我需要将32位和64位无符号整数转换为xmm寄存器中的浮点值.有一些x86指令可以将有符号整数转换为单精度和双精度浮点值,但对于无符号整数则没有.

额外:如何将xmm寄存器中的浮点值转换为32位和64位无符号整数?

x86 assembly sse

5
推荐指数
1
解决办法
4563
查看次数

是否有未签名的x87 FILD和SSE CVTSI2SD指令?

我想在GHC Haskell编译器中实现C的uint-to- doublecast 的等价物.我们已经实现了int-到- double使用FILDCVTSI2SD.是否有这些操作的无符号版本,或者我应该uint将转换前的最高位置零(从而丢失范围)?

floating-point assembly sse x87

5
推荐指数
2
解决办法
894
查看次数

在64位x 64位乘法中使用Karatsuba算法真的很有效吗?

我在AVX2上工作,需要计算64位x64位 - > 128位加宽乘法,并以最快的方式获得64位高位.由于AVX2没有这样的指令,使用Karatsuba算法提高效率和提高速度是否合理?

c++ parallel-processing performance simd avx2

5
推荐指数
1
解决办法
1316
查看次数

穷人是_mm_cvttpd_epi64的替代品

AXV512DQ,我们发现_mm_cvttpd_epi64,例如在文件中avx512vldqintrin.h

static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_cvttpd_epi64 (__m128d __A) {
  return (__m128i) __builtin_ia32_cvttpd2qq128_mask ((__v2df) __A,
               (__v2di) _mm_setzero_si128(),
               (__mmask8) -1);
}
Run Code Online (Sandbox Code Playgroud)

它将两个打包的64位浮点数(__m128d)转换为两个打包的64位整数(__m128i).还有_mm256_cvttpd_epi64用于将四个打包的64位浮点数(__m256d)转换为四个打包的64位整数(__m256i).

但是,很多机器都不支持AXV512DQ.所以我想知道一个穷人的最佳选择是什么.

我应该说我已经满意的解决方案仅适用于64位浮点数,可以无损转换为32位浮点数.

c c++ avx avx512

5
推荐指数
0
解决办法
228
查看次数

在 0..1 之间将 u64 转换为 f64

我需要一个非常快速的伪随机数生成器来用于我一直在进行的项目。到目前为止,我已经实现了 xorshift 算法,并且可以生成伪随机 u64。但是,我需要将这些 u64 转换为 0 到 1 范围内的浮点值。

我主要使用这个这个作为参考。

由于某种原因,我无法接近我想要的行为;这让我感到困惑,因为我使用了与此处完全相同的方法。尽管我看到实现没有任何差异,但我得到了不同的结果。

    let seeds: [u64; 64] = core::array::from_fn(|i| i as u64);

    let bitshift12 = u64x64::splat(12);
    let bitshift25 = u64x64::splat(25);
    let bitshift27 = u64x64::splat(27);
    
    let bitshift52 = u64x64::splat(52);
    
    let mut random_states = Simd::from(seeds);
    
    random_states ^= random_states >> bitshift12;
    random_states ^= random_states << bitshift25;
    random_states ^= random_states >> bitshift27;
    
    random_states = random_states | ((u64x64::splat(1023) + u64x64::splat(0)) << bitshift52);
    
    let mut generated = Simd::<f64, 64>::from_bits(random_states);
    
    println!("{:?}", generated); …
Run Code Online (Sandbox Code Playgroud)

random floating-point simd rust

2
推荐指数
1
解决办法
194
查看次数