Android 金额转换精度丢失

Posted 吹着空调哼着歌

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 金额转换精度丢失相关的知识,希望对你有一定的参考价值。

在开发中经常会遇到Double.parseDouble() 、Integer.parseInt()转换后与我们想要得到的值不一致的问题?
我们先了解一下Java中各类型的域

当超出这个范围就会转换错误
解决方案 -----> 使用BigDecimal

BigDecimal概述

Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数,但在实际应用中,可能需要对更大或者更小的数进行运算和处理。一般情况下,对于那些不需要准确计算精度的数字,我们可以直接使用Float和Double处理,但是Double.valueOf(String) 和Float.valueOf(String)会丢失精度。所以开发中,如果我们需要精确计算的结果,则必须使用BigDecimal类来操作。

​ BigDecimal所创建的是对象,故我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。

BigDecimal常用构造函数

BigDecimal(int)

创建一个具有参数所指定整数值的对象

BigDecimal(double)

创建一个具有参数所指定双精度值的对象

BigDecimal(long)

创建一个具有参数所指定长整数值的对象

BigDecimal(String)

创建一个具有参数所指定以字符串表示的数值的对象

常用api

add(BigDecimal)

BigDecimal对象中的值相加,返回BigDecimal对象

subtract(BigDecimal)

BigDecimal对象中的值相减,返回BigDecimal对象

multiply(BigDecimal)

BigDecimal对象中的值相乘,返回BigDecimal对象

divide(BigDecimal)

BigDecimal对象中的值相除,返回BigDecimal对象

toString()

将BigDecimal对象中的值转换成字符串

doubleValue()

将BigDecimal对象中的值转换成双精度数

floatValue()

将BigDecimal对象中的值转换成单精度数

longValue()

将BigDecimal对象中的值转换成长整数

intValue()

将BigDecimal对象中的值转换成整数

compareTo()
比大小

金额转换工具类

/**
 * 金额工具类
 * 元转分   分转元
 */

/**
 * 加法 add()函数     减法subtract()函数
 * 乘法multiply()函数    除法divide()函数    绝对值abs()函数
 */
    
public class AmountUtil 
    /**
     * 金额为分的格式
     */
    public static final String CURRENCY_FEN_REGEX = "\\\\-?[0-9]+";

    /**
     * 将分为单位的转换为元并返回金额格式的字符串 (除100)
     *
     * @param amount
     * @return
     * @throws Exception
     */
    @NonNull
    public static String changeF2Y(@NonNull Long amount) throws Exception 
        if (!amount.toString().matches(CURRENCY_FEN_REGEX)) 
            throw new Exception("金额格式有误");
        

        int flag = 0;
        String amString = amount.toString();
        if (amString.charAt(0) == '-') 
            flag = 1;
            amString = amString.substring(1);
        
        StringBuffer result = new StringBuffer();
        if (amString.length() == 1) 
            result.append("0.0").append(amString);
         else if (amString.length() == 2) 
            result.append("0.").append(amString);
         else 
            String intString = amString.substring(0, amString.length() - 2);
            for (int i = 1; i <= intString.length(); i++) 
                if ((i - 1) % 3 == 0 && i != 1) 
                    result.append(",");
                
                result.append(intString.substring(intString.length() - i, intString.length() - i + 1));
            
            result.reverse().append(".").append(amString.substring(amString.length() - 2));
        
        if (flag == 1) 
            return "-" + result.toString();
         else 
            return result.toString();
        
    

    /**
     * 将分为单位的转换为元 (除100)
     *
     * @param amount
     * @return
     * @throws Exception
     */
    @NonNull
    public static String changeF2Y(Context context, @NonNull String amount) 
        if (!amount.matches(CURRENCY_FEN_REGEX)) 
            Toast.makeText(context, "金额格式有误", Toast.LENGTH_LONG).show();
        
        return BigDecimal.valueOf(Long.valueOf(amount)).divide(new BigDecimal(100)).toString();
    

    public static String changeF2Y(String amount)
        BigDecimal value = new BigDecimal(amount);
        BigDecimal value1 = new BigDecimal("100");
        String s = value.divide(value1, 2, RoundingMode.HALF_UP).toString();
        return s+"";
    


    /**
     * 将元为单位的转换为分 (乘100)
     *
     * @param amount
     * @return
     */
    @NonNull
    public static String changeY2F(Long amount) 
        return BigDecimal.valueOf(amount).multiply(new BigDecimal(100)).toString();
    

    public static String subtract(String bill,String money)
        BigDecimal billDecimal = new BigDecimal(bill);
        BigDecimal valueDecimal = new BigDecimal(money);
        String s = billDecimal.subtract(valueDecimal).toString();
        return s;
    

    /**
     * 将元为单位的转换为分 替换小数点,支持以逗号区分的金额
     *
     * @param amount
     * @return
     */
    @NonNull
    public static String changeY2F(@NonNull String amount) 
        String currency = amount.replaceAll("\\\\$|\\\\¥|\\\\,", "");  //处理包含, ¥ 或者$的金额
        int index = currency.indexOf(".");
        int length = currency.length();
        Long amLong = 0l;
        if (index == -1) 
            amLong = Long.valueOf(currency + "00");
         else if (length - index >= 3) 
            amLong = Long.valueOf((currency.substring(0, index + 3)).replace(".", ""));
         else if (length - index == 2) 
            amLong = Long.valueOf((currency.substring(0, index + 2)).replace(".", "") + 0);
         else 
            amLong = Long.valueOf((currency.substring(0, index + 1)).replace(".", "") + "00");
        
        return amLong.toString();
    

    /**
     * 限制小数点后两位
     *
     * EditText属性改成如下:
     * numberDecimal表示只能输入一个小数点
     *
     *             <EditText
     *                 android:id="@+id/et_amt"
     *                 android:layout_width="wrap_content"
     *                 android:layout_height="wrap_content"
     *                 android:layout_marginLeft="20dp"
     *                 android:background="@null"
     *                 android:layout_weight="1"
     *                 android:layout_gravity="center_vertical"
     *                 android:textColorHint="@color/font_CCCCCC"
     *                 android:textColor="@color/font_333333"
     *                 android:textSize="14sp"
     *                 android:paddingTop="20dp"
     *                 android:paddingBottom="20dp"
     *                 android:inputType="number|numberDecimal"
     *                 android:hint="需小于或等于本期金额"/>
     *
     */
    public static void limitTwoDecimal(@NonNull EditText editText) 
        editText.addTextChangedListener(new TextWatcher() 
            public void afterTextChanged(@NonNull Editable edt) 
                String temp = edt.toString();
                int posDot = temp.indexOf(".");
                if (posDot <= 0) return;
                if (temp.length() - posDot - 1 > 2) 
                    edt.delete(posDot + 3, posDot + 4);
                
            

            public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) 
            

            public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) 
            
        );
    

    /**
     * 金额转换  防止数据精度丢失
     */
    public static int  amountConversion(String money)
        if (null == money || money.isEmpty())
            return 0;
        
        BigDecimal money1 = new BigDecimal(money).multiply(new BigDecimal("100"));
        int money3 = money1.intValue();
        return money3;
    




以上是关于Android 金额转换精度丢失的主要内容,如果未能解决你的问题,请参考以下文章

数值金额计算js封装--包含加减乘除四个方法,能确保浮点数运算不丢失精度

前后的交互js数字精度丢失解决,金额保留两位小数四舍五入统一解决,自定义Json序列化处理方法,@JsonSerialize使用

java里面double 做乘法和加法会丢失精度嘛?

float精度丢失问题解决,用decimal.Decimal

浮点型数据丢失精度的原因

剖析金额不能用浮点数表示的原因