Java中的BigDecimal使用注意事项

1.BigDecial是immutable的,就像String一样,它的所有操作都会生成一个新的对象,所以

amount.add( thisAmount );

是错误的;而应该是:

amount = amount.add( thisAmount );

2. 不要用equals方法来比较BigDecimal对象,因为它的equals方法会比较scale,如果scale不一样,它会返回false;例如:

BigDecimal a = new BigDecimal(“2.00”);
BigDecimal b = new BigDecimal(“2.0”);
print(a.equals(b)); // false

所以你应该使用compareTo()和signum()方法

a.compareTo(b); // returns (-1 if a < b), (0 if a == b), (1 if a > b)
a.signum(); // returns (-1 if a < 0), (0 if a == 0), (1 if a > 0)

3. 使用BigDecimal的字符串构造函数,不要使用double参数的构造函数,否则的话会出现你不想要的结果。

例如下面的代码分别使用double和String的构造函数,然后使用HALF_EVEN的round方法,但是输出结果不一样:

System.out.println("==================");
for(int i = 0; i < 10;  i ++) {
    StringBuffer sb = new StringBuffer();
    sb.append("0.");
    sb.append(i);
    sb.append("5");
    BigDecimal bdx = new BigDecimal(sb.toString());
    System.out.println(sb + " " +bdx.setScale(1, RoundingMode.HALF_EVEN));
}

System.out.println("==================");
for(int i = 0; i < 10;  i ++) {
    StringBuffer sb = new StringBuffer();
    sb.append("0.");
    sb.append(i);
    sb.append("5");
    BigDecimal bdx = new BigDecimal(Double.valueOf(sb.toString()));
    System.out.println(sb + " " +bdx.setScale(1, RoundingMode.HALF_EVEN));
}

输出是:

==================

0.05 0.0
0.15 0.2
0.25 0.2
0.35 0.4
0.45 0.4
0.55 0.6
0.65 0.6
0.75 0.8
0.85 0.8

0.95 1.0

0.05 0.1
0.15 0.1
0.25 0.2
0.35 0.3
0.45 0.5
0.55 0.6
0.65 0.7
0.75 0.8
0.85 0.8
0.95 0.9


http://www.opentaps.org/docs/index.php/How_to_Use_Java_BigDecimal:_A_Tutorial

Java BigDecimal中的RoundingMode

BigDecimal有八种RoundingMode,其中最基本的有两种,它们是:

ROUND_UP:Always increments the digit prior to a nonzero discarded fraction.
总是将要丢掉的数字前一位的数字加1.

例如:

Rounding mode UP Examples Input Number | Input rounded to one digit
with UP rounding
—|—
5.5 | 6
2.5 | 3
1.6 | 2
1.1 | 2
1.0 | 1
-1.0 | -1
-1.1 | -2
-1.6 | -2
-2.5 | -3
-5.5 | -6

比方说5.5的scale是1,那么需要丢掉的数字的0.5, 将0.5丢掉,然后给5加1,就变成6了;

需要注意的是-5.5,这里的负号是不参加运算的,将它当成5.5,先进行Round up,然后将负号加上;

ROUND_DOWN:Never increments the digit prior to a discarded fraction (i.e.,
truncates).将要丢掉的数字直接丢掉。

Rounding mode DOWN Examples Input Number | Input rounded to one digit
with DOWN rounding
—|—
5.5 | 5
2.5 | 2
1.6 | 1
1.1 | 1
1.0 | 1
-1.0 | -1
-1.1 | -1
-1.6 | -1
-2.5 | -2
-5.5 | -5

比方说5.5的scale是1,那么需要丢掉的数字的0.5, 直接将0.5丢掉就可以了;

需要注意的是-5.5,这里的负号是不参加运算的,将它当成5.5,先进行Round Down,然后将负号加上;

然后其它五中都是根据Round Down/Up来推出来的;

例如:

ROUND_CEILING:If the result is positive, behaves as for RoundingMode.UP ;
if negative, behaves as for RoundingMode.DOWN
.如果参数是正数,使用UP规则,如果参数是负数,使用DOWN规则;

Rounding mode CEILING Examples Input Number | Input rounded to one digit
with CEILING rounding
—|—
5.5 | 6
2.5 | 3
1.6 | 2
1.1 | 2
1.0 | 1
-1.0 | -1
-1.1 | -1
-1.6 | -1
-2.5 | -2
-5.5 | -5

ROUND_FLOOR:If the result is positive, behave as for RoundingMode.DOWN ;
if negative, behave as for RoundingMode.UP
.如果参数是正数,使用DOWN规则,如果参数是负数,使用UP规则;

Rounding mode FLOOR Examples Input Number | Input rounded to one digit
with FLOOR rounding
—|—
5.5 | 5
2.5 | 2
1.6 | 1
1.1 | 1
1.0 | 1
-1.0 | -1
-1.1 | -2
-1.6 | -2
-2.5 | -3
-5.5 | -6

ROUND_HALF_UP: Behaves as for RoundingMode.UP if the discarded fraction is ≥
0.5; otherwise, behaves as for RoundingMode.DOWN.
如果要丢掉的数字大于等于0.5,使用UP规则;否则使用DOWN规则;

Rounding mode HALF_UP Examples Input Number | Input rounded to one digit
with HALF_UP rounding
—|—
5.5 | 6
2.5 | 3
1.6 | 2
1.1 | 1
1.0 | 1
-1.0 | -1
-1.1 | -1
-1.6 | -2
-2.5 | -3
-5.5 | -6

ROUND_HALF_DOWN: Behaves as for RoundingMode.UP if the discarded fraction is

0.5; otherwise, behaves as for RoundingMode.DOWN.
如果要丢掉的数字大于0.5,使用UP规则;否则使用DOWN规则;

Rounding mode HALF_DOWN Examples Input Number | Input rounded to one
digit
with HALF_DOWN rounding
—|—
5.5 | 5
2.5 | 2
1.6 | 2
1.1 | 1
1.0 | 1
-1.0 | -1
-1.1 | -1
-1.6 | -2
-2.5 | -2
-5.5 | -5

ROUND_HALF_EVEN:Rounding mode to round towards the “nearest neighbor” unless
both neighbors are equidistant, in which case, round towards the even
neighbor. Behaves as for RoundingMode.HALF_UP if the digit to the left of
the discarded fraction is odd; behaves as for RoundingMode.HALF_DOWN if
it’s even.
如果要丢掉的数字不是5的话,需要看这个数字前面的数字的奇偶性,如果是奇数,使用HALF_UP规则;如果是偶数使用HALF_DOWN规则;如果要丢掉的数字是5的话,round到它的偶数邻居上;

Rounding mode HALF_EVEN Examples Input Number | Input rounded to one
digit
with HALF_EVEN rounding
—|—
5.5 | 6
2.5 | 2
1.6 | 2
1.1 | 1
1.0 | 1
-1.0 | -1
-1.1 | -1
-1.6 | -2
-2.5 | -2
-5.5 | -6

ROUND_UNNECESSARY:不需要ROUND

最后来一张总表,

Summary of Rounding Operations Under Different Rounding Modes | Result of
rounding input to one digit with the given rounding mode
—|—
Input Number | UP | DOWN | CEILING | FLOOR | HALF_UP
| HALF_DOWN | HALF_EVEN | UNNECESSARY
5.5 | 6 | 5 | 6 | 5 | 6 | 5 | 6 | throw ArithmeticException
2.5 | 3 | 2 | 3 | 2 | 3 | 2 | 2 | throw ArithmeticException
1.6 | 2 | 1 | 2 | 1 | 2 | 2 | 2 | throw ArithmeticException
1.1 | 2 | 1 | 2 | 1 | 1 | 1 | 1 | throw ArithmeticException
1.0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1
-1.0 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1
-1.1 | -2 | -1 | -1 | -2 | -1 | -1 | -1 | throw ArithmeticException
-1.6 | -2 | -1 | -1 | -2 | -2 | -2 | -2 | throw ArithmeticException
-2.5 | -3 | -2 | -2 | -3 | -3 | -2 | -2 | throw ArithmeticException
-5.5 | -6 | -5 | -5 | -6 | -6 | -5 | -6 | throw ArithmeticException

refs:

http://stackoverflow.com/questions/792237/why-and-how-does-round-half-even-
minimize-cumulative-error-when-applied-repeated

jdk document

http://en.wikipedia.org/wiki/Floor_and_ceiling_functions


http://www.opentaps.org/docs/index.php/How_to_Use_Java_BigDecimal:_A_Tutorial

如何实现上舍入到0.05

这个问题是上次去一家公司去面试的时候,把我给难住了的地方。

只能怪自己没有好好的学习ceil和floor的用法;

其实google了以下只需要简单的方法一句话就可以了;

如下:

private static void roundUpToZeroPZeroFive2(double input) {
    double output = 0;
    System.out.println("before round :" + input);

    output = Math.ceil(input*20)/20;
    System.out.println("after round :" + output);
}

还有一种笨方法:

public static BigDecimal roundTax(BigDecimal bd){  
    if(bd == null || BigDecimal.ZERO.compareTo(bd) == 1){  
        return BigDecimal.ZERO.setScale(2);  
    }  
    bd = bd.setScale(2,RoundingMode.HALF_UP);  
    String strBd = bd.toString();  
    String strLastBit = strBd.substring(strBd.length()-1,strBd.length());  
    BigDecimal bdTemp = BigDecimal.ZERO;  
    bdTemp.setScale(2);  
    int iLastBit = Integer.valueOf(strLastBit);  
    if(iLastBit%5 != 0){  
        bdTemp = BigDecimal.valueOf(iLastBit).divide(BigDecimal.valueOf(100));  
        bdTemp = bdTemp.multiply(BigDecimal.valueOf(-1));  
        bdTemp = bdTemp.add(iLastBit>5 ? new BigDecimal("0.1") : new BigDecimal("0.05"));  
    }  
    bd = bd.add(bdTemp);  
    return bd;  
} 

参见这里:

http://blog.csdn.net/daxiang12092205/article/details/37989071

http://stackoverflow.com/questions/6330852/round-off-decimal-value-up-to-
nearest-0-05-value

面试题目可以看这里:

http://blog.csdn.net/daxiang12092205/article/details/37938915

Java Math.ulp方法是什么意思

如果要理解什么是ulp,先要了解在计算机中保存的数和我们在数学上认为的数是不一样的;

比方说2.0和3.0之间有多少个数,在数学中是无限的,但是在计算机中是有限的,因为计算机需要用一堆字节来表示double或者float,但是因为计算机表示不了无限的数(因为没有无限内存)。

所以就有了ulp,假设在float
2.0和3.0之间有8,388,609个数,那么在2.0和3.0之间的数的ulp就是8,388,609/1.0约等于0.0000001。

你如果想知道某一个具体的double或float的先一个或者上一个数字是什么可以使用函数

public static double nextAfter(float start, float direction)
public static double nextAfter(double start, double direction)

http://www.ibm.com/developerworks/library/j-math2/

Java Math类中的Math.rint(double) and Math.round(double)

1. 对于rint()

a) 2.50 在2.0和3.0之间. rint() 返回里的最近的偶数. 所有rint(2.50) 返回 2.0
b) 1.50 在2.0和1.0之间. rint() 返回里的最近的偶数. 所有rint(1.50) 返回 2.0

2. 对于round()

a) 2.50 在2.0和3.0之间. round() 返回离他最近的比较大的数. 所以round(2.50) 返回 3
b) 1.50 在2.0和1.0之间. round() 返回离他最近的比较大的数. 所以round(1.50) 返回 2

注意: rint() 返回的是double值,而round() 返回的是int/long.

3. 如果参数已经是整数,这两个方法的返回值都和传的参数一样

1. System.out.println(Math.rint(3.0)); // prints 3.0

2. System.out.println(Math.round(3.0)); // prints 3.

其他的请参见:

http://way2java.com/java-lang/class-math-java-lang/difference-of-math-
rintdouble-and-math-rounddouble/

如何使用Excel创建Box plot

  1. 首先在Excel中输入你想话Box plot的数据;
- West East
1 47 1
2 23 3
3 25 6
4 28 3
5 19 12
5 24 10
6 38 9
7 22 80

2.然后计算需要的值:

Min 19 1
Q1 22.75 3
Median 24.5 7.5
Q3 30.5 10.5
Max 47 80
box1-hidden 22.75 3 Q1
box2-lower 1.75 4.5 Median-Q1
box3-upper 6 3 Q3-Median
whisker top 16.5 69.5 Max-Q3
whisker bottom 3.75 2 Q1-Min

3. 选择B2:C2和A19:C21,然后Insert–>Column(In Charts group)–>Stacked
Column,插入一个stacked的chart,如果x轴和y轴不对的话,可以通过Design–>Switch Row/Column交换xy轴;
4. 选中stacked column中的最下面的一个series,将它的背景色去掉,也可以将gridline去掉;
5. 关键的一步是用ErrorBar生成Box plot的upper whisker和lower
whisker;选择最下面的一个series,在Layout–>Analysis–>Error Bar–>More Error Bars
Options–>Custom–>选择whiker bottom一行的两个数据。就可以了。

最后的结果
http://blog.contextures.com/archives/2013/06/11/create-a-simple-box-plot-in-
excel/

http://peltiertech.com/excel-box-and-whisker-diagrams-box-plots/

Percentile和Quartile

要介绍这两个概念,需要先介绍一个简单的概念;中值(median)。

中值简单的说,就是一堆给定的数字,最中间的值;

例如:1,2,3,4,5的中值就是3;

1,2,3,4的中值就是2.5;

引入数学公式就是:

If _n_ is odd then Median ( _M_ ) = value of (( _n_ + 1)/2)th item term.

If _n_ is even then Median ( _M_ ) = value of [(( _n_ )/2)th item term +
(( _n_ )/2 + 1)th item term ]/2

http://en.wikipedia.org/wiki/Median

什么是quartile呢?quartile的意思是四分位数,second quartile就是中值;

四分位数,从字面上看是四个数字将一堆数分割开来,对,就是分割;

第一个四分位数(Q1),也叫做25th percentile或者lower quartile;

第二个四分位数(Q2),也叫做中值或者50th percentile;

第三个四分位数(Q3),也叫做75th percentile或者upper quartile;

interquartile range(IQR),IQR=Q3-Q1;

四分位数的计算方法有很多,下面是从wikipedia复制过来的。

Method 1

  1. Use the median to divide the ordered data set into two halves. Do not include the median in either half.使用中值将有序的数据集分成两部分,这两部分不包括中值

  2. The lower quartile value is the median of the lower half of the data. The upper quartile value is the median of the upper half of the data.Q1就是小数据部分的中值,Q3就是大数据的中值

Method 2

  1. Use the median to divide the ordered data set into two halves. If the median is a datum (as opposed to being the mean of the middle two data), include the median in both halves.使用中值将有序的数据集分成两部分,数据集的个数的奇数的话,将中值加入到分成的两部分的末尾和头
  2. The lower quartile value is the median of the lower half of the data. The upper quartile value is the median of the upper half of the data.和方法1一样

Method 3

  1. If there are an even number of data points, then the method is the same as above.如果数据集是偶数的话,同上;
  2. If there are (4 _n_ +1) data points, then the lower quartile is 25% of the _n_ th data value plus 75% of the ( _n_ +1)th data value; the upper quartile is 75% of the (3 _n_ +1)th data point plus 25% of the (3 _n_ +2)th data point.如果数据集是4n+1个的话,Q1=Set[n]25%+Set[n+1]75%;Q3=Set[3n+1]75%+Set[3n+2]25%

  3. If there are (4 _n_ +3) data points, then the lower quartile is 75% of the ( _n_ +1)th data value plus 25% of the ( _n_ +2)th data value; the upper quartile is 25% of the (3 _n_ +2)th data point plus 75% of the (3 _n_ +3)th data point.如果数据集是4n+3个的话,Q1=Set[n+1]75%+Set[n+2]25%; Q3=Set[3n+2]25%+Set[3n+3]75%

Example 1

Ordered Data Set: 6, 7, 15, 36, 39, 40, 41, 42, 43, 47, 49

Method 1 Method 2 Method 3

\\begin{cases}Q_1  = 15 \\\\Q_2  = 40 \\\\Q_3 =
43\\end{cases}
| \\begin{cases}Q_1  = 25.5 \\\\Q_2  = 40 \\\\Q_3 =
42.5\\end{cases}
| \\begin{cases}Q_1  = 20.25 \\\\Q_2  = 40 \\\\Q_3 =
42.75\\end{cases}

Example 2

Ordered Data Set: 7, 15, 36, 39, 40, 41

As there are an even number of data points, all three methods give the same
results.

Method 1 Method 2 Method 3

\\begin{cases}Q_1  = 15 \\\\Q_2  = 37.5 \\\\Q_3 =
40\\end{cases}
| \\begin{cases}Q_1 = 15 \\\\Q_2 = 37.5 \\\\Q_3 =
40\\end{cases}
| \\begin{cases}Q_1 = 15.0 \\\\Q_2 = 37.5 \\\\Q_3 =
40.0\\end{cases}

需要一提的是,如果数据比Q1-1.5IQR小,比Q3+1.5IQR大的话,我们称之为outiler(异常值)

http://en.wikipedia.org/wiki/Quartile

什么是percentile呢?percentile的意思是百分位数,50th percentile就是中值;25th percentile就是Q1;

percentile怎样计算呢?

例如:

First worked example of the Nearest Rank method

Consider the ordered list {15, 20, 35, 40, 50}, which contains five data
values. What are the 30th, 40th, 50th and 100th percentiles of this list using
the Nearest Rank method?

Percentile
P | Number in list
N | Ordinal rank
n | Number from the ordered list
that has that rank | Percentile
value | Notes
—|—|—|—|—|—
30th | 5 | n = \\left\\lceil \\frac{30}{100} \\times 5 \\right \\rceil =
\\lceil 1.5 \\rceil =
2.
| the second number in the ordered list, which is 20 | 20 | 20 is an
element of the list
40th | 5 | n = \\left\\lceil \\frac{40}{100} \\times 5 \\right \\rceil =
\\lceil 2.0 \\rceil =
2.
| the second number in the ordered list, which is 20 | 20 | In this
example it is the same as the 30th percentile.
50th | 5 | n = \\left\\lceil \\frac{50}{100} \\times 5 \\right \\rceil =
\\lceil 2.5 \\rceil =
3.
| the third number in the ordered list, which is 35 | 35 | 35 is an
element of the ordered list.
100th | 5 | Last | 50, which is the last number in the ordered list |
50 | The 100th percentile is defined to be the largest value in the list,
which is 50.

http://en.wikipedia.org/wiki/Percentile

build工具的基本原理

1.首先读取一堆配置文件,从中可以知道所有的target,这些target需要什么编译命令和什么输入;

2.根据上面的信息,构建一个很大的依赖树;

3.然后build通过从树的叶子向根节点遍历,通过检查文件系统(时间戳,hash等),来判断对应的target有没有过期,如果过期了的话,会使用第一步中的编译命令和输入来生成新的target。

make, ant, scons都是这样的。