C++ Convert String to Double Speed

(There is also a string-to-int performance test.)

A performance benchmark of which method is faster of converting an std::string to a double. The goal is ending up with a double of the value represented in an std::string.

The tested methods are:

Source for the test is at speed-string-to-double.cpp with cycle.h.

The compilers are Microsoft Visual C++ 2010 with _SECURE_SCL disabled, GNU g++ 4.6.0, and LLVM clang++ from Arch.

Tests were run for converting 100000 string containing doubles in the range +/- 99999.99999. The result for the naive loop and atof() are set as the baseline 100% and the other numbers is time spent relative to those. The naive loop wins by a large margin, but Boost.Spirit is the fastest correct implementation.

Windows: MSVC++ 2010

  • Compiler: MSVC++ 2010 _SECURE_SCL=0
  • Arch: Windows 7 64 bit, 1.60GHz Core i7 Q720, 8 GiB RAM
VC++ 2010 Ticks Relative to naive Relative to atof()
naive 4366220 1.00 0.05
atof() 82732774 18.95 1.00
strtod() 83189198 19.05 1.01
sscanf() 168568387 38.61 2.04
spirit qi 18932917 4.34 0.23
lexical_cast 332374407 76.12 4.02
stringstream 361943816 82.90 4.37
stringstream reused 240848392 55.16 2.91

Linux: GNU g++ 4.6.0

  • Compiler: GNU g++ 4.6.0 -O3
  • Arch: VirtualBox on the Windows machine, VT-x, Arch Linux, kernel 2.6.38-ARCH, 1 GiB RAM
g++ 4.6.0 Ticks Relative to naive Relative to atof()
naive 4656159 1.00 0.15
atof() 30605490 6.57 1.00
strtod() 30963926 6.65 1.01
sscanf() 56235197 12.08 1.84
spirit qi 20731062 4.45 0.68
lexical_cast 139521406 29.96 4.56
stringstream 184723298 39.67 6.04
stringstream reused 100905407 21.67 3.30

Linux: LLVM clang++ 2.9

  • Compiler: clang++ 2.9 -O3
  • Arch: VirtualBox on the Windows machine, VT-x, Arch Linux, kernel 2.6.38-ARCH, 1 GiB RAM
clang++ 2.9 Ticks Relative to naive Relative to atof()
naive 6804881 1.00 0.22
atof() 30829865 4.53 1.00
strtod() 30871514 4.54 1.00
sscanf() 57903993 8.51 1.88
spirit qi 24411041 3.59 0.79
lexical_cast 149339833 21.95 4.84
stringstream 191239066 28.10 6.20
stringstream reused 100461405 14.76 3.26
 
 
#ifdef _MSC_VER
#define _SECURE_SCL 0
#define _CRT_SECURE_NO_DEPRECATE 1
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#define NOMINMAX
#endif #include <cstdlib>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <cmath>
#include <iostream>
#include <string>
#include <vector>
#include <iomanip>
#include <sstream>
#include <boost/lexical_cast.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include "cycle.h" static const size_t N = ;
static const size_t R = ; void PrintStats(std::vector<double> timings) {
double fastest = std::numeric_limits<double>::max(); std::cout << std::fixed << std::setprecision();
std::cout << "[";
for (size_t i = ; i<timings.size()- ; ++i) {
fastest = std::min(fastest, timings[i]);
std::cout << timings[i] << ",";
}
std::cout << timings.back();
std::cout << "]"; double sum = 0.0;
for (size_t i = ; i<timings.size() ; ++i) {
sum += timings[i];
}
double avg = sum / static_cast<double>(timings.size()-); sum = 0.0;
for (size_t i = ; i<timings.size() ; ++i) {
timings[i] = pow(timings[i]-avg, );
sum += timings[i];
}
double var = sum/(timings.size()-);
double sdv = sqrt(var); std::cout << " with fastest " << fastest << ", average " << avg << ", stddev " << sdv;
} double naive(const char *p) {
double r = 0.0;
bool neg = false;
if (*p == '-') {
neg = true;
++p;
}
while (*p >= '' && *p <= '') {
r = (r*10.0) + (*p - '');
++p;
}
if (*p == '.') {
double f = 0.0;
int n = ;
++p;
while (*p >= '' && *p <= '') {
f = (f*10.0) + (*p - '');
++p;
++n;
}
r += f / std::pow(10.0, n);
}
if (neg) {
r = -r;
}
return r;
} int main() {
std::vector<std::string> nums;
nums.reserve(N);
for (size_t i= ; i<N ; ++i) {
std::string y;
if (i & ) {
y += '-';
}
y += boost::lexical_cast<std::string>(i);
y += '.';
y += boost::lexical_cast<std::string>(i);
nums.push_back(y);
} {
double tsum = 0.0;
std::vector<double> timings;
timings.reserve(R);
for (size_t r= ; r<R ; ++r) {
ticks start = getticks();
for (size_t i= ; i<nums.size() ; ++i) {
double x = naive(nums[i].c_str());
tsum += x;
}
ticks end = getticks();
double timed = elapsed(end, start);
timings.push_back(timed);
} std::cout << "naive: ";
PrintStats(timings);
std::cout << std::endl;
std::cout << tsum << std::endl;
} {
double tsum = 0.0;
std::vector<double> timings;
timings.reserve(R);
for (size_t r= ; r<R ; ++r) {
ticks start = getticks();
for (size_t i= ; i<nums.size() ; ++i) {
double x = atof(nums[i].c_str());
tsum += x;
}
ticks end = getticks();
double timed = elapsed(end, start);
timings.push_back(timed);
} std::cout << "atof(): ";
PrintStats(timings);
std::cout << std::endl;
std::cout << tsum << std::endl;
} {
double tsum = 0.0;
std::vector<double> timings;
timings.reserve(R);
for (size_t r= ; r<R ; ++r) {
ticks start = getticks();
for (size_t i= ; i<nums.size() ; ++i) {
double x = strtod(nums[i].c_str(), );
tsum += x;
}
ticks end = getticks();
double timed = elapsed(end, start);
timings.push_back(timed);
} std::cout << "strtod(): ";
PrintStats(timings);
std::cout << std::endl;
std::cout << tsum << std::endl;
} {
double tsum = 0.0;
std::vector<double> timings;
timings.reserve(R);
for (size_t r= ; r<R ; ++r) {
ticks start = getticks();
for (size_t i= ; i<nums.size() ; ++i) {
double x = 0.0;
sscanf(nums[i].c_str(), "%lf", &x);
tsum += x;
}
ticks end = getticks();
double timed = elapsed(end, start);
timings.push_back(timed);
} std::cout << "sscanf(): ";
PrintStats(timings);
std::cout << std::endl;
std::cout << tsum << std::endl;
} {
double tsum = 0.0;
std::vector<double> timings;
timings.reserve(R);
for (size_t r= ; r<R ; ++r) {
ticks start = getticks();
for (size_t i= ; i<nums.size() ; ++i) {
double x = boost::lexical_cast<double>(nums[i]);
tsum += x;
}
ticks end = getticks();
double timed = elapsed(end, start);
timings.push_back(timed);
} std::cout << "lexical_cast: ";
PrintStats(timings);
std::cout << std::endl;
std::cout << tsum << std::endl;
} {
using boost::spirit::qi::double_;
using boost::spirit::qi::parse;
double tsum = 0.0;
std::vector<double> timings;
timings.reserve(R);
for (size_t r= ; r<R ; ++r) {
ticks start = getticks();
for (size_t i= ; i<nums.size() ; ++i) {
double x = 0.0;
char const *str = nums[i].c_str();
parse(str, &str[nums[i].size()], double_, x);
tsum += x;
}
ticks end = getticks();
double timed = elapsed(end, start);
timings.push_back(timed);
} std::cout << "spirit qi: ";
PrintStats(timings);
std::cout << std::endl;
std::cout << tsum << std::endl;
} {
double tsum = 0.0;
std::vector<double> timings;
timings.reserve(R);
for (size_t r= ; r<R ; ++r) {
ticks start = getticks();
for (size_t i= ; i<nums.size() ; ++i) {
std::istringstream ss(nums[i]);
double x = 0.0;
ss >> x;
tsum += x;
}
ticks end = getticks();
double timed = elapsed(end, start);
timings.push_back(timed);
} std::cout << "stringstream: ";
PrintStats(timings);
std::cout << std::endl;
std::cout << tsum << std::endl;
} {
double tsum = 0.0;
std::vector<double> timings;
timings.reserve(R);
for (size_t r= ; r<R ; ++r) {
ticks start = getticks();
std::istringstream ss;
for (size_t i= ; i<nums.size() ; ++i) {
ss.str(nums[i]);
ss.clear();
double x = 0.0;
ss >> x;
tsum += x;
}
ticks end = getticks();
double timed = elapsed(end, start);
timings.push_back(timed);
} std::cout << "stringstream reused: ";
PrintStats(timings);
std::cout << std::endl;
std::cout << tsum << std::endl;
}
}

c++ stod很慢的更多相关文章

  1. 看到了必须要Mark啊,最全的编程中英文词汇对照汇总(里面有好几个版本的,每个版本从a到d的顺序排列)

    java:  第一章: JDK(Java Development Kit) java开发工具包 JVM(Java Virtual Machine) java虚拟机 Javac  编译命令 java   ...

  2. C++11特性中的stoi、stod

    本文摘录柳神笔记:   使⽤ stoi . stod 可以将字符串 string 转化为对应的 int 型. double 型变量,这在字符串处理的很 多问题中很有帮助-以下是示例代码和⾮法输⼊的处理 ...

  3. 很多人很想知道怎么扫一扫二维码就能打开网站,就能添加联系人,就能链接wifi,今天说下这些格式,明天做个demo

    有些功能部分手机不能使用,网站,通讯录,wifi基本上每个手机都可以使用. 在看之前你可以扫一扫下面几个二维码先看看效果: 1.二维码生成 网址 (URL) 包含网址的 二维码生成 是大家平时最常接触 ...

  4. 再谈C#采集,一个绕过高强度安全验证的采集方案?方案很Low,慎入

    说起采集,其实我是个外行,以前拔过阿里巴巴的客户数据,在我博客的文章:C#+HtmlAgilityPack+XPath带你采集数据(以采集天气数据为例子) 中,介绍过采集用的工具,其实很Low的,分析 ...

  5. [.NET] 打造一个很简单的文档转换器 - 使用组件 Spire.Office

    打造一个很简单的文档转换器 - 使用组件 Spire.Office [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6024827.html 序 之前,& ...

  6. ElasticSearch 5学习(5)——第一个例子(很实用)

    想要知道ElasticSearch是如何使用的,最快的方式就是通过一个简单的例子,第一个例子将会包括基本概念如索引.搜索.和聚合等,需求是关于公司管理员工的一些业务. 员工文档索引 业务首先需要存储员 ...

  7. 11 个很少人知道但很有用的 Linux 命令

    Linux命令行吸引了大多数Linux爱好者.一个正常的Linux用户一般掌握大约50-60个命令来处理每日的任务.Linux命令和它们的转换对于Linux用户.Shell脚本程序员和管理员来说是最有 ...

  8. 在网站开发中很有用的8个 jQuery 效果【附源码】

    jQuery 作为最优秀 JavaScript 库之一,改变了很多人编写 JavaScript 的方式.它简化了 HTML 文档遍历,事件处理,动画和 Ajax 交互,而且有成千上万的成熟 jQuer ...

  9. Web 开发中很实用的10个效果【附源码下载】

    在工作中,我们可能会用到各种交互效果.而这些效果在平常翻看文章的时候碰到很多,但是一时半会又想不起来在哪,所以养成知识整理的习惯是很有必要的.这篇文章给大家推荐10个在 Web 开发中很有用的效果,记 ...

随机推荐

  1. Nginx详解九:Nginx基础篇之Nginx的访问控制

    基于IP的访问控制:http_access_module 不允许指定网段的用户访问:配置语法:deny address | CIDR | unix: | all;默认状态:-配置方法:http.ser ...

  2. python基础复习

    复习-基础 一.review-base 其他语言吗和python的对比 c vs Python c语言是python的底层实现,解释器就是由python编写的. c语言开发的程序执行效率高,开发现率低 ...

  3. SVN重新设置用户名和密码

    在第一次使用TortoiseSVN从服务器CheckOut的时候,会要求输入用户名和密码,这时输入框下面有个选项是保存认证信息,如果选了这个选项,那么以后就不用每次都输入一遍用户名密码了. 不过,如果 ...

  4. 如何使用Scrapy框架实现网络爬虫

    现在用下面这个案例来演示如果爬取安居客上面深圳的租房信息,我们采取这样策略,首先爬取所有租房信息的链接地址,然后再根据爬取的地址获取我们所需要的页面信息.访问次数多了,会被重定向到输入验证码页面,这个 ...

  5. Python模块的导入以及软件开发规范

    Python文件的两种用途 1 . 当脚本直接使用,直接当脚本运行调用即可 def func(): print("from func1") func() 2 . 当做模块被导入使用 ...

  6. 使用docker方式安装etcd集群,带TLS证书

    网上文档也多,安装的时候,还是踩了几个坑. 现在作一个安装记录吧. 1,先作自签名的证书ca-csr.json(为了和k8s共用根证书,可能将信息调为k8s). { "CN": & ...

  7. 一脸懵逼学习keepalived(对Nginx进行热备)

    1:Keepalived的官方网址:http://www.keepalived.org/ 2:Keepalived:可以实现高可靠: 高可靠的概念: HA(High Available), 高可用性集 ...

  8. 使用SecureCRT脚本备份网络设备配置的一点感悟

    https://blog.csdn.net/qq_25294171/article/details/85158458

  9. URL地址编码和解码

    0. 参考 [整理]关于http(GET或POST)请求中的url地址的编码(encode)和解码(decode) python3中的urlopen对于中文url是如何处理的? 中文URL的编码问题 ...

  10. 分布式系统的BASE理论

    一.BASE理论 eBay的架构师Dan Pritchett源于对大规模分布式系统的实践总结,在ACM上发表文章提出BASE理论,BASE理论是对CAP理论的延伸,核心思想是即使无法做到强一致性(St ...