首页 > 其他分享 >js 计算加减乘除导致精度丢失

js 计算加减乘除导致精度丢失

时间:2023-08-03 15:36:50浏览次数:27  
标签:function return int Decimal js 丢失 exp var 加减乘除

(function() {
    var ROOT = this;
    var DECIMAL_SEPARATOR = '.';

    // Decimal
    var Decimal = function(num) {
        if(this.constructor != Decimal) {
            return new Decimal(num);
        }

        if(num instanceof Decimal) {
            return num;
        }

        this.internal = String(num);
        this.as_int = as_integer(this.internal);

        this.add = function(target) {
            var operands = [this, new Decimal(target)];
            operands.sort(function(x, y) { return x.as_int.exp - y.as_int.exp });

            var smallest = operands[0].as_int.exp;
            var biggest = operands[1].as_int.exp;

            var x = Number(format(operands[1].as_int.value, biggest - smallest));
            var y = Number(operands[0].as_int.value);
            var result = String(x + y);

            return Decimal(format(result, smallest));
        };

        this.sub = function(target) {
            return Decimal(this.add(target * -1));
        };

        this.mul = function(target) {
            target = new Decimal(target);
            var result = String(Math.abs(this.as_int.value) * Math.abs(target.as_int.value));
            var _symbol = this.as_int.value * target.as_int.value
            var exp = this.as_int.exp + target.as_int.exp;

            return Decimal(format(result, exp, _symbol));
        };

        this.div = function(target) {
            target = new Decimal(target);

            var smallest = Math.min(this.as_int.exp, target.as_int.exp);

            var x = Decimal.mul(Math.pow(10, Math.abs(smallest)), this);
            var y = Decimal.mul(Math.pow(10, Math.abs(smallest)), target);

            return Decimal(x / y);
        };

        this.toString = function() {
            return this.internal;
        };

        this.toNumber = function() {
            return Number(this.internal);
        }
    };

    var as_integer = function(number) {
        number = String(number);

        var value,
            exp,
            tokens = number.split(DECIMAL_SEPARATOR),
            integer = tokens[0],
            fractional = tokens[1];

        if(!fractional) {
           var trailing_zeros = integer.match(/0+$/);

            if(trailing_zeros) {
                var length = trailing_zeros[0].length;
                value = integer.substr(0, integer.length - length);
                exp = length;
            } else {
                value = integer;
                exp = 0;
            }
        } else {
            value = parseInt(number.split(DECIMAL_SEPARATOR).join(''), 10);
            exp = fractional.length * -1;
        }

        return {
            'value': value,
            'exp': exp
        };
    };


    // Helpers
    var neg_exp = function(str, position, symbol = 1) {
        position = Math.abs(position);
        const _symbol = symbol > 0 ? '' : '-' 
        var offset = position - str.length;
        var sep = DECIMAL_SEPARATOR;

        if(offset >= 0) {
            str = zero(offset) + str;
            sep = '0.';
        }

        var length = str.length;
        var head = str.substr(0, length - position);
        var tail = str.substring(length  - position, length);
        return _symbol + head + sep + tail;
    };

    var pos_exp = function(str, exp, symbol = 1) {
        var zeros = zero(exp);
        const _symbol = symbol > 0 ? '' : '-' 
        return _symbol + String(str + zeros);
    };

    var format = function(num, exp, symbol = 1) {
        num = String(num);
        var func = exp >= 0 ? pos_exp : neg_exp;
        return func(num, exp, symbol);
    };

    var zero = function(exp) {
        return new Array(exp + 1).join('0');
    };

    // Generics
    var methods = ['add', 'mul', 'sub', 'div'];
    for(var i = 0; i < methods.length; i++) {
        (function(method) {
            Decimal[method] = function(a, b) {
                return new Decimal(a)[method](b);
            }
        })(methods[i]);
    }

    if(typeof module != 'undefined' && module.exports) {
        module.exports = Decimal;
    } else {
        ROOT.Decimal = Decimal;
    }

    
})();
Decimal(.1).add(.2).toNumber()
0.3

 

标签:function,return,int,Decimal,js,丢失,exp,var,加减乘除
From: https://www.cnblogs.com/HePandeFeng/p/17603456.html

相关文章

  • web前端技能方法总结(css、js、jquery、html)(2)
    创建链接块display:block;列表样式在一个无序列表中,列表项的标志(marker)是出现在各列表项旁边的圆点。在有序列表中,标志可能是字母、数字或另外某种计数体系中的一个符号。要修改用于列表项的标志类型,可以使用属性list-style-type:ul{list-style-type:square;}1上面的声明把......
  • 关于js toFixed 失真的问题
    不精准原因:下面我们来说一下浮点数运算产生误差的原因:(拿0.1+0.2=0.30000000000000004进行举例)首先,我们要站在计算机的角度思考0.1+0.2这个看似小儿科的问题。我们知道,能被计算机读懂的是二进制,而不是十进制,所以我们先把0.1和0.2转换成二进制看看:0.1=>0.00011001100......
  • 遇到:nodejs unhandledPromiseRejectionWarning 错误应该如何解决
    遇到"unhandledPromiseRejectionWarning"错误是因为在Node.js中,一个Promise被rejected了,但是没有被处理(handled)。这可能是因为你没有使用适当的错误处理机制,导致Promise的rejected状态没有被捕获。要解决这个问题,你可以考虑以下几个步骤:使用catch方法捕获错误:在你的......
  • Vuejs+WebApi导出Excel
    前后端分离,前端Vuejs,后端.Net6WebApi后端代码1publicclassSalesReportController:BaseController2{3privateSerilog.ILogger_log=GetLogger<SalesReportController>();4privatereadonlyISqlSugarClient_db;5privateIHostEnvironme......
  • Node.js 事件
    一、Node.js事件循环Node.js是单进程单线程应用程序,但是因为V8引擎提供的异步执行回调接口,通过这些接口可以处理大量的并发,所以性能非常高。Node.js几乎每一个API都是支持回调函数的。Node.js基本上所有的事件机制都是用设计模式中观察者模式实现。Node.js单线程类似......
  • 控制台出现lockdown-install.js文件报Removing intrinsics.问题告警
    查的原因是:警告来自MetaMaskChrome扩展。解决方法:关闭MetaMask扩展程序。参考资料:https://www.jdk5.com/ask/282/what-is-causing-the-warning-removing-intrinsics-arrayprototype-toreversed-in......
  • Nuxt.JS实战指南:从入门到精通的练习之旅
    官网:Nuxt.js-Vue.js通用应用框架|Nuxt.js中文网搭建Nuxt2-参考文献:Nuxt-超详细环境搭建及创建项目整体流程(create-nuxt-app)_王佳斌的博客-CSDN博客一、为什么用NuxtSEO:所搜引擎优化1.1如何进行搜索引擎优化?多页面Title、描述、关键字网站内容1.2-预渲染1.2.1-预渲染图解1.2......
  • 手摸手实现js拍照
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=d......
  • 老杜 JavaWeb 讲解(十八) ——项目优化(Servlet+JSP+EL+JSTL)
    (十六)项目优化(Servlet+JSP+EL+JSTL)相关视频:55-EL表达式JSTL和base标签改造OA新旧代码对比:注意点:Java代码不需要改动,只需要更改jsp代码。将需要的包导入:jakarta.servlet.jsp.jstl-2.0.0.jarjakarta.servlet.jsp.jstl-api-2.0.0.jarmysql-connector-j-8.0.31.j......
  • ThreeJs实现简单的动画
    上一节实现可用鼠标控制相机的方式实现动态效果,但很多时候是需要场景自己产恒动态效果,而不是通过鼠标拖动,此时引入一个requestAnimationFrame方法,它实际上是通过定时任务的方式,每隔一点时间改变场景中内容后重新渲染一遍,间隔时间短的话视觉上就显示出连续的动画效果,Js本身也自带定......