由于减法中的浮点误差,在以下情况下是否可以除零?
float x, y, z;
...
if (y != 1.0)
z = x / (y - 1.0);
Run Code Online (Sandbox Code Playgroud)
换句话说,以下是否更安全?
float divisor = y - 1.0;
if (divisor != 0.0)
z = x / divisor;
Run Code Online (Sandbox Code Playgroud) c++ floating-point floating-accuracy divide-by-zero floating-point-precision
为什么必须使用-ffast-math
g ++来实现使用double
s 的循环向量化?我不喜欢-ffast-math
因为我不想失去精确度.
我目前正在尝试优化一些占用50%时间的代码std::pow()
.我知道指数将始终是一个正整数,并且基数将始终是区间(0,1)中的双精度.为了好玩,我写了一个函数:
inline double int_pow(double base, int exponent)
{
double out = 1.0;
for(int i = 0; i < exponent; i++)
{
out *= base;
}
return out;
}
Run Code Online (Sandbox Code Playgroud)
我正在编译:
> g++ fast-pow.cpp -O3 --std=c++11
Run Code Online (Sandbox Code Playgroud)
我在(0,1)之间产生了1亿个双打,并比较了(1) std::pow
(2)int_pow
上面我自制函数的时间和(3)直接乘法.这是我的计时例程的草图(这是一个非常快速的组合测试):
void time_me(int exp, size_t reps)
{
volatile double foo = 0.0;
double base = 0.0;
size_t i;
for (i = 0; i < reps; ++i)
{
base = ((double) rand() / (RAND_MAX)) + 1;
foo = pow(base, …
Run Code Online (Sandbox Code Playgroud) 在C代码中,通常写
a = b*b;
Run Code Online (Sandbox Code Playgroud)
代替
a = pow(b, 2.0);
Run Code Online (Sandbox Code Playgroud)
对于double
变量.我知道因为它pow
是一个能够处理非整数指数的通用函数,所以应该天真地认为第一个版本更快.我不知道编译器(gcc)是否将调用转换为pow
整数指数,以指示乘法作为任何可选优化的一部分.
假设没有进行这种优化,那么手动写出乘法的最大整数指数是b*b* ... *b
多少,如?
我知道我可以在给定的机器上进行性能测试,以确定我是否应该关心,但我想更深入地了解什么是"正确的事情".
我开始使用 Boost ICL,并偶然发现了非常基本的东西。例如,函数contains
应返回 true 或 false,具体取决于给定元素是否在区间内。然而,这适用[right,left]_open_intervals
但不适用[open,closed]_inteval
(参见下面的示例)。
这似乎太明显了,不可能是一个疏忽。我正在以预期的方式使用图书馆吗?
例如(使用 gcc 4.8 或 clang 3.3 和 Boost 1.54):
#include <boost/concept_check.hpp> //needed to make this MWE work, boost icl should include it internally
#include<boost/icl/right_open_interval.hpp>
#include<boost/icl/closed_interval.hpp>
#include<boost/icl/open_interval.hpp>
int main(){
boost::icl::right_open_interval<double> roi(6.,7.);
assert(boost::icl::contains(roi, 6.) == true); //ok
assert(boost::icl::contains(roi, 6.) == false); //ok
boost::icl::closed_interval<double> oi(4.,5.); // or open_interval
assert(boost::icl::contains( oi, 4.) == false); //error: "candidate template ignored"
assert(boost::icl::contains( oi, 5.) == false); //error: "candidate template ignored"
}
Run Code Online (Sandbox Code Playgroud)
注意:以上称为“静态”间隔(因为它们的绑定属性是类型的一部分)。动态间隔按预期工作。
我有一组由计算机代数系统(CAS)产生的多项式表达式.例如,这是该集合的一个元素.
-d*d*L*L*QB*B*L*L*Q + 2*d*F*Ĵ*L*Q + 2*b*表F*H*L*QF*F*Ĵ*Ĵ*QB*b*表Ĵ*∫*q + 2*b*表d*H*Ĵ*QF*F*H*H*QD*d*H*H*q + b*b*∫*∫*○*O-2*b*d*H*Ĵ*○*O + d*d*H*H*○*0-2*b*b*∫*L*N*O + 2*b*表d*H*L*n个*O + 2*b*表F*H*Ĵ*N*0-2*d*F*H*H*N*O + 2*b*表d*∫*L*M*0-2*d*d*H*L*M*0-2*b*表F*Ĵ*∫*M*O + 2*d*F*H*Ĵ*M*O + b*b*L*L*N*N-2*b*表F*H*L*N*N + F*F*H*H*N*N-2*b*表d*L*L*m*n个+ 2*b*表F*Ĵ*L*米*N + 2*d*F*H*L*m*n个-2*F*F*H*Ĵ*m*n个+ d*d*L*L*m*m的-2*d*F*Ĵ*L*M*M + F*F*Ĵ*Ĵ*m*m的
我需要尽快在C程序中执行所有这些操作.如果你仔细研究这些公式中的任何一个,很明显我们可以优化它们的计算速度.例如,在上面粘贴的多项式中,我可以立即看到术语-d*d*l*l*q,2*d*f*j*l*q和-f*f*j*j*q,这样我就可以用-q*square(d*lf*j)替换它们的总和.我相信这里可以做很多这样的事情.我不相信(但也许我错了)任何编译器都能找到这个优化,或者更高级的优化.我试图让maxima(一个CAS)为我做这个,但没有任何结果(因为我是极限初学者,我可能错过了一个神奇的命令).所以,我的第一个问题是:我们可以使用什么工具/算法来优化多项式表达式以获得计算速度?
当优化一组共享大多数变量的多项式表达式时,事情变得更加复杂.实际上,通过表达式优化表达式可能是次优的,因为在优化之前编译器可以识别公共部分,但是如果不作为整体执行则不再存在.所以,我的第二个问题是:我们可以使用哪些工具/算法来优化一组多项式表达式以获得计算速度?
最好的祝福,
PS:这篇文章与" 计算机代数软件以及最小化一组多项式中的操作数量 "有一些相似之处,但是那一点给出的答案指向CAS程序而不是说我们如何使用它们来实现我们的目标.
algorithm optimization performance computer-algebra-systems polynomials
请问以下代码的第2行
int bar;
int foo = bar * 3 * 5;
Run Code Online (Sandbox Code Playgroud)
被优化为
int bar;
int foo = bar * 15;
Run Code Online (Sandbox Code Playgroud)
甚至更多:
int foo = 3 * bar * 5;
Run Code Online (Sandbox Code Playgroud)
可以优化吗?
目的实际上是问我是否可以写
int foo = bar * 3 * 5;
Run Code Online (Sandbox Code Playgroud)
代替
int foo = bar * (3 * 5);
Run Code Online (Sandbox Code Playgroud)
保存括号.(并且减轻了手动操作那些常量排序的需要=>并且在许多情况下,使用相关变量的分组常量更有意义,而不是为了优化而分组常量)
我想大致了解何时可以期望编译器对循环进行矢量化,以及何时值得我展开循环以帮助它决定使用矢量化。
我知道细节非常重要(什么编译器,什么编译选项,什么架构,如何在循环中编写代码等),但我想知道是否有一些针对现代编译器的通用指南。
我将更具体地给出一个简单循环的示例(代码不应该计算任何有用的东西):
double *A,*B; // two arrays
int delay = something
[...]
double numer = 0, denomB = 0, denomA = 0;
for (int idxA = 0; idxA < Asize; idxA++)
{
int idxB = idxA + (Bsize-Asize)/2 + delay;
numer += A[idxA] * B[idxB];
denomA += A[idxA] * A[idxA];
denomB += B[idxB] * B[idxB];
}
Run Code Online (Sandbox Code Playgroud)
我可以期望编译器对循环进行矢量化吗?或者重写如下代码是否有用?
for ( int idxA = 0; idxA < Asize; idxA+=4 )
{
int idxB = idxA + (Bsize-Asize)/2 …
Run Code Online (Sandbox Code Playgroud) 考虑这个 C++ 代码:
#include <cstdint>
// returns a if less than b or if b is INT32_MIN
int32_t special_min(int32_t a, int32_t b)
{
return a < b || b == INT32_MIN ? a : b;
}
Run Code Online (Sandbox Code Playgroud)
GCC-fwrapv
正确地认识到减去 1b
可以消除特殊情况,并为 x86-64 生成以下代码:
lea edx, [rsi-1]
mov eax, edi
cmp edi, edx
cmovg eax, esi
ret
Run Code Online (Sandbox Code Playgroud)
但如果没有-fwrapv
它,会生成更糟糕的代码:
mov eax, esi
cmp edi, esi
jl .L4
cmp esi, -2147483648
je .L4
ret
.L4:
mov eax, edi …
Run Code Online (Sandbox Code Playgroud) 往上看.我写了示例函数:
source.ll:
define i32 @bleh(i32 %x) {
entry:
%addtmp = add i32 %x, %x
%addtmp1 = add i32 %addtmp, %x
%addtmp2 = add i32 %addtmp1, %x
%addtmp3 = add i32 %addtmp2, %x
%addtmp4 = add i32 %addtmp3, 1
%addtmp5 = add i32 %addtmp4, 2
%addtmp6 = add i32 %addtmp5, 3
%multmp = mul i32 %x, 3
%addtmp7 = add i32 %addtmp6, %multmp
ret i32 %addtmp7
}
Run Code Online (Sandbox Code Playgroud)
source-fp.ll:
define double @bleh(double %x) {
entry:
%addtmp = fadd double %x, %x
%addtmp1 …
Run Code Online (Sandbox Code Playgroud) c++ ×6
optimization ×4
gcc ×3
c ×2
performance ×2
algorithm ×1
boost ×1
boost-icl ×1
double ×1
fast-math ×1
g++ ×1
gnu ×1
llvm ×1
polynomials ×1
x86-64 ×1