一个经验非常丰富的程序员可能可以静态分析程序的性能瓶颈,但大多数人做不到这些。这个时候我们往往需要借助一些辅助工具来分析程序的性能瓶颈,火焰图就是其中之一。
一张典型的火焰图长这样

本文主要介绍如何生成和分析火焰图。
(更多…)一个经验非常丰富的程序员可能可以静态分析程序的性能瓶颈,但大多数人做不到这些。这个时候我们往往需要借助一些辅助工具来分析程序的性能瓶颈,火焰图就是其中之一。
一张典型的火焰图长这样
本文主要介绍如何生成和分析火焰图。
(更多…)python和c++的代码中均有使用crc32分流的操作,需要保证分流得到的结果一致,那么两个crc32的方法得到的结果需要一致才行。然而实际测试中发现python2中zlib.crc32和c++的zlib中crc32得到的结果却不一致。
import zlib
print zlib.crc32("helloworld")
结果为 -102031187。
如下:
C++ 版zlib crc32
#include <zlib.h>
#include <iostream>
int main() {
std::string str = "helloworld";
std::cout << crc32(0, reinterpret_cast<unsigned const char*>(&str[0]), str.size()) << std::endl;
return 0;
}
运行结果为:4192936109
python版得出的结果是-102031187,而C++版本得出的结果是4192936109。
(更多…)本文利用神经网络对股市的预测结果作为分析的对象,打开神经网络的黑箱,找到股市中涨跌的秘密。
想要预测股市涨跌,就需要了解在股票上涨和下跌的时候,前一天发生了什么。就好像我们想要预测明天天气的时候,总会想尽办法找到过去几十年甚至几百年下雨的前一段时间都有哪些征兆。预测股票也一样,我们需要想尽一切办法找到某只股票过去几年里面价格上涨的前一天都有哪些特征,越全面越好。
找特征不是一件简单的事情,有效的特征可以为我们增加预测的精准度,而无效的特征会对训练造成干扰。首先从最简单的量价特征开始,即今天的股票的价格变化和交易量变化。
为什么是这两个特征?我的理论依据是市场所有的信息最终都会体现在今天的交易价格和交易量上。这两个特征一定是有效的特征。
为了让预测更加准确,我们加上一个五日均价变化,体现股票最近一段时间的价格变化趋势。
为了尽可能减少可能存在的人为操控股市的影响,我选择了沪深300指数作为分析对象,沪深300整体交易量大,波动小,比较适合分析。
构建一个单层一个节点的网络,如下图,这样训练得到的结果得出来的参数我们会有一个直观的印象。
假设R是股票明日的最终涨跌情况,涨为1、跌为0,那么这个网络想要表示的就是价格变化,量变化,五日均价变化分别和未来的涨跌到底是正相关还是负相关。
如果没有额外的设置,iterm2 使用 rzsz 的时候会卡在
waiting to receive.**B0100000023be50
这个时候就需要使用iterm2提供的trigger来实现rzsz的功能。
使用rzsz之前本地也需要安装
brew install lrzsz
如果没有安装brew,请先安装brew,mac必备的包管理器!
发送文件的脚本如下,可以复制下面的内容,保存在 /usr/local/bin/iterm2-send-zmodem.sh中。
#!/bin/bash
# Author: Matt Mastracci (matthew@mastracci.com)
# AppleScript from http://stackoverflow.com/questions/4309087/cancel-button-on-osascript-in-a-bash-script
# licensed under cc-wiki with attribution required
# Remainder of script public domain
osascript -e 'tell application "iTerm2" to version' > /dev/null 2>&1 && NAME=iTerm2 || NAME=iTerm
if [[ $NAME = "iTerm" ]]; then
FILE=`osascript -e 'tell application "iTerm" to activate' -e 'tell application "iTerm" to set thefile to choose file with prompt "Choose a file to send"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")"`
else
FILE=`osascript -e 'tell application "iTerm2" to activate' -e 'tell application "iTerm2" to set thefile to choose file with prompt "Choose a file to send"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")"`
fi
if [[ $FILE = "" ]]; then
echo Cancelled.
# Send ZModem cancel
echo -e \\x18\\x18\\x18\\x18\\x18
sleep 1
echo
echo \# Cancelled transfer
else
/usr/local/bin/sz "$FILE" -e -b
sleep 1
echo
echo \# Received $FILE
fi
vim /usr/local/bin/iterm2-send-zmodem.sh
chmod +x /usr/local/bin/iterm2-send-zmodem.sh
接收文件的脚本如下,同样可以复制保存在/usr/local/bin/iterm2-recv-zmodem.sh
#!/bin/bash
# Author: Matt Mastracci (matthew@mastracci.com)
# AppleScript from http://stackoverflow.com/questions/4309087/cancel-button-on-osascript-in-a-bash-script
# licensed under cc-wiki with attribution required
# Remainder of script public domain
osascript -e 'tell application "iTerm2" to version' > /dev/null 2>&1 && NAME=iTerm2 || NAME=iTerm
if [[ $NAME = "iTerm" ]]; then
FILE=`osascript -e 'tell application "iTerm" to activate' -e 'tell application "iTerm" to set thefile to choose folder with prompt "Choose a folder to place received files in"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")"`
else
FILE=`osascript -e 'tell application "iTerm2" to activate' -e 'tell application "iTerm2" to set thefile to choose folder with prompt "Choose a folder to place received files in"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")"`
fi
if [[ $FILE = "" ]]; then
echo Cancelled.
# Send ZModem cancel
echo -e \\x18\\x18\\x18\\x18\\x18
sleep 1
echo
echo \# Cancelled transfer
else
cd "$FILE"
/usr/local/bin/rz -E -e -b
sleep 1
echo
echo
echo \# Sent \-\> $FILE
fi
vim /usr/local/bin/iterm2-recv-zmodem.sh<br>chmod +x /usr/local/bin/iterm2-recv-zmodem.sh
teigger需要设置两个,一个实发送文件的trigger,一个是接收文件的trigger。
打开iterm2->Preferences->Profiles->Advanced->Triggers
点击Edit,点击+号,几个框分别填入下面的内容
Regular expression: \*\*B0100
Action: Run Silent Coprocess
Parameters: /usr/local/bin/iterm2-send-zmodem.sh
Regular expression: \*\*B00000000000000
Action: Run Silent Coprocess
Parameters: /usr/local/bin/iterm2-recv-zmodem.sh
最后设置好结果入如下
每次换电脑都需要设置一遍,记录下来备忘。
mac下pip安装ta-lib会报错
Running setup.py install for ta-lib ... error
ERROR: Command errored out with exit status 1:
command: /usr/bin/python -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/private/var/folders/gk/sw9sly3x5w3_mspdt4h8tm380000gn/T/pip-install-1emRyO/ta-lib/setup.py'"'"'; __file__='"'"'/private/var/folders/gk/sw9sly3x5w3_mspdt4h8tm380000gn/T/pip-install-1emRyO/ta-lib/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /private/var/folders/gk/sw9sly3x5w3_mspdt4h8tm380000gn/T/pip-record-wXGPIe/install-record.txt --single-version-externally-managed --user --prefix= --compile --install-headers /Users/huchao/Library/Python/2.7/include/python2.7/ta-lib
cwd: /private/var/folders/gk/sw9sly3x5w3_mspdt4h8tm380000gn/T/pip-install-1emRyO/ta-lib/
Complete output (27 lines):
/private/var/folders/gk/sw9sly3x5w3_mspdt4h8tm380000gn/T/pip-install-1emRyO/ta-lib/setup.py:71: UserWarning: Cannot find ta-lib library, installation may fail.
warnings.warn('Cannot find ta-lib library, installation may fail.')
报错的原因是缺少ta-lib library,看起来是编译时候缺少链接库。需要安装ta-lib静态库,于是使用brew安装一下ta-lib。
brew install ta-lib
安装完毕之后就可以pip install ta-lib,就可以安装成功了。
上一篇预测股市涨跌的翻车了!毕竟概率在这儿,70%-80%的的概率毕竟不能保证一定是正确的。
今天沪深300指数上午上涨,下午开始下跌,最终收跌-0.06%,感觉还好!
今天晚上用之前训练好的模型去预测,结果看起来还比较乐观,如图:
虽然模型也没能给出明确的涨还是跌,但看起来涨的概率还是比跌的概率稍微大一点点。
此外,从我个人的主观感觉来看,明天沪深300上涨的概率也比较大,毕竟前值是下跌的趋势,而最近几天基本跌不下去了。
简单说一下模型里面的数字都是什么意思吧。这些模型是根据过去2年的沪深300的波动特征训练得到的模型,上面的精准度代表预测正确的次数/总次数,比如model_6,精准度为0.71,大概能表示10次中有7次是正确的,这个概率虽然不高,但是也能给我们提供一些指导。
明日涨跌表示的是根据当前的收盘状况预测明天一天的涨跌,大于0.5表示涨,小于0.5表示跌。
C++中,动态内存管理是通过一对运算符来完成:new 和 delete。new操作符在内存中为对象分配空间并返回一个指向该对象的指针,delete接收一个动态对象的指针,销毁该对象,并释放与之相关的内存。
手动管理内存看起来只有这两个操作,似乎很轻松,但实际上这是一件非常繁琐的事情,分配了内存但没有释放内存的场景发生的概率太大了!回想一下,你有多少次打开抽屉却没关上,拿出来的护肤品擦完脸之后却忘了放回去,吃完饭却忘了洗碗。类似这种没有收尾的事情我做的太多了。(以上这些都是在实际生活中我爱人批评我的点)
我连这种明面上的事情都能忘记收尾,何况分配内存!所以为了世界和平,我放弃了手动管理内存。好在C++引入了两种智能指针:shared_ptr和unique_ptr。这两种智能指针可以自动管理内存。(生活中要是有这种东西能自动帮我把东西放回去该多好!)
接下来就介绍一下这两种智能指针的使用方法,使用shared_ptr和unique_ptr需要引入头文件memory。
(更多…)Attention:this blog is a translation of https://www.internalpointers.com/post/c-rvalue-references-and-move-semantics-beginners ,which is posted by @internalpoiners.
在我的前一篇文章里,我解释了右值背后的逻辑。核心的思想就是:在C++中你总会有一些临时的、生命周期较短的值,这些值无论如何你都无法改变。
令人惊喜的是,现代C++(通常指C++0x或者更高的版本)引入了右值引用(rvalue reference)的概念:它是一个新的可以被绑定到临时对象的类型,允许你改变他们。为什么呢?
Attention:this blog is a translation of https://www.internalpointers.com/post/understanding-meaning-lvalues-and-rvalues-c ,which is posted by @internalpoiners.
一直以来,我都对C++中左值(lvalue)和右值(lvalue)的概念模糊不清。我认为是时候好好理解他们了,因为这些概念随着C++语言的进化变得越来越重要。
首先,让我们避开那些正式的定义。在C++中,一个左值是指向一个指定内存的东西。另一方面,右值就是不指向任何地方的东西。通常来说,右值是暂时和短命的,而左值则活的很久,因为他们以变量的形式(variable)存在。我们可以将左值看作为容器(container)而将右值看做容器中的事物。如果容器消失了,容器中的事物也就自然就无法存在了。
让我们现在来看一些例子:
int x = 666; //ok
在这里,666
是一个右值。一个数字(从技术角度来说他是一个字面常量(literal constant))没有指定的内存地址,当然在程序运行时一些临时的寄存器除外。在该例中,666
被赋值(assign)给x
,x
是一个变量。一个变量有着具体(specific)的内存位置,所以他是一个左值。C++中声明一个赋值(assignment)需要一个左值作为它的左操作数(left operand):这完全合法。
对于左值x
,你可以做像这样的操作:
int* y = &x; //ok
在这里我通过取地址操作符&
获取了x
的内存地址并且把它放进了y
。&
操作符需要一个左值并且产生了一个右值,这也是另一个完全合法的操作:在赋值操作符的左边我们有一个左值(一个变量),在右边我们使用取地址操作符产生的右值。
然而,我们不能这样写:
int y;
666 = y; //error!
可能上面的结论是显而易见的,但是从技术上来说是因为666
是一个字面常量也就是一个右值,它没有一个具体的内存位置(memory location),所以我们会把y
分配到一个不存在的地方。
下面是GCC给出的变异错误提示:
error: lvalue required as left operand of assignment
赋值的左操作数需要一个左值,这里我们使用了一个右值666
。
我们也不能这样做:
int* y = &666;// error~
GCC给出了以下错误提示:
error: lvalue required as unary ‘&’ operand`
&
操作符需要一个左值作为操作数,因为只有一个左值才拥有地址。
我们知道一个赋值的左操作数必须是一个左值,因此下面的这个函数肯定会抛出错误:lvalue required as left operand of assignment
int setValue()
{
return 6;
}
// ... somewhere in main() ...
setValue() = 3; // error!
错误原因很清楚:setValue()
返回了一个右值(一个临时值6
),他不能作为一个赋值的左操作数。现在,我们看看如果函数返回一个左值,这样的赋值会发生什么变化。看下面的代码片段(snippet):
int global = 100;
int& setGlobal()
{
return global;
}
// ... somewhere in main() ...
setGlobal() = 400; // OK
该程序可以运行,因为在这里setGlobal()
返回一个引用(reference),跟之前的setValue()
不同。一个引用是指向一个已经存在的内存位置(global
变量)的东西,因此它是一个左值,所以它能被赋值。注意这里的&
:它不是取地址操作符,他定义了返回的类型(一个引用)。
可以从函数返回左值看上去有些隐晦,它在你做一些进阶的编程例如实现一些操作符的重载(implementing overload operators)时会很有作用,这些知识会在未来的章节中讲述。
一个左值可以被转换(convert)为右值,这完全合法且经常发生。让我们先用+
操作符作为一个例子,根据C++的规范(specification),它使用两个右值作为参数并返回一个右值(译者按:可以将操作符理解为一个函数)。
让我们看下面的代码片段:
int x = 1;
int y = 3;
int z = x + y; // ok
等一下,x
和y
是左值,但是加法操作符需要右值作为参数:发生了什么?答案很简单:x
和y
经历了一个隐式(implicit)的左值到右值(lvalue-to-rvalue)的转换。许多其他的操作符也有同样的转换——减法、加法、除法等等。
相反呢?一个右值可以被转化为左值吗?不可以,它不是技术所限,而是C++编程语言就是那样设计的。
在C++中,当你做这样的事:
int y = 10;
int& yref = y;
yref++; // y is now 11
这里将yref
声明为类型int&
:一个对y
的引用,它被称作左值引用(lvalue reference)。现在你可以开心地通过该引用改变y
的值了。
我们知道,一个引用必须只想一个具体的内存位置中的一个已经存在的对象,即一个左值。这里y
确实存在,所以代码运行完美。
现在,如果我缩短整个过程,尝试将10
直接赋值给我的引用,并且没有任何对象持有该引用,将会发生什么?
int& yref = 10; // will it work?
在右边我们有一个临时值,一个需要被存储在一个左值中的右值。在左边我们有一个引用(一个左值),他应该指向一个已经存在的对象。但是10
是一个数字常量(numeric constant),也就是一个左值,将它赋给引用与引用所表述的精神冲突。
如果你仔细想想,那就是被禁止的从右值到左值的转换。一个volitile
的数字常量(右值)如果想要被引用,需要先变成一个左值。如果那被允许,你就可以通过它的引用来改变数字常量的值。相当没有意义,不是吗?更重要的是,一旦这些值不再存在这些引用该指向哪里呢?
下面的代码片段同样会发生错误,原因跟刚才的一样:
void fnc(int& x)
{
}
int main()
{
fnc(10); // Nope!
// This works instead:
// int x = 10;
// fnc(x);
}
我将一个临时值10
传入了一个需要引用作为参数的函数中,产生了将右值转换为左值的错误。这里有一个解决方法(workaround),创造一个临时的变量来存储右值,然后将变量传入函数中(就像注释中写的那样)。将一个数字传入一个函数确实不太方便。
先看看GCC对于之前两个代码片段给出的错误提示:
error: invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’
GCC认为引用不是const
的,即一个常量。根据C++规范,你可以将一个const
的左值绑定到一个右值上,所以下面的代码可以成功运行:
const int& ref = 10; // OK!
当然,下面的也是:
void fnc(const int& x)
{
}
int main()
{
fnc(10); // OK!
}
背后的道理是相当直接的,字面常量10
是volatile
的并且会很快失效(expire),所以给他一个引用是没什么意义的。如果我们让引用本身变成常量引用,那样的话该引用指向的值就不能被改变了。现在右值被修改的问题被很好地解决了。同样,这不是一个技术限制,而是C ++人员为避免愚蠢麻烦所作的选择。
应用:C++中经常通过常量引用来将值传入函数中,这避免了不必要的临时对象的创建和拷贝。
编译器会为你创建一个隐藏的变量(即一个左值)来存储初始的字面常量,然后将隐藏的变量绑定到你的引用上去。那跟我之前的一组代码片段中手动完成的是一码事,例如:
// the following...
const int& ref = 10;
// ... would translate to:
int __internal_unique_name = 10;
const int& ref = __internal_unique_name;
现在你的引用指向了真实存在的事物(知道它走出作用域外)并且你可以正常使用它,出克改变他指向的值。
const int& ref = 10;
std::cout << ref << "\n"; // OK!
std::cout << ++ref << "\n"; // error: increment of read-only reference ‘ref’
理解左值和右值的含义让我弄清楚了几个C++内在的工作方式。C++11进一步推动了右值的限定,引入了右值引用(rvalue reference)和移动(move semantics)的概念。
来源 https://www.jianshu.com/p/94b0221f64a5
这是我学习C++的第三篇笔记,函数。我的学习路径是
1. 变量和数据类型
2. 流程控制
3. 函数
4. 面向对象
5. 标准库
现在学习的是函数的声明、定义、调用等相关知识。
函数的声明包含返回类型,函数名字,0个或者多个形参,无函数体,通常在头文件中对函数进行声明。
返回类型 函数名称(参数类型1 参数1, 参数类型2 参数2);
// 例如声明一个求阶乘的函数
int fact(int val);
函数的定义包含返回类型,函数名字,0个或多个形参,以及函数体。
返回类型 函数名称(参数类型1 参数1, 参数类型2 参数2) {
函数体
}
比如写一个求阶乘的函数,可以写成下面这样
int fact(int val)
{
int ret = 1;
while (val > 1) {
ret *= val--; // ret乘val的值返回给ret,val再自减1
}
return ret;
}
写一些简单的函数大多数语言都差不多,不过可惜每种语言或多或少都有自己的特色,这是比较令人头秃的地方。
(更多…)