工具类-百分比计算

工具类

1.计算百分比,保证和是1
2. 返回的结果和输入计算的数值一致

import cn.hutool.core.collection.CollUtil;

import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

/**
 * <p>描述:</p>
 *
 * @author fangdayang
 * @create 2024-12-04 16:34
 */
public class PercentageUtils {


    /**
     * 最佳百分比计算
     * 列如: 
     *    输入  2  100 [88,12,10]
     *    输出 [0.88,0.12,0.1]
     * @param newScale 小数点的位数
     * @param totalNum 被除数  必须保证 totalNum等于asList之和
     * @param asList   除数的集合
     * @return 有几个除数就会返回几个小数
     */
    public static List<Double> computeBestScale(@NotNull Integer newScale, Integer totalNum, @NotNull int[] asList) {
        List<Double> returnDoubleList = new ArrayList<>(asList.length);
        // 根据精度 得到最小值
        Double minScale = 1 / Math.pow(10, newScale);
        Map<Integer, Boolean> postionMap = new HashMap<>();
        for (int i = 0; i < asList.length; i++) {
            int divisor = asList[i];
            postionMap.put(i, true);
            Double aDouble = null;
            if (Objects.isNull(totalNum) || totalNum == 0) {
                // 被除数为0 不需要进行计算 返回null
            } else {
                if (divisor == 0) {
                    aDouble = 0.0;
                } else {
                    aDouble = (divisor + 0.0) / totalNum;
                    postionMap.put(i, false);
                }
            }
            returnDoubleList.add(aDouble);
        }
        // 处理未被确认的值
        // 保证整体之和是1   0.7654334  0.230002   0.002  0.003
        // 处理方案 不足精度的值 设置为最小值 不足或者大于1的值在最大值进行抹平
        Map<Integer, Double> notFixMap = new HashMap<>();
        // 找出无法固定的值  并设置最小值
        final Double[] totalDoubleValue = {0.0};
        postionMap.forEach((k, v) -> {
            if (!v) {
                Double value = returnDoubleList.get(k);
                if (value.compareTo(minScale) < 0) {
                    value = minScale;
                } else {
                    value = fourDecimalPlaces(value, newScale);

                }
                notFixMap.put(k, value);
                totalDoubleValue[0] = value + totalDoubleValue[0];
            }
        });
        // 返回需要的精度
        if (CollUtil.isNotEmpty(notFixMap)) {
            double v = 1 - totalDoubleValue[0];
            if (Math.abs(v) > minScale) {
                // 需要进行进度处理 最大的数值减去该值
                AtomicInteger maxIndex = new AtomicInteger();
                AtomicReference<Double> maxValue = new AtomicReference<>(0.0);
                notFixMap.forEach((k, val) -> {
                    if (maxValue.get().compareTo(val) < 0) {
                        maxValue.set(val);
                        maxIndex.set(k);
                    }
                });
                notFixMap.put(maxIndex.get(), maxValue.get() + fourDecimalPlaces(v, newScale));
            }
        }

        List<Double> doubleList = new ArrayList<>(asList.length);

        for (int i = 0; i < returnDoubleList.size(); i++) {
            Double aDouble = notFixMap.get(i);
            if (Objects.nonNull(aDouble)) {
                doubleList.add(aDouble);
            } else {
                doubleList.add(returnDoubleList.get(i));
            }
        }
        return doubleList;
    }

    public static Double fourDecimalPlaces(Double value, Integer newScale) {
        BigDecimal bd = new BigDecimal(value);
        return bd.setScale(newScale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值