最近做需求,需要用到数字人民币转大写的方法,项目里面本身就有相应的工具方法,我就直接拿来用,结果到了生产上就有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数字人民币转大写的方法及注意事项相关推荐

  1. java数字转汉字大写(全)

    MoneyUtil.java public class MoneyUtil { public static String[] chineseDigits = new String[] { " ...

  2. Java数字转中文大写,数字转英文

    这个类的最初版本曾经发在我的另一个博客: http://www.cnblogs.com/codejar/archive/2012/02/15/2352606.html 这里贴的是refactor后的最 ...

  3. Java字符串首字母大写高效方法

    我们日常编码过程中,通常会使用反射,通过对象获取其属性,并通过属性得到其getter.setter方法,而得到get.set方法时候需要属性首字母大写.字符串首字母大写,我们通常的做法是:传统方法为先 ...

  4. php 数字小写转大写,php将金钱小写数字转为金钱大写的方法

    function change_num($num) { $d = array('零','壹','贰','叁','肆','伍','陆','柒','捌','玖'); $e = array('元','拾', ...

  5. java把小写变大写_用java实现人民币小写变大写的方法

    用java语言可以实现人民币小写转换为大写吗?如何实现呢?下面常见的用java实现人民币小写变大写的方法可以说是最精简的了,希望大家可以学习下. 这里介绍一个通过取余的办法来实现将人民币小写转换为大写 ...

  6. java开发_数字转换汉语中人民币的大写_完整版

    转自:https://www.cnblogs.com/hongten/p/hongten_java_money.html 做这个应用,源于突然的一个想法:看到发票上面的数字要转换成汉语中人民币的大写 ...

  7. java转大写_java实现数字转大写的方法

    java实现数字转大写的方法 说明: 将数字金额转大写,如下: public class Test { /** * @param args * add by zxx ,Nov 29, 2008 */ ...

  8. java人民币大小写转换函数_java开发_数字转换汉语中人民币的大写_完整版

    1 package com.b510.number2char;2 3 import java.math.BigDecimal;4 5 /**6 * 数字转换为汉语中人民币的大写 7 *8 * @aut ...

  9. Java数字转换为人民币的大写

    工具类: import java.math.BigDecimal;/*** 数字转换为人民币的大写*/ public class NumberToCN {/*** 汉语中数字大写*/private s ...

最新文章

  1. mac  安装brew时报错的问题及解决方式
  2. python读取文件特定内容_python读取指定内存的内容
  3. Windows Service方式启动的Tomcat如何配置PermGen Space
  4. sublime 无法下载插件解决办法(亲测有效)
  5. 两次被简书签约作者拉黑的经历
  6. [转载] 动态口令,动态密码生成(OTP)
  7. 电子科技大学《图论及其应用》复习总结--第一章 图的基本概念
  8. 大天使之剑H5游戏超详细图文架设教程
  9. matlab 线性拟合(好像也可以由两点得出直线)
  10. 谁是靠算法挑战华尔街的赌神?
  11. 对话深喉:中小App如何突围?(开发者必看)
  12. Vue React大屏可视化进阶
  13. f1c100s kernel调试记录
  14. Oracle报表计算合计函数ROLLUP
  15. 计算机硬件相关的论文,计算机硬件论文
  16. 计算机基础论文任务书,《计算机基础项目任务书》.doc
  17. 裸眼3D大屏首秀!变形金刚登陆成都太古里;包装巨头安姆科计划在中国江阴建新工厂 | 美通社头条...
  18. 常用估值方法的编程实现(1):自由现金流折现
  19. bootstrap4侧边栏_如何使用纯CSS和Bootstrap 4构建多个堆叠式粘性侧边栏
  20. 微信h5支付和公众号支付、支付宝h5支付

热门文章

  1. 【前端 HTML+CSS+JavaScript(JS)】DOM练习-onkeydown键盘事件-用wasd移动图片的位置 带注释/总结
  2. C# 批量修改图片尺寸和DPI
  3. SD-WAN设备白盒刷机
  4. matlab数字和字符byte数的区别,字符和字节的概念及区别解析
  5. 【Linux】Sed简明教程
  6. 用Python通过用户cookies访问微博首页
  7. PCA SVD opencv 降维对比
  8. 14、降维,PCA算法
  9. 医学影像处理软件ITK-SNAP
  10. Games104 Lecture 3 如何构建一个游戏世界