摇号中签生成随机号
来源:互联网 发布:编程教学 编辑:程序博客网 时间:2024/04/29 12:07
在现在很多类似于股票市场的交易中,很多项目发行都需要进行申购,等到申购结束,进行摇号,根据中签尾号确定每个用户的中签数量。
如果用户U1购买了10个产品,那么他申购的产品尾号就是10000001到10000010,用户U2再购买5个,那么U2的产品尾号10000011到10000015。
现在假如发行项目A,发行量为12345,申购量为675893。随机生成中签尾号:
package com.fbd.core.util;import java.util.ArrayList;import java.util.Iterator;import java.util.LinkedHashMap;import java.util.List;import java.util.Map;import java.util.Map.Entry;import com.fbd.core.exception.ApplicationException;/** * 摇号中签工具类 生成中签号码 * * @author Lip * */public class LotterySystem {// 已经选中的尾号的数量// public static long chooseNum = 0;public static void main(String[] args) {// 起始申购序列号long start = 10000000001L;// 实际申购数量long purchaseNum =675893;// 实际发行long distributeNum = 12345;Map<String, Integer> distributeMap = getLottery(purchaseNum, distributeNum);int total = 0;Iterator iterator = distributeMap.entrySet().iterator();while (iterator.hasNext()) {Entry entry = (Entry) iterator.next();System.out.println(entry.getKey() + ":" + entry.getValue());total += (int) entry.getValue();}System.out.println("中签数量:" + total);}/** * 得到各个尾数的中签数量 * * @param purchaseNum * @param distributeNum * @return */public static Map<String, Integer> getLottery(long purchaseNum, long distributeNum) {// 中签尾数及数量Map<String, Integer> distributeMap = new LinkedHashMap<>();if (purchaseNum <= distributeNum) {int n1 = (int) (purchaseNum % 10);int n2 = (int) (purchaseNum / 10);for (int i = 0; i < 10; i++) {if (i >= n1)distributeMap.put(i + "", n2);elsedistributeMap.put(i + "", n2 + 1);}return distributeMap;}long chooseNum = 0;double allocationRate = distributeNum * 1.0 / purchaseNum;// 0.001204177...System.out.println("中签率:" + allocationRate);int len = getDigitNum(purchaseNum);long distributeX = (long) (allocationRate * Math.pow(10, len));// 1204177List<Integer> digitList = getEachDigit(distributeX, len);// 1,2,0,4,1,7,7int lenX = getDigitNum(distributeX);List<Long> distributeList = new ArrayList<>();for (int i = 0; i < digitList.size(); i++) {int rate = digitList.get(i);// 尾号余数如232,158 也可以中奖long temp = (long) (purchaseNum % Math.pow(10, len - lenX + 1 + i));for (int j = 0; j < rate; j++) {if (chooseNum == distributeNum)return distributeMap;// 该随机号有多少个String lotteryNum = getRandom(distributeList, len - lenX + 1 + i);int number = (int) (purchaseNum * Math.pow(10, -(len - lenX + 1 + i)));long lotteryLong = Long.parseLong(lotteryNum);if (lotteryLong <= temp && lotteryLong > 0) {number++;}if (chooseNum + number <= distributeNum)chooseNum += number;elsebreak;distributeList.add(lotteryLong);distributeMap.put(lotteryNum, number);}}int left = (int) (distributeNum - chooseNum);while (left > 0)// 每次产生一个号码{String lotteryNum = getRandom(distributeList, len);long lotteryLong = Long.parseLong(lotteryNum);if (lotteryLong > purchaseNum || lotteryLong == 0) {continue;}distributeList.add(lotteryLong);distributeMap.put(lotteryNum, 1);left--;}return distributeMap;}/** * 得到一个数的位数 * * @param value * @return */public static int getDigitNum(long value) {return String.valueOf(value).length();}/** * 得到一个num位的随机数 * * @param except * @param num * @return */public static String getRandom(List<Long> except, int num) {boolean confict = true;long obj = 0l;while (confict) {obj = (long) (Math.random() * Math.pow(10, num));while (except.contains(obj) || obj == 0) {// obj肯定不在except中obj = (long) (Math.random() * Math.pow(10, num));}confict = false;int len = getLen(obj);for (long temp : except) {int len2 = getLen(temp);if (len2 == len) {continue;}if (Math.abs(obj - temp) % Math.pow(10, len2) == 0) // 有冲突{confict = true;break;}}}return String.format("%0" + num + "d", obj);}/** * 得到一个整数的位数 * * @param num * @return */public static int getLen(long num) {int len = 0;while (num != 0) {num /= 10;len++;}return len;}/** * 得到每位的中签比率 * * @param value * @param len * @return */public static List<Integer> getEachDigit(long value, int len) {String valueS = String.valueOf(value);List<Integer> result = new ArrayList<>();for (int i = 0; i < valueS.length() - 1; i++) {result.add(Integer.parseInt(valueS.charAt(i) + ""));}return result;}}生成的中签尾号完全是随机的,如下图:
有一个特殊的情况需要注意,那就是申购总量很少,小于发行量,那么相当于每个尾号都是中签的,当然,在实际中,这种情况不可能存在,出现那么也意味着该项目失败了。不过本文解决了申购量小于等于发行量的特殊情况。
该项目的中签率很低,用户U1和U2都不会中签。
算法原理:
- 计算中签率R=12345/675893=0.018264...
- 拆分小数位,百分位是为1,说明两位数的中签尾号有1个,千分位为8,说明三位数的中签尾号有8个....依次类推,直到产生足够的中签尾号
摇号结束后,知道了所有的中签尾号,也知道每个用户的购买数,那么可以计算每个用户的中签数量。我是利用存储过程来计算用户的中签数量的:
BEGINDECLARE v_num varchar(11); DECLARE v_len int; DECLARE done INT; DECLARE v_result int;DECLARE v_start_result int;DECLARE v_end_result int;DECLARE v_num_pow int; DECLARE cur_success CURSOR FOR SELECT number from lottery_number where project_id=projectId; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; set v_result = 0;set v_start_result=0;set v_end_result=0; OPEN cur_success; BEGIN_success: LOOP FETCH cur_success INTO v_num; IF done THEN LEAVE BEGIN_success; ELSE set v_len = LENGTH(v_num); set v_num_pow=POWER(10,v_len); set v_start_result=v_start_result+FLOOR(startNum/v_num_pow); IF startNum % v_num_pow>v_num THEN set v_start_result=v_start_result + 1; END IF; set v_end_result=v_end_result+FLOOR(endNum/v_num_pow); IF endNum%v_num_pow>=v_num THEN set v_end_result=v_end_result+1; END IF; END IF; END LOOP BEGIN_success; CLOSE cur_success;SET v_result=v_end_result-v_start_result;RETURN v_result;END原理其实很简单,每个用户都有一个起始配号,一个结束配号,那么只需要计算0到起始配号之间的中签数量n1,再计算0到结束配号之间的中签数量n2,那么n2-n1+1就是用户的中签数量。
1 0
- 摇号中签生成随机号
- 摇号中签生成随机号
- 如何让北京小车摇号中签更容易?
- 粤传媒中签号
- 新嘉联中签号,新嘉联中签率,002188中签号,002188中签率
- 北京汽车摇号
- 外卖摇号函数
- GridBagLayoutFrameDemo--摇号
- 摇号程序设计
- 云海金属股票中签号
- DELPHI 7 学习---------摇号
- 北京摇号日志第一章
- 摇号条件 断月也可以
- 车牌摇号 程序设计题
- 华天科技中签号公布
- 利达光电中签号公布
- 成飞集成中签号公布,002190成飞集成中签率公布
- 利达光电002189中签号公布;002189中签率公布
- ADB server didn't ACK'的解决办法
- LTE物理传输资源(2)-频带、信道带宽和频点号EARFCN
- git pull无法保存密码的问题
- 【SSH网上商城项目实战06】基于DataGrid的数据显示
- asp.net后台调用前端js
- 摇号中签生成随机号
- HTML列表
- PPT转换格式时,ppt每页大小和用户需求图片大小中的小问题
- Linux下__u8的定义头文件
- 程序员如何在职场中实现“跨越式”成长?
- Spring中@Transactional事务回滚
- 去掉导航栏下面的横线, 保证界面颜色一致
- myeclipse 选中效果属性、方法同属性变色
- 详细介绍Screenshot Reader支持的语言和文档格式