小编xiv*_*r77的帖子

浮点文字中有效十进制数字的最小数量是多少才能尽可能正确地表示值?

例如,使用 IEEE-754 32 位二进制浮点数,让我们表示 的值1 / 3。它无法精确完成,但0x3eaaaaab会产生最接近 的值1 / 3。您可能希望以十进制形式写入值,并让编译器将十进制文字转换为二进制浮点数。

\n
0.333333f    -> 0x3eaaaa9f (0.333332986)\n0.3333333f   -> 0x3eaaaaaa (0.333333313)\n0.33333333f  -> 0x3eaaaaab (0.333333343)\n0.333333333f -> 0x3eaaaaab (0.333333343)\n
Run Code Online (Sandbox Code Playgroud)\n

您可以看到 8 位(有效)十进制数字足以表示尽可能正确的值(最接近实际值)。

\n

我用 \xcf\x80 和 e(自然对数的底数)进行了测试,两者都需要 8 位十进制数字才能最正确。

\n
3.14159f    -> 0x40490fd0 (3.14159012)\n3.141593f   -> 0x40490fdc (3.14159298)\n3.1415927f  -> 0x40490fdb (3.14159274)\n3.14159265f -> 0x40490fdb (3.14159274)\n\n2.71828f    -> 0x402df84d (2.71828008)\n2.718282f   -> 0x402df855 (2.71828198)\n2.7182818f  -> 0x402df854 (2.71828175)\n2.71828183f -> 0x402df854 (2.71828175)\n
Run Code Online (Sandbox Code Playgroud)\n

不过,\xe2\x88\x9a2似乎需要 9 位数字。

\n
1.41421f     -> 0x3fb504d5 (1.41420996)\n1.414214f    -> 0x3fb504f7 …
Run Code Online (Sandbox Code Playgroud)

c floating-point precision ieee-754 numerical-methods

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

为什么 SSE/AVX 缺少加载立即值?

据我所知,SSE/AVX 中没有用于加载立即数的指令。一种解决方法是将值加载到普通寄存器 和movd,但编译器似乎认为这比从内存加载成本更高,即使对于单个标量值也是如此。

这使得每次使用常见常量(例如10x800000000x7fffffff0x3f8000000x3f000000等)进行操作时都需要进行内存访问。好吧,将这些值编码在机器代码中每个将占用 4 个字节,但 32 位绝对或rip相对地址也是如此,而且我相信立即加载比任何类型的内存加载都便宜。

我一直认为有类似movss xmm, imm32或 之类的东西broadcastss xmm, imm32会很好,但不做出这样的指示肯定是有原因的。为什么要这样设计呢?

x86 assembly sse instruction-set immediate-operand

7
推荐指数
0
解决办法
388
查看次数

SSE 中的矢量化分支表查找快速近似余弦

我正在制作一个供个人使用的小型游戏引擎。目标架构是 x86_64,最好使用 SSE2。

\n

正弦/余弦函数是核心部分之一,它是作为输入范围的 1024 个余弦值的预先计算表来实现的[0, \xcf\x80 / 2]

\n

标量的实现非常简单。

\n
typedef unsigned uns;\ntypedef float flt;\n\nenum {COS_TABLE_SIZE = 1 << 10};\nextern flt COS_TABLE[COS_TABLE_SIZE];\n\nflt f(uns i) {\n    flt *t = COS_TABLE;\n    uns z = COS_TABLE_SIZE;\n    switch (i / z) {\n    case 0:\n        return +t[+(i - z * 0) + 0];\n    case 1:\n        return -t[-(i - z * 1) + z];\n    case 2:\n        return -t[+(i - z * 2) + 0];\n    case 3:\n        return +t[-(i - z * …
Run Code Online (Sandbox Code Playgroud)

c x86 assembly sse vectorization

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

用 C 语言实现 SHLD/SHRD 指令

我正在尝试在不使用内联汇编的情况下有效地实现SHLDSHRD说明x86

uint32_t shld_UB_on_0(uint32_t a, uint32_t b, uint32_t c) {
    return a << c | b >> 32 - c;
}
Run Code Online (Sandbox Code Playgroud)

似乎有效,但当c == 0第二个移位的操作数变为时会调用未定义的行为32SHLD第三个操作数的实际指令0被明确定义为不执行任何操作。(https://www.felixcloutier.com/x86/shld

uint32_t shld_broken_on_0(uint32_t a, uint32_t b, uint32_t c) {
    return a << c | b >> (-c & 31);
}
Run Code Online (Sandbox Code Playgroud)

不会调用未定义的行为,但当c == 0结果是a | b而不是a.

uint32_t shld_safe(uint32_t a, uint32_t b, uint32_t c) {
    if (c == …
Run Code Online (Sandbox Code Playgroud)

c x86 assembly compiler-optimization bigint

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

当被除数为64位且商为32位时,如何使gcc或clang使用64位/32位除法而不是128位/64位除法?

Currently, from research and various attempts, I'm pretty sure that the only solution to this problem is to use assembly. I'm posting this question to show an existing problem, and maybe get attention from compiler developers, or get some hits from searches about similar problems.

If anything changes in the future, I will accept it as an answer.

This is a very related question for MSVC.


In x86_64 machines, it is faster to use div/idiv with a 32-bit …

c x86 gcc clang compiler-optimization

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

为什么 GCC 和 Clang 不使用指数的浮点到整数 PADDD 来优化乘以 2^n 的乘法,即使使用 -ffast-math 也是如此?

考虑到这个功能,

float mulHalf(float x) {
    return x * 0.5f;
}
Run Code Online (Sandbox Code Playgroud)

以下函数与正常输入/输出产生相同的结果。

float mulHalf_opt(float x) {
    __m128i e = _mm_set1_epi32(-1 << 23);
    __asm__ ("paddd\t%0, %1" : "+x"(x) : "xm"(e));
    return x;
}
Run Code Online (Sandbox Code Playgroud)

这是带有 的汇编输出-O3 -ffast-math

mulHalf:
        mulss   xmm0, DWORD PTR .LC0[rip]
        ret

mulHalf_opt:
        paddd   xmm0, XMMWORD PTR .LC1[rip]
        ret
Run Code Online (Sandbox Code Playgroud)

-ffast-math启用-ffinite-math-only“假设参数和结果不是 NaN 或 +-Infs” [1]

因此,如果在 的容差下生成更快的代码,则的编译输出可能会更好地与onmulHalf一起使用。paddd-ffast-math-ffast-math

我从Intel Intrinsics Guide中获得了下表。

(MULSS)
Architecture    Latency Throughput (CPI)
Skylake         4       0.5 …
Run Code Online (Sandbox Code Playgroud)

c floating-point x86 assembly compiler-optimization

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

乘以 66049 如何重复位?

这是提高精度的像素混合操作的一部分。

typedef unsigned uint;

uint h(uint x) {
    x &= 0xff;
    return x << 8 | x;
}

uint g(uint x, uint y) {
    return h(x) * h(y) >> 24;
}
Run Code Online (Sandbox Code Playgroud)

我查看了编译器的输出,发现了一行非常有趣的内容。

g:
        movzx   edi, dil
        movzx   esi, sil
        imul    esi, edi
        imul    eax, esi, 66049  # <---
        shr     eax, 24
        ret
Run Code Online (Sandbox Code Playgroud)

这可以反编译为,

uint g_(uint x, uint y) {
    return (x & 0xff) * (y & 0xff) * 66049 >> 24;
}
Run Code Online (Sandbox Code Playgroud)

我无法理解乘以66049如何产生所需的结果。它背后的数学原理是什么?

c x86 assembly bit-manipulation alphablending

3
推荐指数
1
解决办法
121
查看次数