scMathUtil.ts 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /**
  2. * Created by Tony on 2017/4/14.
  3. */
  4. 'use strict';
  5. export default {
  6. innerRoundTo: function(num: number, digit: number){
  7. let lFactor = Math.pow(10, digit);
  8. let fOffSet = 0.5;
  9. let sign = '';
  10. // 处理符号
  11. if (num < 0){
  12. sign = '-';
  13. num = Math.abs(num);
  14. }
  15. // 计算
  16. let result = Math.floor((num / lFactor) + fOffSet).toString();
  17. let iLength = result.length;
  18. // 因为数值被转为整数计算,当目标位数在小数点后,且数值小于0,需要补齐前面的位数
  19. if (iLength < -digit){
  20. result = this.zeroString(-digit) + result;
  21. }
  22. // 当目标位数在小数点前,需要补齐后面的位数
  23. else if ((digit > 0) && (iLength < digit)){
  24. result = result + this.zeroString(digit);
  25. }
  26. iLength = result.length;
  27. // 获得小数点前的数字
  28. let r1 = result.substring(0, iLength + digit);
  29. // 获得小数点后的数字
  30. let r2 = result.substring(iLength + digit, iLength);
  31. // 拼出完整结果
  32. return Number(sign + r1 + '.' + r2);
  33. },
  34. // 原来直接用num.toString(2),如果小数段最后位数是0,会被舍掉,导致进位计算bug
  35. // 改为自己计算二进制,固定为53位。
  36. // 经验证速度没有差别
  37. // 另:经手工验证,用num.toString(2)将十进制浮点数转换为二进制浮点数时,最后一位有错误的情况出现,例子(10.0311)
  38. floatToBin: function(num: number): string {
  39. let sign = '';
  40. let dNum = num;
  41. // 符号位
  42. if (num < 0) {
  43. sign = '-';
  44. dNum = -num;
  45. };
  46. // 解析整数段
  47. let iNum = Math.floor(dNum);
  48. let iFactor;
  49. let sResult1 = '';
  50. // 计算二进制整数段
  51. while (iNum > 0){
  52. iFactor = iNum % 2;
  53. iNum = Math.floor(iNum / 2);
  54. sResult1 = iFactor + sResult1;
  55. }
  56. // 判断是否有整数段
  57. let bIntZero = sResult1 === '';
  58. if (bIntZero){
  59. sResult1 = '0';
  60. }
  61. // 解析小数段
  62. let fNum = dNum - Math.floor(dNum);
  63. let sResult2 = '';
  64. if (fNum > 0){
  65. // 双精度浮点数,尾数总长52位,因为第一位总是1,存储时已经被隐藏,所以有效位数为53位
  66. // 由于js未对浮点数做优化,所以在有运算的情况下,误差会被放大,因此放弃一位有效位数来消除误差,二进制有效位数50位,十进制有效位数15位
  67. const floatLength = 50;
  68. let iLength;
  69. // js的bug,浮点数直接取小数可能不能获得精确值,只有转成字符串,截取字符串中的小数段
  70. let sNum = dNum.toString(10);
  71. let iDot = sNum.indexOf('.');
  72. sNum = '0' + sNum.substring(iDot, sNum.length);
  73. fNum = Number(sNum);
  74. // 有整数段,则小数位数为全部位数-整数位数
  75. if (!bIntZero){
  76. iLength = floatLength - sResult1.length;
  77. }
  78. else{
  79. iLength = floatLength;
  80. }
  81. // 计算二进制小数段
  82. while (iLength > 0){
  83. fNum = fNum * 2;
  84. iFactor = Math.floor(fNum);
  85. fNum = fNum % 1;
  86. sResult2 = sResult2 + iFactor;
  87. if (iFactor > 0){
  88. bIntZero = false;
  89. }
  90. if (bIntZero && (iFactor === 0)){
  91. continue;
  92. }
  93. iLength--;
  94. }
  95. }
  96. return sign + sResult1 + '.' + sResult2;
  97. },
  98. binToFloat: function(bin: string): string {
  99. let result = 0;
  100. let iLength = bin.length;
  101. let sign = '';
  102. if (iLength > 0 && bin[0]==='-'){
  103. sign = '-';
  104. bin = bin.substring(1, iLength);
  105. }
  106. iLength = bin.length;
  107. let iDot = bin.indexOf('.');
  108. if (iDot >= 0) {
  109. for (let i = 0; i < iLength; i++) {
  110. let num = Number(bin[i]);
  111. let idx = iDot - i;
  112. if (idx === 0) {
  113. continue
  114. };
  115. if (idx > 0) {
  116. idx -= 1
  117. };
  118. let r = Math.pow(2, idx);
  119. result += num * r;
  120. }
  121. }
  122. else {
  123. result = parseInt(bin, 2);
  124. };
  125. return sign + result;
  126. },
  127. zeroString: function(length: number){
  128. let result = '';
  129. for (let i = 0; i < length; i++){
  130. result = result + '0';
  131. };
  132. return result;
  133. },
  134. incMantissa: function(bin: string): string {
  135. let result = bin;
  136. const me = this;
  137. let iDot = bin.indexOf('.');
  138. if (iDot < 0) {
  139. return result
  140. };
  141. let iLength = bin.length;
  142. iLength = bin.length;
  143. for (let i = iLength - 1; i > iDot; i--){
  144. let num = Number(bin[i]);
  145. if (num === 0){
  146. num = 1;
  147. let bin1 = bin.substring(0, i);
  148. let bin2 = me.zeroString(iLength - (i + 1));//bin.substring(i + 1, iLength);
  149. result = bin1 + num.toString() + bin2;
  150. break;
  151. }
  152. };
  153. return result;
  154. },
  155. roundTo: function(num: number, digit: number) {
  156. let me = this;
  157. // let str1 = me.floatToBin(num);
  158. // let str2 = me.incMantissa(str1);
  159. // return me.innerRoundTo( parseFloat(me.binToFloat(str2)), digit);
  160. return me.innerRoundTo( parseFloat(me.binToFloat( me.incMantissa( me.floatToBin(num)))), digit);
  161. },
  162. isNumber : function (obj: any) {
  163. return obj === +obj;
  164. },
  165. roundForObj:function(obj: any, decimal: number) {
  166. let me = this;
  167. let value;
  168. if(me.isNumber(obj)){
  169. value = me.roundTo(obj,-decimal)
  170. }else {
  171. value = me.roundTo(Number(obj),-decimal);
  172. }
  173. return value
  174. },
  175. roundToString:function(obj: any, decimal: number){
  176. let me = this;
  177. let value;
  178. if(me.isNumber(obj)){
  179. value = me.roundTo(obj,-decimal)
  180. }else {
  181. value = me.roundTo(Number(obj),-decimal);
  182. }
  183. return value.toFixed(decimal);
  184. },
  185. // isNumOrFormula:function (text: any) {
  186. // let value = Number(text);
  187. // if(value ==0 ) return value;
  188. // if (!value) {
  189. // try {
  190. // let exp = new Expression('');
  191. // exp.Expression(text);
  192. // value = Number(exp.Evaluate());
  193. // } catch (error) {
  194. // value = 0;
  195. // }
  196. // }
  197. // if(text == null || text == ''){
  198. // value = 0;
  199. // }
  200. // return value;
  201. // },
  202. isDef:function (v: any) {
  203. return v !== undefined && v !== null;
  204. },
  205. //获取ID引用
  206. getFIDArr: function (exp: any) {
  207. let fidRex = /@[\d,a-z,A-Z,-]{36}/g;
  208. let fidArr = exp.match(fidRex);
  209. return this.isDef(fidArr) ? fidArr : [];
  210. }
  211. };