java后端
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

DecimalUtils.java 15 KiB

há 5 meses
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. package com.ruoyi.common.utils;
  2. import java.math.BigDecimal;
  3. import java.math.RoundingMode;
  4. import java.text.NumberFormat;
  5. import java.text.ParseException;
  6. import java.util.Arrays;
  7. import java.util.List;
  8. import java.util.Locale;
  9. /**
  10. * 字符串工具类
  11. *
  12. * @author ruoyi
  13. */
  14. public class DecimalUtils {
  15. private static final List<String> CN_NUMBERS = Arrays.asList("零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖");
  16. private static final List<String> CN_UNITS = Arrays.asList("", "拾", "佰", "仟");
  17. private static final List<String> CN_BIG_UNITS = Arrays.asList("", "万", "亿", "兆");
  18. private static final String CN_NEGATIVE = "负";
  19. private static final String CN_INTEGER = "整";
  20. private static final String CN_FULL = "圆";
  21. private static final String CN_DECIMAL_UNIT = "角分";
  22. private static final int MAXIMUM_NUMBER = 999999999;
  23. /**
  24. * 将金额数字转换为中文大写
  25. * @param amount 金额数字,支持最大到999999999.99
  26. * @return 中文大写金额字符串
  27. */
  28. public static String bigDecimalToChinese(BigDecimal amount) {
  29. if (amount == null) {
  30. throw new IllegalArgumentException("金额不能为空");
  31. }
  32. // 检查金额范围
  33. if (amount.abs().compareTo(new BigDecimal(MAXIMUM_NUMBER + ".99")) > 0) {
  34. throw new IllegalArgumentException("金额超出最大范围(999999999.99)");
  35. }
  36. StringBuilder result = new StringBuilder();
  37. // 处理负数
  38. if (amount.compareTo(BigDecimal.ZERO) < 0) {
  39. result.append(CN_NEGATIVE);
  40. amount = amount.abs();
  41. }
  42. // 转换为字符串处理
  43. String amountStr = amount.setScale(2, BigDecimal.ROUND_HALF_UP).toString();
  44. String[] parts = amountStr.split("\\.");
  45. String integerPart = parts[0];
  46. String decimalPart = parts.length > 1 ? parts[1] : "";
  47. // 处理整数部分
  48. boolean hasInteger = !"0".equals(integerPart);
  49. if (hasInteger) {
  50. result.append(convertIntegerPart(integerPart)).append(CN_FULL);
  51. }
  52. // 处理小数部分
  53. String decimalStr = convertDecimalPart(decimalPart);
  54. if (!decimalStr.isEmpty()) {
  55. // 如果没有整数部分且有小部分,则不显示"零圆"
  56. if (!hasInteger && decimalStr.charAt(0) != CN_NUMBERS.get(0).charAt(0)) {
  57. result.append(decimalStr);
  58. } else {
  59. // 如果有整数部分或小数部分以零开头,则正常拼接
  60. if (!hasInteger) {
  61. result.append(CN_NUMBERS.get(0)).append(CN_FULL);
  62. }
  63. result.append(decimalStr);
  64. }
  65. } else {
  66. // 如果没有小数部分,添加"整"
  67. result.append(CN_INTEGER);
  68. }
  69. return result.toString();
  70. }
  71. private static String convertIntegerPart(String integerPart) {
  72. StringBuilder sb = new StringBuilder();
  73. int length = integerPart.length();
  74. int zeroCount = 0; // 连续零的个数
  75. for (int i = 0; i < length; i++) {
  76. int digit = Character.getNumericValue(integerPart.charAt(i));
  77. int pos = length - i - 1; // 当前位数
  78. int unitPos = pos % 4; // 单位位置(个十百千)
  79. int bigUnitPos = pos / 4; // 大单位位置(万,亿)
  80. if (digit == 0) {
  81. zeroCount++;
  82. } else {
  83. if (zeroCount > 0) {
  84. sb.append(CN_NUMBERS.get(0));
  85. zeroCount = 0;
  86. }
  87. sb.append(CN_NUMBERS.get(digit)).append(CN_UNITS.get(unitPos));
  88. }
  89. // 添加大单位(万,亿)
  90. if (unitPos == 0 && bigUnitPos > 0) {
  91. if (zeroCount < 4) { // 如果当前段不全为零
  92. sb.append(CN_BIG_UNITS.get(bigUnitPos));
  93. }
  94. zeroCount = 0;
  95. }
  96. }
  97. // 处理全零的情况
  98. if (sb.length() == 0) {
  99. return CN_NUMBERS.get(0);
  100. }
  101. return sb.toString();
  102. }
  103. private static String convertDecimalPart(String decimalPart) {
  104. StringBuilder sb = new StringBuilder();
  105. boolean hasNonZero = false;
  106. for (int i = 0; i < decimalPart.length() && i < CN_DECIMAL_UNIT.length(); i++) {
  107. int digit = Character.getNumericValue(decimalPart.charAt(i));
  108. if (digit != 0) {
  109. sb.append(CN_NUMBERS.get(digit)).append(CN_DECIMAL_UNIT.charAt(i));
  110. hasNonZero = true;
  111. } else if (hasNonZero || (i > 0 && sb.length() > 0)) {
  112. // 如果前面已经有非零数字,或者不是第一位,可以添加零
  113. sb.append(CN_NUMBERS.get(0));
  114. }
  115. }
  116. // 去除末尾的零
  117. while (sb.length() > 0 && sb.charAt(sb.length() - 1) == CN_NUMBERS.get(0).charAt(0)) {
  118. sb.deleteCharAt(sb.length() - 1);
  119. }
  120. return sb.toString();
  121. }
  122. //默认除法运算精度
  123. private static final int DEF_DIV_SCALE = 10;
  124. /**
  125. * 提供精确的加法运算
  126. *
  127. * @param v1 被加数
  128. * @param v2 加数
  129. * @return 两个参数的和
  130. */
  131. public static double add(double v1, double v2) {
  132. BigDecimal b1 = new BigDecimal(Double.toString(v1));
  133. BigDecimal b2 = new BigDecimal(Double.toString(v2));
  134. return b1.add(b2).doubleValue();
  135. }
  136. /**
  137. * 提供精确的加法运算
  138. *
  139. * @param v1 被加数
  140. * @param v2 加数
  141. * @return 两个参数的和
  142. */
  143. public static BigDecimal add(String v1, String v2) {
  144. BigDecimal b1 = new BigDecimal(v1);
  145. BigDecimal b2 = new BigDecimal(v2);
  146. return b1.add(b2);
  147. }
  148. /**
  149. * 提供精确的加法运算
  150. *
  151. * @param v1 被加数
  152. * @param v2 加数
  153. * @param scale 保留scale 位小数
  154. * @return 两个参数的和
  155. */
  156. public static String add(String v1, String v2, int scale) {
  157. if (scale < 0) {
  158. throw new IllegalArgumentException(
  159. "The scale must be a positive integer or zero");
  160. }
  161. BigDecimal b1 = new BigDecimal(v1);
  162. BigDecimal b2 = new BigDecimal(v2);
  163. return b1.add(b2).setScale(scale, RoundingMode.HALF_UP).toString();
  164. }
  165. /**
  166. * 提供精确的减法运算
  167. *
  168. * @param v1 被减数
  169. * @param v2 减数
  170. * @return 两个参数的差
  171. */
  172. public static double sub(double v1, double v2) {
  173. BigDecimal b1 = new BigDecimal(Double.toString(v1));
  174. BigDecimal b2 = new BigDecimal(Double.toString(v2));
  175. return b1.subtract(b2).doubleValue();
  176. }
  177. /**
  178. * 提供精确的减法运算。
  179. *
  180. * @param v1 被减数
  181. * @param v2 减数
  182. * @return 两个参数的差
  183. */
  184. public static BigDecimal sub(String v1, String v2) {
  185. BigDecimal b1 = new BigDecimal(v1);
  186. BigDecimal b2 = new BigDecimal(v2);
  187. return b1.subtract(b2);
  188. }
  189. /**
  190. * 提供精确的减法运算
  191. *
  192. * @param v1 被减数
  193. * @param v2 减数
  194. * @param scale 保留scale 位小数
  195. * @return 两个参数的差
  196. */
  197. public static String sub(String v1, String v2, int scale) {
  198. if (scale < 0) {
  199. throw new IllegalArgumentException(
  200. "The scale must be a positive integer or zero");
  201. }
  202. BigDecimal b1 = new BigDecimal(v1);
  203. BigDecimal b2 = new BigDecimal(v2);
  204. return b1.subtract(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
  205. }
  206. /**
  207. * 提供精确的乘法运算
  208. *
  209. * @param v1 被乘数
  210. * @param v2 乘数
  211. * @return 两个参数的积
  212. */
  213. public static double mul(double v1, double v2) {
  214. BigDecimal b1 = new BigDecimal(Double.toString(v1));
  215. BigDecimal b2 = new BigDecimal(Double.toString(v2));
  216. return b1.multiply(b2).doubleValue();
  217. }
  218. /**
  219. * 提供精确的乘法运算
  220. *
  221. * @param v1 被乘数
  222. * @param v2 乘数
  223. * @return 两个参数的积
  224. */
  225. public static BigDecimal mul(String v1, String v2) {
  226. BigDecimal b1 = new BigDecimal(v1);
  227. BigDecimal b2 = new BigDecimal(v2);
  228. return b1.multiply(b2);
  229. }
  230. /**
  231. * 提供精确的乘法运算
  232. *
  233. * @param v1 被乘数
  234. * @param v2 乘数
  235. * @param scale 保留scale 位小数
  236. * @return 两个参数的积
  237. */
  238. public static double mul(double v1, double v2, int scale) {
  239. BigDecimal b1 = new BigDecimal(Double.toString(v1));
  240. BigDecimal b2 = new BigDecimal(Double.toString(v2));
  241. return round(b1.multiply(b2).doubleValue(), scale);
  242. }
  243. /**
  244. * 提供精确的乘法运算
  245. *
  246. * @param v1 被乘数
  247. * @param v2 乘数
  248. * @param scale 保留scale 位小数
  249. * @return 两个参数的积
  250. */
  251. public static String mul(String v1, String v2, int scale) {
  252. if (scale < 0) {
  253. throw new IllegalArgumentException(
  254. "The scale must be a positive integer or zero");
  255. }
  256. BigDecimal b1 = new BigDecimal(v1);
  257. BigDecimal b2 = new BigDecimal(v2);
  258. return b1.multiply(b2).setScale(scale, RoundingMode.HALF_UP).toString();
  259. }
  260. /**
  261. * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
  262. * 小数点以后10位,以后的数字四舍五入
  263. *
  264. * @param v1 被除数
  265. * @param v2 除数
  266. * @return 两个参数的商
  267. */
  268. public static double div(double v1, double v2) {
  269. return div(v1, v2, DEF_DIV_SCALE);
  270. }
  271. /**
  272. * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
  273. * 定精度,以后的数字四舍五入
  274. *
  275. * @param v1 被除数
  276. * @param v2 除数
  277. * @param scale 表示表示需要精确到小数点以后几位。
  278. * @return 两个参数的商
  279. */
  280. public static double div(double v1, double v2, int scale) {
  281. if (scale < 0) {
  282. throw new IllegalArgumentException("The scale must be a positive integer or zero");
  283. }
  284. BigDecimal b1 = new BigDecimal(Double.toString(v1));
  285. BigDecimal b2 = new BigDecimal(Double.toString(v2));
  286. return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue();
  287. }
  288. /**
  289. * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
  290. * 定精度,以后的数字四舍五入
  291. *
  292. * @param v1 被除数
  293. * @param v2 除数
  294. * @param scale 表示需要精确到小数点以后几位
  295. * @return 两个参数的商
  296. */
  297. public static String div(String v1, String v2, int scale) {
  298. if (scale < 0) {
  299. throw new IllegalArgumentException("The scale must be a positive integer or zero");
  300. }
  301. BigDecimal b1 = new BigDecimal(v1);
  302. BigDecimal b2 = new BigDecimal(v1);
  303. return b1.divide(b2, scale, RoundingMode.HALF_UP).toString();
  304. }
  305. /**
  306. * 提供精确的小数位四舍五入处理
  307. *
  308. * @param v 需要四舍五入的数字
  309. * @param scale 小数点后保留几位
  310. * @return 四舍五入后的结果
  311. */
  312. public static double round(double v, int scale) {
  313. if (scale < 0) {
  314. throw new IllegalArgumentException("The scale must be a positive integer or zero");
  315. }
  316. BigDecimal b = new BigDecimal(Double.toString(v));
  317. return b.setScale(scale, RoundingMode.HALF_UP).doubleValue();
  318. }
  319. /**
  320. * 提供精确的小数位四舍五入处理
  321. *
  322. * @param v 需要四舍五入的数字
  323. * @param scale 小数点后保留几位
  324. * @return 四舍五入后的结果
  325. */
  326. public static String round(String v, int scale) {
  327. if (scale < 0) {
  328. throw new IllegalArgumentException(
  329. "The scale must be a positive integer or zero");
  330. }
  331. BigDecimal b = new BigDecimal(v);
  332. return b.setScale(scale, RoundingMode.HALF_UP).toString();
  333. }
  334. /**
  335. * 取余数
  336. *
  337. * @param v1 被除数
  338. * @param v2 除数
  339. * @param scale 小数点后保留几位
  340. * @return 余数
  341. */
  342. public static String remainder(String v1, String v2, int scale) {
  343. if (scale < 0) {
  344. throw new IllegalArgumentException(
  345. "The scale must be a positive integer or zero");
  346. }
  347. BigDecimal b1 = new BigDecimal(v1);
  348. BigDecimal b2 = new BigDecimal(v2);
  349. return b1.remainder(b2).setScale(scale, RoundingMode.HALF_UP).toString();
  350. }
  351. /**
  352. * 取余数 BigDecimal
  353. *
  354. * @param v1 被除数
  355. * @param v2 除数
  356. * @param scale 小数点后保留几位
  357. * @return 余数
  358. */
  359. public static BigDecimal remainder(BigDecimal v1, BigDecimal v2, int scale) {
  360. if (scale < 0) {
  361. throw new IllegalArgumentException(
  362. "The scale must be a positive integer or zero");
  363. }
  364. return v1.remainder(v2).setScale(scale, RoundingMode.HALF_UP);
  365. }
  366. /**
  367. * 比较大小
  368. *
  369. * @param v1 被比较数
  370. * @param v2 比较数
  371. * @return 如果v1 大于v2 则 返回true 否则false
  372. */
  373. public static boolean compare(String v1, String v2) {
  374. BigDecimal b1 = new BigDecimal(v1);
  375. BigDecimal b2 = new BigDecimal(v2);
  376. int bj = b1.compareTo(b2);
  377. boolean res;
  378. res = bj > 0;
  379. return res;
  380. }
  381. /**
  382. * 将数字格式化为千分位
  383. *
  384. * @param number
  385. * @return 字符串
  386. */
  387. public static String convert(BigDecimal number) {
  388. if (null == number || number.compareTo(BigDecimal.ZERO) == 0) {
  389. return "";
  390. }
  391. NumberFormat numberFormat = NumberFormat.getNumberInstance(Locale.ENGLISH);
  392. // 设置最大分数位数,这里设置为0表示不使用分数
  393. numberFormat.setMaximumFractionDigits(2);
  394. // 设置最小整数位数,这里设置为2表示整数部分至少2位
  395. //numberFormat.setMinimumIntegerDigits(2);
  396. // 设置grouping used属性为false,表示不使用千分位分隔符
  397. numberFormat.setGroupingUsed(true);
  398. return numberFormat.format(number);
  399. }
  400. /**
  401. * 将千分位数字字符串格式化为 BigDecimal
  402. * @param formattedNumber
  403. * @return 字符串
  404. */
  405. public static BigDecimal convert(String formattedNumber) {
  406. if (StringUtils.isEmpty(formattedNumber)) {
  407. return BigDecimal.ZERO;
  408. }
  409. try {
  410. NumberFormat format = NumberFormat.getInstance(Locale.US);
  411. Number number = format.parse(formattedNumber);
  412. BigDecimal bigDecimal = new BigDecimal(number.toString());
  413. return bigDecimal;
  414. } catch (ParseException e) {
  415. e.printStackTrace();
  416. return BigDecimal.ZERO;
  417. }
  418. }
  419. public static boolean isZero_s(BigDecimal b) {
  420. return null == b || b.compareTo(BigDecimal.ZERO) == 0;
  421. }
  422. /**
  423. * 将是0的处理成空
  424. * @param number
  425. * @return BigDecimal
  426. */
  427. public static String zeroToNull(BigDecimal number) {
  428. if(number.compareTo(BigDecimal.ZERO) == 0){
  429. return null;
  430. }else{
  431. return number.toString();
  432. }
  433. }
  434. }