package com.xzx.gc.util;
|
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.commons.lang3.StringUtils;
|
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Service;
|
|
import java.math.BigDecimal;
|
import java.math.RoundingMode;
|
import java.text.DecimalFormat;
|
import java.util.Random;
|
import java.util.regex.Pattern;
|
|
@Slf4j
|
public class DoubleUtil {
|
|
// 默认除法运算精度
|
private static final Integer DEF_DIV_SCALE = 10;
|
private static final String REGEX_MOBILE ="((\\+86|0086)?\\s*)((134[0-8]\\d{7})|(((13([0-3]|[5-9]))|(14[5-9])|15([0-3]|[5-9])|(16(2|[5-7]))|17([0-3]|[5-8])|18[0-9]|19(1|[8-9]))\\d{8})|(14(0|1|4)0\\d{7})|(1740([0-5]|[6-9]|[10-12])\\d{7}))";
|
static Random random = new Random();
|
static {
|
random.setSeed(System.currentTimeMillis());
|
}
|
/**
|
* 提供精确的加法运算。
|
* @param value1 被加数
|
* @param value2 加数
|
* @return 两个参数的和
|
*/
|
public static Double add(Double value1, Double value2) {
|
BigDecimal b1 = new BigDecimal(Double.toString(value1));
|
BigDecimal b2 = new BigDecimal(Double.toString(value2));
|
return b1.add(b2).doubleValue();
|
}
|
|
/**
|
* 提供精确的减法运算。
|
* @param value1 被减数
|
* @param value2 减数
|
* @return 两个参数的差
|
*/
|
public static double sub(Double value1, Double value2) {
|
BigDecimal b1 = new BigDecimal(Double.toString(value1));
|
BigDecimal b2 = new BigDecimal(Double.toString(value2));
|
return b1.subtract(b2).doubleValue();
|
}
|
|
/**
|
* 提供精确的乘法运算。
|
* @param value1 被乘数
|
* @param value2 乘数
|
* @return 两个参数的积
|
*/
|
public static Double mul(Double value1, Double value2) {
|
BigDecimal b1 = new BigDecimal(Double.toString(value1));
|
BigDecimal b2 = new BigDecimal(Double.toString(value2));
|
return b1.multiply(b2).doubleValue();
|
}
|
|
/**
|
* 提供(相对)精确的除法运算,当发生除不尽的情况时, 精确到小数点以后10位,以后的数字四舍五入。
|
* @param dividend 被除数
|
* @param divisor 除数
|
* @return 两个参数的商
|
*/
|
public static Double divide(Double dividend, Double divisor) {
|
if(divisor.intValue() == 0){ return 0.0;}
|
return divide(dividend, divisor, DEF_DIV_SCALE);
|
}
|
|
/**
|
* 提供(相对)精确的除法运算。 当发生除不尽的情况时,由scale参数指定精度,以后的数字四舍五入。
|
* @param dividend 被除数
|
* @param divisor 除数
|
* @param scale 表示表示需要精确到小数点以后几位。
|
* @return 两个参数的商
|
*/
|
public static Double divide(Double dividend, Double divisor, Integer scale) {
|
if (scale < 0) {
|
throw new IllegalArgumentException("The scale must be a positive integer or zero");
|
}
|
BigDecimal b1 = new BigDecimal(Double.toString(dividend));
|
BigDecimal b2 = new BigDecimal(Double.toString(divisor));
|
return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue();
|
}
|
|
|
public static String roundThree(String value){
|
DecimalFormat format = new DecimalFormat("0.000");
|
return format.format(new BigDecimal(value));
|
}
|
public static String roundTwo(String value){
|
DecimalFormat format = new DecimalFormat("0.00");
|
return format.format(new BigDecimal(value));
|
}
|
public static String roundSix(String value){
|
DecimalFormat format = new DecimalFormat("0.000000");
|
return format.format(new BigDecimal(value));
|
}
|
public static String roundFive(String value){
|
DecimalFormat format = new DecimalFormat("0.00000");
|
return format.format(new BigDecimal(value));
|
}
|
public static String roundOne(String value){
|
DecimalFormat format = new DecimalFormat("0.0");
|
return format.format(new BigDecimal(value));
|
}
|
|
public static Double roundByScale(double v, int scale) {
|
if (scale < 0) {
|
throw new IllegalArgumentException(
|
"保留位数不能小于0!");
|
}
|
if(scale == 0){
|
return new Double("0");
|
}
|
String formatStr = "0.";
|
for(int i=0;i<scale;i++){
|
formatStr = formatStr + "0";
|
}
|
String str = new DecimalFormat(formatStr).format(v);
|
|
DecimalFormat df = new DecimalFormat(formatStr);
|
System.out.println(str);
|
return Double.parseDouble(str);
|
}
|
|
|
|
|
|
public static double restRound(double min,double max,int i,double money,int count){
|
double redpac=0;
|
if(i==19){
|
redpac=money;
|
}else{
|
redpac=(Math.random()*(max-min)+min)/100;
|
}
|
return redpac;
|
}
|
|
|
/**
|
* 生产min和max之间的随机数,但是概率不是平均的,从min到max方向概率逐渐加大。
|
* 先平方,然后产生一个平方值范围内的随机数,再开方,这样就产生了一种“膨胀”再“收缩”的效果。
|
*
|
* @param min
|
* @param max
|
* @return
|
*/
|
static long xRandom(long min, long max) {
|
return sqrt(nextLong(sqr(max - min)));
|
}
|
|
/**
|
*
|
* @param totalStr
|
* 红包总额
|
* @param count
|
* 红包个数
|
* @param maxStr
|
* 每个小红包的最大额
|
* @param minStr
|
* 每个小红包的最小额
|
* @return 存放生成的每个小红包的值的数组
|
*/
|
public static long[] generate(String totalStr, int count, String maxStr, String minStr) {
|
|
double mind = Double.parseDouble(minStr)*100;
|
double maxd = Double.parseDouble(maxStr)*100;
|
double totald = Double.parseDouble(totalStr)*100;
|
|
log.debug(mind+"========"+maxd);
|
|
long min = new Double(mind).longValue();
|
long max = new Double(maxd).longValue();
|
long total =new Double(totald).longValue();
|
|
long[] result = new long[count];
|
|
long average = total / count;
|
|
long a = average - min;
|
long b = max - min;
|
|
//这样的随机数的概率实际改变了,产生大数的可能性要比产生小数的概率要小。
|
//这样就实现了大部分红包的值在平均数附近。大红包和小红包比较少。
|
long range1 = sqr(average - min);
|
long range2 = sqr(max - average);
|
|
for (int i = 0; i < result.length; i++) {
|
//因为小红包的数量通常是要比大红包的数量要多的,因为这里的概率要调换过来。
|
//当随机数>平均值,则产生小红包
|
//当随机数<平均值,则产生大红包
|
if (nextLong(min, max) > average) {
|
// 在平均线上减钱
|
// long temp = min + sqrt(nextLong(range1));
|
long temp = min + xRandom(min, average);
|
result[i] = temp;
|
total -= temp;
|
} else {
|
// 在平均线上加钱
|
// long temp = max - sqrt(nextLong(range2));
|
long temp = max - xRandom(average, max);
|
result[i] = temp;
|
total -= temp;
|
}
|
}
|
// 如果还有余钱,则尝试加到小红包里,如果加不进去,则尝试下一个。
|
while (total > 0) {
|
for (int i = 0; i < result.length; i++) {
|
if (total > 0 && result[i] < max) {
|
result[i]++;
|
total--;
|
}
|
}
|
}
|
// 如果钱是负数了,还得从已生成的小红包中抽取回来
|
while (total < 0) {
|
for (int i = 0; i < result.length; i++) {
|
if (total < 0 && result[i] > min) {
|
result[i]--;
|
total++;
|
}
|
}
|
}
|
return result;
|
}
|
|
static long sqrt(long n) {
|
// 改进为查表?
|
return (long) Math.sqrt(n);
|
}
|
|
static long sqr(long n) {
|
// 查表快,还是直接算快?
|
return n * n;
|
}
|
|
static long nextLong(long n) {
|
return random.nextInt((int) n);
|
}
|
|
static long nextLong(long min, long max) {
|
return random.nextInt((int) (max - min + 1)) + min;
|
}
|
|
public static void main(String[] args) {
|
// System.out.println(roundByScale(new Double("1.10"),2));
|
//double min_money=5; // 每个人最少能收到0.05元、
|
//double max_money=20; // 每个人最少能收到0.05元、
|
//randomPackage(100,10,40,2000);
|
//long max = 2000;
|
//long min = 40;
|
//System.out.println(getStringRandom(6));
|
}
|
/**
|
* 判断是否是手机号
|
* @param tel 手机号
|
* @return boolean true:是 false:否
|
*/
|
public static boolean isMobile(String tel) {
|
if (StringUtils.isEmpty(tel)){ return false;}
|
return Pattern.matches(REGEX_MOBILE, tel);
|
}
|
|
|
/**
|
* 使用java正则表达式去掉多余的.与0
|
* @param s
|
* @return
|
*/
|
public static String subZeroAndDot(String s){
|
if(StringUtils.isBlank(s)){
|
return null;
|
}
|
if(s.indexOf(".") > 0){
|
s = s.replaceAll("0+?$", "");//去掉多余的0
|
s = s.replaceAll("[.]$", "");//如最后一位是.则去掉
|
}
|
return s;
|
}
|
|
public static String getLowerLetterNumber(int length) {
|
String str = "0123456789abcdefghijklmnopqrstuvwxyz0123456789";
|
Random random = new Random();
|
StringBuffer sb = new StringBuffer();
|
for (int i = 0; i < length; ++i) {
|
sb.append(str.charAt(random.nextInt(46)));
|
}
|
return sb.toString();
|
}
|
|
}
|