java学习 浮点运算 [2012-06-19]

java学习 浮点运算


1、 问题的引入首先从一个简单的计算开始。
 

Java代码 

float a=1.0f;  
float b=0.1f;  
System.out.println(a-b);  


打印出来
   0.9
或许你想肯定是0.9,这还用问。其实你被System.out.println欺骗了。再看
用System.out.printf("%1.20f\n",a-b) 打印出来
   0.89999997615814210000
这才是实际值,System.out.println隐藏的做了精度四舍五入。
同理System.out.printf("%1.20f\n",0.1f),打印出来
  0.10000000149011612000
为什么呢?看到这里,我们应该想到这是float引起的了吧。

2、float在计算机里表示
     java中的float和double,采用IEEE754标准,实际上是用利用科学计数法来表达实数。即用一个尾数(Mantissa也叫有效数字 ),一个基数(Base),一个指数(Exponent)以及
一个表示正负的符号来表达实数。实数表示分为三个域。
   float用32bit存储,double用64bit存储。
   第一个域为符号域,0 表示数值为正数,而 1 则表示负数;
   第二个域为指数域,对应于我们之前介绍的二进制科学计数法中的指数部分。其中单精度数为 8 位,双精度数为 11 位。float单精度的指数范围为-127 和 127 之间。
   第三个域为尾数域,其中单精度数为 23 位长,双精度数为 52 位长。
造成无法准确的计算出来我们想要的结果,原因是科学计算法无法准确的存储,只有相近的取近似值(看样子,计算机也不太聪明,呵呵)。举例

Java代码 

System.out.printf("%1.10f\n",9.625f);  
System.out.printf("%1.10f\n",9.624f);  


打印出来
  9.6250000000
  9.6239995956

3、总结
   所以在进行浮点运算的时候,一定要小心。解决办法是用BigDecimal,进行计算之后取精度。
网上也有这种办法计算。

Java代码 

Java中的小数精确计算   
public class FloatCalc {  
  
    // 默认除法运算精度  
    private static final int DEF_DIV_SCALE = 10;  
  
    /** 
     * 提供精确的加法运算。 
     *  
     * @param v1     *            被数 
     * @param v2     *            加数 
     * @return 两个参数的和 
     */  
  
    public static double add(double v1, double v2) {  
        BigDecimal b1 = new BigDecimal(Double.toString(v1));  
        BigDecimal b2 = new BigDecimal(Double.toString(v2));  
        return b1.add(b2).doubleValue();  
    }  
  
    /** 
     * 提供精确的减法运算。 
     *  
     * @param v1     *            被减数 
     * @param v2     *            减数 
     * @return 两个参数的差 
     */  
    public static double sub(double v1, double v2) {  
        BigDecimal b1 = new BigDecimal(Double.toString(v1));  
        BigDecimal b2 = new BigDecimal(Double.toString(v2));  
        return b1.subtract(b2).doubleValue();  
    }  
  
    /** 
     * 提供精确的乘法运算。 
     *  
     * @param v1     *            被乘数 
     * @param v2     *            乘数 
     * @return 两个参数的积 
     */  
    public static double mul(double v1, double v2) {  
        BigDecimal b1 = new BigDecimal(Double.toString(v1));  
        BigDecimal b2 = new BigDecimal(Double.toString(v2));  
        return b1.multiply(b2).doubleValue();  
    }  
  
    /** 
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后10位,以后的数字四舍五入。 
     *  
     * @param v1     *            被除数 
     * @param v2     *            除数 
     * @return 两个参数的商 
     */  
  
    public static double div(double v1, double v2) {  
        return div(v1, v2, DEF_DIV_SCALE);  
    }  
  
    /** 
     * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入。 
     *  
     * @param v1     *            被除数 
     * @param v2     *            除数 
     * @param scale 
     *            表示表示需要精确到小数点以后几位。 
     * @return 两个参数的商 
     */  
    public static double div(double v1, double v2, int scale) {  
        if (scale < 0) {  
            throw new IllegalArgumentException(  
                    "The scale must be a positive integer or zero");  
        }  
        BigDecimal b1 = new BigDecimal(Double.toString(v1));  
        BigDecimal b2 = new BigDecimal(Double.toString(v2));  
        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();  
    }  
  
    /** 
     * 提供精确的小数位四舍五入处理。 
     *  
     * @param v  *            需要四舍五入的数字 
     * @param scale  *            小数点后保留几位 
     * @return 四舍五入后的结果 
     */  
    public static double round(double v, int scale) {  
        if (scale < 0) {  
            throw new IllegalArgumentException(  
                    "The scale must be a positive integer or zero");  
        }  
        BigDecimal b = new BigDecimal(Double.toString(v));  
        BigDecimal one = new BigDecimal("1");  
        return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();  
    }  
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jyworker1313

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值