在阅读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代表整数类型,如int或unsigned 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) 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位版本的两倍.
为什么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) 在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) 如何以正确的方式比较整数和浮点值?
内置比较运算符在某些情况下会给出错误的结果,例如:
#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,这会导致精度损失,并导致错误的结果。
即使我了解发生了什么,也不确定如何解决此问题。
免责声明:该示例使用float和long long,但我正在寻找一种通用解决方案,该解决方案适用于整数类型和浮点类型的每种组合。
下面是我想要转换的代码:该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) 使用AVX512,有一个internal函数_mm256_lzcnt_epi32,该函数返回一个向量,该向量对于8个32位元素中的每个元素,包含输入向量元素中前导零位的数量。
是否有仅使用AVX和AVX2指令来实现此目标的有效方法?
目前,我正在使用一个循环,该循环提取每个元素并应用该_lzcnt_u32函数。
相关:要对一个大位图进行位扫描,请参见__m256i字中的前导零计数,该字使用pmovmskb->位扫描以找到要执行标量位扫描的字节。
这个问题是关于当您实际上要使用全部8个结果而不仅仅是选择一个时,对8个单独的32位元素执行8个单独的lzcnts。
我需要将32位和64位无符号整数转换为xmm寄存器中的浮点值.有一些x86指令可以将有符号整数转换为单精度和双精度浮点值,但对于无符号整数则没有.
额外:如何将xmm寄存器中的浮点值转换为32位和64位无符号整数?
我想在GHC Haskell编译器中实现C的uint-to- doublecast 的等价物.我们已经实现了int-到- double使用FILD或CVTSI2SD.是否有这些操作的无符号版本,或者我应该uint将转换前的最高位置零(从而丢失范围)?
我在AVX2上工作,需要计算64位x64位 - > 128位加宽乘法,并以最快的方式获得64位高位.由于AVX2没有这样的指令,使用Karatsuba算法提高效率和提高速度是否合理?
在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位浮点数.
我需要一个非常快速的伪随机数生成器来用于我一直在进行的项目。到目前为止,我已经实现了 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)