“红音列表实现引发的思考”的版本间的差异
Jihongchang(讨论 | 贡献) |
Jihongchang(讨论 | 贡献) |
||
第164行: | 第164行: | ||
=== 那么浮点数的极限在哪里? === | === 那么浮点数的极限在哪里? === | ||
+ | 这一节点可以参考一下:[[Java中的浮点型]] | ||
==== float ==== | ==== float ==== |
2022年11月12日 (六) 10:48的版本
需求
是:
要为当前登录用户显示一个列表,这个列表里是过去72小时内所有登录过的用户;
这些用户要按一定的规则排序,规则是:
比如当前登录用户是女性,那么男性用户要排在女性用户前面(1、0);
同样是男性用户,有房的要排在没房的前面(1、0);
同样有房的,有车的要排在没车的前面(1、0);
受教育程度(博士、硕士、学士、高中)……(4、3、2、1);
婚姻状况(未婚、离异、丧偶)(3、2、1)
工作(央企、国企、公务员、……)(4、3、2、1)
年龄(28~35、35~40、23~28、……)(4、3、2、1);
身材((kg~kg)苗条、(kg~kg)匀称、(kg~kg)偏瘦、(kg~kg)偏胖、……)(4、3、2、1)
GPS定位计算出相对距离(km数、m数)
…… 要求实现一套权重机制
简单的实现
是:
public class RankRecord {
/**
* 性别
*/
private int gender;
/**
* 是否有房
*/
private int house;
/**
* 是否有车
*/
private int car;
/**
* 身高
*/
private int height;
/**
* 体重
*/
private int weight;
/**
* 权重
*/
private int weights;
public RankRecord(int gender, int house, int car, int height, int weight) {
this.gender = gender;
this.house = house;
this.car = car;
this.height = height;
this.weight = weight;
initWeights();
}
/**
* 初始化权重
* 整型应用位运算计算权重要把权重最大的属性放在前面,权重小的属性放在后面
*/
private void initWeights() {
int weights = gender;
weights = (weights << 1) + house;
weights = (weights << 1) + car;
weights = (weights << 1) + height;
weights = (weights << 1) + weights;
this.weights = weights;
}
}
但是 int 只有4个字节,最大值是 231,即便不考虑单个字段多值的情况(不止有0和1,还有像GPS定位计算出的相距公理、米数)作为权重因子,
应用左移扩大2倍很可能放不下所有的权重字段。
那么 weight 就声明成 long,可 long 最大也就是 263,还有比 long 能存储更大的值以便应用所有、甚至更多的权重因数吗?
float、double、BigDecimal、BigInteger?那么它们是怎么存的呢?每个字段存放进去又是怎么一个情况呢?
浮点数的实现
需要注意的是:不能应用位运算在浮点数上。
package rank;
public class RankRecord {
/**
* 性别
*/
private int gender;
/**
* 是否有房
*/
private int house;
/**
* 是否有车
*/
private int car;
/**
* 身高
*/
private int height;
/**
* 体重
*/
private int weight;
/**
* 权重
*/
private double weights;
public RankRecord(int gender, int house, int car, int height, int weight) {
this.gender = gender;
this.house = house;
this.car = car;
this.height = height;
this.weight = weight;
initWeights();
}
/**
* 初始化权重
*/
private void initWeights() {
double weights = 0;
weights += gender;
weights = weights * 2 + house;
weights = weights * 2 + car;
weights = weights * 2 + height;
weights = weights * 2 + weights;
this.weights = weights;
}
}
这样应该能放下很多权重因子了
那么浮点数的极限在哪里?
这一节点可以参考一下:Java中的浮点型
float
比如float的精度:
public class FloatPrecision {
public static void main(String[] args) {
float a = 12345.12346f;
System.out.println(a);
float b = 123456789f;
System.out.println(b);
}
}
12345.123
1.23456792E8
这么看 float 应用科学计数法存储二进制之后也就只能达到 7、8 位有效数/尾数 的样子,应用在字段上做权重的话就是:
public class Test4 {
public static void main(String[] args) {
float f1 = 12345678f;
System.out.println(f1);
float f2 = 123456789f;
System.out.println(f2);
System.out.println(Math.log(f1)/Math.log(2));
}
}
1.2345678E7
1.23456792E8
23.557502732800643
就是大概20个字段左右,这还是字段权重是绝对的、是2倍乘的关系。
那么 double 呢?
public class DoublePrecision {
public static void main(String[] args) {
double a = 123456789.01234567890123d;
System.out.println(a);
double b = 1234567890123456789d;
System.out.println(b);
}
}
1.2345678901234567E8
1.23456789012345677E18
double 也是存个17、18位的十进制有效数的样子,做权重的话就是:
public class Test5 {
public static void main(String[] args) {
double d = 12345678901234567d;
System.out.println(d);
System.out.println(Math.log(d)/Math.log(2));
}
}
1.2345678901234568E16
53.45485569210364
50个字段左右,少于50个字段,属性不多的话应该是够用了。
最终解决方案还是要 BigInteger、BigDecimal
字段要是比较多、字段权重因数比较高的话,还是要用 BigInteger、BigDecimal