在C++中,float占4个字节,double占8个字节,均采用 IEEE 754 浮点标准;内部都是以二进制为基础,表述实数,有些实数可以被精确表述,比如0.2,但有些不行,比如0.3。针对这一点,前不久有篇专门的文章介绍这个:浮点运算为什么不准?有人为0.30000000000000004建了个网站

IEEE 754浮点标准

IEEE标准包含一组实数的二进制表示。一个浮点数字包含三个部分:符号(+或者-)、尾数(包含一串有效数位)和一个指数,这些部分都在一个计算机字里。常用的浮点数精度有:单精度(C++内的float类型)、双精度(C++内的double类型),分配的数位分别是32、64。这些数位被分成如下不同的部分:

精度 符号 指数 尾数
float 1 8 23
double 1 11 52

以双精度浮点数为例,每个浮点数字被分配了8字节,或者64位,来存储对应的三个部分。每个字都具有如下的形式

\[se_1e_2...e_{11}b_1b_2...b_{52}
\]

其中第一位保存了符号位,后面11位用于保存指数,再后面小数点后的52位保存尾数。符号位是0表示正数,1表示负数。11位的指数表示的正二进制整数,这些正数通过往指数上叠加 \(2^{10}-1=1023\) 得到,指数范围在-1022和1023之间。e1...e11覆盖了从1到2046之间对应的指数,由于特殊目的,这里没有使用0和2047。

机器精度

机器精度对应的数字,是1和比1大的最小浮点数之间的距离,对于IEEE双精度浮点表示,该值为 \(2^{-52}\),对应 float.h 文件内宏 DBL_EPSILON 的值。

最小的可表达双精度数字

\(2^{-52}*2^{-1022}\) 是最小的可表达双精度数字。最小可表达数字和机器精度之间的差别是在于,许多在机器精度以下的数字都是机器可表达的数字,尽管将这些数字加到1上可能没有什么影响,另一方面,在最小可表达数字以下的双精度数字完全不能被表示。

boost multiprecision

为了能够表述更高精度的浮点数,就得向库方向查找了。gmp, mpfr 可以表述无限精度,但编译只能gcc吧,boost在1.56版时开始提供 boost.multiprecision 用于支持更高精度数值表述,许可证较其他库宽松,但在计算效率等方向要逊于gmp, mpfr。

比如采用 bbp 公式(可参考The BBP Algorithm for Pi)计算 pi 的精确结果,代码如下:

// Author: bitbybit3d@163.com

#include <iostream>
#include <iomanip>
#include <boost/math/constants/constants.hpp>
#include <boost/multiprecision/cpp_bin_float.hpp> // 通过 BBP 公式计算 PI
template <class Type>
Type calc_pi_bbp(int n)
{
Type pi = 0; std::streamsize prevsize = std::cout.precision(50);
for (int k = 0; k < n; ++k)
{
Type it = static_cast<Type>(1) / pow(16, k)
* (static_cast<Type>(4) / (8 * k + 1)
- static_cast<Type>(2) / (8 * k + 4)
- static_cast<Type>(1) / (8 * k + 5)
- static_cast<Type>(1) / (8 * k + 6));
pi += it;
std::cout << std::left << std::setw(8) << k << pi << std::endl;
}
std::cout.precision(prevsize);
return pi;
} int main(int argc, char* argv[])
{
std::cout << "Use double: " << std::endl;
calc_pi_bbp<double>(20);
std::cout << std::endl; std::cout << "Use boost multiprecision: " << std::endl;
calc_pi_bbp<boost::multiprecision::cpp_bin_float_100>(30);
return 0;
}

以double值计算20次结果如下:

再以boost.multiprecision计算30次结果如下:

明显使用double计算时,第10次之后就每没有什么变化了(小于2.2204460492503131e-016 (即DBL_EPSILON)的值与 1.0 相加仍然为1.0),而boost.multiprecision还一直在变化,并且结果可以与Window操作系统中计算器存储的pi值相同(但小数点之后更多数字,这些准不准确就没比较了)。

浮点运算与boost.multiprecision的更多相关文章

  1. boost之multiprecision

    multiprecision boost中提供的高精度库,支持高精度整型,浮点型等.并且提供统一的接口模板,只需要指定对应的后端类型即可实现对应类型的高精度计算: boost::multiprecis ...

  2. 在Visual Sutdio 2017中使用boost库

    在Visual Sutdio 2017中使用boost库     转载 https://blog.csdn.net/u011054333/article/details/78648294 对C++有一 ...

  3. Awesome C/C++

    Awesome C/C++ A curated list of awesome C/C++ frameworks, libraries, resources, and shiny things. In ...

  4. zz A list of open source C++ libraries

    A list of open source C++ libraries < cpp‎ | links http://en.cppreference.com/w/cpp/links/libs Th ...

  5. awesome cpp

    https://github.com/fffaraz/awesome-cpp Awesome C/C++ A curated list of awesome C/C++ frameworks, lib ...

  6. C/C++ 开源库及示例代码

    C/C++ 开源库及示例代码 Table of Contents 说明 1 综合性的库 2 数据结构 & 算法 2.1 容器 2.1.1 标准容器 2.1.2 Lockfree 的容器 2.1 ...

  7. [转]awsome c++

    原文链接 Awesome C++ A curated list of awesome C++ (or C) frameworks, libraries, resources, and shiny th ...

  8. Boost 1.61.0 Library Documentation

    http://www.boost.org/doc/libs/1_61_0/ Boost 1.61.0 Library Documentation Accumulators Framework for ...

  9. boost库的安装,使用,介绍,库分类

    1)首先去官网下载boost源码安装包:http://www.boost.org/ 选择下载对应的boost源码包.本次下载使用的是 boost_1_60_0.tar.gz (2)解压文件:tar - ...

随机推荐

  1. ARTS-S 做事情的正确方法

    有同学改bug的思路是:你们别管我怎么改,先看改的效果对不对.效果对,就这样改,效果不对,我再想别的办法.这样其实把自己关起来,盲目试错,效率太低. 合理的方法应该是和其他大佬们商量一个大家认为正确的 ...

  2. leetcode -- 最长回文子串

    题目: 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为 1000. 示例 1: 输入: "babad" 输出: "bab" 注意: ...

  3. Mybatis获取自动增长Id

    Mybatis获取自动增长Id MyBatis成功插入后获取自动增长的id 1.向xxMapping.xml配置中加上两个配置. <insert id="insertUser" ...

  4. JS内置对象-Array之indexOf和lastIndexOf

    indexOf() var num = [1, 7, 2, 3, 4, 7, 9] var pos = num.indexOf(7) var pos1 = num.indexOf(7, 2) cons ...

  5. java 反射的意义

    具体的关于反射的介绍可以参考我的另外一篇博文<深入解析java反射>. 反射的意义是什么,其实就是为了代码简洁,提高代码的复用率,外部调用方便,源代码,反编译都能看到. 某些情况下解耦用反 ...

  6. 你不知道的JavaScript(中)读书笔记(二)

    第三章 原生函数 常用的原生函数(内建函数)有: String() Number() Boolean Array() Object() Function() RegExp() Date() Erroe ...

  7. SpringBoot集成Swagger2在线文档

    目录 SpringBoot集成Swagger2在线文档 前言 集成SpringBoot 登录接口文档示例 代码 效果 注解说明 总结 SpringBoot集成Swagger2在线文档 前言 不得不说, ...

  8. go 利用chan的阻塞机制,实现协程的开始、阻塞、返回控制器

    一.使用场景 大背景是从kafka 中读取oplog进行增量处理,但是当我想发一条命令将这个增量过程阻塞,然后开始进行一次全量同步之后,在开始继续增量. 所以需要对多个协程进行控制. 二.使用知识 1 ...

  9. LImax服务器框架学习--安装、使用ant工具、生成limax相关代码

    一.安装ant ant 是一个将软件编译.测试.部署等步骤联系在一起加以自动化的一个工具,大多用于Java环境中的软件开发.在实际软件开发中,有很多地方可以用到ant. 首先现在一个ant安装压缩包, ...

  10. JS Math对象、日期对象、函数、定时器

    Math对象 开平方:sqrt 绝对值:abs π:PI x的y次方:pow 四舍五入取整:round 向下取整:floor 向上取整:ceil 最大值:max 最小值: min 随机数:random ...