123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- /**
- * Created by jimiz on 2017/3/28.
- * 经验证:10000次四舍五入,用num.toFixed为15毫秒,用roundTo为47毫秒,速度低一些,但可以接受
- * 另:经手工验证,用num.toString(2)将十进制浮点数转换为二进制浮点数时,最后一位有错误的情况出现,例子(10.0311)
- */
- let scMathUtil = {
- innerRoundTo: function(num, digit){
- let lFactor = Math.pow(10, digit);
- let fOffSet = 0.5;
- let sign = '';
- // 处理符号
- if (num < 0){
- sign = '-';
- num = Math.abs(num);
- }
- // 计算
- let result = Math.floor((num / lFactor) + fOffSet).toString();
- let iLength = result.length;
- // 因为数值被转为整数计算,当目标位数在小数点后,且数值小于0,需要补齐前面的位数
- if (iLength < -digit){
- result = this.zeroString(-digit) + result;
- }
- // 当目标位数在小数点前,需要补齐后面的位数
- else if ((digit > 0) && (iLength < digit)){
- result = result + this.zeroString(digit);
- }
- iLength = result.length;
- // 获得小数点前的数字
- let r1 = result.substring(0, iLength + digit);
- // 获得小数点后的数字
- let r2 = result.substring(iLength + digit, iLength);
- // 拼出完整结果
- return Number(sign + r1 + '.' + r2);
- },
- // 原来直接用num.toString(2),如果小数段最后位数是0,会被舍掉,导致进位计算bug
- // 改为自己计算二进制,固定为53位。
- // 经验证速度没有差别
- // 另:经手工验证,用num.toString(2)将十进制浮点数转换为二进制浮点数时,最后一位有错误的情况出现,例子(10.0311)
- floatToBin: function(num) {
- let sign = '';
- let dNum = num;
- // 符号位
- if (num < 0) {
- sign = '-';
- dNum = -num;
- };
- // 解析整数段
- let iNum = Math.floor(dNum);
- let iFactor;
- let sResult1 = '';
- // 计算二进制整数段
- while (iNum > 0){
- iFactor = iNum % 2;
- iNum = Math.floor(iNum / 2);
- sResult1 = iFactor + sResult1;
- }
- // 判断是否有整数段
- let bIntZero = sResult1 === '';
- if (bIntZero){
- sResult1 = '0';
- }
- // 解析小数段
- let fNum = dNum - Math.floor(dNum);
- let sResult2 = '';
- if (fNum > 0){
- // 双精度浮点数,尾数总长52位,因为第一位总是1,存储时已经被隐藏,所以有效位数为53位
- const floatLength = 53;
- let iLength;
- // js的bug,浮点数直接取小数可能不能获得精确值,只有转成字符串,截取字符串中的小数段
- let sNum = dNum.toString(10);
- let iDot = sNum.indexOf('.');
- sNum = '0' + sNum.substring(iDot, sNum.length);
- fNum = Number(sNum);
- // 有整数段,则小数位数为全部位数-整数位数
- if (!bIntZero){
- iLength = floatLength - sResult1.length;
- }
- else{
- iLength = floatLength;
- }
- // 计算二进制小数段
- while (iLength > 0){
- fNum = fNum * 2;
- iFactor = Math.floor(fNum);
- fNum = fNum % 1;
- sResult2 = sResult2 + iFactor;
- if (iFactor > 0){
- bIntZero = false;
- }
- if (bIntZero && (iFactor === 0)){
- continue;
- }
- iLength--;
- }
- }
- return sign + sResult1 + '.' + sResult2;
- },
- binToFloat: function(bin) {
- let result = 0;
- let iLength = bin.length;
- let sign = '';
- if (iLength > 0 && bin[0]==='-'){
- sign = '-';
- bin = bin.substring(1, iLength);
- }
- iLength = bin.length;
- let iDot = bin.indexOf('.');
- if (iDot >= 0) {
- for (let i = 0; i < iLength; i++) {
- let num = Number(bin[i]);
- let idx = iDot - i;
- if (idx === 0) {
- continue
- };
- if (idx > 0) {
- idx -= 1
- };
- let r = Math.pow(2, idx);
- result += num * r;
- }
- }
- else {
- result = parseInt(bin, 2);
- };
- return sign + result;
- },
- zeroString: function(length){
- let result = '';
- for (let i = 0; i < length; i++){
- result = result + '0';
- };
- return result;
- },
- incMantissa: function(bin){
- let result = bin;
- let iDot = bin.indexOf('.');
- if (iDot < 0){return result};
- let iLength = bin.length;
- iLength = bin.length;
- for (let i = iLength - 1; i > iDot; i--){
- let num = Number(bin[i]);
- if (num === 0){
- num = 1;
- let bin1 = bin.substring(0, i);
- let bin2 = this.zeroString(iLength - (i + 1));//bin.substring(i + 1, iLength);
- result = bin1 + num.toString() + bin2;
- break;
- }
- };
- return result;
- },
- roundTo: function(num, digit){
- let me = this;
- return me.innerRoundTo(me.binToFloat(me.incMantissa(me.floatToBin(num))), digit);
- },
- isNumber : function (obj) {
- return obj === +obj;
- },
- roundForObj:function(obj,decimal){
- let me = this;
- let value;
- if(me.isNumber(obj)){
- value = me.roundTo(obj,-decimal)
- }else {
- value = me.roundTo(Number(obj),-decimal);
- }
- return value
- },
- roundToString:function(obj,decimal){
- let me = this;
- let value;
- if(me.isNumber(obj)){
- value = me.roundTo(obj,-decimal)
- }else {
- value = me.roundTo(Number(obj),-decimal);
- }
- return value.toFixed(decimal);
- }
- };
- Number.prototype.toDecimal = function (ADigit) {
- //return parseFloat(this.toFixed(ADigit));
- digit = (ADigit && typeof(ADigit) === 'number' && Number.isInteger(ADigit) && ADigit >= 0) ? -ADigit : -2;
- // var s = scMathUtil.roundTo(this, digit);
- // console.log('Number: ' + this + ' Digit: ' + digit + ' Result: ' + s);
- // return parseFloat(s);
- return scMathUtil.roundTo(this, digit);
- };
|