使用常数整数除数的高效浮点除法。

48

最近有一个问题,关于编译器是否允许用浮点乘法代替浮点除法,这启发了我提出这个问题。

在严格要求下,代码转换后的结果应该与实际除法操作的位相同,对于二进制IEEE-754算术,可以看出这对于2的幂次方除数是可能的。只要除数的倒数是可表示的,乘以除数的倒数就可以得到与除法相同的结果。例如,乘以0.5可以取代除以2.0

然后我们想知道,在允许任何短的指令序列以更快的速度运行但提供位相同结果的情况下,对于其他除数,这种替换是否有效。特别是在纯乘法之外,还允许融合乘加运算。在评论中,我指出了以下相关论文:

Nicolas Brisebarre、Jean-Michel Muller和Saurabh Kumar Raina。已知除数时加速正确舍入的浮点除法。IEEE计算机学报,第53卷,第8期,2004年8月,pp. 1069-1072。

这篇论文提倡的技术是预先计算除数y的倒数作为标准化的头尾对zh:zl,方法如下:zh = 1 / y,zl = fma(-y, zh, 1) / y。然后,除法q = x / y被计算为q = fma(zh,x,zl * x)。该论文导出了除数y必须满足的各种条件,以便使此算法起作用。显而易见的是,当头和尾的符号不同时,此算法会遇到无穷大和零的问题。更重要的是,当被除数x的值非常小时,商的尾数zl * x的计算将受到下溢的影响,从而无法得出正确的结果。
该论文还简单提到了一种替代的基于FMA的除法算法,由IBM的Peter Markstein开创。相关参考文献为:
P. W. Markstein. 计算IBM RISC System/6000处理器上的基本函数。 IBM研究与开发杂志,第34卷,第1期,1990年1月,111-119页。
在Markstein的算法中,首先计算倒数rc,然后形成初始商q = x * rc。然后,使用FMA精确地计算除法的余数r = fma (-y,q,x),最终计算出更准确的商q = fma (r,rc,q)。
该算法对于x为零或无穷大也存在问题(可以通过适当条件执行轻松解决),但是使用IEEE-754单精度float数据进行全面测试表明,它在许多除数y中为所有可能的被除数x提供正确的商,其中包括许多小整数。这段C代码实现了它:
/* precompute reciprocal */
rc = 1.0f / y;

/* compute quotient q=x/y */
q = x * rc;
if ((x != 0) && (!isinf(x))) {
    r = fmaf (-y, q, x);
    q = fmaf (r, rc, q);
}

在大多数处理器结构中,这应该转化为一系列无分支的指令,使用谓词、条件移动或选择类型指令。举个具体例子:对于除以3.0f,CUDA 7.5的nvcc编译器为Kepler级别的GPU生成以下机器代码:
    LDG.E R5, [R2];                        // load x
    FSETP.NEU.AND P0, PT, |R5|, +INF , PT; // pred0 = fabsf(x) != INF
    FMUL32I R2, R5, 0.3333333432674408;    // q = x * (1.0f/3.0f)
    FSETP.NEU.AND P0, PT, R5, RZ, P0;      // pred0 = (x != 0.0f) && (fabsf(x) != INF)
    FMA R5, R2, -3, R5;                    // r = fmaf (q, -3.0f, x);
    MOV R4, R2                             // q
@P0 FFMA R4, R5, c[0x2][0x0], R2;          // if (pred0) q = fmaf (r, (1.0f/3.0f), q)
    ST.E [R6], R4;                         // store q

为了进行我的实验,我编写了下面展示的小型C语言测试程序,它按照递增顺序遍历整数除数,并针对每个除数详尽地测试上述代码序列与正确除法的匹配性。它会打印出通过了这个详尽测试的除数列表。部分输出如下:

PASS: 1, 2, 3, 4, 5, 7, 8, 9, 11, 13, 15, 16, 17, 19, 21, 23, 25, 27, 29, 31, 32, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 64, 65, 67, 69,

作为一种优化方式,将替换算法加入编译器中是不可行的,因为无法列出适用于上述代码转换的除数白名单。该程序迄今为止的输出(每分钟约一个结果)表明,在奇整数或2的幂次方的除数y对x进行所有可能的编码时,快速代码的工作正确。当然,这只是一些例证,而不是证明。 有哪些数学条件可以事先确定将除法转换为上述代码序列是否安全? 答案可以假设所有浮点运算都在“四舍五入到最近的偶数”默认舍入模式下执行。
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

int main (void)
{
    float r, q, x, y, rc;
    volatile union {
        float f;
        unsigned int i;
    } arg, res, ref;
    int err;

    y = 1.0f;
    printf ("PASS: ");
    while (1) {
        /* precompute reciprocal */
        rc = 1.0f / y;

        arg.i = 0x80000000;
        err = 0;
        do {
            /* do the division, fast */
            x = arg.f;
            q = x * rc;
            if ((x != 0) && (!isinf(x))) {
                r = fmaf (-y, q, x);
                q = fmaf (r, rc, q);
            }
            res.f = q;
            /* compute the reference, slowly */
            ref.f = x / y;

            if (res.i != ref.i) {
                err = 1;
                break;
            }
            arg.i--;
        } while (arg.i != 0x80000000);

        if (!err) printf ("%g, ", y);
        y += 1.0f;
    }
    return EXIT_SUCCESS;
}

不确定为什么这个问题被标记为“过于宽泛”。如果投票者能解释一下他们的理由,我会很感激。我正在尝试确定何时可以使用在问题中显示的非常特定的代码序列,用一个恒定的整数除数替换浮点除法是“安全”的。我的测试结果的轶事证据似乎表明它适用于奇数和2的幂。但是,要将其提议为通用优化,需要对哪些整数是“安全”的进行坚实的数学推理;我没有那种数学技能。 - njuffa
3
我希望你能回答这个问题并列出几个必须强加在除数上的条件,以及最多一页的证明或推导,我认为这对于SO的格式来说不算“太长”。我没有在数学 Stackexchange 上问这个问题是因为浮点数问题在那里几乎没有任何反响,而在Stackoverflow上有许多数学家,这个问题绝对与编程有关,所以我认为适合在此处使用[math]标签。 - njuffa
1
@aka.nice 是的。这个事实让我感到困惑,我也有将这样的除法分成两个阶段的想法。我还没有尝试过,但我认为它可能行不通,因为当结果是非规格化数时,除以二并不总是精确的。 - njuffa
2
@Claudiu 根据对计算机科学Stackexchange的一般浏览,搜索相关标签,并检查该网站上与浮点运算相关的选定问答主题,我对能得到有意义的回答(甚至是有用的评论)的期望非常低。由于在SO/SE宇宙中强烈不鼓励跨贴,我无法简单地进行相关实验以找出是否如此。 - njuffa
1
@Claudiu 我不认为有任何精通浮点数的专家会在CS堆栈交换上出现,所以实际上并没有。而这里有许多经常贡献的人(包括njuffa本人)非常有知识。 - Stephen Canon
显示剩余9条评论
4个回答

7
让我重新开始第三次。我们正在尝试加速。
    q = x / y

其中y是一个整数常量,qxy都是IEEE 754-2008 binary32浮点值。下面,fmaf(a,b,c)表示使用binary32值的融合乘加a * b + c

朴素算法是通过预先计算倒数来实现的。

    C = 1.0f / y

因此,在运行时只需要进行(更快速的)乘法即可:

    q = x * C

Brisebarre-Muller-Raina 加速使用两个预先计算的常数。
    zh = 1.0f / y
    zl = -fmaf(zh, y, -1.0f) / y

因此,在运行时,只需要一次乘法和一次融合乘加即可:

    q = fmaf(x, zh, x * zl)

马克斯坦算法将朴素方法与两个融合的乘加操作相结合,如果朴素方法在最不重要的地方产生了一个单位内的结果,则可以得到正确的结果,通过预先计算。
    C1 = 1.0f / y
    C2 = -y

以便可以使用近似方法来计算除法

    t1 = x * C1
    t2 = fmaf(C1, t1, x)
    q  = fmaf(C2, t2, t1)

这种朴素的方法适用于所有2的幂次方y,但对于其他情况则效果不佳。例如,在除数为7、14、15、28和30的情况下,它会对超过一半的可能x产生错误结果。

Brisebarre-Muller-Raina方法同样适用于几乎所有非2次幂的y,但产生错误结果的x较少(所有可能x中不到半个百分点,具体取决于y)。

Brisebarre-Muller-Raina文章显示,朴素方法的最大误差为±1.5 ULPs。

Markstein方法可用于2的幂次方y和奇整数y,(我还没有找到Markstein方法失败的奇数除数)。


对于Markstein方法,我已经分析了1-19700的除数(原始数据在这里)。
绘制失败情况的数量(横轴为除数,在该除数下Markstein方法失败的x值数量),我们可以看到一个简单的模式出现: Markstein failure cases (来源:nominal-animal.net 请注意,这些图都具有水平和垂直对数轴。奇数除数没有点,因为该方法对我测试过的所有奇数除数都产生了正确的结果。
如果我们将x轴改为因子的位反转(二进制数字反向,即0b11101101→0b10110111,data),我们会得到一个非常清晰的模式: Markstein failure cases, bit reverse divisor
(来源:nominal-animal.net 如果我们通过点集中心画一条直线,我们得到曲线4194304/x。(请记住,图表仅考虑可能的浮点数的一半,因此在考虑所有可能的浮点数时,请将其加倍。) 8388608/x2097152/x完全框定了整个误差模式。
因此,如果我们使用rev(y)来计算除数y的位反转,那么8388608/rev(y)是所有可能的浮点数中,马克斯坦方法对于偶数、非2次幂除数y产生错误结果的情况的很好的一级近似。(或者使用16777216/rev(x)作为上限。)
添加于2016-02-28: 我找到了一个关于使用马克斯坦方法的误差案例数量的逼近值,给定任何整数(binary32)除数。这里是伪代码:
function markstein_failure_estimate(divisor):
    if (divisor is zero)
        return no estimate
    if (divisor is not an integer)
        return no estimate

    if (divisor is negative)
        negate divisor

    # Consider, for avoiding underflow cases,
    if (divisor is very large, say 1e+30 or larger)
        return no estimate - do as division

    while (divisor > 16777216)
        divisor = divisor / 2

    if (divisor is a power of two)
        return 0

    if (divisor is odd)
        return 0

    while (divisor is not odd)
        divisor = divisor / 2

    # Use return (1 + 83833608 / divisor) / 2
    # if only nonnegative finite float divisors are counted!
    return 1 + 8388608 / divisor

这将在我测试的Markstein失败案例中提供正确的误差估计,精度为±1(但我尚未充分测试大于8388608的除数)。最终的除法应该报告没有错误零点,但我不能保证(至少现在还不能)。它不考虑非常大的除数(比如0x1p100或1e+30等),这些除数会有下溢问题,无论如何我都会排除这样的除数来加速运算。
在初步测试中,估计值似乎非常准确。我没有画出比较1到20000除数的估计和实际误差的图表,因为在图表中所有点都完全重合。(在这个范围内,估计是精确的,或者说多一个)基本上,这些估计完全复制了这个答案中的第一个图表。
马克斯坦方法的失败模式是有规律的,非常有趣。该方法适用于所有二次幂除数和所有奇整数除数。
对于大于16777216的除数,我始终看到与被最小二次幂除以产生小于16777216值的除数相同的错误。例如,0x1.3cdfa4p+23和0x1.3cdfa4p+41、0x1.d8874p+23和0x1.d8874p+32、0x1.cf84f8p+23和0x1.cf84f8p+34、0x1.e4a7fp+23和0x1.e4a7fp+37。(在每一对中,尾数相同,只有二次幂不同。)
假设我的测试台没有错误,这意味着如果除数被最小二次幂除以产生小于16777216值的商是奇数,并且商的大小介于16777216和1e+30之间,则马克斯坦方法也适用于该除数。

我现在可能太累了,但我很难理解这是什么意思:“大于16777216,使得当除以最小的2的幂时,商小于16777216,且商为奇数”。你能用数学方式描述一下吗?顺便说一句,我花了两天时间研究了超过2 ** 24的因子,但无法找出哪些是有效的模式。请注意,您上面提到的“Brisebarre-Muller-Raina”算法实际上是他们论文中的“算法1(使用一次乘法和两个融合的mac进行除法)”,并由他们归属于Markstein(与参考文献相符)。 - njuffa
这是你第三条规则的反例吗?除数为y:对于y=33554334 y/2**n=16777167 (y/2**n)&1=1,基于Markstein FMA的除法无法得出正确结果y=0x1.ffff9ep+24 arg=0x1.1f589ap-101 (0d0fac4d) res=0x1.1f58d0p-126 (008fac68) ref=0x1.1f58d2p-126 (008fac69) - njuffa
在我的sm_50 GPU上,使用CUDA 7.5,我得到的结果是:division = 0x1.1f589ap-101 / 0x1.ffff9ep+24 = 0x1.1f58d2p-126。Markstein: residual=-0x1.ffff9cp-126 final_quot=0x1.1f58d2p-126。对于这个被除数,Markstein序列可以使用,因为结果是匹配的。我后来才注意到我无意中在Intel编译器中省略了/fp:strict标志,这很可能是之前CPU不匹配的原因。对于造成的混乱,我表示抱歉,将进一步调查。 - njuffa
@NominalAnimal非常好的工作。 顺便说一句,根据我的重新测试框架,似乎存在其他除数> 2 ** 24,除了那些满足“缩小后奇数”测试的除数,它们使用Markstein算法在所有可能的被除数上都能提供正确的结果。 您也看到了这一点吗?有没有办法描述这些额外的除数? 我仍在查看新数据,可能无法在未来几天内详细研究它。 - njuffa
@njuffa:我添加了一个更加准确的Markstein失败案例计数估算器(对于给定除数,Markstein将产生错误答案的参数数量)。在我的测试中(尽管有限;已验证1到20000的除数,其余部分随机抽样),它可以在±1(实际上是-0+1)的范围内正确地计算出失败案例的数量。 - Nominal Animal
显示剩余10条评论

7
这个问题要求找到常量Y的值,使得对于所有可能的x值,将x / Y转换为更便宜的FMA计算是安全的。另一种方法是使用静态分析来确定x可以取的值的过度逼近,以便在知道转换后代码与原始除法不同的值不会出现时应用通常不准确的转换。
使用适合浮点计算问题的浮点数值集表示,即使从函数开头开始进行正向分析也可以产生有用的信息。例如:
float f(float z) {
  float x = 1.0f + z;
  float r = x / Y;
  return r;
}

假设默认的四舍五入模式(*),在上述函数中,x 只能是 NaN(如果输入为 NaN)、+0.0f 或大于 2-24 的数,但不能是 -0.0f 或比 2-24 更接近零的任何数。这为许多常量 Y 的值证明了可以转换成问题中显示的两种形式之一。
(*) 这是一个假设,没有它很多优化是不可能的,并且 C 编译器已经在程序中使用,除非程序显式使用 #pragma STDC FENV_ACCESS ON
预测上述 x 信息的前向静态分析可以基于浮点值集合的表示,其中一个表达式可以采用以下元组:
  • 可能的 NaN 值的表示(由于 NaN 的行为未规定,选择仅使用布尔值,其中 true 表示可能存在某些 NaN,而 false 表示不存在 NaN),
  • 分别指示 +inf、-inf、+0.0、-0.0 是否存在的四个布尔标志,
  • 负有限浮点值的包含区间,和
  • 正有限浮点值的包含区间。
为了遵循这种方法,所有可能出现在 C 程序中的浮点运算都必须被静态分析器理解。例如,用于处理分析代码中的 + 的值集合 U 和 V 之间的加法可以实现为:
  • 如果一个操作数中存在NaN,或者操作数可以成为相反符号的无穷大,则结果中会出现NaN。
  • 如果U和V的值相加不能得到0,则使用标准区间算法。结果的上限是通过将U中最大值与V中最大值进行四舍五入相加得到的,因此应使用四舍五入计算这些上下限。
  • 如果正值U与负值V相加可以得到0,则将M设为U中最小的正值,使得-M在V中存在。
    • 如果succ(M)在U中存在,则该值对结果的正值贡献为succ(M)-M。
    • 如果-succ(M)在V中存在,则该值对结果的负值贡献为M-succ(M)。
    • 如果pred(M)在U中存在,则该值对结果的负值贡献为pred(M)-M。
    • 如果-pred(M)在V中存在,则该值对结果的正值贡献为M-pred(M)。
  • 如果负值U与正值V相加可得到0,则同样处理。

致谢:以上内容借鉴自“Improving the Floating Point Addition and Subtraction Constraints”,作者为Bruno Marre & Claude Michel


例子:编译以下函数f

float f(float z, float t) {
  float x = 1.0f + z;
  if (x + t == 0.0f) {
    float r = x / 6.0f;
    return r;
  }
  return 0.0f;
}

该问题中的方法拒绝将函数f中的除法转换为另一种形式,因为6不是可以无条件转换除法的值之一。相反,我建议从函数的开头应用一个简单的值分析,确定x是一个有限浮点数,要么是+0.0f,要么至少具有2^-24的大小,并使用这些信息来应用Brisebarre等人的变换,确信x * C2不会下溢。
明确地说,我建议使用以下算法来决定是否将除法转换为更简单的形式:
1. Y是否是可以根据Brisebarre等人的算法使用他们的方法进行转换的值之一? 2. Brisebarre等人的方法中的C1和C2是否具有相同的符号,或者可以排除被除数是无穷大的可能性? 3. Brisebarre等人的方法中的C1和C2是否具有相同的符号,或者x只能采用0的两种表示之一?如果在C1和C2具有不同符号且x只能是零的一种表示时,在基于FMA的计算中调整符号以使其在x为零时产生正确的零。 4. 能否保证被除数的大小足够大,以排除x * C2下溢的可能性?
如果四个问题的答案都是“是”,则可以在编译函数的上下文中将除法转换为乘法和FMA。上述静态分析用于回答2、3和4号问题。
“调整符号”意味着在需要时使用-FMA(-C1,x,(-C2)* x)代替FMA(C1,x,C2 * x),以使结果在x只能是两个带符号的零之一时正确地输出。

我很难理解答案与问题的关系,现在担心我可能误传了它的实际方面:当遇到浮点除法x / fpconst时,其中fpconst是一个整数,而x可以采用float中的任何编码方式,如何确定替换代码是否基于fpconst提供相同的结果?是/否结果。这可能作为上述通用算法的特殊情况,但我不知道在哪里。我不理解“M存在于Y”这句话的意思:Y似乎不是一个区间? - njuffa
从对float(实现为IEEE-754 binary32)的详尽测试中,我知道可以用基于FMA的序列替换x/3.0f,对于所有可能的x值,提供与除法完全相同的结果(即结果为TRUE)。对于x/6.0f,这是不可能的,因为当x的大小非常小的时候,替换不会返回正确的结果(即结果为FALSE)。如何根据答案中的过程得出相同的结果?该过程是否比详尽测试更快(对于float每个结果约一分钟)? - njuffa
2
@njuffa 是的,这个答案没有提供关于常量Y的充分条件,以便用另一种形式替换x / Y,例如在编译器的上下文中。这个答案指出,相反地,在编译器的上下文中,更简单、更有效的方法是计算有关x值的信息,以使得更频繁和更简单地确定变换是否正确。如果您认为它太偏离主题,我可以删除这个答案,但我发布它是因为我认为它解决了同样的原始问题:编译x / Y - Pascal Cuoq
我并不建议你删除这个答案。仅仅因为我个人理解有困难,并不意味着其他人不能理解它。我理解你的回答的反向观点:对于给定的除数fpconst,确定一组浮点值x,使得基于FMA的代码提供与除法相同的结果。如果已经存在关于x的范围信息,我可以看出从那个方向进行的方法是有优势的。从与编译器专家的交谈中,我知道对于浮点数,往往没有范围信息,x可以是任何float编码。 - njuffa
@njuffa 没错,这就是为什么我最初开发的答案部分是如何实现一个价值分析,以有用地回答关于股息取值的问题,从而推理出简化除法的机会。 - Pascal Cuoq
@njuffa 我希望上述浮点值分析将在大约三个月后实现。完成后我会通知你。 - Pascal Cuoq

1
我喜欢@Pascal的回答,但在优化中,拥有一个简单且易于理解的转换子集通常比拥有完美的解决方案更好。
所有当前和普遍历史的浮点格式都共同具有一个二进制尾数。
因此,所有分数都是以下形式的有理数:
x / 2^n
这与程序中的常量(以及所有可能的十进制分数)形成对比,后者是以下形式的有理数:
x / (2^n * 5^m)
因此,一种优化方法就是测试输入和倒数是否满足m == 0,因为这些数字在FP格式中被准确表示,并且使用它们进行运算应该产生在格式内精确的数字。
因此,例如,在(小数2位数)范围内的.01到0.99之间,除以或乘以以下数字将得到优化:
.25 .50 .75

而其他任何事情都不会。 (我想,先测试一下,哈哈。)

1
请注意,问题已经限制了要考虑的除数为整数,因为我认为解决任意除数的问题会太难。因此,所考虑的除数都可以精确表示为float(最高2*24)。然而,根据经验,我已经证明了建议代码可用的唯一整数除数是形如2x+12**n*的除数。即使这样,这也是一个猜想,因为我无法测试它们全部(我保持我的测试应用程序运行以生成白名单)。 - njuffa
我不想让问题偏离主题。但是值得一提的是,除了奇数和2的幂之外,代码在所有可能的被除数上都能正确地给出商的除数还有很多。例如,如果我以0.5f的增量搜索,我会得到以下部分列表:PASS: 1, 1.5, 2, 2.5, 3, 4, 5, 5.5, 6.5, 7, 8, 9, 9.5, 10.5, 11, 13, 13.5, 14.5, 15, 16, 17, 17.5, 18.5, 19, 21, 21.5, 22.5, 23, 25, 25.5, 26.5, 27, 29, - njuffa
所有这些数字实际上都有几位精确的浮点表示,没有重复模式,因此根据我的确切论点,它们应该可以正常工作。但是你说得对,会偏离主题。把我的答案看作是为其他人提供的素材。虽然不完全是你要的答案,但可能是别人需要的答案。 - DigitalRoss
@njuffa 不好意思,如果我特别迟钝,那么奇整数除数的重要性是什么? 任何非零的'float'都可以通过...即通过适当的2的幂次方缩放而成一个奇整数。因此,如果您证明了基于FMA的除法对所有奇整数都起作用,并且您知道可轻松进行按位正确的2的幂次方除法,则已经证明了FMA算法适用于所有“floats”。 - Iwillnotexist Idonotexist
1
@Iwillnotexist Idonotexist 您可能默认将除以2的幂次方视为精确操作,但实际上并非总是如此。当结果是一种非规格化数时,会发生舍入。这就是为什么我在问题中发布的代码适用于除以 3.0f,但不适用于除以 6.0f 的原因。您现在可能会问:为什么不使用 FTZ 模式避免非规格化数?这会导致代码失败,因为计算出的剩余量突然下溢为零。您可以通过运行包含在问题中的测试应用程序来轻松检查哪些除数适用于该代码序列。 - njuffa
显示剩余2条评论

0

浮点数除法的结果包括:

  • 符号标志
  • 有效数字
  • 指数
  • 一组标志(溢出、下溢、不精确等 - 请参见 fenv()

仅正确获取前3个部分(但标志集不正确)是不够的。如果没有进一步的知识(例如,结果的哪些部分实际上很重要,被除数的可能值等),我会认为用常数乘法(和/或复杂的FMA混乱)替换除法几乎从来都不安全。

此外,对于现代CPU,我也不会假设用2个FMAs替换除法总是更好的。例如,如果瓶颈是指令提取/解码,则这种“优化”会使性能变差。另一个例子,如果后续指令不依赖于结果(CPU可以在等待结果时并行执行许多其他指令),则FMA版本可能会引入多个依赖停顿,并使性能变差。第三个例子,如果所有寄存器都在使用中,则FMA版本(需要额外的“活动”变量)可能会增加“溢出”,并使性能变差。

请注意(在许多但不是所有情况下),通过添加移位计数到指数,可以仅使用加法来进行2的常数倍数的除法或乘法(特别是)。

3
该问题标记为“C”。在没有明确的 #pragma STDC FENV_ACCESS ON 前,访问浮点状态标志位的 C 程序不应期望结果是正确的,因此编译器知道什么时候必须保留标志位以及什么时候不需要。你提出的问题前半部分所做的注释(在大多数情况下)适用于基本的优化,如常量传播。(来自C11标准7.6.1:2) - Pascal Cuoq
1
就除法的成本而言,在我所了解的所有支持硬件FMA的处理器上,除法比两个FMA(甚至是五个FMA)要昂贵得多。在具有硬件浮点除法的平台上,所提出的优化可能会稍微增加寄存器压力,但许多其他优化措施如CSE或早期加载调度也会有相同影响。对于使用软件执行浮点除法的平台来说,所提出的代码很可能会降低寄存器压力,因为通用的IEEE兼容除法程序可能在“最宽”点需要十个活动寄存器。 - njuffa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接