- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我在我的程序中做了很多散列,所以我决定破解一个 constexpr 函数,它至少可以在编译时为我做一些散列。成功实现 constexpr 哈希函数后,我分析了代码,发现它实际上很花时间——这很奇怪,因为计算应该发生在编译时,而不是运行时。使用 G++ 4.7.3。
下面是 gprof 的一些输出,以及一个完整的演示程序,由于 constexpr 函数难以阅读,因此使用了非 constexpr 实现,同时也展示了它的工作原理。
我从以下链接中获取了建议,并将 char 数组设为 constexpr 和 const: why is a const array not accessible from a constexpr function?
注意:已从代码中删除一些内容以简化演示,例如测试和断言。
1.) 我的 constexpr 函数是否在运行时执行? (对我来说似乎很明显)
2.) 如果是,为什么?我如何让它在编译时而不是运行时执行?
gprof:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls us/call us/call name
50.00 0.06 0.06 600012 0.09 0.09 string_length(char const*, unsigned int)
36.36 0.10 0.04 50001 0.80 2.20 HASHOAT_CONSTEXPR(char const*, unsigned int, unsigned int, unsigned int)
9.09 0.10 0.01 1100022 0.01 0.01 oat_part_two(unsigned int const&)
4.55 0.11 0.01 50001 0.10 0.10 oat_part_six(unsigned int const&)
0.00 0.11 0.00 1650033 0.00 0.00 oat_part_one(unsigned int const&, char)
0.00 0.11 0.00 550011 0.00 0.00 oat_part_three(unsigned int const&)
0.00 0.11 0.00 200004 0.00 0.00 oat_part_four(unsigned int const&)
0.00 0.11 0.00 100002 0.00 0.00 oat_part_five(unsigned int const&)
0.00 0.11 0.00 1 0.00 0.00 HashOAT(char const*, unsigned int)
演示程序:
#include <cstdio>
#include <cstring>
// "One-at-a-time" Hash
// the non-constexpr implementation:
unsigned int HashOAT( const char *key, const unsigned int size = 1009 ); // size must be prime
unsigned int HashOAT( const char *key, const unsigned int size ) {
unsigned int h = 0;
const std::size_t len = strlen(key);
for ( std::size_t i = 0; i < len; ++i ) {
h += static_cast< unsigned int >( key[i] );
h += ( h << 10 );
h ^= ( h >> 6 );
}
h += ( h << 3 );
h ^= ( h >> 11 );
h += ( h << 15 );
return h % size;
}
constexpr unsigned int HASHOAT_CONSTEXPR( const char* str, const std::size_t size=1009, const std::size_t idx=0, const std::size_t h=0 );
constexpr unsigned int oat_part_one( const std::size_t& h, const char c );
constexpr unsigned int oat_part_two( const std::size_t& h );
constexpr unsigned int oat_part_three( const std::size_t& h );
constexpr unsigned int oat_part_four( const std::size_t& h );
constexpr unsigned int oat_part_five( const std::size_t& h );
constexpr unsigned int oat_part_six( const std::size_t& h );
constexpr unsigned int oat_part_one( const std::size_t& h, const char c ) {
return ( h + static_cast<unsigned int>( c ) );
}
constexpr unsigned int oat_part_two( const std::size_t& h ) {
return ( h << 10 );
}
constexpr unsigned int oat_part_three( const std::size_t& h ) {
return ( h >> 6 );
}
constexpr unsigned int oat_part_four( const std::size_t& h ) {
return ( h << 3 );
}
constexpr unsigned int oat_part_five( const std::size_t& h ) {
return ( h >> 11 );
}
constexpr unsigned int oat_part_six( const std::size_t& h ) {
return ( h << 15 );
}
constexpr std::size_t string_length( const char* str, std::size_t index = 0 ) {
return ( str == nullptr || str[index] == '\0' ) ? 0 : 1 + string_length( str, index+1 );
}
constexpr unsigned int HASHOAT_CONSTEXPR( const char* str, const std::size_t size, const std::size_t idx, const std::size_t h ) {
return (
( idx == string_length( str ) ) ? (
(
(
( h + oat_part_four( h ) ) ^
oat_part_five( h + oat_part_four( h ) )
) +
oat_part_six(
( h + oat_part_four( h ) ) ^
oat_part_five( h + oat_part_four( h ) )
)
) % size
) : (
HASHOAT_CONSTEXPR( str, size, idx+1,
(
oat_part_one( h, str[idx] ) +
oat_part_two( h + static_cast< unsigned int>( str[idx] ) )
) ^
oat_part_three( oat_part_one( h, str[idx] ) +
oat_part_two( oat_part_one( h, str[idx] ) )
)
)
)
);
}
int main ( void ) {
constexpr const char* str="Some String";
printf("Hash: %i\n", HashOAT(str) );
printf("Hash: %i\n", HASHOAT_CONSTEXPR(str) );
// make the program take some time so we can see if the constexpr function is actually taking run-time
for ( int i=0; i<50000; ++i ) {
HASHOAT_CONSTEXPR(str);
}
return 0;
}
最佳答案
20 天过去了,没有任何人回答,所以我决定深入挖掘一下。
我想到在编译时尝试各种优化级别(使用 g++ -O#)
我将 for 循环迭代了几百万次(在相当老的计算机上),并在优化级别 0、1、2、3 和 4 上计时执行。
我还编译成 ASM(使用 G++ -S)并检查程序生成的程序集。
我得出的结论是,constexpr 函数,或者可能特别复杂的 constexpr 函数,在低于 2 的任何优化级别上都被视为普通函数。在 2 级或更高级别,G++ 在编译时评估函数,并且它们没有进入可执行文件(通过检查程序集。asm 文件要短得多)。完全优化的可执行文件在不到一秒的时间内完成执行,而未优化的可执行文件花费了大约十倍的时间。此外,优化后的可执行文件在使用 gprof 进行分析时,未在其输出中显示任何 constexpr 函数。
底线是 constexpr 仅在以优化级别 2 或更高级别编译时在编译时进行评估。
关于c++ - 使用 const char 数组参数分析 constexpr 显示运行时执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19072539/
简而言之:我想从可变参数模板参数中提取各种选项,但不仅通过标签而且通过那些参数的索引,这些参数是未知的 标签。我喜欢 boost 中的方法(例如 heap 或 lockfree 策略),但想让它与 S
我可以对单元格中的 excel IF 语句提供一些帮助吗? 它在做什么? 对“BaselineAmount”进行了哪些评估? =IF(BaselineAmount, (Variance/Baselin
我正在使用以下方法: public async Task Save(Foo foo,out int param) { ....... MySqlParameter prmparamID
我正在使用 CodeGear RAD Studio IDE。 为了使用命令行参数测试我的应用程序,我多次使用了“运行 -> 参数”菜单中的“参数”字段。 但是每次我给它提供一个新值时,它都无法从“下拉
我已经为信用卡类编写了一些代码,粘贴在下面。我有一个接受上述变量的构造函数,并且正在研究一些方法将这些变量格式化为字符串,以便最终输出将类似于 号码:1234 5678 9012 3456 截止日期:
MySql IN 参数 - 在存储过程中使用时,VarChar IN 参数 val 是否需要单引号? 我已经像平常一样创建了经典 ASP 代码,但我没有更新该列。 我需要引用 VarChar 参数吗?
给出了下面的开始,但似乎不知道如何完成它。本质上,如果我调用 myTest([one, Two, Three], 2); 它应该返回元素 third。必须使用for循环来找到我的解决方案。 funct
将 1113355579999 作为参数传递时,该值在函数内部变为 959050335。 调用(main.c): printf("%d\n", FindCommonDigit(111335557999
这个问题在这里已经有了答案: Is Java "pass-by-reference" or "pass-by-value"? (92 个回答) 关闭9年前。 public class StackOve
我真的很困惑,当像 1 == scanf("%lg", &entry) 交换为 scanf("%lg", &entry) == 1 没有区别。我的实验书上说的是前者,而我觉得后者是可以理解的。 1 =
我正在尝试使用调用 SetupDiGetDeviceRegistryProperty 的函数使用德尔福 7。该调用来自示例函数 SetupEnumAvailableComPorts .它看起来像这样:
我需要在现有项目上实现一些事件的显示。我无法更改数据库结构。 在我的 Controller 中,我(从 ajax 请求)传递了一个时间戳,并且我需要显示之前的 8 个事件。因此,如果时间戳是(转换后)
rails 新手。按照多态关联的教程,我遇到了这个以在create 和destroy 中设置@client。 @client = Client.find(params[:client_id] || p
通过将 VM 参数设置为 -Xmx1024m,我能够通过 Eclipse 运行 Java 程序-Xms256M。现在我想通过 Windows 中的 .bat 文件运行相同的 Java 程序 (jar)
我有一个 Delphi DLL,它在被 Delphi 应用程序调用时工作并导出声明为的方法: Procedure ProduceOutput(request,inputs:widestring; va
浏览完文档和示例后,我还没有弄清楚 schema.yaml 文件中的参数到底用在哪里。 在此处使用 AWS 代码示例:https://github.com/aws-samples/aws-proton
程序参数: procedure get_user_profile ( i_attuid in ras_user.attuid%type, i_data_group in data_g
我有一个字符串作为参数传递给我的存储过程。 dim AgentString as String = " 'test1', 'test2', 'test3' " 我想在 IN 中使用该参数声明。 AND
这个问题已经有答案了: When should I use "this" in a class? (17 个回答) 已关闭 6 年前。 我运行了一些java代码,我看到了一些我不太明白的东西。为什么下
我输入 scroll(0,10,200,10);但是当它运行时,它会传递字符串“xxpos”或“yypos”,我确实在没有撇号的情况下尝试过,但它就是行不通。 scroll = function(xp
我是一名优秀的程序员,十分优秀!