1. 程式人生 > 其它 >js 小數點計算精度問題

js 小數點計算精度問題

/* 由於很多時候都會設計到浮點小數的演算法,

 * 在JS 中只用普通的parseFlost之類的進信封資料型別轉換會使資料失去精度  * 因此採用先轉整數再計算的方式  * */ //浮點數相加  
function dcmAdd(arg1,arg2){
    var r1,r2,m; 
    try{r1=arg1.toString().split(".")[1].length;}catch(e){r1=0;}
    try{r2=arg2.toString().split(".")[1].length;}catch(e){r2=0;}
    m=Math.pow(10,Math.max(r1,r2));
    
return (accMul(arg1,m)+accMul(arg2,m))/m; }

//浮點數相減  

/*  * 說明同上面的加法  * */
function dcmSub(arg1,arg2){ 
     return dcmAdd(arg1,-arg2);
}
  //浮點數取餘數 /*  * 跟據實際中的案例很容易喪失精度,通常做法是同時擴大10000倍,但考慮  * 跟前有關因此還是採用先轉整數再計算  * */
function  dcmYu(arg1,arg2){
var r1,r2,m; 
    try{r1=arg1.toString().split(".")[1].length;}catch
(e){r1=0;} try{r2=arg2.toString().split(".")[1].length;}catch(e){r2=0;} m=Math.pow(10,Math.max(r1,r2)); return (accMul(arg1,m)%accMul(arg2,m))/m; }

/*  除法函式,用來得到精確的除法結果

說明:javascript的除法結果會有誤差,在兩個浮點數相除的時候會比較明顯。這個函式返回 較為精確的除法結果。 呼叫:accDiv(arg1,arg2)     返回值:arg1除以arg2的精確結果 */
function accDiv(arg1,arg2){
    
var t1=0,t2=0,r1,r2; try{t1=arg1.toString().split(".")[1].length}catch(e){} try{t2=arg2.toString().split(".")[1].length}catch(e){} with(Math){ r1=Number(arg1.toString().replace(".","")) r2=Number(arg2.toString().replace(".","")) return (r1/r2)*pow(10,t2-t1); } }
/* 乘法函式,用來得到精確的乘法結果 說明:javascript的乘法結果會有誤差,在兩個浮點數相乘的時候會比較明顯。這個函式返回較為精確的乘法結果。 呼叫:accMul(arg1,arg2) 返回值:arg1乘以arg2的精確結果 */
function accMul(arg1,arg2){
    var m=0,s1=arg1.toString(),s2=arg2.toString();
    try{m+=s1.split(".")[1].length}catch(e){}
    try{m+=s2.split(".")[1].length}catch(e){}
    return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m)
}
// 轉化成小數, 原函式toDecimal(datavalue)存在的精度問題,因涉及過多遮蔽。
function toDecimal(datevalue){
if(datevalue.indexOf('%') != -1){
datevalue = datevalue.replace(/%/g,'');
       if(datevalue.indexOf(',') != -1) {
       datevalue = datevalue.replace(/,/g,'');
       }      
       // 除100精度在原有基礎上增加2位。
var decimal = (datevalue.indexOf('.') == -1) ? 0 : (datevalue.length - datevalue.indexOf('.') - 1);
       datevalue = accDiv(datevalue, 100).toFixed(decimal + 2);
//     alert("toDecimal: " + datevalue);
    } else {
if(datevalue.indexOf(',') != -1){
       datevalue = datevalue.replace(/,/g,'');
       }
    }
    return datevalue;
}
 
// 將小數轉換為百分數。
function toPercentFormat(datevalue) {
var aa = accMul(datevalue, 100);
return "" + aa + "%";  
}
   * 在JS 中只用普通的parseFlost之類的進信封資料型別轉換會使資料失去精度  * 因此採用先轉整數再計算的方式  * */ //浮點數相加  
function dcmAdd(arg1,arg2){
    var r1,r2,m; 
    try{r1=arg1.toString().split(".")[1].length;}catch(e){r1=0;}
    try{r2=arg2.toString().split(".")[1].length;}catch(e){r2=0;}
    m=Math.pow(10,Math.max(r1,r2));
    return (accMul(arg1,m)+accMul(arg2,m))/m;
}
 

//浮點數相減  

/*  * 說明同上面的加法  * */
function dcmSub(arg1,arg2){ 
     return dcmAdd(arg1,-arg2);
}
  //浮點數取餘數 /*  * 跟據實際中的案例很容易喪失精度,通常做法是同時擴大10000倍,但考慮  * 跟前有關因此還是採用先轉整數再計算  * */
function  dcmYu(arg1,arg2){
var r1,r2,m; 
    try{r1=arg1.toString().split(".")[1].length;}catch(e){r1=0;}
    try{r2=arg2.toString().split(".")[1].length;}catch(e){r2=0;}
    m=Math.pow(10,Math.max(r1,r2));
    return (accMul(arg1,m)%accMul(arg2,m))/m;
}

/*  除法函式,用來得到精確的除法結果

說明:javascript的除法結果會有誤差,在兩個浮點數相除的時候會比較明顯。這個函式返回 較為精確的除法結果。 呼叫:accDiv(arg1,arg2)     返回值:arg1除以arg2的精確結果 */
function accDiv(arg1,arg2){
    var t1=0,t2=0,r1,r2;
    try{t1=arg1.toString().split(".")[1].length}catch(e){}
    try{t2=arg2.toString().split(".")[1].length}catch(e){}
    with(Math){
        r1=Number(arg1.toString().replace(".",""))
        r2=Number(arg2.toString().replace(".",""))
        return (r1/r2)*pow(10,t2-t1);
    }
}
/* 乘法函式,用來得到精確的乘法結果 說明:javascript的乘法結果會有誤差,在兩個浮點數相乘的時候會比較明顯。這個函式返回較為精確的乘法結果。 呼叫:accMul(arg1,arg2) 返回值:arg1乘以arg2的精確結果 */
function accMul(arg1,arg2){
    var m=0,s1=arg1.toString(),s2=arg2.toString();
    try{m+=s1.split(".")[1].length}catch(e){}
    try{m+=s2.split(".")[1].length}catch(e){}
    return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m)
}
// 轉化成小數, 原函式toDecimal(datavalue)存在的精度問題,因涉及過多遮蔽。
function toDecimal(datevalue){
if(datevalue.indexOf('%') != -1){
datevalue = datevalue.replace(/%/g,'');
       if(datevalue.indexOf(',') != -1) {
       datevalue = datevalue.replace(/,/g,'');
       }      
       // 除100精度在原有基礎上增加2位。
var decimal = (datevalue.indexOf('.') == -1) ? 0 : (datevalue.length - datevalue.indexOf('.') - 1);
       datevalue = accDiv(datevalue, 100).toFixed(decimal + 2);
//     alert("toDecimal: " + datevalue);
    } else {
if(datevalue.indexOf(',') != -1){
       datevalue = datevalue.replace(/,/g,'');
       }
    }
    return datevalue;
}
 
// 將小數轉換為百分數。
function toPercentFormat(datevalue) {
var aa = accMul(datevalue, 100);
return "" + aa + "%";  
}