工具类
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();
}
}