关于javascript:银行家算法大揭秘在前端表格中利用自定义公式实现四舍六入五成双

16次阅读

共计 2692 个字符,预计需要花费 7 分钟才能阅读完成。

银行的盈利模式是什么? 三个字:信息差! 从储户手中收拢资金,而后放贷进来,而所谓的“利润”就是这其中的利息差额。
在我国,人民银行规定每个季度月末的 20 号为银行结息日,每一年四次结息,因而每年须要十分频繁的计算付给储户的利息。在计算利息时,小数点如何解决就变得很重要,并成为决定利润多少的要害细节。

(图片来自于网络)

通常,咱们都晓得在保留小数点的时候,经常会用到四舍五入。小于 5 的数字被舍去,大于等于 5 的数字进位后舍去,因为所有位上的数字都是天然计算出来的,依照概率计算可知,被舍入的数字均匀分布在 0 到 9 之间。
咱们无妨以 10 笔贷款利息计算作为模型,以银行家的身份来思考这个算法:

四舍,舍弃的值蕴含:0.000、0.001、0.002、0.003、0.004,对银行而言舍弃的内容就不再须要领取,所以舍弃的局部咱们能够了解为“赚到了”。

五入,进位的内容包含:0.005、0.006、0.007、0.008、0.009,对银行而言进位内容会造成亏损,对应亏损的金额则是:0.005、0.004、0.003、0.002、0.001。
因为舍弃和进位的数字是在 0 到 9 之间均匀分布的,所以对于银行家来说,每 10 笔贷款的利息因采纳四舍五入而取得的盈利是:
0.000 + 0.001 + 0.002 + 0.003 + 0.004 – 0.005 – 0.004 – 0.003 – 0.002 – 0.001 = -0.005
总体来讲每 10 笔的利息,通过四舍五入计算就会导致 0.005 元的损失,即每笔利息计算损失 0.0005 元。假如某家银行有 5 千万储户,每年仅仅因为四舍五入的误差而损失的金额是:

public class Client {public static void main(String[] args) {  
          // 银行账户数量,5 千万  
          int accountNum =5000*10000;  
          // 依照人行的规定,每个季度末月的 20 日为银行结息日  
          double cost = 0.0005 * accountNum * 4 ;  
          System.out.println("银行每年损失的金额:" + cost);  
     }  
} 

计算结果是:“银行每年损失的金额:100000.0”。你可能难以相信,四舍五入小小一个动作,就导致了每年损失 10 万。但在实在环境中,理论损失可能事更多。
这个状况是由美国的私人银行家发现,为了解决这一状况提出了一个修改算法:
“舍去位的数值小于 5 时,间接舍去;
舍去位的数值大于等于 6 时,进位后舍去;
当舍去位的数值等于 5 时,分两种状况:5 前面还有其余数字(非 0),则进位后舍去;若 5 前面是 0(即 5 是最初一个数字),则依据 5 前一位数的奇偶性来判断是否须要进位,奇数进位,偶数舍去。”
以上这么多,汇成一句话就是:四舍六入五思考,五后非零就进一,五后为零看奇偶,五前为偶应舍去,五前为奇要进一。
咱们举例说明,取 2 位精度:
10.5551= 10.56
10.555= 10.56
10.545= 10.54

(图片来自于网络)

简略来说,有了“四舍六入五成双”这样的银行家算法,就能够更为迷信准确地解决数据。

在理论利用中,咱们应用银行家算法最多的状况就是在大数据量的表格计算中,然而在表格计算中须要通过一系列的内置公式进行复合。对于普通用户来说无论是了解还是最终应用,都很繁琐且简单。
为了更加不便地解决这个问题,咱们能够通过自定义函数来实现这样的需要,这样用户只须要记住自定义的函数名即可应用具备这样一个规定的函数。
接下来咱们一起看看,如何在前端表格中疾速地实现“四舍六入五成双”。
咱们首先须要定义函数的名称,以及外面的参数数目。因为咱们想要实现的是,传递两个参数,“1”是须要被约修的数值,“2”是保留小数点前面的位数,依据值和位数进行约修。

var FdaFunction = function() {
             this.name = "FDA";
             this.minArgs = 1;
             this.maxArgs = 2;
         };

接下来就是为了不便用户了解和应用,咱们须要对这个自定义函数增加一些形容:

 FdaFunction.prototype.description = function() {
             return {
                 description: "对 value 进行四舍六入五留双修约,保留小数点后指定位数",
                 parameters: [{
                     name: "value",
                     repeatable: false,
                     optional: false
                 }, {
                     name: "places",
                     repeatable: false,
                     optional: false
                 }]
             }
         }

最初到了关键步骤,也就是函数的逻辑运行都放在 evaluate 中,咱们会对传入的值做一些判断,并且会利用正则表达式做一些匹配。要实现“五成双”,那么咱们还要对须要约修的最初一个位值做判断,来决定是否进位。具体能够参考附件残缺的 demo。

         FdaFunction.prototype.evaluate = function(context, num, places) {if (!isNaN(parseInt(num)) && !isNaN(parseInt(places))) {console.log("evaluate")
                 num = numGeneral(num);
                if (!isNumber(num)) {return num;}
                var d = places || 0;
                var m = Math.pow(10, d);
                var n = +(d ? num * m : num).toFixed(8); // Avoid rounding errors
                var i = Math.floor(n),
                    f = n - i;
                var e = 1e-8; // Allow for rounding errors in f
                var r = f > 0.5 - e && f < 0.5 + e ? (i % 2 == 0 ? i : i + 1) : Math.round(n);
                var result = d ? r / m : r;

                if (places > 0) {var s_x = result.toString();
                    var pos_decimal = s_x.indexOf(".");
                    if (pos_decimal < 0) {
                        pos_decimal = s_x.length;
                        s_x += ".";
                    }
                    while (s_x.length <= pos_decimal + places) {s_x += "0";}
                    return s_x;
                } else {return result;}
            }else{return "#VALUE!";}
           
         }

体验下载残缺 demo:
https://gcdn.grapecity.com.cn…

大家如果想理解更多与自定义公式相干内容,能够查看链接:
https://demo.grapecity.com.cn…

扩大浏览

SpreadJS 纯前端表格控件

正文完
 0