forked from fanruan/fineui
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
222 lines
8.5 KiB
222 lines
8.5 KiB
8 years ago
|
/**
|
||
|
* Created by zcf on 2017/3/1.
|
||
|
* 万恶的IEEE-754
|
||
|
* 使用字符串精确计算含小数加法、减法、乘法和10的指数倍除法,支持负数
|
||
|
*/
|
||
|
BI.AccurateCalculationModel = BI.inherit(BI.Widget, {
|
||
|
_defaultConfig: function () {
|
||
|
return BI.extend(BI.AccurateCalculationModel.superclass._defaultConfig.apply(this, arguments), {
|
||
|
baseCls: ""
|
||
|
})
|
||
|
},
|
||
|
|
||
|
_init: function () {
|
||
|
BI.AccurateCalculationModel.superclass._init.apply(this, arguments);
|
||
|
},
|
||
|
|
||
|
_getMagnitude: function (n) {
|
||
|
var magnitude = "1";
|
||
|
for (var i = 0; i < n; i++) {
|
||
|
magnitude += "0";
|
||
|
}
|
||
|
return BI.parseInt(magnitude);
|
||
|
},
|
||
|
|
||
|
_formatDecimal: function (stringNumber1, stringNumber2) {
|
||
|
if (stringNumber1.numDecimalLength === stringNumber2.numDecimalLength) {
|
||
|
return;
|
||
|
}
|
||
|
var magnitudeDiff = stringNumber1.numDecimalLength - stringNumber2.numDecimalLength;
|
||
|
if (magnitudeDiff > 0) {
|
||
|
var needAddZero = stringNumber2
|
||
|
} else {
|
||
|
var needAddZero = stringNumber1;
|
||
|
magnitudeDiff = (0 - magnitudeDiff);
|
||
|
}
|
||
|
for (var i = 0; i < magnitudeDiff; i++) {
|
||
|
if (needAddZero.numDecimal === "0" && i === 0) {
|
||
|
continue
|
||
|
}
|
||
|
needAddZero.numDecimal += "0"
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_stringNumberFactory: function (num) {
|
||
|
var strNum = num.toString();
|
||
|
var numStrArray = strNum.split(".");
|
||
|
var numInteger = numStrArray[0];
|
||
|
if (numStrArray.length === 1) {
|
||
|
var numDecimal = "0";
|
||
|
var numDecimalLength = 0;
|
||
|
} else {
|
||
|
var numDecimal = numStrArray[1];
|
||
|
var numDecimalLength = numStrArray[1].length;
|
||
|
}
|
||
|
return {
|
||
|
"numInteger": numInteger,
|
||
|
"numDecimal": numDecimal,
|
||
|
"numDecimalLength": numDecimalLength
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_accurateSubtraction: function (num1, num2) {//num1-num2 && num1>num2
|
||
|
var stringNumber1 = this._stringNumberFactory(num1);
|
||
|
var stringNumber2 = this._stringNumberFactory(num2);
|
||
|
//整数部分计算
|
||
|
var integerResult = BI.parseInt(stringNumber1.numInteger) - BI.parseInt(stringNumber2.numInteger);
|
||
|
//小数部分
|
||
|
this._formatDecimal(stringNumber1, stringNumber2);
|
||
|
var decimalMaxLength = getDecimalMaxLength(stringNumber1, stringNumber2);
|
||
|
|
||
|
if (BI.parseInt(stringNumber1.numDecimal) >= BI.parseInt(stringNumber2.numDecimal)) {
|
||
|
var decimalResultTemp = (BI.parseInt(stringNumber1.numDecimal) - BI.parseInt(stringNumber2.numDecimal)).toString();
|
||
|
var decimalResult = addZero(decimalResultTemp, decimalMaxLength);
|
||
|
} else {//否则借位
|
||
|
integerResult--;
|
||
|
var borrow = this._getMagnitude(decimalMaxLength);
|
||
|
var decimalResultTemp = (borrow + BI.parseInt(stringNumber1.numDecimal) - BI.parseInt(stringNumber2.numDecimal)).toString();
|
||
|
var decimalResult = addZero(decimalResultTemp, decimalMaxLength);
|
||
|
}
|
||
|
var result = integerResult + "." + decimalResult;
|
||
|
return BI.parseFloat(result);
|
||
|
|
||
|
function getDecimalMaxLength(num1, num2) {
|
||
|
if (num1.numDecimal.length >= num2.numDecimal.length) {
|
||
|
return num1.numDecimal.length
|
||
|
}
|
||
|
return num2.numDecimal.length
|
||
|
}
|
||
|
|
||
|
function addZero(resultTemp, length) {
|
||
|
var diff = length - resultTemp.length;
|
||
|
for (var i = 0; i < diff; i++) {
|
||
|
resultTemp = "0" + resultTemp;
|
||
|
}
|
||
|
return resultTemp
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_accurateAddition: function (num1, num2) {//加法结合律
|
||
|
var stringNumber1 = this._stringNumberFactory(num1);
|
||
|
var stringNumber2 = this._stringNumberFactory(num2);
|
||
|
//整数部分计算
|
||
|
var integerResult = BI.parseInt(stringNumber1.numInteger) + BI.parseInt(stringNumber2.numInteger);
|
||
|
//小数部分
|
||
|
this._formatDecimal(stringNumber1, stringNumber2);
|
||
|
|
||
|
var decimalResult = (BI.parseInt(stringNumber1.numDecimal) + BI.parseInt(stringNumber2.numDecimal)).toString();
|
||
|
|
||
|
if (decimalResult !== "0") {
|
||
|
if (decimalResult.length <= stringNumber1.numDecimal.length) {
|
||
|
decimalResult = addZero(decimalResult, stringNumber1.numDecimal.length)
|
||
|
} else {
|
||
|
integerResult++;//进一
|
||
|
decimalResult = decimalResult.slice(1);
|
||
|
}
|
||
|
}
|
||
|
var result = integerResult + "." + decimalResult;
|
||
|
return BI.parseFloat(result);
|
||
|
|
||
|
function addZero(resultTemp, length) {
|
||
|
var diff = length - resultTemp.length;
|
||
|
for (var i = 0; i < diff; i++) {
|
||
|
resultTemp = "0" + resultTemp;
|
||
|
}
|
||
|
return resultTemp
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_accurateMultiplication: function (num1, num2) {//乘法分配律
|
||
|
var stringNumber1 = this._stringNumberFactory(num1);
|
||
|
var stringNumber2 = this._stringNumberFactory(num2);
|
||
|
//整数部分计算
|
||
|
var integerResult = BI.parseInt(stringNumber1.numInteger) * BI.parseInt(stringNumber2.numInteger);
|
||
|
//num1的小数和num2的整数
|
||
|
var dec1Int2 = this._accurateDivisionTenExponent(BI.parseInt(stringNumber1.numDecimal) * BI.parseInt(stringNumber2.numInteger), stringNumber1.numDecimalLength);
|
||
|
//num1的整数和num2的小数
|
||
|
var int1dec2 = this._accurateDivisionTenExponent(BI.parseInt(stringNumber1.numInteger) * BI.parseInt(stringNumber2.numDecimal), stringNumber2.numDecimalLength);
|
||
|
//小数*小数
|
||
|
var dec1dec2 = this._accurateDivisionTenExponent(BI.parseInt(stringNumber1.numDecimal) * BI.parseInt(stringNumber2.numDecimal), (stringNumber1.numDecimalLength + stringNumber2.numDecimalLength));
|
||
|
|
||
|
return this._accurateAddition(this._accurateAddition(this._accurateAddition(integerResult, dec1Int2), int1dec2), dec1dec2);
|
||
|
},
|
||
|
|
||
|
_accurateDivisionTenExponent: function (num, n) {// num/10^n && n>0
|
||
|
var stringNumber = this._stringNumberFactory(num);
|
||
|
if (stringNumber.numInteger.length > n) {
|
||
|
var integerResult = stringNumber.numInteger.slice(0, (stringNumber.numInteger.length - n));
|
||
|
var partDecimalResult = stringNumber.numInteger.slice(-n);
|
||
|
} else {
|
||
|
var integerResult = "0";
|
||
|
var partDecimalResult = addZero(stringNumber.numInteger, n);
|
||
|
}
|
||
|
var result = integerResult + "." + partDecimalResult + stringNumber.numDecimal;
|
||
|
return BI.parseFloat(result);
|
||
|
|
||
|
function addZero(resultTemp, length) {
|
||
|
var diff = length - resultTemp.length;
|
||
|
for (var i = 0; i < diff; i++) {
|
||
|
resultTemp = "0" + resultTemp;
|
||
|
}
|
||
|
return resultTemp
|
||
|
}
|
||
|
},
|
||
|
|
||
|
accurateSubtraction: function (num1, num2) {
|
||
|
if (num1 >= 0 && num2 >= 0) {
|
||
|
if (num1 >= num2) {
|
||
|
return this._accurateSubtraction(num1, num2)
|
||
|
}
|
||
|
return -this._accurateSubtraction(num2, num1)
|
||
|
}
|
||
|
if (num1 >= 0 && num2 < 0) {
|
||
|
return this._accurateAddition(num1, -num2)
|
||
|
}
|
||
|
if (num1 < 0 && num2 >= 0) {
|
||
|
return -this._accurateAddition(-num1, num2)
|
||
|
}
|
||
|
if (num1 < 0 && num2 < 0) {
|
||
|
if (num1 >= num2) {
|
||
|
return this._accurateSubtraction(-num2, -num1)
|
||
|
}
|
||
|
return this._accurateSubtraction(-num1, -num2)
|
||
|
}
|
||
|
},
|
||
|
|
||
|
accurateAddition: function (num1, num2) {
|
||
|
if (num1 >= 0 && num2 >= 0) {
|
||
|
return this._accurateAddition(num1, num2)
|
||
|
}
|
||
|
if (num1 >= 0 && num2 < 0) {
|
||
|
return this.accurateSubtraction(num1, -num2)
|
||
|
}
|
||
|
if (num1 < 0 && num2 >= 0) {
|
||
|
return this.accurateSubtraction(num2, -num1)
|
||
|
}
|
||
|
if (num1 < 0 && num2 < 0) {
|
||
|
return -this._accurateAddition(-num1, -num2)
|
||
|
}
|
||
|
},
|
||
|
|
||
|
accurateMultiplication: function (num1, num2) {
|
||
|
if (num1 >= 0 && num2 >= 0) {
|
||
|
return this._accurateMultiplication(num1, num2)
|
||
|
}
|
||
|
if (num1 >= 0 && num2 < 0) {
|
||
|
return -this._accurateMultiplication(num1, -num2)
|
||
|
}
|
||
|
if (num1 < 0 && num2 >= 0) {
|
||
|
return -this._accurateMultiplication(-num1, num2)
|
||
|
}
|
||
|
if (num1 < 0 && num2 < 0) {
|
||
|
return this._accurateMultiplication(-num1, -num2)
|
||
|
}
|
||
|
},
|
||
|
|
||
|
accurateDivisionTenExponent: function (num1, n) {
|
||
|
if (num1 >= 0) {
|
||
|
return this._accurateDivisionTenExponent(num1, n);
|
||
|
}
|
||
|
return -this._accurateDivisionTenExponent(-num1, n);
|
||
|
}
|
||
|
});
|