js计算器组件Calc.js

js浮点型

在编程语言中关于浮点型数字计算问题的解决方案有很多种,其实很多人都会根据个人爱好进行封装,那么首先探讨一下浮点型小数计算存在什么问题。计算机存储的数据是二进制数据,也即1、0,那么在数学中的十进制数据如何映射为二进制数?对于整数,可以除于2取余数,最后倒叙排列来得出二进制编码(负数则数取补码),例如10的二进制为1010,而-10的二进制为0110,当然看你的计算机是32位还是64位,表示数据的精度不同。对于浮点数,常有乘法表示和除法表示两种(基数为2),对于除法,当小数位大于2-n次方时(0.5,0.25,0.125,…)表示1,小于当前2-n次方为0,最后可以得出小数的二进制,例如0.5 二进制为0.1,0.52的二进制为1000010…(后面无穷),因为表示不过来,所以要截取一定的位数来近似表示,例如这里的0.52的二进制为0.10000101。我们都知道在js中进行0.1+0.2=0.30000000000000004而不是0.3,就是因为截取了小数的二进制位数造成。所以在js中进行浮点数计算时,都是在精度特定的情况下进行。


(function(win) {
    //计算器
    var Calc = {        
        add: add, substract: substract, multiply:  multiply, divid: divid, 
        setScale: _setScale, scale: 2, isNumeric: _isNumeric,equal: equal,
        getInstance: function() {
            var instance = {};
            //继承类
            for(var name in Calc) { if(name != "getInstance") { instance[name] = Calc[name]; } }
            return instance;
        }       
    };

    //加法
    function add() {
        var i = 0, len = arguments.length, sum = 0,
            arg1 = this.isNumeric(arguments[0]) && arguments[0] || 0,
            arg2 = this.isNumeric(arguments[1]) && arguments[1] || 0;
        sum = _add.call(this, arg1, arg2);
        if(len > 2) {
            //用递归实现就是方便
            sum = _add.call(this, sum, this.add.apply(this, Array.prototype.slice.call(arguments,2)));
        }
        return sum;
    }

    //两个数相加
    function _add(arg1, arg2) {
        var pow = Math.pow(10, this.scale), number = arg1 * pow + arg2 * pow;
        return number / pow;    
    }

    //减法
    function substract() {
        var i = 0, len = arguments.length, arg2 = 0,
            arg1 = this.isNumeric(arguments[0]) && arguments[0] || 0;
        if(len > 2) {
            arg2 = this.add.apply(this, Array.prototype.slice.call(arguments,1));
        } else {
            arg2 = this.isNumeric(arguments[1]) && arguments[1] || 0;
        }
        return _substract.call(this, arg1, arg2);
    }

    //两个数相减
    function _substract(arg1, arg2) {
        var pow = Math.pow(10, this.scale), number = arg1 * pow - arg2 * pow;
        return number / pow;        
    }

    //乘法
    function multiply() {
        var i = 0, len = arguments.length, sum = 1, 
            arg1 = this.isNumeric(arguments[0]) && arguments[0] || 0,
            arg2 = this.isNumeric(arguments[1]) && arguments[1] || 0;
        sum = _multiply.call(this, arg1, arg2);
        if(len > 2) {
            sum = _multiply.call(this, sum, this.multiply.apply(this, Array.prototype.slice.call(arguments,2)));
        }
        return sum;
    }

    //两个数相乘
    function _multiply(arg1, arg2) {
        var pow = Math.pow(10, this.scale), number = (arg1 * pow) * (arg2 * pow);
        return number / (pow * pow);
    }

    //除法
    function divid() {
        var i = 0, len = arguments.length, sum = 1, 
            arg1 = this.isNumeric(arguments[0]) && arguments[0] || 0,
            arg2 = 1;
        if(len > 2) {
            arg2 = this.multiply.apply(this, Array.prototype.slice.call(arguments,1));
        } else {
            arg2 = this.isNumeric(arguments[1]) && arguments[1] || arg2;
        }
        return arg2 && _divid.call(this, arg1, arg2) || 0;      
    }

    //两个数相除
    function _divid(arg1, arg2) {
        var pow = Math.pow(10, this.scale), number = (arg1 * pow) / (arg2 * pow);
        return number ;
    }

    //设置精度
    function _setScale(number, scale, notRound) {
        //默认精度为2,因为电价的字段一般都是精度为2
        var _scale = scale || this.scale, _pow = Math.pow(10, _scale), 
            _number = this.isNumeric(number) && number || 0;
        if(notRound) {
            //将浮点数进行提升为整数
            _number = win.parseInt(_number * _pow) / _pow;
        } 
        //toFixed会自动进行四舍五入,如果_number的精度大于_scale时
        return Number(_number).toFixed(_scale); 
    }

    //判断是否为数字
    function _isNumeric(number) {
        var fNaN = win.isNaN(number);
        return !fNaN && !!number || fNaN && number != undefined;
    }

    //两个浮点数比较
    function equal(arg1, arg2, scale) {
        var _scale = scale || this.scale;
        return Number(arg1).toFixed(_scale) === Number(arg2).toFixed(_scale);
    }

    //接口绑定
    win = win || window;
    win.Calc = Calc;

    return Calc;
})(window);

注意

对于Calc.js中的Calc采用的是组件极简定定义法,同时利用工厂方法模式getInstance来创建Calc的实例对象,当然还可以采用function配合prototype来定义组件,但是这种小计算器采用极简定义法更方便些。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值