精华内容
下载资源
问答
  • 浮点数精度
    2022-08-29 01:00:18

    前言

    可能各位对计算机比较了解的人都明白为什么浮点数处理会出现丢失精度的问题,这里就不赘述了。
    在如下运算中,都可发现精度问题

    >>> 2.0 - 1.9
    0.10000000000000009
    >>> 0.5 - 0.4
    0.09999999999999998
    

    解决方法

    可以使用decimal模块进行运算,可以得到一个精确的结果

    >>> inport decimal
    >>> a = decimal.Decimal('0.5')
    >>> b = decimal.Decimal('0.4')
    >>> a - b
    Decimal('0.1')
    

    如果想把值取出来可以这么做

    >>> res = a - b
    >>> float(res.to_eng_string())
    0.1
    
    更多相关内容
  • C语言中浮点数精度问题分析.pdf
  • 而python是以双精度(64)位来保存浮点数,多余的位会被截掉,所以看到的是0.1,但在电脑上实际保存的已不是精确的0.1,参与运算后,也就有可能点误差,特别是金融邻域里面,对精度更是要求更高,如何在Python中获取...
  • def c1 (n,i): minNI = min(i,n-1) result = 1 for j in range (0,minNI): result = result * (n-j)/(minNI-j) return result print ('更改前C(5,3)数值为:',c1(5,3)) print ('更改前C(100,97)数值为:',...
  • 浮点数精度

    千次阅读 2019-03-18 19:07:32
    printf("%.2lf",a);//这里是将a四舍五入输出 计算几何头疼的地方一般...精度问题则不好说,有时候一个精度问题就可能成为一道题的瓶颈,简直“画龙点睛”。这些年的题目基本是朝着越来越不卡精度的方向发展了,但是...

    https://blog.csdn.net/waitfor_/article/details/8035773
    printf("%.2lf",a);//这里是将a四舍五入输出

    计算几何头疼的地方一般在于代码量大和精度问题,代码量问题只要平时注意积累模板一般就不成问题了。精度问题则不好说,有时候一个精度问题就可能成为一道题的瓶颈,简直“画龙点睛”。这些年的题目基本是朝着越来越不卡精度的方向发展了,但是也不乏一些%&%题#$%$,另外有些常识不管题目卡不卡,都是应该知道的。今天我就开膛回顾下见过且还有印象的精度问题,由于本人见识和记忆均有限,望各位大神瞄过后不吝补充。另外,为了弥补我匮乏的文思,我可能乱扯些不太相关或者尽人皆知的东西凑数。那么,现在开始。

    计算几何的精度问题说到底其实是浮点数的精度问题,但我觉得“计算几何”比“浮点数”更能吸引眼球,所以选了这个标题。

    1.浮点数为啥会有精度问题:

    浮点数(以C/C++为准),一般用的较多的是float, double。

    占字节数

    数值范围

    十进制精度位数

    float

    4

    -3.4e-38~3.4e38

    6~7

    double

    8

    -1.7e-308~1.7e308

    14~15

    如果内存不是很紧张或者精度要求不是很低,一般选用double。14位的精度(是有效数字位,不是小数点后的位数)通常够用了。注意,问题来了,数据精度位数达到了14位,但有些浮点运算的结果精度并达不到这么高,可能准确的结果只有10~12位左右。那低几位呢?自然就是不可预料的数字了。这给我们带来这样的问题:即使是理论上相同的值,由于是经过不同的运算过程得到的,他们在低几位有可能(一般来说都是)是不同的。这种现象看似没太大的影响,却会一种运算产生致命的影响: == 。恩,就是判断相等。注意,C/C++中浮点数的 == 需要完全一样才能返回true。来看下面这个例子:

    #include<stdio.h>

    #include<math.h>

    int main()

    {

    double a = asin(sqrt(2.0) / 2) * 4.0;

    double b = acos(-1.0);

    printf(" a = %.20lf\n", a);

    printf(" b = %.20lf\n", b);

    printf(" a - b = %.20lf\n", a - b);

    printf(“a == b = %d\n”, a == b);

    return 0;

    }

    输出:

      a = 3.14159265358979360000
    
      b = 3.14159265358979310000
    

    a - b = 0.00000000000000044409

    a == b = 0

    我们解决的办法是引进eps,来辅助判断浮点数的相等。

    1. eps

    eps缩写自epsilon,表示一个小量,但这个小量又要确保远大于浮点运算结果的不确定量。eps最常见的取值是1e-8左右。引入eps后,我们判断两浮点数a、b相等的方式如下:

    定义三出口函数如下: int sgn(double a){return a < -eps ? -1 : a < eps ? 0 : 1;}

    则各种判断大小的运算都应做如下修正:

    传统意义修正写法1修正写法2
    a == bsgn(a - b) == 0fabs(a – b) < eps
    a != bsgn(a - b) != 0fabs(a – b) > eps
    a < bsgn(a - b) < 0a – b < -eps
    a <= bsgn(a - b) <= 0a – b < eps
    a > bsgn(a - b) > 0a – b > eps
    a >= bsgn(a - b) >= 0a – b > -eps

    这样,我们才能把相差非常近的浮点数判为相等;同时把确实相差较大(差值大于eps)的数判为不相等。

    PS: 养成好习惯,尽量不要再对浮点数做 == 判断。例如,我的修正写法2里就没有出现==。

    1. eps带来的函数越界

    如果sqrt(a), asin(a), acos(a) 中的a是你自己算出来并传进来的,那就得小心了。

    如果a本来应该是0的,由于浮点误差,可能实际是一个绝对值很小的负数(比如1e-12),这样sqrt(a)应得0的,直接因a不在定义域而出错。

    类似地,如果a本来应该是±1,则asin(a)、acos(a)也有可能出错。

    因此,对于此种函数,必需事先对a进行校正。

    1. 输出陷阱I

    这一节和下一节一样,都是因为题目要求输出浮点数,导致的问题。而且都和四舍五入有关。

    说到四舍五入,就再扯一下相关内容,据我所知有三种常见的方法:

    1. printf(“%.3lf”, a); //保留a的三位小数,按照第四位四舍五入

    2. (int)a; //将a靠进0取整

    3. ceil(a); floor(a); //顾名思义,向上取证、向下取整。需要注意的是,这两个函数都返回double,而非int

    其中第一种很常见于输出(nonsense…)。

    现在考虑一种情况,题目要求输出保留两位小数。有个case的正确答案的精确值是0.005,按理应该输出0.01,但你的结果可能是0.005000000001(恭喜),也有可能是0.004999999999(悲剧),如果按照printf(“%.2lf”, a)输出,那你的遭遇将和括号里的字相同。

    解决办法是,如果a为正,则输出a+eps, 否则输出a-eps

    典型案例: POJ2826

    1. 输出陷阱II

    ICPC题目输出有个不成文的规定(有时也成文),不要输出: -0.000

    那我们首先要弄清,什么时候按printf(“%.3lf\n”, a)输出会出现这个结果。

    直接给出结果好了:a∈(-0.000499999……, -0.000……1)

    所以,如果你发现a落在这个范围内,请直接输出0.000。更保险的做法是用sprintf直接判断输出结果是不是-0.000再予处理。

    典型案例:UVA746

    1. 范围越界

    这个严格来说不属于精度范畴了,不过凑数还是可以的。请注意,虽然double可以表示的数的范围很大,却不是不穷大,上面说过最大是1e308。所以有些时候你得小心了,比如做连乘的时候,必要的时候要换成对数的和。

    典型案例:HDU3558

    1. 关于set

    有时候我们可能会有这种需求,对浮点数进行 插入、查询是否插入过 的操作。手写hash表是一个方法(hash函数一样要小心设计),但set不是更方便吗。但set好像是按 == 来判重的呀?貌似行不通呢。经观察,set不是通过==来判断相等的,是通过<来进行的,具体说来,只要a<b 和 b<a 都不成立,就认为a和b相等,可以发现,

    如果将小于定义成: bool operator < (const Dat dat)const{return val < dat.val - eps;}就可以解决问题了。 (基本类型不能重载运算符,所以封装了下)

    1. 输入值波动过大

    这种情况不常见,不过可以帮助你更熟悉eps。假如一道题输入说,给一个浮点数a, 1e-20 < a < 1e20。那你还敢用1e-8做eps么?合理的做法是把eps按照输入规模缩放到合适大小。

    典型案例: HUSTOJ 1361

    1. 一些建议

    容易产生较大浮点误差的函数有asin、 acos。欢迎尽量使用atan2。

    另外,如果数据明确说明是整数,而且范围不大的话,使用int或者long long代替double都是极佳选择,因为就不存在浮点误差了(尽管我几乎从来都只用double --!)

    展开全文
  • 浮点数精度丢失分析及解决

    千次阅读 2021-12-01 22:43:54
    Java语言在处理浮点数,其实现逻辑与整数不同,如果使用不当可能会造成精度丢失、计算不准确、死循环等问题,严重的话,会造成经济损失。本文将从浮点数精度丢失入手,详细介绍下浮点数的原理及使用。

    Java语言在处理浮点数,其实现逻辑与整数不同,如果使用不当可能会造成精度丢失、计算不准确、死循环等问题,严重的话,会造成经济损失。本文将从浮点数精度丢失入手,详细介绍下浮点数的原理及使用。

    为什么会出现精度丢失

    计算机使用二进制存储数据,由于二进制自身局限性,导致其无法精确的表示所有小数。而浮点数是由整数部分和小数部分组成,这也就意味着,计算机无法精确表示浮点数。也即,在计算机中,浮点数存在精度丢失的问题。这里将以十进制小数转为二进制数为例,介绍下为何二进制无法精确表示小数。
    十进制小数转换成二进制小数采用"乘2取整,顺序排列"的做法。基本思想如下:用二乘以当前十进制小数,然后将乘积的整数部分取出,如果乘积中的小数部分为零或者达到所要求的精度则停止计算。否则再用二乘以余下的小数部分,又得到一个乘积,再将积的整数部分取出,如此进行。完成计算后,把每次执行取出的整数部分按顺序排列起来,先取的整数作为二进制小数的高位有效位,后取的整数作为低位有效位。这里介绍下如何把十进制小数0.8125转换为二进制小数。
    0.8125转二进制.png
    当然,也存在无法准确适用二进制表示的小数。如十进制小数0.7。
    0.7转二进制.png
    对于无法用二进制表示的小数,只能根据精度近似的表示。

    浮点数底层存储实现

    与整数存储数值不同,浮点数在计算机的存储时,会拆分成是三个部分:符号位、指数位、尾数位。其抽象公式是:
    ( − 1 ) S ∗ ( 1. M . . . ) ∗ 2 E (-1)^S*(1.M...)*2^E (1)S(1.M...)2E
    其中, S S S表示符号(正数、负数)、E表示指数、M表示尾数。在Java中,float是32位存储,double是64存储,各部分的存储长度是:
    float存储结构
    double存储结构
    因为指数位影响数的大小,指数位决定大小范围。而小数位则决定计算精度,小数位能表示的数越大,则能计算的精度越大。
    float 的小数位只有 23 位,即二进制的 23 位,能表示的最大的十进制数为 2 的 23 次方,即 8388608,即十进制的 7 位,严格点,精度只能百分百保证十进制的 6 位运算。
    double 的小数位有 52 位,对应十进制最大值为 4 503 599 627 370 496,这个数有 16 位,所以计算精度只能百分百保证十进制的 15 位运算。

    浮点数操作

    既然浮点数不能精确表示小数,那么在执行浮点数操作时(算数运算、比较运算等),要考虑精度丢失可能带来的问题。这里以浮点数比较为例,介绍两个浮点数比较带来的死循环问题。

    public void createEndlessLoop() {
        double a = 1.6;
        double b = 0.3;
        double c = a + b;
        double d = 1.9;
        while (c != d) {
            System.out.println("c: " + c + ", d: " + d);
        }
        System.out.print("c == d");
    }
    

    执行上述方法,该方法将进入到死循环。浮点数的比较,由于精度丢失问题,其比较结果常常与预期相左。一种基本的思路是引入误差来辅助浮点数比较,但是这种做法仍不能满足某些场景。更多该思路的拓展可以参考链接

    如何避免精度丢失

    那么如何避免浮点数的精度丢失问题。其实这个问题没有银弹。要根据不同的业务场景,选择合适的处理方式。如果可以不对浮点数进行运算,则尽量不使用浮点数进行运算。如果必须使用浮点数进行运算,要根据场景,选择合适的处理方式。如浮点数四则运算、比较运算场景,使用BigDecimal。上一个问题的正确处理方式如下:

    public void createEndlessLoopWithBigDecimal() {
        BigDecimal a = new BigDecimal("1.6");
        BigDecimal b = new BigDecimal("0.3");
        BigDecimal c = a.add(b);
        BigDecimal d = new BigDecimal("1.9");
        while (c.doubleValue() != d.doubleValue()) {
            System.out.println("c: " + c.doubleValue()  + ", d: " + d.doubleValue());
        }
        System.out.print("c == d");
    }
    

    注意,这里并没有使用形如"BigDecimal a = new BigDecimal(1.6);"的方式初始化BigDecimal实例,这是因为浮点数无法精确表示,所以使用BigDecimal(Double)创建的BigDecimal是可能损失了精度,其赋值结果可能和实际有差异。考虑下面的代码,将进入死循环。

    public void createEndlessLoopWithBigDecimal() {
        BigDecimal a = new BigDecimal(1.6);
        BigDecimal b = new BigDecimal(0.3);
        BigDecimal c = a.add(b);
        BigDecimal d = new BigDecimal(1.9);
        while (c.doubleValue() != d.doubleValue()) {
            System.out.println("c: " + c.doubleValue()  + ", d: " + d.doubleValue());
        }
        System.out.print("c == d");
    }
    

    更多BigDecimal使用上的坑,可参考链接

    参考

    https://www.cnblogs.com/fuzongle/p/14986543.html Java浮点数计算精度丢失与解决方案
    https://www.cnblogs.com/xujishou/p/7491932.html java中double和float精度丢失问题
    https://www.runoob.com/w3cnote/decimal-decimals-are-converted-to-binary-fractions.html 十进制小数转化为二进制小数
    https://blog.csdn.net/qq_36915078/article/details/106019023 浮点数如何转二进制
    https://www.runoob.com/w3cnote/java-the-different-float-double.html Java 浮点类型 float 和 double 的主要区别
    https://www.cnblogs.com/PrimoPrimo/archive/2013/02/22/3307196.html 浮点数的比较
    https://blog.csdn.net/wangxufa/article/details/121722126 BigDecimal源码分析及使用

    原创不易,如果本文对您有帮助,欢迎关注我,谢谢 ~_~

    展开全文
  • 浮点数精度问题

    千次阅读 2021-09-17 11:58:05
    在程序中,对于加、减、乘、除运算的的浮点结果必须是实数上精确运算的舍入结果。 二进制浮点数(IEEE-754) 32位float型的二进制存储(32位浮点型数的二进制存储)

    在程序中,小数一般都采用的是32位浮点型(float)的二进制存储,如果要使用小数计算,对于加、减、乘、除运算的数字和结果必须是实数上精确表示的。由于浮点数的特殊性,无法采用整数的补码存储方式,浮点数需要有特定的存储方式。IEEE754标准规定了浮点数在计算机中的存储方式以及算术标准等。一个浮点数可以分为3部分存储:

     按照这种形式存储的数称为规约浮点数,一般C中的float、double都是采取的这种形式。通过这种存储方式,32位浮点数表示范围介于-1.18X10+38和3.40X10+38之间,虽然浮点数表示的范围很广,但存储的尾数只有23位,因此它并不能精确表示其范围内的所有数字。

    比如,我们想计算1e+12,但这个数在浮点数中是不能精确表示的,所以对于精确计算,输入的数值为999999995904。

    浮点数78.375的表示

    浮点数精度

    浮点数的精度指的是小数点后的有效数字位数,是由尾数的位数来决定的,对于单精度(float),它的尾数为23位,而2^23=8388608,共7位,也就是说最多能有7位有效数字,但至少能保证6位,因此32位浮点数的小数点后有效位为6~7位。C语言中浮点型一般分为float单精度型、double双精度型、long double长精度型,单精度浮点型小数点后面有效数字为6~7位和双精度浮点型小数点后面有效数字为15~16位。单精度为32位,双精度为64位,8位为一个字节。

    C语言标准库头文件float.h定义了浮点数小数点后的有效位数 :

    //float.h头文件的部分代码

    #define DBL_DIG 15 //双精度小数点后15位

    #define FLT_DIG 6 //单精度小数点后6位

    #define LDBL_DIG 19 //长双精度小数点19

    可以用一段C程序来验证32位浮点数的存储值和精度:

    #include <stdio.h>

    int main(void)

    {

             float k1=1e12;

             float k2=1;

             float f=4230.0;

             float y1=k1/f/f;

             float y2=k2/f/f;

             printf(“k1=  %f\n”,k1);

             printf(“y1=  %f\n”,y1);

             printf(“y2=  %f\n”,y2);

             return 0;

    }

    程序运行结果为:

    k1=  999999995904.000000

    y1=  55888.089844

    y2=  0.000000

     

    展开全文
  • JS浮点数精度

    2021-08-20 16:28:59
    JS中浮点数精度问题 使用加减乘除时偶尔会出现精度问题,如: 0.1 + 0.2 = 0.30000000000000004 0.3 - 0.2 = 0.09999999999999998 0.1 * 3 = 0.30000000000000004 0.3 / 0.1 = 2.9999999999999996 为什么 让我们来...
  • 浮点数精度问题透析:小数计算不准确+浮点数精度丢失根源无论在java python javaScript里面都存在 1+ 2!== 3 问题,这个问题的产生根源在于计算存储数字是二进制,对无限循环小数和无理数采用双精度64位double浮点数_...
  • 一、PHP浮点数精度损失问题 先看下面这段代码: 复制代码 代码如下: $f = 0.57; echo intval($f * 100); //56 结果可能有点出乎你的意外,PHP遵循IEEE 754双精度: 浮点数, 以64位的双精度, 采用1位符号位(E), 11...
  • 浮点数精度详解

    千次阅读 2020-12-06 14:42:03
    浮点数精度问题分析float精度不止7位结论分析结语 float精度不止7位 网络上很多博客都说float的精度为7位,这其实是不正确的说法。 int iA = 1610612864; float fA = iA; std::cout << std::setprecision(10) ...
  • 浮点数精度丢失问题详解

    万次阅读 2021-09-21 23:45:26
    根据IEEE 754的标准,将数据分为三部分: 从左到右分别表示:符号位(正负数)、指数位和小数位 以单精度浮点数为例,单精度浮点数一共32位(双精度64位,即平时所说的double类型),具体内部表示为: 1个bit表示符号位 ...
  • a = 1.1 b = 2.2 r1 = b-a print(r1) import decimal decimal.getcontext().prec = 2 a = decimal....= r2 结果5:float(r2) == r3 考虑不同情况,可以选择:①使用decimal库②使用round或者format修改float数精度
  • 【MySQL】浮点数精度问题

    千次阅读 2021-11-17 22:02:42
    不要盲目的说float和double精度可能发生丢失,而是说在存取时因为精度不一致会发生丢失,当然这里的丢失指的是扩展或者截断了,丢失了原有的精度。decimal是好,但不是说不会发生任何精度丢失。如果问题看得不深入,...
  • python数字类型与浮点数精度

    千次阅读 2022-01-21 16:38:24
    python数字类型与浮点数精度
  • 小数在内存中的存储精度是不准确的,举例说明; 1、浮点型 const float pai = 3.14; std::cout << std::setprecision(20) << pai << std::endl; float型pai在内存中实际存储的值为: 2、双精度 ...
  • java处理浮点数精度

    2021-01-26 21:34:06
    在使用浮点数过程中,必须考虑到精度问题 java使用Double类型进行计算时,会出现数值不够精确的情况 如: Double a1 = 5.1; Double b1 = 4.9; System.out.println(a1-b1); 运行结果: 与期待的结果有了一定的...
  • 2.浮点数,C语言中整数加上小数就成了浮点数,比如7.00,同样计算机也是二进制存储浮点数, 不过计算机却是把浮点数分为小数部分和指数部分分开存储, (这里不理解也没关系)而书写浮点数的方法(e计数法)也做一下...
  • Python使用decimal模块解决浮点数减法精度问题
  • Java浮点数精度丢失及解决方法
  • 浮点数精度问题概述解决方案 概述 之前提到过,Python 中浮点类型之间的运算,其结果并不像我们想象的那样,例如: >>> 0.1+0.2 0.30000000000000004 >>> 0.1+0.1-0.2 0.0 >>> 0.1+0.1...
  • 记录一下浮点数精度设置的几种方法1. round方式内置函数,四舍五入,但是和我们一般理解意义上的四舍五入不太一样,先看下使用姿势1round(digit, num)第一个参数是浮点数,第二个参数标识保留的小数个数,第二个参数...
  • C++ 中浮点数精度丢失问题

    千次阅读 2021-06-16 12:16:11
    所以浮点数在计算机中存储时,可能出现 精度丢失 问题。 所以编程时一般都用 double 而不用 float,以免造成难以发现的 bug。 下面来看编译结果及代码(浮点数规格化就是对非规格化浮点数进行的处理,包括溢出...
  • 【C语言】 浮点数精度丢失

    千次阅读 2022-04-26 10:58:08
    浮点数精度丢失 比如我们赋值给a=1.23456789e10,加10后,应该得到的值是1.234567891e10 #include<stdio.h> int main() { float a,b; a = 1.23456789e10; b = a + 10; printf("%f",b); return 0; } 但...
  • 给大家介绍了Java中浮点数精度问题的解决方法,本文给大家介绍的非常详细,有问题描述有原因分析,非常不错,具有参考借鉴价值,感兴趣的朋友一起看看吧
  • 浮点数精度问题以及原理解释

    千次阅读 2020-04-01 23:03:49
    IEEE 754规定,有四种精度浮点数:单精确度(32位)、双精确度(64位)、延伸单精确度(43比特以上,很少使用)与延伸双精确度(79比特以上,通常以80位实现)。 对于32位的浮点数,最高的1位是符号位s,接着的8...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 146,975
精华内容 58,790
关键字:

浮点数精度

友情链接: ddd.rar