转载

年终奖避税程序优化

春节前写了个年终奖避税的程序。但是之前的实现上效率有点儿低,这次的博客就写一写如何优化这个程序好了( 其实是快到deadline才想起来要写博客临时抓的题目……

针对这个年终奖避税的程序,优化的主要方向是降低程序运行的速度。之前的实现,最耗时的是 getOneMonthBonusgetTwoMonthBonus 中的循环。这是在使用穷举搜索最低纳税点。针对穷举的优化,我了解的比较通用的优化方法,一种是增加缓存,一种是对穷举进行剪枝。

经过观察发现,拆分年终奖不可能把年终奖的50%以上拆到工资里,因为年终奖是用商数来确定交税比例的,确定比例所用的表相当于月薪减去起征点。这样我们就减少了一半的计算量。还有,我们还可以用一个对象来存储计算过的拆分方案,如果遇到相同的情况就直接使用对象里面的结果就可以了。

其实在编写其他程序的时候,这两种也是最简单有效的优化方法。概括的说,就是拿空间换时间和减少计算量……

ok,最后放上优化后的程序,这一期的瞎扯就这么愉快的结束了,咱们下期再见~!/( ̄︶ ̄)/

var baseQuota = 3500;
var taxQuota = [1500, 4500, 9000, 35000, 55000, 80000];
var taxRat = [0.03, 0.10, 0.20, 0.25, 0.30, 0.35, 0.45];
var taxQuick = [0, 105, 555, 1005, 2755, 5505, 13505];
var cacheGetOnlyBonusTax = {};
var cacheGetOneMonthBonus = {};
var cacheGetTwoMonthBonus = {};

// 获取不拆分年奖交税总额
functiongetOnlyBonusTax(yearBonus, monthSalary){
	var cached = cacheGetOnlyBonusTax[yearBonus + ',' + monthSalary]
	if (typeof cached != 'undefined') {
		return cached;
	}
    var tax = 0;
    if (monthSalary > baseQuota) {
        perMonth = yearBonus / 12;
        tax = round(yearBonus * getTaxRat(perMonth) - getTaxQuick(perMonth), 2);
    } else {
        if (yearBonus < baseQuota - monthSalary) {
            tax = 0;
        } else {
            perMonth = (yearBonus - (baseQuota - monthSalary)) / 10;
            tax = (yearBonus - (baseQuota - monthSalary)) * getTaxRat(perMonth) - getTaxQuick(perMonth);
        }
    }
	cacheGetOnlyBonusTax[yearBonus + ',' + monthSalary] = tax
    return tax;
}

// 获取税率等级
functiongetTaxNum(money){
    for (var i = 0, l = taxQuota.length; i < l; i++) {
        if (money <= taxQuota[i]) {
            return i;
        }
    }
    return i;
}

// 获取税率
functiongetTaxRat(money){
    return taxRat[getTaxNum(money)];
}

// 获取速算扣除数
functiongetTaxQuick(money){
    return taxQuick[getTaxNum(money)];
}

// 获取平常月交税金额
functiongetMonthTax(money){
    if (money > baseQuota) {
        return getTax(money - baseQuota);
    } else {
        return 0;
    }
}

// 获取年奖平均月交税金额
functiongetPerMonthTax(money){
    return getTax(money);
}

// 计算个人所得税金额
functiongetTax(money){
    return round(money * getTaxRat(money) - getTaxQuick(money), 2);
}

// 计算增加的交税金额
functiongetMonthTaxAdd(monthSalary, addNum){
    var monthAddSalary = monthSalary + addNum;
    monthTaxAdd = round(getMonthTax(monthAddSalary) - getMonthTax(monthSalary), 2);
    return monthTaxAdd;
}

// 计算金额小数
functionround(num, toFix){
    return parseFloat(num.toFixed(toFix), 10);
}

// 获取拆分为一个月交税总额
functiongetOneMonthBonus(yearBonus, monthSalary){
	var cached = cacheGetOneMonthBonus[yearBonus + ',' + monthSalary]
	if (typeof cached != 'undefined') {
		return cached
	}
    var nowBonusTax = getOnlyBonusTax(yearBonus, monthSalary);
	var halfBonus = round(yearBonus/2);
    for (var i = 1; i < halfBonus; i++) {
        var bonusRemain = yearBonus - i;
        var monthTaxAdd = getMonthTaxAdd(monthSalary, i);
        var bonusTax = round(getOnlyBonusTax(bonusRemain, monthSalary) + monthTaxAdd, 2);
        if (bonusTax < nowBonusTax) {
            nowBonusTax = bonusTax;
            oneMonth = i;
        }
    }
	var result = {
		tax: nowBonusTax,
		bonus: i
	};
	cacheGetOneMonthBonus[yearBonus + ',' + monthSalary] = result;
    return result;
}

// 获取拆分为两个月交税总额
functiongetTwoMonthBonus(yearBonus, monthSalary){
	var cached = cacheGetTowMonthBonus[yearBonus + ',' + monthSalary]
	if (typeof cached != 'undefined') {
		return cached
	}
    var nowBonusTax = getOnlyBonusTax(yearBonus, monthSalary);
	var halfBonus = round(yearBonus/2);
    for (var i = 1; i < halfBonus; i++) {
        var bonusRemain = yearBonus - i;
        var monthTaxAdd = getMonthTaxAdd(monthSalary, (i / 2)) * 2;
        var bonusTax = round(getOnlyBonusTax(bonusRemain, monthSalary) + monthTaxAdd, 2);
        if (bonusTax < nowBonusTax) {
            nowBonusTax = bonusTax;
            twoMonth = i / 2;
        }
    }
	var result = {
		tax: nowBonusTax,
		bonus: i
	};
	cacheGetTowMonthBonus[yearBonus + ',' + monthSalary] = result
    return result
}

functionrun(yearBonus, monthSalary){
    var startTime = (new Date).getTime();
    var yearBonusTax = getOnlyBonusTax(yearBonus, monthSalary);
    var oneMonthTax = getOneMonthBonus(yearBonus, monthSalary);
    var twoMonthTax = getTwoMonthBonus(yearBonus, monthSalary);
    var minTax = Math.min(yearBonusTax, oneMonthTax.tax, twoMonthTax.tax);
    var bonusRemain = yearBonus - minTax;

    if (minTax == yearBonusTax) {
        console.log('年终奖发放:' + yearBonus, '第一个月发放:' + 0, '第二个月发放:' + 0, '实际收入:' + bonusRemain);
    } else if (minTax == oneMonthTax.tax) {
        console.log('年终奖发放:' + (yearBonus - oneMonthTax.bonus), '第一个月发放:' + oneMonthTax.bonus, '第二个月发放:' + 0, '实际收入:' + bonusRemain);
    } else if (minTax == twoMonthTax.tax) {
        console.log('年终奖发放:' + (yearBonus - (twoMonthTax.bonus * 2)), '第一个月发放:' + twoMonthTax.bonus, '第一个月发放:' + twoMonthTax.bonus, '实际收入:' + bonusRemain);
    }
    var endTime = (new Date).getTime();
    console.log('耗时:' + (endTime - startTime) + 'ms');
}

run(19000, 9500);
原文  http://brooch.me/2017/02/03/javascript-year-bonus-evade-tax-2/
正文到此结束
Loading...