为了保证各个平台上的计算结果一致,花了近一个星期,总算摸清楚Chrome,IE,和JRE的脾气了。
Chrome最大气,就算结果超出容器范围,也会自动丢弃溢出的数据,保证范围内的数据正确。而且只要运行在64位系统上,自动支持64位整型。IE最渣,64位整型非要64位IE也就算了,Ajax控制器老喜欢没事Cache,也不管别人更新了没有,Ctrl F5都没用,尼玛非要在URL里加个随机UID来强制刷新。
JRE最坑爹的是,这么多年了,居然没人想到要支持unsigned整型......大概是没人会拿Java做高密度计算的原因吧,搞得int最大值其实只有31位......
于是,为了保证长~~~~~整型在各个平台上的计算都能在各自的安全范围内进行,参考U128自己写了个96位计算器。很简单,4个24位计算器连在一起,只有加法,移位和与或,U128里有乘法除法取余等等,但是懒得移植了......用来做Hash足够了。
var evergreenlabs = {}; evergreenlabs.u96 = {}; // Hex string to number evergreenlabs.u96.hexval = function(n) { var r = new Array(4); n = "0000000000000000000000000000000" + n; n = n.slice(-24); r[3] = parseInt(n.substring(0, 6), 16); r[2] = parseInt(n.substring(6, 12), 16); r[1] = parseInt(n.substring(12, 18), 16); r[0] = parseInt(n.substring(18, 24), 16); return r; }; // internal: array dup evergreenlabs.u96._cloneArray = function(arr) { return arr.slice(0); }; // Left shift evergreenlabs.u96.shl = function(n, s) { var ns = evergreenlabs.u96._cloneArray(n); for (var i = 0; i ns[3] = ((ns[3]<<1) | ((ns[2]>>>23) & 1)) & 0xFFFFFF; ns[2] = ((ns[2]<<1) | ((ns[1]>>>23) & 1)) & 0xFFFFFF; ns[1] = ((ns[1]<<1) | ((ns[0]>>>23) & 1)) & 0xFFFFFF; ns[0] = (ns[0]<<1) & 0xFFFFFF; } return ns; }; // Unsigned right shift evergreenlabs.u96.shr = function(n, s) { var ns = evergreenlabs.u96._cloneArray(n); for (var i = 0; i ns[0] = ((ns[0]>>>1) | (ns[1]<<23 )) & 0xFFFFFF; ns[1] = ((ns[1]>>>1) | (ns[2]<<23 )) & 0xFFFFFF; ns[2] = ((ns[2]>>>1) | (ns[3]<<23 )) & 0xFFFFFF; ns[3] = (ns[3]>>>1) & 0xFFFFFF; } return ns; }; // New u96 = 0 evergreenlabs.u96.zero = function() { return [0, 0, 0, 0]; }; // New u96 = 1 evergreenlabs.u96.one = function() { return [1, 0, 0, 0]; }; // Add evergreenlabs.u96.add = function(n1, n2) { var retval = evergreenlabs.u96.zero(); var carry = 0; for (var i = 0; i < 4; i++) { retval[i] = (0xFFFFFF & (n1[i] + n2[i] + carry)) >>> 0; if (evergreenlabs.u96._cmp32ABOVE(n1[i], retval[i])) { carry = 1; } else { carry = 0; } } return retval; }; // Unsigned 32 bit comparison, true if n1 is above n2 evergreenlabs.u96._cmp32ABOVE = function(n1, n2) { return (n1 >>> 0) > (n2 >>> 0); }; // Binary XOR evergreenlabs.u96.xor = function(n1, n2) { var retval = evergreenlabs.u96.zero(); for (var i = 0; i < 4; i++) { retval[i] = (n1[i] ^ n2[i]) & 0xFFFFFF; } return retval; };
public class U96 {
// Hex string to number
public static int[] hexval(String n) {
int r[] = { 0, 0, 0, 0 };
n = "0000000000000000000000000000000" + n;
n = n.substring(n.length() - 24);
r[3] = Integer.parseInt(n.substring(0, 6), 16);
r[2] = Integer.parseInt(n.substring(6, 12), 16);
r[1] = Integer.parseInt(n.substring(12, 18), 16);
r[0] = Integer.parseInt(n.substring(18, 24), 16);
return r;
}
// longernal: array dup
public static int[] _cloneArray(int arr[]) {
return arr.clone();
}
// Left shift
public static int[] shl(int n[], int s) {
int ns[] = _cloneArray(n);
for (int i = 0; i < s; i++) {
ns[3] = (ns[3] << 1) | ((ns[2] >>> 23) & 1) & 0xFFFFFF;
ns[2] = (ns[2] << 1) | ((ns[1] >>> 23) & 1) & 0xFFFFFF;
ns[1] = (ns[1] << 1) | ((ns[0] >>> 23) & 1) & 0xFFFFFF;
ns[0] = (ns[0] << 1) & 0xFFFFFF;
}
return ns;
}
// Unsigned right shift
public static int[] shr(int n[], int s) {
int ns[] = _cloneArray(n);
for (int i = 0; i < s; i++) {
ns[0] = ((ns[0] >>> 1) | (ns[1] << 23)) & 0xFFFFFF;
ns[1] = ((ns[1] >>> 1) | (ns[2] << 23)) & 0xFFFFFF;
ns[2] = ((ns[2] >>> 1) | (ns[3] << 23)) & 0xFFFFFF;
ns[3] = (ns[3] >>> 1) & 0xFFFFFF;
}
return ns;
}
// New u128 = 0
public static int[] zero() {
int ret[] = { 0, 0, 0, 0 };
return ret;
}
// New u128 = 1
public static int[] one() {
int ret[] = { 1, 0, 0, 0 };
return ret;
}
// Add
public static int[] add(int n1[], int n2[]) {
int retval[] = zero();
int carry = 0;
for (int i = 0; i < 4; i++) {
retval[i] = (0xFFFFFF & (n1[i] + n2[i] + carry)) >>> 0;
if (_cmp32ABOVE(n1[i], retval[i])) {
carry = 1;
} else {
carry = 0;
}
}
return retval;
}
// Unsigned 32 bit comparison, true if n1 is above n2
public static boolean _cmp32ABOVE(int n1, int n2) {
return (n1 >>> 0) > (n2 >>> 0);
}
// Binary XOR
public static int[] xor(int n1[], int n2[]) {
int retval[] = zero();
for (int i = 0; i < 4; i++) {
retval[i] = (n1[i] ^ n2[i]) & 0xFFFFFF;
}
return retval;
}
}