python的浮点数运算是否精度有问题阿

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python的浮点数运算是否精度有问题阿相关的知识,希望对你有一定的参考价值。

再计算机的硬件中,浮点数以二进制小数表示。比如小数

[python] view plain copy

    0.125  

    可看做1/10+2/100+5/1000,同样的方式二进制小数

    [python] view plain copy

    0.001  

    可看做0/2+0/4+1/8。

    这两个小数实际的值是相同的,唯一的不同是0.125是十进制表示,0.001是二进制表示。可是不幸的是,多数的十进制小数不能用二进制小数准确的表示。通常,你输入的十进制浮点数只能由存储在机器中的二进制浮点数近似表示。无论你使用多少位二进制数字,十进制的0.1都不能准确的由二进制小数表示,其是无限重复的小数

    [python] view plain copy

    0.0001100110011001100110011001100110011001100110011...  



    在一个运行python的典型计算机中,一个浮点数具有53位的精度,所以十进制的0.1在内部会以如下形式存储

    [python] view plain copy

    0.00011001100110011001100110011001100110011001100110011010  


    实际中,我们很容易忘记存储的数据是原始十进制的的近似表示。Python只会显示出以二进制形式存储再计算机中的真正十进制数的近似数。如

    [python] view plain copy

    0.1000000000000000055511151231257827021181583404541015625  


    其中的多数位数都不会被人使用到,所以python只显示它的四舍五入后的值

    [python] view plain copy

    0.1  


    在实际中有很多这样的例子可以说明:

    [python] view plain copy

    >>> 0.1 + 0.2  

    0.30000000000000004  


    [python] view plain copy

    >>> round(2.675, 2)  

    2.67  


    可以使用decimal模块,可以看到准确的浮点数的值。

    [python] view plain copy

    >>> from decimal import Decimal  

    >>> Decimal(2.675)  

    Decimal('2.67499999999999982236431605997495353221893310546875')  

参考技术A 因为 Python 中使用双精度浮点数来存储小数。在 Python 使用的 IEEE 754
标准(52M/11E/1S)中,8字节64位存储空间分配了52位来存储浮点数的有效数字,11位存储指数,1位存储正负号,即这是一种二进制版的科学计数法格式。虽然52位有效数字看起来很多,但麻烦之处在于,二进制小数在表示有理数时极易遇到无限循环的问题。其中很多在十进制小数中是有限的,比如十进制的
1/10,在十进制中可以简单写为 0.1
,但在二进制中,他得写成:0.0001100110011001100110011001100110011001100110011001…..(后面全是
1001 循环)。因为浮点数只有52位有效数字,从第53位开始,就舍入了。这样就造成了标题里提到的”浮点数精度损失“问题。
舍入(round)的规则为“0 舍 1 入”,所以有时候会稍大一点有时候会稍小一点。本回答被提问者采纳

Java 中的浮点数取精度方法

Java 中的浮点数取精度方法

一、内容

  一般在Java代码中取一个double类型的浮点数的精度,四舍五入或者直接舍去等的方式,使用了4中方法,推荐使用第一种,我已经封装成工具类了。

二、代码实现

   ①使用BigDecimal的方法:RoundTool.java(封装为工具类,推荐使用)

  1 package cn.com.cxsw.utils;
  2 
  3 import java.math.BigDecimal;
  4 
  5 /**
  6  * 与小数位精度(四舍五入等)相关的一些常用工具方法.
  7  * 
  8  * float/double的精度取值方式分为以下几种: <br>
  9  * java.math.BigDecimal.ROUND_UP <br>
 10  * java.math.BigDecimal.ROUND_DOWN <br>
 11  * java.math.BigDecimal.ROUND_CEILING <br>
 12  * java.math.BigDecimal.ROUND_FLOOR <br>
 13  * java.math.BigDecimal.ROUND_HALF_UP<br>
 14  * java.math.BigDecimal.ROUND_HALF_DOWN <br>
 15  * java.math.BigDecimal.ROUND_HALF_EVEN <br>
 16  * 
 17  * @title RoundTool
 18  * @describe
 19  * @author zfc
 20  * @date 2017年10月25日上午11:18:47
 21  */
 22 
 23 public final class RoundTool {
 24     /**
 25      * 对double数据进行取精度.
 26      * <p>
 27      * For example: <br>
 28      * double value = 100.345678; <br>
 29      * double ret = round(value,4,BigDecimal.ROUND_HALF_UP); <br>
 30      * ret为100.3457 <br>
 31      * 
 32      * @param value
 33      *            double数据.
 34      * @param scale
 35      *            精度位数(保留的小数位数).
 36      * @param roundingMode
 37      *            精度取值方式.
 38      * @return 精度计算后的数据.
 39      */
 40     public static double round(double value, int scale, int roundingMode) {
 41         BigDecimal bd = new BigDecimal(value);
 42         bd = bd.setScale(scale, roundingMode);
 43         double d = bd.doubleValue();
 44         bd = null;
 45         return d;
 46     }
 47 
 48     /**
 49      * 测试用的main方法.
 50      * 
 51      * @param argc
 52      *            运行参数.
 53      * 
 54      */
 55     public static void main(String[] argc) {
 56         // 下面都以保留2位小数为例
 57 
 58         // ROUND_UP
 59         // 只要第2位后面存在大于0的小数,则第2位就+1
 60         System.out.println(round(12.3401, 2, BigDecimal.ROUND_UP));// 12.35
 61         System.out.println(round(-12.3401, 2, BigDecimal.ROUND_UP));// -12.35
 62 
 63         // ROUND_DOWN
 64         // 与ROUND_UP相反
 65         // 直接舍弃第2位后面的所有小数
 66         System.out.println(round(12.349, 2, BigDecimal.ROUND_DOWN));// 12.34
 67         System.out.println(round(-12.349, 2, BigDecimal.ROUND_DOWN));// -12.34
 68 
 69         // ROUND_CEILING
 70         // 如果数字>0 则和ROUND_UP作用一样
 71         // 如果数字<0 则和ROUND_DOWN作用一样
 72         System.out.println(round(12.3401, 2, BigDecimal.ROUND_CEILING));// 12.35
 73         System.out.println(round(-12.349, 2, BigDecimal.ROUND_CEILING));// -12.34
 74 
 75         // ROUND_FLOOR
 76         // 如果数字>0 则和ROUND_DOWN作用一样
 77         // 如果数字<0 则和ROUND_UP作用一样
 78         System.out.println(round(12.349, 2, BigDecimal.ROUND_FLOOR));// 12.34
 79         System.out.println(round(-12.3401, 2, BigDecimal.ROUND_FLOOR));// -12.35
 80 
 81         // ROUND_HALF_UP [这种方法最常用,四舍五入]
 82         // 如果第3位数字>=5,则第2位数字+1
 83         // 备注:只看第3位数字的值,不会考虑第3位之后的小数的
 84         System.out.println(round(12.345, 2, BigDecimal.ROUND_HALF_UP));// 12.35
 85         System.out.println(round(12.3449, 2, BigDecimal.ROUND_HALF_UP));// 12.34
 86         System.out.println(round(-12.345, 2, BigDecimal.ROUND_HALF_UP));// -12.35
 87         System.out.println(round(-12.3449, 2, BigDecimal.ROUND_HALF_UP));// -12.34
 88 
 89         // ROUND_HALF_DOWN
 90         // 如果第3位数字>=5,则做ROUND_UP
 91         // 如果第3位数字<5,则做ROUND_DOWN
 92         System.out.println(round(12.345, 2, BigDecimal.ROUND_HALF_DOWN));// 12.35
 93         System.out.println(round(12.3449, 2, BigDecimal.ROUND_HALF_DOWN));// 12.34
 94         System.out.println(round(-12.345, 2, BigDecimal.ROUND_HALF_DOWN));// -12.35
 95         System.out.println(round(-12.3449, 2, BigDecimal.ROUND_HALF_DOWN));// -12.34
 96 
 97         // ROUND_HALF_EVEN
 98         // 如果第3位是偶数,则做ROUND_HALF_DOWN
 99         // 如果第3位是奇数,则做ROUND_HALF_UP
100         System.out.println(round(12.346, 2, BigDecimal.ROUND_HALF_EVEN));// 12.35
101         System.out.println(round(12.345, 2, BigDecimal.ROUND_HALF_EVEN));// 12.35
102 
103     }
104 
105 }

 ②一些简单的方法:DoubleNumberFormat.java

 1 package cn.com.zfc.example;
 2 
 3 import java.text.DecimalFormat;
 4 import java.text.NumberFormat;
 5 
 6 /**
 7  * double类型的浮点数取精度(以保留两位小数为例)
 8  * 
 9  * @author zfc
10  *
11  */
12 public class DoubleNumberFormat {
13     public static void main(String[] args) {
14         double num = 1234.123534;
15         // 1、使用String的format()方法
16         System.out.println(num + " 保留两位小数:" + String.format("%.2f", num));
17 
18         // 2、使用DecimalFormat的format()方法
19         DecimalFormat decimalFormat = new DecimalFormat("#.00");
20         System.out.println(num + " 保留两位小数:" + decimalFormat.format(num));
21 
22         // 3、使用NumberFormat的format()方法
23         NumberFormat numberFormat = NumberFormat.getNumberInstance();
24         numberFormat.setMaximumFractionDigits(2);
25         System.out.println(num + " 保留两位小数:" + numberFormat.format(num));
26     }
27 }

 

以上是关于python的浮点数运算是否精度有问题阿的主要内容,如果未能解决你的问题,请参考以下文章

工具类---提供精确的浮点数运算

浮点数的运算精度丢失

JavaScript 浮点数运算的精度问题

keil浮点数不带df是哪一个

用decimal模块增加python的浮点数精度

Java 避免精度丢失之BigDecimal 运算