assert(0.1 + 0.2 != 0.3); // shall be true
Run Code Online (Sandbox Code Playgroud)
是我最喜欢的检查,语言使用本机浮点运算.
#include <cstdio>
int main()
{
printf("%d\n", (0.1 + 0.2 != 0.3));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
1
Run Code Online (Sandbox Code Playgroud)
print(0.1 + 0.2 != 0.3)
Run Code Online (Sandbox Code Playgroud)
输出:
True
Run Code Online (Sandbox Code Playgroud)
为什么D不适用?理解D使用本机浮点数.这是一个错误吗?他们是否使用某些特定的数字代表?别的什么?很混乱.
import std.stdio;
void main()
{
writeln(0.1 + 0.2 != 0.3);
}
Run Code Online (Sandbox Code Playgroud)
输出:
false
Run Code Online (Sandbox Code Playgroud)
码:
import std.stdio;
void main()
{
writeln(0.1 + 0.2 != 0.3); // …Run Code Online (Sandbox Code Playgroud) 在许多编程比赛中,我看到有人写这种类型的for-loop
for(i = 0; i < (1 << 7); i++)
Run Code Online (Sandbox Code Playgroud)
除非我遗漏了什么,否则就是这样
for(i = 0; i < 128; i++)
Run Code Online (Sandbox Code Playgroud)
为何使用该(1 << 7)版本?
每次不必要的开销是不是计算条件?
对于以下C源代码:
#include <math.h>
int main(void)
{
double x;
x = log(0.0);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我编译时gcc -lm,我得到:
/tmp/ccxxANVH.o: In function `main':
a.c:(.text+0xd): undefined reference to `log'
collect2: error: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)
但是,如果我替换log(0.0)为log(10.0),那么它可以成功编译.
我不太明白这一点,因为无论它们是否具有数学意义,它们都应该编译 - 没有语法错误.有人能解释一下吗?
以防万一,我的gcc -v输出:
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.2-19ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 …Run Code Online (Sandbox Code Playgroud) 这是我的代码:
int f(double x)
{
return isnan(x);
}
Run Code Online (Sandbox Code Playgroud)
如果我#include <cmath>得到这个集会:
xorl %eax, %eax
ucomisd %xmm0, %xmm0
setp %al
Run Code Online (Sandbox Code Playgroud)
这是相当聪明的:如果x与其自身的比较是无序的,则ucomisd设置奇偶校验标志,意味着x是NAN.然后setp将奇偶校验标志复制到结果中(只有一个字节,因此最初清除%eax).
但是,如果我#include <math.h>得到这个集会:
jmp __isnan
Run Code Online (Sandbox Code Playgroud)
现在代码不是内联的,并且__isnan函数当然没有更快的ucomisd指令,所以我们已经跳过没有任何好处.如果我将代码编译为C,我会得到同样的东西.
现在如果我将isnan()调用更改为__builtin_isnan(),我会得到简单的ucomisd指令指令,无论我包含哪个头,它也可以在C中工作.同样,如果我只是return x != x.
所以我的问题是,为什么C <math.h>头提供的效率isnan()低于C++ <cmath>头?人们真的希望使用__builtin_isnan(),如果是,为什么?
我在x86-64上使用-O2和-O3优化测试了GCC 4.7.2和4.9.0 .
说完看了一眼前面的问题1,2,我在想,如果我可以强制编译器以下代码打印素数进行常量折叠.
#include <iostream>
using namespace std;
inline bool is_prime(int n)
{
if(n<2)
return false;
for(int i=2;i*i<=n;i++)
if(n%i==0)
return false;
return true;
}
int main()
{
for(int i=0;i<20;i++)
if(is_prime(i))
cout<<i<<endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我通过以下方式构建它:
g++ -O3 -S main.cpp -o main.asm
Run Code Online (Sandbox Code Playgroud)
结果是一些:
2,3,5,7,11,13,17,19
Run Code Online (Sandbox Code Playgroud)
我想强制编译看看类似的代码
for(int x:{2,3,5,7,11,13,17,19})
cout<<x<<endl;
Run Code Online (Sandbox Code Playgroud)
要么
cout<< 2 <<endl;
cout<< 3 <<endl;
cout<< 5 <<endl;
cout<< 7 <<endl;
cout<< 11 <<endl;
cout<< 13 <<endl;
cout<< 17 <<endl;
cout<< 19 <<endl;
Run Code Online (Sandbox Code Playgroud)
但阅读大会表明没有发生.
我甚至使用__builtin_expect但它没有用.
有没有办法强制编译器优化器读取for循环并使用输出数据已知的优势?
我想在不使用模板元编程的情况下完成它. …
我在slf4j中看到了一些代码,如下所示.我不知道为什么要避免在这里不断折叠.有必要这样做吗?或者只是最好的做法.这样做有什么好处?
谢谢.
/**
* Declare the version of the SLF4J API this implementation is compiled against.
* The value of this field is usually modified with each release.
*/
// to avoid constant folding by the compiler, this field must *not* be final
public static String REQUESTED_API_VERSION = "1.6"; // !final**
Run Code Online (Sandbox Code Playgroud) 似乎gcc对复杂的常量折叠有一些限制.这是一个例子:
static inline unsigned int DJBHash(const char *str)
{
int i;
unsigned int hash = 5381;
for(i = 0; i < strlen(str); i++)
{
hash = ((hash << 5) + hash) + str[i];
}
return hash;
}
int f(void)
{
return DJBHash("01234567890123456");
}
Run Code Online (Sandbox Code Playgroud)
当使用-O3优化级别(gcc 4.8)运行时,它很好地展开了DJBHash中的循环,并在编译期间计算该字符串的哈希值.
但是,当使字符串长一个字符时,return DJBHash("012345678901234567");它不再折叠它并生成带有条件跳转指令的循环.
我想将任意长度的文字字符串折叠为其哈希值作为编译时常量.
这可以吗?
我的问题是关于gcc的常量折叠优化(请参阅标题 - 请不要删除gcc和编译器标签)
这里的许多答案试图用模板或constexpr解决问题.很高兴知道这些选项,并感谢发布它们为所有人的利益.但是,他们没有直接回答我的问题.
实际上,我正在使用gcc端口,因此我可以根据需要更改和构建gcc源代码.但我只限于C,我想在这个范围内解决这个问题.
c compiler-construction gcc compiler-optimization constantfolding
我想知道,确实-MO=Deparse向您展示了所有Perl优化,为什么不在Perl 5.10中折叠?
$ perl -MO=Deparse -e'[qw/foo bar baz/]->[0]'
['foo', 'bar', 'baz']->[0];
-e syntax OK
Run Code Online (Sandbox Code Playgroud)
IRC的一些人认为O=Deparse可能没有全部显示,但它确实显示了一些不断折叠.
$ perl -MO=Deparse -e'use constant "foo" => "bar"; foo'
use constant ('foo', 'bar');
'???';
-e syntax OK
Run Code Online (Sandbox Code Playgroud)
如果我明确写出常量sub,结果相同.虽然可预测,但是文档中constant.pm包含的是创建常量列表而不是常量数组也很有趣.我假设这不仅仅是像标量常量那样折叠,而是需要在每次调用时创建新数组的开销.
$ perl -MO=Deparse -e'use constant foo => qw/foo bar baz/; (foo)[0]'
use constant ('foo', ('foo', 'bar', 'baz'));
(foo)[0];
-e syntax OK
Run Code Online (Sandbox Code Playgroud)
我能得出的唯一结论-MO=Deparse是显示所有折叠,而常量数组在Perl中没有优化?是这样吗?它有技术原因吗?
基于这个有趣的问题:在Nicholas Carey的回答中提到的添加int和uint以及使用常量折叠进行操作时,我偶然发现了编译器看似不一致的行为:
请考虑以下代码段:
int i = 1;
uint j = 2;
var k = i - j;
Run Code Online (Sandbox Code Playgroud)
这里编译器正确解析k为long.这种特殊行为在规范中有明确定义,如前面提到的问题的答案中所解释的那样.
让我感到惊讶的是,在处理文字常量或常量时,行为会发生变化.阅读Nicholas Carey的回答我意识到行为可能不一致所以我检查并确定:
const int i = 1;
const uint j = 2;
var k = i - j; //Compile time error: The operation overflows at compile time in checked mode.
k = 1 - 2u; //Compile time error: The operation overflows at compile time in …Run Code Online (Sandbox Code Playgroud) 可能重复:
java中是否有任何称为"常量折叠"的概念?
嗨,我遇到过Java编译器使用称为Constant Folding的东西.这是什么?它是如何影响的?
constantfolding ×10
c ×4
c++ ×2
gcc ×2
java ×2
c# ×1
coding-style ×1
core ×1
d ×1
expression ×1
for-loop ×1
g++ ×1
math.h ×1
nan ×1
optimization ×1
perl ×1
perl5.10 ×1
slf4j ×1