- 小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
前言
- 1+1等于几,这种问题相信小学生都是信口拈来。
- 但就是这样常识的问题,为什么在计算机领域就发生了微妙的变化了呢。在计算机领域中1.0-1.0很有可能颠覆我们认知
- 数字真的是很奇妙,纯数字以外还有中文汉字形式的数字,那么他们之间又会如何转换呢?
加减乘除
-
Double类型的加减乘除并不是我们认知中的加减乘除,因为二进制的问题导致浮点数的操作并不是我们常识中的操作。我们需要将Double类型进行稍微的转换
-
首先
BigDecimal类型算是计算机领域中的真正数字类型。我们将浮点数Double转换为BigDecimal就会成为我们习以为常的数据
public Double add(Double v1, Double v2) {
BigDecimal b1 = new BigDecimal(v1.toString());
BigDecimal b2 = new BigDecimal(v2.toString());
return new Double(b1.add(b2).doubleValue());
}
public Double div(Double v1, Double v2) {
BigDecimal b1 = new BigDecimal(v1.toString());
BigDecimal b2 = new BigDecimal(v2.toString());
return new Double(b1.divide(b2, DEF_DIV_SCALE, BigDecimal.ROUND_HALF_UP)
.doubleValue());
}
- 上面简单列举说明了,剩下的两种方法都是通过将double转成BigDecimal来操作然后再讲结果double化输出
中文数字转阿拉伯数字
代码示例
/**
* 中文数字转阿拉伯数字
* 一万两千三百五十四 --> 12354
* @param chinese 阿拉伯数字
* @return 中文数字
*/
public String getNumberFromChinese(String chinese) {
String result = "0";
List<String> lists = new ArrayList<>();
int lastLevelIndex = 0;
for (int i = ChineseNumber.highLevel.size()-1; i>=0; i--) {
int levelIndex = chinese.indexOf(ChineseNumber.highLevel.get(i));
if (levelIndex>0) {
lists.add(chinese.substring(0, levelIndex));
chinese = chinese.substring(levelIndex+1);
} else if (levelIndex == -1) {
lists.add(ChineseNumber.number.get(0));
} else if (levelIndex == 0) {
while (levelIndex > 1) {
levelIndex--;
lists.add(ChineseNumber.number.get(0));
}
lists.add(chinese);
}
}
for (int i = 0; i < lists.size(); i++) {
Integer highLevelIndex = lists.size() - i - 1;
String single = lists.get(i);
String nextResult = getNumberFromFChinese(single);
Long next = Long.valueOf(Integer.valueOf(result) * (int)(Math.pow(10, 4)) + Integer.valueOf(nextResult));
result = next.toString();
}
result = result.replaceFirst("^(0+)", "");
return result;
}
/**
* 通过中文数字获取4位数阿拉伯数字
* 万以内的数据转换
* @param single
* @return
*/
private String getNumberFromFChinese(String single) {
String result = "0";
Integer highIndex = 1;
for (int i = 0; i < single.length(); i++) {
String str = String.valueOf(single.charAt(i));
int unit = ChineseNumber.level.indexOf(str);
int number = ChineseNumber.number.indexOf(str);
if (unit == -1) {
int next = 0;
if (i < single.length() - 1) {
next = ChineseNumber.level.indexOf(String.valueOf(single.charAt(i + 1)));
}
result=String.valueOf(Integer.valueOf(result)+number * (int) (Math.pow(10, next)));
}
}
result = ""+Integer.valueOf(result) * (int) (Math.pow(10, highIndex - 1));
return result;
}
代码解读
首先默认输出结果为0
- 如果没有数据则默认转换为0
然后将数据按4位数切割。一亿、一万、一。这样每四位四位切割
- 通过亿,万这些高级别单位讲中文数字转换为四位数字为一组的集合
解读4位数字的中文数字
- 我们首先定义万以内的单位分别有千百十一这四个基本单位。我们一个一个看字符串是属于单位集合还是属于数字集合。有个特殊的情况就是在遇到中文数字零的时候我们转换的时候需要注意需要填补几个0,这里我采取的是记录上一次的基本单位和0的下一次的基本单位之间的差值就是补0的个数。
阿拉伯数字转中文数字
代码示例
/**
* 阿拉伯数字转中文数字
* 12354 --> 一万两千三百五十四
* @param alabo 阿拉伯数字
* @return 中文数字
*/
public String getNumberFromAlabo(String alabo) {
String result = "";
List<String> list = new ArrayList<>();
for (int length = alabo.length()-1; length >= 0; length--) {
list.add(String.valueOf(alabo.charAt(length)));
}
List<List<String>> lists = CollectionUtil.averageSize(list, 4);
Collections.reverse(lists);
if (CollectionUtil.isNotEmpty(lists)) {
for (int index=0;index<lists.size();index++) {
List<String> singleNumList = lists.get(index);
//反转集合
Collections.reverse(singleNumList);
//默认0 false
Boolean zeroflag =false;
String chinese = "";
for (int j=0 ; j<singleNumList.size();j++) {
Integer number = Integer.valueOf(singleNumList.get(j));
if (number == 0 && !zeroflag && afterNotAllZero(singleNumList, j)) {
chinese += ChineseNumber.number.get(number);
zeroflag = true;
} else if(number!=0) {
chinese += ChineseNumber.number.get(number) + ChineseNumber.level.get(singleNumList.size()-j-1);
}
}
if (index==lists.size()&&chinese.substring(0, 1).equals(ChineseNumber.number.get(0))) {
chinese = chinese.substring(1);
}
if (chinese.length()>0&&!ChineseNumber.highLevel.contains(chinese.substring(chinese.length() - 1))) {
result += chinese + ChineseNumber.highLevel.get(lists.size() - 1 - index);
}
}
}
return result;
}
/**
* 判断singleNumList在j位置之后是否全是0
* @param singleNumList
* @param j
* @return
*/
private boolean afterNotAllZero(List<String> singleNumList, int j) {
for (int i = j+1; i < singleNumList.size(); i++) {
if (!"0".equals(singleNumList.get(i))) {
return true;
}
}
return false;
}
代码解读
同样将阿拉伯数字按4位截取
- 通过集合将集合分拆成4位一组
在4为数中遇到0需要处理上述问题中的反向,遇到多个0注意转成一个零
- 在从高位向低位遍历时,需要注意遇到连续多个0转换成一个零。因为阿拉伯数字是不会有0开头的,所以合并最后不要处理开始为零的数据
- 最后将各个四位数字转换的四位阿拉伯数字拼接在一起就可以了