
/**
 * 数学计算工具类
 * @author 冯聪
 */
export default class MathUtil {

    /** 计算两点之间距离 */
    dis(x1, y1, x2, y2): number {
        return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
    }

    /**
    * 取一个区间内随机整数
    * @param n 开始位置
    * @param m 结束位置
    * @param ifInt 是否是整数
    * @returns 返回的随机整数
    */
    public random(n: number, m: number, ifInt: boolean = true): number {
        let random: number = n;
        if (ifInt) {
            random = Math.floor(Math.random() * (m - n + 1) + n);
        }
        else {
            random = Math.random() * (m - n) + n;
        }
        return random;
    }

    /**
     * 根据权重随机
     * @param weights 权重数组
     * @param total 权重总值 默认100
     * @param asc 权重为降序排列
     * @returns 
     */
    public randomByWeight(weights: number[], total = 100, asc: boolean = true): number {
        if (total != 100) {
            total = 0;
            for (let i = 0; i < weights.length; i++) {
                total += weights[i];
            }
        }
        let random = Math.random() * total;
        let arr = weights.concat(random);
        arr = arr.sort((a, b) => {
            return asc ? a - b : b - a;
        });

        var randomIndex = arr.indexOf(random);
        randomIndex = Math.min(randomIndex, weights.length - 1);
        return randomIndex;
    }

    //---------------------------------------------------------科学计数法-----------------------------------------------------
    /**数字单位 */
    private numUnit = { 4: "万", 8: "亿", 12: "兆", 16: "万兆", 20: "亿兆", 24: "兆兆", 28: "万兆兆", 32: "亿兆兆", 36: "兆兆兆" };

    /**
     * 超大数值加法运算  忽略小数部分
     * @param a
     * @param b
     */
    public addition(a: string, b: string): string {
        var res: any = '',
            temp: any = 0;
        let a1 = a.split('.')[0].split('');
        let b1 = b.split('.')[0].split('');
        while (a1.length || b1.length || temp) {
            temp += ~~a1.pop() + ~~b1.pop();
            res = (temp % 10) + res;
            temp = temp > 9;
        }
        return res.replace(/^0+/, '');
    }

    /**
     * 超大数值减法运算  忽略小数部分
     * @param a
     * @param b
     */
    public subtraction(a: any, b: any): string {
        a = a.split('.')[0].split('');
        b = b.split('.')[0].split('');
        var aMaxb = a.length > b.length;
        if (a.length == b.length) {
            for (var i = 0, len = a.length; i < len; i++) {
                if (a[i] == b[i]) continue;
                aMaxb = a[i] > b[i];
                break;
            }
        }
        if (!aMaxb) a = [b, b = a][0];
        var result = '';
        while (a.length) {
            var temp = parseInt(a.pop()) - parseInt(b.pop() || 0);
            if (temp >= 0) result = temp + result;
            else {
                result = temp + 10 + result;
                a[a.length - 1]--;
            }
        }
        result = (aMaxb ? '' : '-') + result.replace(/^0*/g, '');
        if (result == '-') {
            result = '0'
        }

        return result
    }

    /**
     * 超大数值高位对比  忽略小数部分
     * @param a
     * @param b
     */
    public contrastNumber(a: any, b: any): boolean {
        a = a.split('.')[0].split('');
        b = b.split('.')[0].split('');
        var aMaxb = a.length > b.length;
        if (a.length == b.length) {
            for (var i = 0, len = a.length; i < len; i++) {
                if (a[i] == b[i]) continue;
                aMaxb = a[i] > b[i];
                break;
            }
        }
        if (!aMaxb) a = [b, b = a][0];
        var result = '';
        while (a.length) {
            var temp = parseInt(a.pop()) - parseInt(b.pop() || 0);
            if (temp >= 0) result = temp + result;
            else {
                result = temp + 10 + result;
                a[a.length - 1]--;
            }
        }
        if (a === b) return true;
        return Boolean(aMaxb);
    }

    /**
     * 数值乘法
     * @param a 
     * @param b
     */
    public accMuls(a, b): string {
        let arra = a.split('').reverse(),
            arrb = b.split('').reverse(),
            lena = arra.length,
            lenb = arrb.length,
            result: any = Array(lena + lenb + 1).join('0').split('');
        arra.map((itema, indexa) => {
            arrb.map((itemb, indexb) => {
                result[indexa + indexb] = +result[indexa + indexb] + itema * itemb;
            });
        });
        result.map((item, index) => {
            if (item >= 10) {
                result[index + 1] = ~~result[index + 1] + ~~(result[index] / 10);
                result[index] %= 10;
            }
        });
        return result.reverse().join('').replace(/^0+/, '');
    }

    /**
     * 超大数值乘法
     * @param arg1
     * @param arg2
     */
    public accMul(arg1: string, arg2: string): string {
        var m = 0, s1 = arg1.toString(), s2 = arg2.toString();
        try { m += s1.split(".")[1].length } catch (e) { }
        try { m += s2.split(".")[1].length } catch (e) { }
        let targe = this.accMuls(s1.replace(".", ""), s2.replace(".", ""));

        return this.accDiv(targe, Math.pow(10, m).toString())
    }

    /** 科学技术法转为数值字符串形式 */
    public toNonExponential(num: number): string {
        return num.toLocaleString().replace(/[,]/g, '')
    }

    /**
     * 超大数值除法运算
     * @param arg1
     * @param arg2
     */
    public accDiv(arg1: string, arg2: string): string {

        var t1 = 0, t2 = 0, t3 = 0, r1, r2;

        try { t1 = arg1.toString().split(".")[1].length } catch (e) { }

        try { t2 = arg2.toString().split(".")[1].length } catch (e) { }

        r1 = Number(arg1.toString().replace(".", ""))

        r2 = Number(arg2.toString().replace(".", ""))

        if (r2 == 0)
            return '0';

        var result = String(r1 / r2);

        try { t3 = result.toString().split(".")[1].length } catch (e) { }

        var index = t2 - t1 - t3;

        if (index < 0) {
            result = result.replace(".", "");

            while (result.length <= Math.abs(index)) {
                result = '0' + result;
            }

            var start = result.substring(0, result.length + index);
            var end = result.substring(result.length + index, result.length);

            result = start + '.' + end;

            return this.toNonExponential(Number(result));
        }
        else if (index > 0) {
            result = result.replace(".", "");

            while (result.length <= Math.abs(index)) {
                result += '0';
            }
            return this.toNonExponential(Number(result));
        }
        else return this.toNonExponential(Number(result.replace(".", "")));
    }

    /**
     * 数值格式化
     * @param value
     * @param showDeci
     */
    public format(value: string, showDeci: boolean = true): string {
        var a = value.split('.')[0];
        var b;
        for (let i in this.numUnit) {
            let ii = Number(i);
            if (a.length - 1 >= ii) {
                if (showDeci) {
                    let deci = a.slice(a.length - ii, a.length - ii + 1)
                    if (Number(deci) >= 1) {
                        b = a.slice(0, a.length - ii) + "." + deci + this.numUnit[ii];
                    }
                    else {
                        b = a.slice(0, a.length - ii) + this.numUnit[ii];
                    }
                }
                else {
                    b = a.slice(0, a.length - ii) + this.numUnit[ii];
                }
            }
        };
        if (!b) return a;
        return b;
    }
}
