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.6 KiB
222 lines
8.6 KiB
/** |
|
* 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); |
|
} |
|
}); |