java数字人民币转大写的方法及注意事项
最近做需求,需要用到数字人民币转大写的方法,项目里面本身就有相应的工具方法,我就直接拿来用,结果到了生产上就有bug,原来是double类型十进制转二进制后小数点后的精度问题。于是自己总结写了一个比较健全的,顺便把对应的坑贴一下,提醒自己
先上正确的代码,需要的同学可以直接拿走,想要了解注意事项的同学往代码下面翻
public static String digitCapital(double n) {String fraction[] = {"角", "分"};String digit[] = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};String unit[][] = {{"元", "万", "亿"}, {"", "拾", "佰", "仟"}};String head = n < 0 ? "负" : "";// 如果是负数取绝对值n = Math.abs(n);String s = "";BigDecimal bigDecimal = null;String value = String.valueOf(n);if(value.contains("E")){bigDecimal = new BigDecimal(n);}else{bigDecimal = new BigDecimal(value);}String nStr = bigDecimal.toString();// 小数部分String[] split = nStr.split("\\.");if (split.length > 1) {// 小数点为特殊符号,在分割时需进行转义String decimalStr = split[1];if (decimalStr.length() > 2) {decimalStr = decimalStr.substring(0, 2);}// 将小数部分转换为整数Integer integer = Integer.valueOf(decimalStr);String p = "";for (int i = 0; i < decimalStr.length() && i < fraction.length; i++) {p = digit[integer % 10] + fraction[decimalStr.length() - i - 1] + p;integer = integer / 10;}s = p.replaceAll("(零.)+", "") + s;}if (s.length() < 1) {s = "整";}int integerPart = (int)Math.floor(n);// 整数部分for (int i = 0; i < unit[0].length && integerPart > 0; i++) {String p = "";for (int j = 0; j < unit[1].length && n > 0; j++) {p = digit[integerPart % 10] + unit[1][j] + p;integerPart = integerPart / 10;}s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s;}return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整");
}
接下来说一下注意事项:
1、网上大多数是直接使用double类型,没有转bigDecimal,这样就把double类型十进制转二进制精度丢失的天然属性问题带进来了,比如会把 “82602.65” 转成 “捌万贰仟陆佰零贰元陆角肆分” ,底层机制分析一下。
先按常规的十进制转二进制逻辑来一遍(稍后再反着转一遍看得更明白)
(1) 十进制整数如何转化为二进制数算法很简单。82602表示成二进制数:82602/2=41301 余 041301/2=20650 余 120650/2=10325 余 010325/2=5162 余 15162/2=2581 余 02581/2=1290 余 11290/2=645 余 0645/2=322 余 1322/2=161 余 0161/2=80 余 180/2=40 余 040/2=20 余 020/2=10 余 010/2=5 余 05/2=2 余 12/2=1 余 01/2=0 余 10结束 82602二进制表示为(从下往上):10100001010101010这里提一点:只要遇到除以后的结果为0了就结束了,大家想一想,所有的整数除以2是不是一定能够最终得到0。换句话说,所有的整数转变为二进制数的算法会不会无限循环下去呢?绝对不会,整数永远可以用二进制精确表示 ,但小数就不一定了。(2) 十进制小数如何转化为二进制数算法是乘以2直到没有了小数为止。0.65表示成二进制数0.65*2=1.3 取整数部分 10.3(1.3的小数部分)*2=0.6 取整数部分 00.6*2=1.2 取整数部分 10.2*2=0.4 取整数部分 00.4*2=0.8 取整数部分 00.8*2=1.6 取整数部分 10.6*2=1.2 取整数部分 1(这个时候开始了循环)......... 0.65二进制表示为(从上往下): 101001100110011......注意:上面的计算过程循环了,也就是说*2永远不可能消灭小数部分,这样算法将无限下去。很显然,小数的二进制表示有时是不可能精确的 。其实道理很简单,十进制系统中能不能准确表示出1/3呢?同样二进制系统也无法准确表示1/10。这也就解释了为什么浮点型减法出现了"减不尽"的精度丢失问题。我们得把10100001010101010.101001100110011.…放进一个 double 双精度浮点数里面双精度浮点数能表示多少精度呢?查看文档会发现:半精度(16bit):11位有效数字单精度(32bit):24位有效数字双精度(64bit):53位有效数字四精度(128bit):113位有效数字
好吧,双精度是53位有效数字,那么上面十进制的82602.65在计算机中的
二进制就是10100001010101010.10100110011001100110011001100110011然后我们再把二进制转换回十进制,整数部分不赘述还是82602;小数部分是1*2^-1+0*2^-2+1*2^-3+0*2^-4+0*2^-5+1*2^-6+1*2^-7+0*2^-8+0*2^-9+1*2^-10+1*2^-11+0*2^-12+0*2^-13+1*2^-14+1*2^-15+0*2^-16+0*2^-17+1*2^-18+1*2^-19+0*2^-20+0*2^-21+1*2^-22+1*2^-23+0*2^-24+0*2^-25+1*2^-26+1*2^-27+0*2^-28+0*2^-29+1*2^-30+1*2^-31+0*2^-32+0*2^-33+1*2^-34+1*2^-35得到了十进制小数0.6499999999941792,这好好的82602.65就变成了82602.6499999999941792,转换成中文大写会自动丢弃分之后的数据,所以就少了一分钱。
2、double类型在大数据时会采用科学计数法表示数值。
比如150000000就会使用1.5E8来表示,如果这里直接使用Double.toString()方法,它真的就会变成字符串“1.5E8”,后面就会直接报错了
java数字人民币转大写的方法及注意事项相关推荐
- java数字转汉字大写(全)
MoneyUtil.java public class MoneyUtil { public static String[] chineseDigits = new String[] { " ...
- Java数字转中文大写,数字转英文
这个类的最初版本曾经发在我的另一个博客: http://www.cnblogs.com/codejar/archive/2012/02/15/2352606.html 这里贴的是refactor后的最 ...
- Java字符串首字母大写高效方法
我们日常编码过程中,通常会使用反射,通过对象获取其属性,并通过属性得到其getter.setter方法,而得到get.set方法时候需要属性首字母大写.字符串首字母大写,我们通常的做法是:传统方法为先 ...
- php 数字小写转大写,php将金钱小写数字转为金钱大写的方法
function change_num($num) { $d = array('零','壹','贰','叁','肆','伍','陆','柒','捌','玖'); $e = array('元','拾', ...
- java把小写变大写_用java实现人民币小写变大写的方法
用java语言可以实现人民币小写转换为大写吗?如何实现呢?下面常见的用java实现人民币小写变大写的方法可以说是最精简的了,希望大家可以学习下. 这里介绍一个通过取余的办法来实现将人民币小写转换为大写 ...
- java开发_数字转换汉语中人民币的大写_完整版
转自:https://www.cnblogs.com/hongten/p/hongten_java_money.html 做这个应用,源于突然的一个想法:看到发票上面的数字要转换成汉语中人民币的大写 ...
- java转大写_java实现数字转大写的方法
java实现数字转大写的方法 说明: 将数字金额转大写,如下: public class Test { /** * @param args * add by zxx ,Nov 29, 2008 */ ...
- java人民币大小写转换函数_java开发_数字转换汉语中人民币的大写_完整版
1 package com.b510.number2char;2 3 import java.math.BigDecimal;4 5 /**6 * 数字转换为汉语中人民币的大写 7 *8 * @aut ...
- Java数字转换为人民币的大写
工具类: import java.math.BigDecimal;/*** 数字转换为人民币的大写*/ public class NumberToCN {/*** 汉语中数字大写*/private s ...
最新文章
- mac 安装brew时报错的问题及解决方式
- python读取文件特定内容_python读取指定内存的内容
- Windows Service方式启动的Tomcat如何配置PermGen Space
- sublime 无法下载插件解决办法(亲测有效)
- 两次被简书签约作者拉黑的经历
- [转载] 动态口令,动态密码生成(OTP)
- 电子科技大学《图论及其应用》复习总结--第一章 图的基本概念
- 大天使之剑H5游戏超详细图文架设教程
- matlab 线性拟合(好像也可以由两点得出直线)
- 谁是靠算法挑战华尔街的赌神?
- 对话深喉:中小App如何突围?(开发者必看)
- Vue React大屏可视化进阶
- f1c100s kernel调试记录
- Oracle报表计算合计函数ROLLUP
- 计算机硬件相关的论文,计算机硬件论文
- 计算机基础论文任务书,《计算机基础项目任务书》.doc
- 裸眼3D大屏首秀!变形金刚登陆成都太古里;包装巨头安姆科计划在中国江阴建新工厂 | 美通社头条...
- 常用估值方法的编程实现(1):自由现金流折现
- bootstrap4侧边栏_如何使用纯CSS和Bootstrap 4构建多个堆叠式粘性侧边栏
- 微信h5支付和公众号支付、支付宝h5支付