新版仿ok交易所-后端
zyy3
2026-03-03 1256f9068913160f9893b4382cb408835a54349a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package com.yami.trading.huobi.data;
 
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
 
public class RandomNumbersGenerator {
 
    /**
     * 生成多个有正有负的数,总和等于目标value
     * @param target 目标总和(BigDecimal)
     * @param count 生成的数字数量(至少为2)
     * @param scale 小数位数(确保精度)
     * @return 满足条件的数字列表
     */
    public static List<BigDecimal> generateNumbers(BigDecimal target, int count, int scale) {
        // 校验参数:数量至少为2
        if (count < 2) {
            throw new IllegalArgumentException("生成数量必须至少为2");
        }
 
        List<BigDecimal> numbers;
 
        // 计算target的20%(绝对值,作为最后一个数的阈值)
        BigDecimal threshold = target.abs().multiply(new BigDecimal("0.2")).setScale(scale, RoundingMode.HALF_UP);
 
        do {
            numbers = new ArrayList<>(count);
            Random random = new Random();
 
            // 步骤1:确定单个数字的最大绝对值范围(目标值的15%,可调整)
            BigDecimal maxAbsValue = target.abs().multiply(new BigDecimal("0.15"));
            if (maxAbsValue.compareTo(BigDecimal.ZERO) == 0) {
                maxAbsValue = new BigDecimal("100"); // 目标为0时的默认范围
            }
 
            // 正数概率60%
            double positiveProbability = 0.6;
 
            // 步骤2:生成前count-1个随机数
            for (int i = 0; i < count - 1; i++) {
                BigDecimal randomValue = generateRandomValue(maxAbsValue, scale, random);
                // 按概率设置正负
                if (random.nextDouble() >= positiveProbability) {
                    randomValue = randomValue.negate();
                }
                numbers.add(randomValue);
            }
 
            // 步骤3:计算最后一个数(确保总和为target)
            BigDecimal sumPrev = numbers.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal lastNum = target.subtract(sumPrev).setScale(scale, RoundingMode.HALF_UP);
            numbers.add(lastNum);
 
            // 步骤4:确保有正有负
            ensureBothPositiveAndNegative(numbers, scale);
 
            // 检查最后一个数是否超过阈值:若lastNum的绝对值 > threshold,则重新生成
        } while (numbers.get(numbers.size() - 1).abs().compareTo(threshold) > 0);
 
        return numbers;
    }
 
    /**
     * 生成0到max之间的随机BigDecimal(指定小数位数,兼容Java 8+)
     */
    private static BigDecimal generateRandomValue(BigDecimal max, int scale, Random random) {
        // 将max转换为整数(放大10^scale倍),避免double精度问题
        BigDecimal scaleFactor = new BigDecimal(Math.pow(10, scale)).setScale(scale);
        long maxLong = max.multiply(scaleFactor).setScale(0, RoundingMode.FLOOR).longValue();
 
        // 兼容Java 8+的写法:生成[0, maxLong]范围内的随机long
        long randomLong;
        if (maxLong == 0) {
            // 若最大值为0,直接返回0
            randomLong = 0;
        } else {
            // 生成[0, maxLong]的随机数(避免nextLong()的负数问题)
            // 逻辑:(random.nextLong() % (maxLong + 1) + (maxLong + 1)) % (maxLong + 1)
            long range = maxLong + 1; // 范围长度(0到maxLong共range个数字)
            randomLong = (random.nextLong() % range + range) % range;
        }
 
        // 转换回BigDecimal并缩小scaleFactor倍
        return new BigDecimal(randomLong).divide(scaleFactor, scale, RoundingMode.HALF_UP);
    }
 
    /**
     * 确保列表中既有正数也有负数,若不满足则调整
     */
    private static void ensureBothPositiveAndNegative(List<BigDecimal> numbers, int scale) {
        boolean hasPositive = numbers.stream().anyMatch(num -> num.compareTo(BigDecimal.ZERO) > 0);
        boolean hasNegative = numbers.stream().anyMatch(num -> num.compareTo(BigDecimal.ZERO) < 0);
 
        if (hasPositive && hasNegative) {
            return; // 已满足条件,无需调整
        }
 
        // 若全为非负(可能有0),需要调整出一个负数
        if (!hasNegative) {
            adjustToHaveNegative(numbers, scale);
        }
        // 若全为非正(可能有0),需要调整出一个正数
        else if (!hasPositive) {
            adjustToHavePositive(numbers, scale);
        }
    }
 
    /**
     * 当全为非负时,调整出一个负数(保持总和不变)
     */
    private static void adjustToHaveNegative(List<BigDecimal> numbers, int scale) {
        // 选第一个非零的数(避免调整0,否则还是0)
        int idx = -1;
        for (int i = 0; i < numbers.size(); i++) {
            if (numbers.get(i).compareTo(BigDecimal.ZERO) > 0) {
                idx = i;
                break;
            }
        }
        if (idx == -1) {
            // 极端情况:全为0(目标值必为0),直接将第一个数设为1,最后一个设为-1
            numbers.set(0, new BigDecimal("1").setScale(scale));
            numbers.set(numbers.size() - 1, new BigDecimal("-1").setScale(scale));
            return;
        }
 
        // 调整逻辑:将选中的数变为负数,同时将最后一个数加上2倍的原数(保持总和不变)
        BigDecimal original = numbers.get(idx);
        BigDecimal negative = original.negate();
        numbers.set(idx, negative);
 
        BigDecimal last = numbers.get(numbers.size() - 1);
        BigDecimal adjustedLast = last.add(original.multiply(new BigDecimal("2")))
                .setScale(scale, RoundingMode.HALF_UP);
        numbers.set(numbers.size() - 1, adjustedLast);
    }
 
    /**
     * 当全为非正时,调整出一个正数(保持总和不变)
     */
    private static void adjustToHavePositive(List<BigDecimal> numbers, int scale) {
        // 选第一个非零的数(避免调整0)
        int idx = -1;
        for (int i = 0; i < numbers.size(); i++) {
            if (numbers.get(i).compareTo(BigDecimal.ZERO) < 0) {
                idx = i;
                break;
            }
        }
        if (idx == -1) {
            // 极端情况:全为0(目标值必为0),直接将第一个数设为1,最后一个设为-1
            numbers.set(0, new BigDecimal("1").setScale(scale));
            numbers.set(numbers.size() - 1, new BigDecimal("-1").setScale(scale));
            return;
        }
 
        // 调整逻辑:将选中的数变为正数,同时将最后一个数减去2倍的原数(保持总和不变)
        BigDecimal original = numbers.get(idx);
        BigDecimal positive = original.negate();
        numbers.set(idx, positive);
 
        BigDecimal last = numbers.get(numbers.size() - 1);
        BigDecimal adjustedLast = last.subtract(original.multiply(new BigDecimal("2")))
                .setScale(scale, RoundingMode.HALF_UP);
        numbers.set(numbers.size() - 1, adjustedLast);
    }
 
 
    // 测试示例
    public static void main(String[] args) {
        // 测试1:目标值为100,生成5个数,保留2位小数
        BigDecimal target1 = new BigDecimal("0.01");
        List<BigDecimal> result1 = generateNumbers(target1, 200/10, 10);
        System.out.println("目标值:" + target1 + ",生成的数:" + result1);
        System.out.println("总和:" + result1.stream().reduce(BigDecimal.ZERO, BigDecimal::add) + "\n");
 
    }
}