Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C++中截断浮点到最近的2的幂 在C++中假定至少C++ 11,给定浮点值A,我需要找到满足以下约束的浮点值b: b必须与a有相同的符号。 b的大小必须小于或等于a的大小[*]。 b的大小必须是2的幂。 在这些约束条件下,b的大小必须尽可能大。_C++_Performance_Floating Point - Fatal编程技术网

在C++中截断浮点到最近的2的幂 在C++中假定至少C++ 11,给定浮点值A,我需要找到满足以下约束的浮点值b: b必须与a有相同的符号。 b的大小必须小于或等于a的大小[*]。 b的大小必须是2的幂。 在这些约束条件下,b的大小必须尽可能大。

在C++中截断浮点到最近的2的幂 在C++中假定至少C++ 11,给定浮点值A,我需要找到满足以下约束的浮点值b: b必须与a有相同的符号。 b的大小必须小于或等于a的大小[*]。 b的大小必须是2的幂。 在这些约束条件下,b的大小必须尽可能大。,c++,performance,floating-point,C++,Performance,Floating Point,换句话说,我需要将a的大小截断为最接近的2次方,同时保持符号不变 [*在我的情况下,less或equal约束是宽松的,less也会起作用。] 给出一些IEEE754二进制表示,实现这一点的一种方法 简单地通过位碰撞清除所有尾数位,同时保持符号和指数位不变 一种更便于携带的方法是: 使用logb、ilogb或更便携的log2或frexp获取震级的以2为底的对数,向下舍入。 使用整数位移位、负幂和值范围问题、pow2.0、n、exp2n或ldexp1.0、n等将2提高到n次方。 通过copysign

换句话说,我需要将a的大小截断为最接近的2次方,同时保持符号不变

[*在我的情况下,less或equal约束是宽松的,less也会起作用。]

给出一些IEEE754二进制表示,实现这一点的一种方法 简单地通过位碰撞清除所有尾数位,同时保持符号和指数位不变

一种更便于携带的方法是:

使用logb、ilogb或更便携的log2或frexp获取震级的以2为底的对数,向下舍入。 使用整数位移位、负幂和值范围问题、pow2.0、n、exp2n或ldexp1.0、n等将2提高到n次方。 通过copysign复制标志。 这允许许多可能的组合来解决任务,在考虑单精度备选方案时更是如此。有没有人对这些方法在现代硬件上的性能和使用现代编译器方面有任何经验?

使用frexp1、ldexp2来呈现并形成答案

这两个功能几乎就是所需的全部功能

frexp函数将浮点数分解为标准分数和2的整数幂。。。frexp函数返回值x, 使得x的幅值在[1/2,1或0]区间内

ldexp函数将浮点数乘以2的整数幂

输出

   -4.94066e-324                -0x1p-1074                -0x1p-1074 1 1
              -0                   -0x0p+0                   -0x0p+0 1 1
    4.94066e-324                 0x1p-1074                 0x1p-1074 1 1
   -4.94066e-324                -0x1p-1074                -0x1p-1074 1 1
               0                    0x0p+0                    0x0p+0 1 1
    4.94066e-324                 0x1p-1074                 0x1p-1074 1 1
   -2.22507e-308  -0x1.0000000000001p-1022                -0x1p-1022 1 1
   -2.22507e-308                -0x1p-1022                -0x1p-1022 1 1
   -2.22507e-308  -0x1.ffffffffffffep-1023                -0x1p-1023 1 1
    2.22507e-308   0x1.ffffffffffffep-1023                 0x1p-1023 1 1
    2.22507e-308                 0x1p-1022                 0x1p-1022 1 1
    2.22507e-308   0x1.0000000000001p-1022                 0x1p-1022 1 1
              -1     -0x1.0000000000001p+0                   -0x1p+0 1 1
              -1                   -0x1p+0                   -0x1p+0 1 1
              -1     -0x1.fffffffffffffp-1                   -0x1p-1 1 1
               1      0x1.fffffffffffffp-1                    0x1p-1 1 1
               1                    0x1p+0                    0x1p+0 1 1
               1      0x1.0000000000001p+0                    0x1p+0 1 1
             -42     -0x1.5000000000001p+5                   -0x1p+5 1 1
             -42                 -0x1.5p+5                   -0x1p+5 1 1
             -42     -0x1.4ffffffffffffp+5                   -0x1p+5 1 1
              42      0x1.4ffffffffffffp+5                    0x1p+5 1 1
              42                  0x1.5p+5                    0x1p+5 1 1
              42      0x1.5000000000001p+5                    0x1p+5 1 1
            -inf                      -inf                   -0x1p-1 1 1
   -1.79769e+308  -0x1.fffffffffffffp+1023                -0x1p+1023 1 1
   -1.79769e+308  -0x1.ffffffffffffep+1023                -0x1p+1023 1 1
    1.79769e+308   0x1.ffffffffffffep+1023                 0x1p+1023 1 1
    1.79769e+308   0x1.fffffffffffffp+1023                 0x1p+1023 1 1
             inf                       inf                    0x1p-1 1 1
             nan                       nan                       nan 1 1
从OP中得到震级的以2为底的对数,使用例如…frexp向下舍入

2从OP的第2次方增加到第n次方,使用例如……ldexp1.0,n.

使用frexp1,ldexp2呈现a并形成答案

这两个功能几乎就是所需的全部功能

frexp函数将浮点数分解为标准分数和2的整数幂…frexp函数返回值x, 使得x的幅值在[1/2,1或0]区间内

ldexp函数将浮点数乘以2的整数幂

输出

   -4.94066e-324                -0x1p-1074                -0x1p-1074 1 1
              -0                   -0x0p+0                   -0x0p+0 1 1
    4.94066e-324                 0x1p-1074                 0x1p-1074 1 1
   -4.94066e-324                -0x1p-1074                -0x1p-1074 1 1
               0                    0x0p+0                    0x0p+0 1 1
    4.94066e-324                 0x1p-1074                 0x1p-1074 1 1
   -2.22507e-308  -0x1.0000000000001p-1022                -0x1p-1022 1 1
   -2.22507e-308                -0x1p-1022                -0x1p-1022 1 1
   -2.22507e-308  -0x1.ffffffffffffep-1023                -0x1p-1023 1 1
    2.22507e-308   0x1.ffffffffffffep-1023                 0x1p-1023 1 1
    2.22507e-308                 0x1p-1022                 0x1p-1022 1 1
    2.22507e-308   0x1.0000000000001p-1022                 0x1p-1022 1 1
              -1     -0x1.0000000000001p+0                   -0x1p+0 1 1
              -1                   -0x1p+0                   -0x1p+0 1 1
              -1     -0x1.fffffffffffffp-1                   -0x1p-1 1 1
               1      0x1.fffffffffffffp-1                    0x1p-1 1 1
               1                    0x1p+0                    0x1p+0 1 1
               1      0x1.0000000000001p+0                    0x1p+0 1 1
             -42     -0x1.5000000000001p+5                   -0x1p+5 1 1
             -42                 -0x1.5p+5                   -0x1p+5 1 1
             -42     -0x1.4ffffffffffffp+5                   -0x1p+5 1 1
              42      0x1.4ffffffffffffp+5                    0x1p+5 1 1
              42                  0x1.5p+5                    0x1p+5 1 1
              42      0x1.5000000000001p+5                    0x1p+5 1 1
            -inf                      -inf                   -0x1p-1 1 1
   -1.79769e+308  -0x1.fffffffffffffp+1023                -0x1p+1023 1 1
   -1.79769e+308  -0x1.ffffffffffffep+1023                -0x1p+1023 1 1
    1.79769e+308   0x1.ffffffffffffep+1023                 0x1p+1023 1 1
    1.79769e+308   0x1.fffffffffffffp+1023                 0x1p+1023 1 1
             inf                       inf                    0x1p-1 1 1
             nan                       nan                       nan 1 1
从OP中得到震级的以2为底的对数,使用例如…frexp向下舍入


2从OP的第二次方到第n次方,使用我自己的测试,例如….ldexp1.0,n.

,到目前为止,我得出了以下结论,但由于我没有一个测试实验室可供使用,我的观察证据有限,陪审团仍然悬而未决:

无论操作是在单精度域还是双精度域中执行,这都是无关紧要的。事实上,所涉及的大多数函数在双精度化身中的执行速度似乎稍快一些,即使这需要额外的转换

应避免使用没有f后缀(例如ilogb)的单精度函数,因为它们的性能通常比f后缀(例如ilogbf)差

位攻击在性能上是无与伦比的。令人惊讶的是,它在64位域中的性能也更好。我在64位机器上进行测试。我看到每次执行少于1ns。相比之下,我的测试床本身在每次迭代中的重量约为15ns

关于pow2floorlog2方法的实现,我的结论如下:

<> P>我没有看到任何特殊组合的基本构建块,它们会从意外的协同效应中获得性能提升,因此,合理地考虑构建块POW2、FLUROLog2和RooGuffE的类型。


假设0.0的情况没有什么关系,处理这个信号的最快方法是基本上做一个pow2floorlog2abs操作,然后通过我自己的测试用一个简单的ifa来修复这个信号,到目前为止,我得出了以下结论,但由于我没有一个测试实验室可供使用,我的观察证据是有限的,而且陪审团还没有出来:

无论操作是在单精度域还是双精度域中执行,这都是无关紧要的。事实上,所涉及的大多数函数在双精度化身中的执行速度似乎稍快一些,即使这需要额外的转换

应避免使用没有f后缀(例如ilogb)的单精度函数,因为它们的性能通常比f后缀(例如ilogbf)差

位攻击在性能上是无与伦比的。令人惊讶的是,它在64位域中的性能也更好。我在64位机器上进行测试。我看到每次执行少于1ns。相比之下,我的测试床本身在每次迭代中的重量约为15ns

至于pow2floorlog的实现 2方法,以下是我到目前为止的结论:

<> P>我没有看到任何特殊组合的基本构建块,它们会从意外的协同效应中获得性能提升,因此,合理地考虑构建块POW2、FLUROLog2和RooGuffE的类型。


假定0个情况不太重要,最快的处理符号的方法是基本上执行PUB2FRORROG2ABS操作,然后用简单的IF成员来修复符号,C和C++是两种非常不同的语言,即使是相似的事物也可以在它们各自的规范中有细微差别。使事情的运作与预期的大不相同。所以除非你想直接比较两种语言,否则请不要使用这两个标签,也不要使用术语C/C++。如果C和C++在这些功能上表现得非常不同,我会感到惊讶,所以我希望C和C++程序员的答案都是相关的。但是,你走了——不再是C,只是C++。@ DRESCHJM,我会对你能分享的关于我所提到的各个构建块的性能或组合的任何观察感兴趣。例如,令我惊讶的是,我刚刚发现在我的机器上,ilogbfloat比ilogbffloat慢,而ilogbfloat又比转换为double并调用ilogbdouble慢。这对我来说毫无意义,但我不能否认实验证据。记住C和C++是两种非常不同的语言,即使是相似的事物,它们的各自的规范中的措辞也可能细微差别,使事情与预期的有很大不同。所以除非你想直接比较两种语言,否则请不要使用这两个标签,也不要使用术语C/C++。如果C和C++在这些功能上表现得非常不同,我会感到惊讶,所以我希望C和C++程序员的答案都是相关的。但是,你走了——不再是C,只是C++。@ DRESCHJM,我会对你能分享的关于我所提到的各个构建块的性能或组合的任何观察感兴趣。例如,令我惊讶的是,我刚刚发现在我的机器上,ilogbfloat比ilogbffloat慢,而ilogbfloat又比转换为double并调用ilogbdouble慢。这对我来说毫无意义,但我不能否认实验证据。我知道这一点。但您是否有经验将其与其他性能方面的可能性进行比较?例如,我天真地认为,对于truncate情况,位攻击是一种更快的方法,只需要一条AND指令,但我不知道AVX和主CPU寄存器之间的数据传输如何抵消这一优势。@ChristophLipka位攻击可以更快地使用double的子集,但是,当整个double范围必须正确处理时,速度肯定会变慢,因为位攻击用户代码随后会复制库frexp,ldexp。在选定的平台和库中,可能已经存在round2power2x,但这对于标准库来说是不可移植的。如果你真的想要更快的东西,你需要编写性能评级工具的平均值x,最坏的情况,…,如果允许的话,double的子集和目标平台/编译器。以上是你的底线。@ChristophLipka Tale关心发布一个移动目标问题。一旦得到答案,将目标语言、通用语言更改为平台特定语言等都是不礼貌的。详细说明、提供缺少的细节是好的。请注意,其他人知道的事情是基于问题而不是不成文/不具体的意图。从技术上讲,如果a为零,就没有解决方案,因为没有b满足问题的约束条件。如果我们不关心当a为零时返回什么,那么frac=copysign.5,frac;足够了,可能会比if…else…表现更好,如果…@EricPostpischil从我目前正在进行的测试来看,ldexpaI似乎意识到了这一点。但您是否有经验将其与其他性能方面的可能性进行比较?例如,我天真地认为,对于truncate情况,位攻击是一种更快的方法,只需要一条AND指令,但我不知道AVX和主CPU寄存器之间的数据传输如何抵消这一优势。@ChristophLipka位攻击可以更快地使用double的子集,但是,当整个double范围必须正确处理时,速度肯定会变慢,因为位攻击用户代码随后会复制库frexp,ldexp。在选定的平台和库中,可能已经存在round2power2x,但这对于标准库来说是不可移植的。如果你真的想要更快的东西,你需要编写性能评级工具的平均值x,最坏的情况,…,如果允许的话,double的子集和目标平台/编译器。以上是你的底线。@ChristophLipka Tale关心发布一个移动


目标问题。一旦得到答案,将目标语言、通用语言更改为平台特定语言等都是不礼貌的。详细说明、提供缺少的细节是好的。请注意,其他人知道的事情是基于问题而不是不成文/不具体的意图。从技术上讲,如果a为零,就没有解决方案,因为没有b满足问题的约束条件。如果我们不关心当a为零时返回什么,那么frac=copysign.5,frac;这就足够了,而且可能比if…else…更好。如果…@EricPostpischil从我目前进行的测试来看,ldexpa
   -4.94066e-324                -0x1p-1074                -0x1p-1074 1 1
              -0                   -0x0p+0                   -0x0p+0 1 1
    4.94066e-324                 0x1p-1074                 0x1p-1074 1 1
   -4.94066e-324                -0x1p-1074                -0x1p-1074 1 1
               0                    0x0p+0                    0x0p+0 1 1
    4.94066e-324                 0x1p-1074                 0x1p-1074 1 1
   -2.22507e-308  -0x1.0000000000001p-1022                -0x1p-1022 1 1
   -2.22507e-308                -0x1p-1022                -0x1p-1022 1 1
   -2.22507e-308  -0x1.ffffffffffffep-1023                -0x1p-1023 1 1
    2.22507e-308   0x1.ffffffffffffep-1023                 0x1p-1023 1 1
    2.22507e-308                 0x1p-1022                 0x1p-1022 1 1
    2.22507e-308   0x1.0000000000001p-1022                 0x1p-1022 1 1
              -1     -0x1.0000000000001p+0                   -0x1p+0 1 1
              -1                   -0x1p+0                   -0x1p+0 1 1
              -1     -0x1.fffffffffffffp-1                   -0x1p-1 1 1
               1      0x1.fffffffffffffp-1                    0x1p-1 1 1
               1                    0x1p+0                    0x1p+0 1 1
               1      0x1.0000000000001p+0                    0x1p+0 1 1
             -42     -0x1.5000000000001p+5                   -0x1p+5 1 1
             -42                 -0x1.5p+5                   -0x1p+5 1 1
             -42     -0x1.4ffffffffffffp+5                   -0x1p+5 1 1
              42      0x1.4ffffffffffffp+5                    0x1p+5 1 1
              42                  0x1.5p+5                    0x1p+5 1 1
              42      0x1.5000000000001p+5                    0x1p+5 1 1
            -inf                      -inf                   -0x1p-1 1 1
   -1.79769e+308  -0x1.fffffffffffffp+1023                -0x1p+1023 1 1
   -1.79769e+308  -0x1.ffffffffffffep+1023                -0x1p+1023 1 1
    1.79769e+308   0x1.ffffffffffffep+1023                 0x1p+1023 1 1
    1.79769e+308   0x1.fffffffffffffp+1023                 0x1p+1023 1 1
             inf                       inf                    0x1p-1 1 1
             nan                       nan                       nan 1 1
double Pow2Trunc(double a)
{
    union { double f; uint64_t i; } hack;
    hack.f = a;
    hack.i &= 0xFFF0000000000000u;
    return hack.f;
}
double Pow2Trunc(double a)
{
    int exp;
    (void)frexp(a,&exp);
    double b = ldexp(0.5, exp);
    if (a < 0) b = -b;
    return b;
}
double Pow2Trunc(double a)
{
    double b = ldexp(1.0, ilogb(a));
    if (a < 0) b = -b;
    return b;
}