精华内容
下载资源
问答
  • js精度丢失解决办法

    2019-09-30 07:13:07
    * 加法运算,避免数据相加小数点后产生多位数和计算精度损失。 * * @param num1加数1 | num2加数2 */ function numAdd(num1, num2) { var baseNum, baseNum1, baseNum2; try { baseNum1 = num1....
    /** 
    * 加法运算,避免数据相加小数点后产生多位数和计算精度损失。 
    * 
    * @param num1加数1 | num2加数2 
    */ 
    function numAdd(num1, num2) { 
    var baseNum, baseNum1, baseNum2; 
    try { 
    baseNum1 = num1.toString().split(".")[1].length; 
    } catch (e) { 
    baseNum1 = 0; 
    } 
    try { 
    baseNum2 = num2.toString().split(".")[1].length; 
    } catch (e) { 
    baseNum2 = 0; 
    } 
    baseNum = Math.pow(10, Math.max(baseNum1, baseNum2)); 
    return (num1 * baseNum + num2 * baseNum) / baseNum; 
    }; 
    /** 
    * 加法运算,避免数据相减小数点后产生多位数和计算精度损失。 
    * 
    * @param num1被减数 | num2减数 
    */ 
    function numSub(num1, num2) { 
    var baseNum, baseNum1, baseNum2; 
    var precision;// 精度 
    try { 
    baseNum1 = num1.toString().split(".")[1].length; 
    } catch (e) { 
    baseNum1 = 0; 
    } 
    try { 
    baseNum2 = num2.toString().split(".")[1].length; 
    } catch (e) { 
    baseNum2 = 0; 
    } 
    baseNum = Math.pow(10, Math.max(baseNum1, baseNum2)); 
    precision = (baseNum1 >= baseNum2) ? baseNum1 : baseNum2; 
    return ((num1 * baseNum - num2 * baseNum) / baseNum).toFixed(precision); 
    }; 
    /** 
    * 乘法运算,避免数据相乘小数点后产生多位数和计算精度损失。 
    * 
    * @param num1被乘数 | num2乘数 
    */ 
    function numMulti(num1, num2) { 
    var baseNum = 0; 
    try { 
    baseNum += num1.toString().split(".")[1].length; 
    } catch (e) { 
    } 
    try { 
    baseNum += num2.toString().split(".")[1].length; 
    } catch (e) { 
    } 
    return Number(num1.toString().replace(".", "")) * Number(num2.toString().replace(".", "")) / Math.pow(10, baseNum); 
    }; 
    /** 
    * 除法运算,避免数据相除小数点后产生多位数和计算精度损失。 
    * 
    * @param num1被除数 | num2除数 
    */ 
    function numDiv(num1, num2) { 
    var baseNum1 = 0, baseNum2 = 0; 
    var baseNum3, baseNum4; 
    try { 
    baseNum1 = num1.toString().split(".")[1].length; 
    } catch (e) { 
    baseNum1 = 0; 
    } 
    try { 
    baseNum2 = num2.toString().split(".")[1].length; 
    } catch (e) { 
    baseNum2 = 0; 
    } 
    with (Math) { 
    baseNum3 = Number(num1.toString().replace(".", "")); 
    baseNum4 = Number(num2.toString().replace(".", "")); 
    return (baseNum3 / baseNum4) * pow(10, baseNum2 - baseNum1); 
    } 
    }; 

     

    展开全文
  • 接下来,我们就详细聊聊webgl精度丢失导致的渲染问题,以及相关解决办法。 问题起因JavaScript 中的Number类型精度为double类型,而一般GPU的图形接口api(如opengl、DirectX等)中浮点数精度为float,所以数据在cpu...

    b79e868592efb2cfdcf21a8bb114cb76.png

    BIM大场景以及GIS场景下一个比较容易出现的问题就是渲染抖动的现象。其本质是由于图形渲染精度与实际精度不匹配导致的。接下来,我们就详细聊聊webgl精度丢失导致的渲染问题,以及相关解决办法。

    问题起因

    JavaScript 中的Number类型精度为double类型,而一般GPU的图形接口api(如opengl、DirectX等)中浮点数精度为float,所以数据在cpu传入GPU做渲染过程中会有精度损失,从而导致了渲染中的闪动问题。

    认识浮点数

    float与double都是常见的计算机浮点数表示类型。区别在于flot为单精度浮点数,double是双精度浮点数。具体的区别在哪里呢,让我们细细的品一品。

    float和double的浮点数都是使用二进制的科学计数法表示,在存储中都分为三个部分:

    符号位(Sign) : 0代表正,1代表为负 指数位(Exponent):用于存储科学计数法中的指数数据,并且采用移位存储 尾数部分(Mantissa):尾数部分

    其中主要区别在于存储的长度,float用32个bit表示,double用64个bit表示。

    float类型的具体位数描述:

    | 符号位 | 指数位 | 尾数部分 |

    | 1 | 8 | 23 |

    float的指数位为8位,范围为 正负 2的7次方即-127~128,所以float的数据范围其实是-2^128 ~ +2^128。尾数部分为23位 2^23 = 8388608,一共7位,这意味着最多能有7位有效数字,但绝对能保证的为6位,也即float的精度为6~7位有效数字。

    double类型的具体位数描述:

    | 符号位 | 指数位 | 尾数部分 |

    | 1 | 11 | 52 |

    double的指数位为11位,范围为 正负 2的10次方即-1023~1024,所以double的数据范围其实是-2^1024 ~ +2^1024。尾数部分为52位 2^52 = 4503599627370496,一共16位,即double的精度为15~16位有效数字。

    webgl中的精度设置

    在webgl的shader中,我们可以在第一行使用precision关键字进行精度设置。声明变量精度高低的三个关键子lowpmediumphighp。注意不同的shader里面有默认值,如果不指定或者指定错误,会导致编译报错。 顶点着色器默认精度

    precision highp float;
    precision highp int;
    precision lowp sampler2D;
    precision lowp samplerCube;
    

    片元着色器默认精度

    precision mediump int;
    precision lowp sampler2D;
    precision lowp samplerCube;
    

    重现问题

    那么,对于精度丢失会造成那些问题呢。我们来一起看看。比如你在里离原点很远的地方(类似距离x 5000000个单位)有个立方体,长宽高都为1。 然后放置相机到立方体正前方。当我们移动相机时,可以看到非常诡异的闪动,如下图:

    5a37f57bc1c1f629e7d592a7cc9875aa.png

    顶点数据:

    var vertices = [
    5000000.5, 0.5, 0.5, 5000000.5, 0.5, -0.5, 5000000.5, -0.5, 0.5, 
    5000000.5, -0.5, -0.5, 4999999.5, 0.5, -0.5, 4999999.5, 0.5, 0.5, 
    4999999.5, -0.5, -0.5, 4999999.5, -0.5, 0.5, 4999999.5, 0.5, -0.5, 
    5000000.5, 0.5, -0.5, 4999999.5, 0.5, 0.5, 5000000.5, 0.5, 0.5, 
    4999999.5, -0.5, 0.5, 5000000.5, -0.5, 0.5, 4999999.5, -0.5, -0.5, 
    5000000.5, -0.5, -0.5, 4999999.5, 0.5, 0.5, 5000000.5, 0.5, 0.5,
    4999999.5, -0.5, 0.5, 5000000.5, -0.5, 0.5, 5000000.5, 0.5, -0.5, 
    4999999.5, 0.5, -0.5, 5000000.5, -0.5, -0.5, 4999999.5, -0.5, -0.5]
    

    从数据上可以看出,立方体的顶点坐标x所需要的是8位数据,已经超过了float最大有效位数7位,所以组成这个立方体的顶点会有精度的丢失,从而导致组成的立方体会不规则。

    同样的问题也会出现在任何顶点数据偏大的渲染上,比如地图上的标识,BIM场景中的模型展示等等。

    解决办法

    RTC方案

    RTC(Relative To Center)的方案将模型的顶点信息,转化为相对于某个中心点的坐标,以上面的例子为例,我们可以将模型的顶点坐标统一到相对(5000000,0,0)这个点下面,顶点数据变成了下面:

    var vertices = [
    0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, 0.5
    ...
    ]
    

    此时,顶点坐标的数据相对于之前已经变成了一个相对值,然后将模型的矩阵做个translate到相对点,即把模型放到相对中心的位置上(modelmatrix)。我们将模型相对观测点的矩阵(modelviewmatrix)传入shader,因为模型离相机的位置已经变成了一个相对不那么大的数据,这样可以模型相对相机较近的矩阵精度可以保证,而离相机较远的矩阵精度可能会丢失(但是一般较远的情况显示稍微有点偏差也问题不大)。

    使用2个float传高精度的数据

    function doubleToTwoFloats(value) {
        var high;
        var low;
        if (value >= 0) {
            tempHigh = Math.floor(value / 65536) * 65536;
            high = tempHigh;
            low = value - tempHigh;
        } else {
            tempHigh = Math.floor(-value / 65536) * 65536;
            high = -tempHigh;
            low = value + tempHigh;
        }
        return [high, low];
    }

    上面的函数将数值中超过 65536 的部分用一个 32bit 数表示,其余部分用另一个 32bit 数表示。 在shader中使用类似如下的函数进行计算

    uniform vec3 uViewerHigh;
    uniform vec3 uViewerLow;
    
    void main(void)
    {
        vec3 highDifference = vec3(gl_VertexHigh - uViewerHigh);
        vec3 lowDifference = vec3(gl_VertexLow.xyz - uViewerLow);
        gl_Position = gl_ModelViewProjectionMatrix *
             vec4(highDifference + lowDifference, 1.0);
    }

    这种方式会增加数据的传输量,除了新增的两个uniform变量代表视点的高位、低位数据,普通的vertex数据也被切为高低两部分,进行分别计算。所以这种方式保证精度的同时也会增加数据量,造成数据带宽瓶颈,具体要视情况而定。

    以上就是对webgl中出现的精度问题的回顾与总结,如有错误之处,欢迎批评指正,大家互相讨论。

    参考:

    cesium关于精度的解决方案

    百度地图关于精度问题的文章

    WebGL着色器32位浮点数精度损失问题

    展开全文
  • 大整数的精度丢失和浮点数本质上是一样的,尾数位最大是 52 位,因此 JS 中能精准表示的最大整数是 Math.pow(2, 53),十进制即 9007199254740992。 所以说比这个数字大的经度就有问题了 解决方案 对于整数,前端...

    今天遇到一个超级恶心的事情,我检查了十几分钟怎么都没看出来,代码哪里有问题,无奈只有debugger一步一步查询错误,终于让我逮到了。

    场景就是后端给了一个活动编号,是一场传数字 201905281559025248,当请求其他的接口时候需要将活动编号带入

    进入正题

    let code = 201905281559025248console.log(code) 

    猜猜会打印出来什么

    console.log(code) ---> 201905281559025250

    这是什么鬼?

    怎么还四舍五入了!

    揉揉眼睛再看一下

    3d49ae0a13e4433607fc13dc3f5af482.gif
    b9e3d89d496faf949148851bb9ab9405.png

    按照度娘的说法,这个叫做精度丢失

    原因

    计算机的二进制实现和位数限制有些数无法有限表示。就像一些无理数不能有限表示,如 圆周率 3.1415926...,1.3333... 等。JS 遵循 IEEE 754 规范,采用双精度存储(double precision),占用 64 bit。如图

    61926bb016e8e081d2567466ef38a301.png

    意义

    • 1位用来表示符号位
    • 11位用来表示指数
    • 52位表示尾数

    案例一浮点数

    0.1 >> 0.0001 1001 1001 1001…(1001无限循环)0.2 >> 0.0011 0011 0011 0011…(0011无限循环)

    说个简单的就是我再小程序内打印

    console.log(0.3234+10.2) ----> 10.523399999999999
    633de81aaa9e9e652b4cf03d7175006b.png
    9b2377fb49670ff3f123bee58bdd0079.png

    噢哟!难受,这是什么鬼~~

    此时只能模仿十进制进行四舍五入了,但是二进制只有 0 和 1 两个,于是变为 0 舍 1 入。这即是计算机中部分浮点数运算时出现误差,丢失精度的根本原因。

    大整数的精度丢失和浮点数本质上是一样的,尾数位最大是 52 位,因此 JS 中能精准表示的最大整数是 Math.pow(2, 53),十进制即 9007199254740992。

    所以说比这个数字大的经度就有问题了

    解决方案

    对于整数,前端出现问题的几率可能比较低,毕竟很少有业务需要需要用到超大整数,只要运算结果不超过 Math.pow(2, 53) 就不会丢失精度。

    对于小数,前端出现问题的几率还是很多的,尤其在一些电商网站涉及到金额等数据。解决方式:把小数放到位整数(乘倍数),再缩小回原来倍数(除倍数)

    例如0.1+0.2

    (0.1*10 + 0.2*10) / 10 == 0.3 // true

    关于数字超长的情况

    我是直接 num + ''

    转成字符串

    baba517c5c5374236cdb334a5d04bcf0.png
    展开全文
  • 例如,在计算1 - 0.8或者0.33 * 1.1时,会计算出有误差的数据:function 那么如何解决此类问题呢?问题根源在于:浮点数值的最高进度是17位小数,但在进行运算的时候其精确度却远远不如整数;整数在进行运算的时候...

    d8c65e0b219b02027aa70f8943dd13c7.png

    在编写JavaScript策略时,由于脚本语言自身的一些问题,经常导致计算时数值精确度问题。对于程序中一些计算、逻辑判断有一定影响。例如,在计算1 - 0.8或者0.33 * 1.1时,会计算出有误差的数据:

    function main() {
        var a = 1 - 0.8
        Log(a)
       
        var c = 0.33 * 1.1
        Log(c) 
    }
    

    db638cb358efaefc147dfb44bdc78477.png

    那么如何解决此类问题呢?问题根源在于:

    浮点数值的最高进度是17位小数,但在进行运算的时候其精确度却远远不如整数;整数在进行运算的时候都会转成10进制; 而Java和JavaScript中计算小数运算时,都会先将十进制的小数换算到对应的二进制,一部分小数并不能完整的换算为二进制,这里就出现了第一次的误差。待小数都换算为二进制后,再进行二进制间的运算,得到二进制结果。然后再将二进制结果换算为十进制,这里通常会出现第二次的误差。

    为了解决这个问题,在网上搜索了一些解决方案,经过测试使用,如下方案比较好的解决了这个问题:

    function mathService() {
        // 加法
        this.add = function(a, b) {
            var c, d, e;
            try {
                c = a.toString().split(".")[1].length;   // 获取a的小数位长度
            } catch (f) {
                c = 0;
            }
            try {
                d = b.toString().split(".")[1].length;   // 获取b的小数位长度
            } catch (f) {
                d = 0;
            }
            //先求e,把a、b 同时乘以e转换成整数相加,再除以e还原
            return e = Math.pow(10, Math.max(c, d)), (this.mul(a, e) + this.mul(b, e)) / e;
        }
        
        // 乘法
        this.mul = function(a, b) {       
            var c = 0,
                d = a.toString(),         // 转换为字符串 
                e = b.toString();         // ...
            try {
                c += d.split(".")[1].length;      // c 累加a的小数位长度
            } catch (f) {}
            try {
                c += e.split(".")[1].length;      // c 累加b的小数位长度
            } catch (f) {}
            // 转换为整数相乘,再除以10^c ,移动小数点,还原,利用整数相乘不会丢失精度
            return Number(d.replace(".", "")) * Number(e.replace(".", "")) / Math.pow(10, c);
        }
    
        // 减法
        this.sub = function(a, b) {
            var c, d, e;
            try {
                c = a.toString().split(".")[1].length;  // 获取a的小数位长度
            } catch (f) {
                c = 0;
            }
            try {
                d = b.toString().split(".")[1].length;  // 获取b的小数位长度
            } catch (f) {
                d = 0;
            }
            // 和加法同理
            return e = Math.pow(10, Math.max(c, d)), (this.mul(a, e) - this.mul(b, e)) / e;
        }
    
        // 除法
        this.div = function(a, b) {
            var c, d, e = 0,
                f = 0;
            try {
                e = a.toString().split(".")[1].length;
            } catch (g) {}
            try {
                f = b.toString().split(".")[1].length;
            } catch (g) {}
            // 同理,转换为整数,运算后,还原
            return c = Number(a.toString().replace(".", "")), d = Number(b.toString().replace(".", "")), this.mul(c / d, Math.pow(10, f - e));
        }
    }
    
    function main() {
        var obj = new mathService()
        
        var a = 1 - 0.8
        Log(a)
        
        var b = obj.sub(1, 0.8)
        Log(b)
        
        var c = 0.33 * 1.1
        Log(c)
        
        var d = obj.mul(0.33, 1.1)
        Log(d)
    }
    

    084b44d320c95b6bf3e2ae1bbe72f4b0.png

    究其原理,是把要做运算的两个操作数转换为整数去计算避免精度问题,在计算后(根据转换为整数时的放大倍数)对计算结果运算还原,得出准确结果。这样当我们想让程序在盘口价格加一跳最小价格精度的时候挂单,就不用担心数值精度问题了

    function mathService() {
    ....    // 省略
    }
    
    function main() {
        var obj = new mathService()
        var depth = exchange.GetDepth()
        exchange.Sell(obj.add(depth.Bids[0].Price, 0.0001), depth.Bids[0].Amount, "买一订单:", depth.Bids[0]) 
    }
    

    有兴趣的同学,可以读一下代码,了解计算过程,欢迎提出问题,一起学习一起进步。

    展开全文
  • 这样一般就可以解决这个问题了,但有时反而需要改大精度,所以这个解决办法相对需要靠点运气。可靠的办法还是想办法修改局部的特征避开这些临界问题,等薄壳成功后再还原,虽然累赘了点,但已经是止损的最好办法了。...
  • 进入我的主页,查看更多JS的分享!我的代码有多短,本篇内容就有多短!先实现标题的内容,贴出代码://格式化金额的输入function formatPrice(p) { if (!p) { return "0.0"; } else { p += ""; //去除非数字,只保留...
  • 怎样去解决这个问题成了数控车床加工厂家的当务之急,我们致力于高品质数控车床对外加工已经拥有十八年经验,为此,我们总结了一些相关的解决办法并分析了加工精度不稳定的因素供您参考,希望能够帮助到您,下面,...
  • json输出到前端显示时发现精度丢失了,查看json数据是没有问题的。后经查询问题原因如下:1、javascript 的 Number 类型最大长度是16位;最大整数是 Math.pow(2, 53),十进制即 9007199254740992,如果超过这个值,...
  • 关于JS数字精度丢失解决办法 关于数字计算的解决方案 var operationNumber = function (arg1,arg2,operator) { var oper=['+','-','*','/']; // 不合法的运算 if (isNaN(arg1)||isNaN(arg2)||oper.indexOf...
  • 文章来源地址:... 37.5*5.5=206.08 (JS算出来是这样的一个结果,我四舍五入取两位小数)  我先怀疑是四舍五入的问题,就直接用JS算了一个结果为:206.08499999999998  怎么会这样,两个只有一位...
  • js浮点运算精度丢失解决办法 博客分类: JS js 浮点运算 js中进行浮点数运算时容易出现精度问题,以下方法可以解决1)//除法函数,用来得到精确的除法结果//说明:javascript的除法结果会有误差,在两个...
  • 走在成为全栈的路上 今天在处理公司业务中遇到一个数字计算精度丢失的问题,于是我询问了前端的小伙伴,get到了,原来可以这样解决 在相加前,把两个值都*10 得出结果再/10 解决le~
  • js精度丢失

    2019-04-03 04:14:03
    由于浮点数存储本身固有的缺陷,浮点数无法精确表示其数值范围内的所有数值,当进行数学运算时出现精度丢失的问题,例如: 解决办法参考如下: 多个数字相乘 function Multiply(...args) { if (args.length < 2...
  • js 精度丢失

    2019-09-02 16:52:22
    今天写微信小程序的遇到两位小数...原来是js中就有这个问题,解决办法: 除法: //除法 function accDiv(arg1, arg2) { var t1 = 0, t2 = 0, r1, r2; try { t1 = arg1.toString().split(".")[1].length } catch (...
  • //加法  Number.prototype.add = function(arg){   var r1,r2,m;   try{r1=this.toString().split(".")[1].length}catch(e){r1=0}   try{r2=arg.toString().split(".")[1].length}catch(e){r2=0} ...http://zm6.sm-img5.com/?src=http%3A%2F%2Fblog.csdn.net%2Fqq282030166%2Farticle%2Fdetails%2F8364343&uid=786557245b09f79404ff7abb851dd3a0&hid=a5df8b9ce3035b5c528b414288832958&pos=4&cid=9&time=1440477098910&from=click&restype=1&pagetype=0040000002000408&bu=web&query=js%E7%B2%BE%E5%BA%A6%E4%B8%A2%E5%A4%B1&uc_param_str=dnntnwvepffrgibijbprsvpi...
  • 在开发过程中,我们的主键字段使用了数字作为主键ID,发现数字精度丢失的问题。 上图红框是后端日志的输出。 在浏览器端F12 看到的结果如上图,数据居然自动变化,这个是数字在浏览器丢失了精度,导致结果不...
  • Java序列化JSON时long型数值,会出现精度丢失的问题。 原因: java中得long能表示的范围比js中number大,也就意味着部分数值在js中存不下(变成不准确的值). 解决办法一: 使用ToStringSerializer的注解,让系统...
  • 前端后接口对接时,如果后台的id或者其他字段使用了长整型Long,就很容易出现js丢失精度问题。用接口工具调用时,往往id返回都是对的,但是一到页面上,js就后缀000。前端说返回的值有问题,F12看看!后端说没问题,...
  • 对于Long类型的数据,如果我们在Controller层将结果序列化为json,直接传给前端的话,在Long长度大于17位时会出现精度丢失的问题。如何避免精度丢失呢?最常用的办法就是将Long类型字段统一转成String类型。 JS ...
  • 对于Long类型的数据,如果我们在Controller层将结果序列化为json,直接传给前端的话,在Long长度大于17位时会出现精度丢失的问题。如何避免精度丢失呢?最常用的办法就是将Long类型字段统一转成String类型。 JS 数字...
  • 原因:js特性不支持16位以上的数值,超过16位以上的数字会进行四舍五入 example: 12345678901234567123 会被解析成...不扯了,说说解决办法。 在response中拿到的数据是正确的,这时是一个字符串,但是...
  • 不管是计算还是 toFixed() 四舍五入,js 浮点数计算会遇到很多问题((6.265).toFixed(2)结果竟为6.26),解决办法是重新 js 的 toFixed() 方法。 Number.prototype.toFixed = function (d) { var s = this + "...
  • js中小数运算精度丢失问题

    千次阅读 2017-06-14 18:40:19
    js中做一些计算的时候,如果直接计算有可能造成精度丢失,比如在计算1.79 + 0.12的时候,直接计算的结果就是1.9100000000000001,但是我们知道正确的计算结果应该1.91.我的解决办法如下(直接放代码) ()"/

空空如也

空空如也

1 2 3 4
收藏数 66
精华内容 26
关键字:

js精度丢失解决办法