whyclxw
2025-05-28 e16302f9d475c7cc4dd18c5abf1a23cb5502e362
src/main/java/com/whyc/util/MathUtil.java
@@ -1,7 +1,12 @@
package com.whyc.util;
import com.whyc.dto.Response;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.*;
/**
 * 计算工具类
@@ -43,4 +48,256 @@
        return (int) (res * 100) + "%";
    }
    /**
     * 提取公共方法,相除获取比例,返回可选String或者Float
     * @param type 1表示小数,2表示除去%的比例,3表示%的比例
     * @return Object String或者Float类型
     * */
    public static Object divide(Object num, Object num2, Integer type, Integer scale){
        Object res = 0;
        double num2Double=Double.parseDouble(num2.toString());
        double numDouble=Double.parseDouble(num.toString());
        if(num2Double!=0){
            //0.05
            if (type == 1) {
                res = BigDecimal.valueOf(numDouble).divide(BigDecimal.valueOf(num2Double), scale, RoundingMode.HALF_UP).floatValue();
            }
            //5
            else {
                BigDecimal multiply = BigDecimal.valueOf(numDouble).multiply(BigDecimal.valueOf(100));
                BigDecimal divide = multiply.divide(BigDecimal.valueOf(num2Double), scale, RoundingMode.HALF_UP);
                if (type == 2) {
                    res = divide.floatValue()+"";
                }
                //5%
                else{
                    res = divide.floatValue()+"%";
                }
            }
            return res;
        }else{
            if(type == 1){
                return 0.0;
            }else{
                if(type==2){
                    return "0";
                }else{
                    return "0%";
                }
            }
        }
    }
    public static float multiply(float num,float num2,int scale){
        return BigDecimal.valueOf(num).multiply(BigDecimal.valueOf(num2)).setScale(2,RoundingMode.HALF_UP).floatValue();
    }
    /**
     * 求自变量X,因变量Y的线性回归 @PerryHsu
     * y = ax+b
     *
     * a = ∑Yi(Xi-X的平均值)/∑(Xi^2)-1/n*(∑(Xi^2)
     *
     * b = 1/n*∑(Yi-aXi)
     *
     * */
    public static Response linearRegressionUnary(List<Double> listX, List<Double> listY,Double x) {
        List<Double> resList = new LinkedList<>();
        int sizeX = listX.size();
        int sizeY = listY.size();
        DecimalFormat df = new DecimalFormat("0.##");
        if (sizeX != sizeY) {
            return new Response<>().set(1,false,"分子分母数量不一致。");
        }
        Double sum = 0d;
        for (Double xi : listX) {
            sum += xi;
        }
        double avgX = sum/ sizeY;
        //a的分子
        double aMolecule = 0;
        for (int i = 0; i < sizeX; i++) {
            aMolecule += listY.get(i) * (listX.get(i) - avgX);
        }
        //a的分母
        double aDenominator = 0;
        int aDenominatorXi = 0;
        for (int i = 0; i < sizeX; i++) {
            aDenominator += Math.pow(listX.get(i), 2);
            aDenominatorXi += listX.get(i);
        }
        aDenominator = aDenominator - (1.0 / sizeX) * (Math.pow(aDenominatorXi, 2));
        //System.out.println("w_denominator:"+w_denominator+" w_denominator_xi:"+w_denominator_xi);
        double a = aMolecule / aDenominator;
        double b = 1.0 / sizeX;
        double sumYAX = 0;
        for (int i = 0; i < sizeX; i++) {
            sumYAX += (listY.get(i) - a * listX.get(i));
        }
        b = b * sumYAX;
        String symbol = "+";
        if (b < 0) {
            symbol = "";
        }
        //System.out.println("y=" + df.format(a) + "x" + symbol + df.format(b));
        Double y = a*x + b;
        resList.add(a);
        resList.add(b);
        resList.add(y);
        return new Response().setII(1,true,resList,null);
    }
    public static void main(String[] args) throws ParseException {
        /*List<Double> x = Arrays.asList(5d, 9d, 15d, 19d, 19d, 45d);
        List<Double> y = Arrays.asList(4d, 6d, 12d, 15d, 15d, 37d);*/
        //按照年为单位为x.变化差值为y
        /*List<Double> x = Arrays.asList(
                DateUtil.YYYY_MM_DD_HH_MM_SS.parse("2021-04-13 09:14:36").getTime()*1d,
                DateUtil.YYYY_MM_DD_HH_MM_SS.parse("2021-10-14 13:46:36").getTime()*1d,
                DateUtil.YYYY_MM_DD_HH_MM_SS.parse("2022-03-18 11:08:36").getTime()*1d,
                DateUtil.YYYY_MM_DD_HH_MM_SS.parse("2022-03-18 13:56:36").getTime()*1d);
        List<Double> y = Arrays.asList(
                99d,
                80d,
                71.9d,
                71d);*/
        /*long time1 = DateUtil.YYYY_MM_DD_HH_MM_SS.parse("2021-04-13 09:14:36").getTime();
        long time2 = DateUtil.YYYY_MM_DD_HH_MM_SS.parse("2021-10-14 13:46:36").getTime();
        long time3 = DateUtil.YYYY_MM_DD_HH_MM_SS.parse("2022-03-18 11:08:36").getTime();
        long time4 = DateUtil.YYYY_MM_DD_HH_MM_SS.parse("2022-03-18 13:56:36").getTime();
        long time5 = DateUtil.YYYY_MM_DD_HH_MM_SS.parse("2023-03-12 13:56:36").getTime();*/
        long time1 = ThreadLocalUtil.parse("2021-04-13 09:14:36",1).getTime();
        long time2 = ThreadLocalUtil.parse("2021-10-14 13:46:36",1).getTime();
        long time3 = ThreadLocalUtil.parse("2022-03-18 11:08:36",1).getTime();
        long time4 = ThreadLocalUtil.parse("2022-03-18 13:56:36",1).getTime();
        long time5 = ThreadLocalUtil.parse("2023-03-12 13:56:36",1).getTime();
        double c1 = 99d;
        double c2 = 98d;
        double c3 = 96.9d;
        double c4 = 95d;
        List<Double> x = Arrays.asList(
                0d,
                (time2-time1)*1d/1000/60/60/24,
                (time3-time1)*1d/1000/60/60/24,
                (time4-time1)*1d/1000/60/60/24
        );
        List<Double> y = Arrays.asList(
                c1,
                c2,
                c3,
                c4
        );
        double v = (time5 - time1) * 1d / 1000 / 60 / 60 /24;
        System.out.println(v);
        Response response = linearRegressionUnary(x, y, v);
        System.out.println(response);
    }
    /**
     *
     * @param startNum 起始数  -1 = limitStart ,因为limit是从0开始
     * @param endNum 终止数
     * @param pageSize 每页条数
     * @param queryCountMap key-年份,value-数量
     * @return {"2023",[2,20]}
     *           表名,[limit 2,20]
     */
    public static Map<String, List<Integer>> getQueryTableAndLimit(int startNum, int endNum, int pageSize, Map<String, Integer> queryCountMap) {
        Map<String,List<Integer>> resultMap = new LinkedHashMap<>();
        //定位起始数,在哪个年份范围内,起始数值;终止数,在哪个年份范围内,终止数值
        Set<String> queryKeySet = queryCountMap.keySet();
        int sum = 0;
        int lastSum = 0;
        String limitStartYear = null;
        int limitStart = 0;
        String limitEndYear = null;
        int limitEndSize = pageSize;
        boolean limitStartFinished = false;
        for (String queryKey : queryKeySet) {
            int queryCount  = queryCountMap.get(queryKey);
            sum+=queryCount;
            if(!limitStartFinished) {
                if (startNum <= sum) {
                    limitStart = startNum - lastSum;
                    limitStartYear = queryKey;
                    //完成了limit 起始值的获取,后续不需要继续执行
                    limitStartFinished = true;
                }
            }
            if(limitStartFinished) { //limit 起始值获取后,开始计算终止的记录数量
                if (endNum <= sum) {
                    limitEndYear = queryKey;
                    break;
                }
                //首次,执行起始limit的时候, limitEndSize(记录预留的查询个数)需要减去limitStart占用的
                if(limitEndSize == pageSize){
                    limitEndSize = pageSize - (sum - startNum + 1);
                }else{ //如果还没达到 终止数值,需要减去本次查询消耗掉的数量
                    limitEndSize = limitEndSize - queryCount;
                }
            }
            lastSum = sum;
        }
        boolean limitStartCompareFlag = true;
        boolean tableStartFlag = false;
        for (String queryKey : queryKeySet) {
            int queryCount  = queryCountMap.get(queryKey);
            if(queryKey.equals(limitStartYear) && limitStartCompareFlag){
                tableStartFlag = true;
                //从这里开始,取记录数
                LinkedList<Integer> limitList = new LinkedList<>();
                if(queryKey.equals(limitEndYear)) { //同一年
                    limitList.add(limitStart-1);
                    limitList.add(pageSize);
                    resultMap.put(queryKey,limitList);
                    break;
                }else{
                    limitList.add(limitStart-1);
                    limitList.add(queryCount);
                    resultMap.put(queryKey,limitList);
                }
                limitStartCompareFlag = false;
                continue;
            }
            //不同年,继续
            if(tableStartFlag) { //已经经过了起始年,才可以取数据. 起始年前的数据无效
                if (queryKey.equals(limitEndYear)) { //找到终止年
                    LinkedList<Integer> limitList = new LinkedList<>();
                    limitList.add(0);
                    limitList.add(limitEndSize);
                    resultMap.put(queryKey, limitList);
                    break;
                } else { //不是终止年,属于中间年
                    LinkedList<Integer> limitList = new LinkedList<>();
                    limitList.add(0);
                    limitList.add(queryCount);
                    resultMap.put(queryKey, limitList);
                }
            }
        }
        return resultMap;
    }
}