* 计算 n*(n-1)*……(n-k) / 1*2*3……*k
* 循环要找到循环体
*/
忽略上面格式的问题,其实我只想说 如果要用一个for循环来计算这个结果,当然按照字面意思,我们可以不假思索的写到
for循环 计算出 n*(n-1)*……(n-k) 的结果
然后再用for循环计算出 1*2*3……*k的结果 然后再相除,但是其实只要我们把这个计算公式做个简单的变形,我们只需要一个for循环就可以计算出这个结果,
所以我明白了一个道理 用for循环尽量简便的找到循环体 和 循环条件,这样 使得 写法简便,但不一定是最好理解的。
n/k * (n-1)/(k-1) * (n-2)/(k-2) .... (n-k)/1 一共是k-1项 所以你是不是发现这样很好做了? 但如果你以为就这么简单的话 我还有必要写一个博客嘛?
这里还有一个陷阱,我们知道 java在计算除法时 结果默认为整形,比如 3/2 =1, 所以 这里这么多除法运算 你还需要借助一个 BIgDecimal 类 来处理,这个类是java自带的类,当然 它用起来极其麻烦,因为里面用的运算 都是通过调用里面的方法来实现的,并且参数类型是 BigDecimal 类 ,这 时候 你就需要自己写个封装类 封装下这层的函数 使得你调用方法简便,快捷, 下面是网上找来的例子:
package xy.base;
import java.math.BigDecimal;
public class Arith{
//默认除法运算精度
private static final int DEF_DIV_SCALE = 10;
//这个类不能实例化
private Arith(){
}
/**
* 提供精确的加法运算。
* @param v1 被加数
* @param v2 加数
* @return 两个参数的和
*/
public static double add(double v1,double v2){
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.add(b2).doubleValue();
}
/**
* 提供精确的减法运算。
* @param v1 被减数
* @param v2 减数
* @return 两个参数的差
*/
public static double sub(double v1,double v2){
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.subtract(b2).doubleValue();
}
/**
* 提供精确的乘法运算。
* @param v1 被乘数
* @param v2 乘数
* @return 两个参数的积
*/
public static double mul(double v1,double v2){
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.multiply(b2).doubleValue();
}
/**
* 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
* 小数点以后10位,以后的数字四舍五入。
* @param v1 被除数
* @param v2 除数
* @return 两个参数的商
*/
public static double div(double v1,double v2){
return div(v1,v2,DEF_DIV_SCALE);
}
/**
* 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
* 定精度,以后的数字四舍五入。
* @param v1 被除数
* @param v2 除数
* @param scale 表示表示需要精确到小数点以后几位。
* @return 两个参数的商
*/
public static double div(double v1,double v2,int scale){
if(scale<0){
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 提供精确的小数位四舍五入处理。
* @param v 需要四舍五入的数字
* @param scale 小数点后保留几位
* @return 四舍五入后的结果
*/
public static double round(double v,int scale){
if(scale<0){
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b = new BigDecimal(Double.toString(v));
BigDecimal one = new BigDecimal("1");
return b.divide(one,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
}
};
都有说明,按照这样的方式调用就好了。
其实虽然做开发时间还算蛮长的了,但一直感觉自己是个low逼,因为感觉心中没有一个写代码的准则,所以又回顾基础知识。到这里 这个循环差不多算是了结了。
下面要说一下可能大部分老手都不一定理解的东西,编码字符集问题:
首先 你要明白 byte char 这对象的含义, byte表示一个字节 一个字节是八位二进制数,这个你知道吧,那么char 表示一个字符,不同的字符集所需要的字节数不一定相同,这里只说下 java内部是用的Unicode字符集,用两个字节 表示一个字符,这里又要介绍另一个术语,代码单元,它就表示一个字符的长度,“A我 ” 表示两个代码单元,四个字节。
还有一个代码点,它是和Unicode的字符集对应的,这个要讲到它的起源,是因为考虑到加入中文,所以原本的八位二进制不够用了,就用了十六位,那么每个数字代表的就是一个代码点。 那么和utf-8是什么关系呢,这个不叫字符集,网上有很多不懂或者一知半解的人乱说,它表示编码的格式,同类的有 GBK...,那么这些编码方式对应的是 在这些数据传输过程中 是怎么进行编码转换的,因为 Unicode字符集 对英文的二进制表示也是十六位,对资源来说是一种浪费,所以就提出了将数据进行编码,数据中英文的还是一个字节表示,中文的用2-4个字节表示,这么说明白了嘛。至于 这之中是怎么转化的 是有一个算法。