Flex 准确基于四舍五入的浮点运算

来源:互联网 发布:spss统计学软件 编辑:程序博客网 时间:2024/05/17 04:17

转自: http://120183228.iteye.com/blog/1772782

先说清楚为什么要做这个东西。

1 系统在运算浮点数的时候并不一定都准确 java在没出BigDecimal的时候也是一样,运算的时候或多或少0.000000(N个0)1

无论加减乘除都有可能出现  甚至一个小数乘以100都有可能出现这种情况

2 flex 

Math.round(n):四舍五入  只计算第一位  比如0.5 =1 0.45 = 0

Math.floor(n):返回小于或等于指定数字n 的最大整数

Math.ceil(n):返回大于或等于指定数字n 的最小整数

 

原理是通过设置最大保留小数位四舍五入(从最后一位开始四舍五入)截掉小数变整数运算  运算完后再加上小数位返回。 测试类里面有使用直接运算和使用BigDecimal.as运算两种方式,有兴趣的朋友多试试几个浮点数运算,很容易出现或多或少0.00000...1的情况。

 

由于项目中金额哪怕是0.01也有可能后台金额验证出错,也许你判断的时候可以忽略掉0.01的差距,但是从源头解决问题不更好吗?

 

 

Flex代码  收藏代码
  1. BigDecimal.as  

 

 

 

 

Flex代码  收藏代码
  1. package  
  2. {  
  3.   
  4.     /**  
  5.      *  准确的计算浮点数 ,四舍五入方式是采用最后一位一直到保留小数位的判断。  
  6.      * */  
  7.     public class BigDecimal  
  8.     {  
  9.           
  10.         /**  
  11.          * 保留小数位  
  12.          * */  
  13.         private var _maxDecimalLength:int = 2;  
  14.           
  15.         /**  
  16.          * 设置保留小数位 如doubleValue有值 设置之后会四舍五入  
  17.          * */  
  18.         public function set maxDecimalLength(i:int):void{  
  19.             _maxDecimalLength = i;  
  20.             _doubleValue = round(_doubleValue.toString());  
  21.         }  
  22.           
  23.           
  24.         private var _validateStringThrow:Boolean = true;  
  25.           
  26.         /**  
  27.          * 设置验证字符串数据时如不是数字类型是否抛异常  
  28.          * 如果不抛异常默认值为0  
  29.          * */  
  30.         public function set validateStringThrow(b:Boolean):void{  
  31.             _validateStringThrow = b;  
  32.         }  
  33.           
  34.         private var _doubleValue:Number = 0;  
  35.           
  36.         /**  
  37.          *  设值  
  38.          *  @param value 可以是String、Number、BigDecimal的任意类型  
  39.          *  @throws Error 传入的String类型不是数字  
  40.          *  @throws Error 传入的类型不是String、Number、BigDecimal其中的一个类型  
  41.          * */  
  42.         public function set doubleValue(value:*):void{  
  43.             _doubleValue = getNumber(value);  
  44.         }  
  45.           
  46.       
  47.         public function get doubleValue():Number{  
  48.             return _doubleValue;  
  49.         }  
  50.           
  51.       
  52.           
  53.         /**  
  54.          *  @param value 可以是String、Number、BigDecimal的任意类型  
  55.          *  @param arg1 保留小数位  
  56.          *  @param arg2 设置验证字符串数据时如不是数字类型是否抛异常,如果不抛异常默认值为0。  
  57.          *  @throws Error 传入的String类型不是数字  
  58.          *  @throws Error 传入的类型不是String、Number、BigDecimal其中的一个类型  
  59.          * */  
  60.         public function BigDecimal(value:*,arg1:int = 2,arg2:Boolean = true)  
  61.         {  
  62.             _maxDecimalLength = arg1;  
  63.             _validateStringThrow = arg2;  
  64.             _doubleValue = getNumber(value);  
  65.         }  
  66.           
  67.           
  68.         /**  
  69.          *   获得String、Number、BigDecimal类型的值  
  70.          *  @param value 可以是String、Number、BigDecimal的任意类型  
  71.          *  @throws Error 传入的String类型不是数字  
  72.          *  @throws Error 传入的类型不是String、Number、BigDecimal其中的一个类型  
  73.          * */  
  74.         private function getNumber(value:*):Number{  
  75.             var _num:Number = 0;  
  76.             if(value is String){  
  77.                 if(new Number(value).toString()=="NaN"){  
  78.                     if(_validateStringThrow){  
  79.                         throw(new Error("值:"+value+" 不是正确的数字类型!"));  
  80.                     }else{  
  81.                         _doubleValue = 0;  
  82.                     }  
  83.                 }else{  
  84.                     _num = round(value);  
  85.                 }  
  86.             }else if(value is Number){  
  87.                 _num = round(value.toString());  
  88.             }else if(value is BigDecimal){  
  89.                 _num = round(value.doubleValue.toString());  
  90.             }else{  
  91.                 throw(new Error("BigDecimal不支持此类型的数据:"+value));  
  92.             }  
  93.             return _num;  
  94.         }  
  95.           
  96.           
  97.         /**  
  98.          *  将移除的小数点加上  
  99.          *  @throws _str  可以是String、Number的类型  
  100.          *  @throws _mDL 相乘后应该恢复的是双倍长度的保留小数长度 相除应该是0  加减就是保留小数长度  
  101.          * */  
  102.         private function getDecimalNumber(_str:*,_mDL:Number = NaN):Number{  
  103.             var str:String = _str.toString();  
  104.             if(_mDL.toString()=="NaN") _mDL = _maxDecimalLength;  
  105.             var _retrunValue:String = "";  
  106.             if(str.length>_mDL){  
  107.                 var _indexOf:Number = str.indexOf(".");  
  108.                 if(_indexOf==-1){  
  109.                     _retrunValue = str.substring(0,str.length-_mDL)+"."+str.substring(str.length-_mDL,str.length);  
  110.                 }else{  
  111.                     str = str.replace(".","");  
  112.                     _retrunValue = str.substring(0,_indexOf-_mDL)+"."+str.substring(_indexOf-_mDL,str.length);  
  113.                 }  
  114.             }else{  
  115.                 _retrunValue = "0.";  
  116.                 for (var i:int = 0; i <_mDL-str.length; i++)   
  117.                 {  
  118.                     _retrunValue += "0";  
  119.                 }  
  120.                 _retrunValue += str;  
  121.             }  
  122.             return new Number(_retrunValue);  
  123.         }  
  124.           
  125.           
  126.         /**  
  127.          *   将多出的小数点去掉  
  128.          *     
  129.          * */  
  130.         private function getIntegerNumber(str:*):Number{  
  131.             var _arr:Array = str.toString().split(".");  
  132.             var _retrunValue:String = _arr[0].toString();  
  133.             if(_arr.length>1){  
  134.                 _retrunValue += _arr[1].toString();  
  135.                 for (var i:int = _arr[1].toString().length; i < _maxDecimalLength; i++)   
  136.                 {  
  137.                     _retrunValue += "0";  
  138.                 }  
  139.             }else{  
  140.                 for (var j:int = 0; j < _maxDecimalLength; j++)   
  141.                 {  
  142.                     _retrunValue += "0";  
  143.                 }  
  144.             }  
  145.             return new Number(_retrunValue);  
  146.         }  
  147.   
  148.         /**  
  149.          * 四舍五入  
  150.          * */  
  151.         private function round(value:String):Number{  
  152.             var _arr:Array = value.split(".");  
  153.             if(_arr.length>1&&_arr[1].toString().length>_maxDecimalLength){  
  154.                 var _arr0:String = _arr[0].toString();  
  155.                 var _arr1:String = _arr[1].toString();  
  156.                 var _v1:String = _arr0+_arr1.substring(0,_maxDecimalLength);  
  157.                 var _v2:String = _arr1.substring(_maxDecimalLength,_arr1.length);  
  158.   
  159.                 while(true){  
  160.                     if(_v2.length == 1){  
  161.                         if(Number(_v2)>4){  
  162.                             _v1 = (new Number(_v1)+1).toString();  
  163.                         }  
  164.                         break;  
  165.                     }  
  166.                     if(Number(_v2.charAt(_v2.length-1))>4){  
  167.                         _v2 = (new Number(_v2.substring(0,_v2.length - 1))+1).toString();  
  168.                     }else{  
  169.                         _v2 = (new Number(_v2.substring(0,_v2.length - 1))).toString();  
  170.                     }  
  171.                       
  172.                 }  
  173.                 return getDecimalNumber(_v1);  
  174.             }  
  175.             return new Number(value);  
  176.         }  
  177.           
  178.         /**  
  179.          * 相加   
  180.          * @param value 可以是String、Number、BigDecimal的任意类型  
  181.          * */  
  182.         public function sum(value:*):Number{  
  183.             var n1:Number = getIntegerNumber(doubleValue);  
  184.             var n2:Number = getIntegerNumber(getNumber(value));  
  185.             _doubleValue = getDecimalNumber(n1 + n2);  
  186.             return _doubleValue;  
  187.         }  
  188.           
  189.         /**  
  190.          * 相减    
  191.          * @param value 可以是String、Number、BigDecimal的任意类型  
  192.          * */  
  193.         public function sub(value:*):Number{  
  194.             var n1:Number = getIntegerNumber(doubleValue);  
  195.             var n2:Number = getIntegerNumber(getNumber(value));  
  196.             _doubleValue = getDecimalNumber(n1 - n2);  
  197.             return _doubleValue;  
  198.         }  
  199.           
  200.         /**  
  201.          * 相乘   
  202.          * @param value 可以是String、Number、BigDecimal的任意类型  
  203.          * */  
  204.         public function mul(value:*):Number{  
  205.             var n1:Number = getIntegerNumber(doubleValue);  
  206.             var n2:Number = getIntegerNumber(getNumber(value));  
  207.             _doubleValue = round(getDecimalNumber((n1 * n2),_maxDecimalLength*2).toString());  
  208.             return _doubleValue;  
  209.         }  
  210.           
  211.           
  212.         /**  
  213.          * 相除   
  214.          * @param value 可以是String、Number、BigDecimal的任意类型  
  215.          * */  
  216.         public function div(value:*):Number{  
  217.             var n1:Number = getIntegerNumber(doubleValue);  
  218.             var n2:Number = getIntegerNumber(getNumber(value));  
  219.             if(n2==0){  
  220.                 _doubleValue = 0;  
  221.             }else{  
  222.                 _doubleValue = round(getDecimalNumber((n1 / n2),0).toString());  
  223.             }  
  224.             return _doubleValue;  
  225.         }  
  226.           
  227.       
  228.     }  
  229. }  

 

 

 

 

 

测试类

 

 

 

Flex代码  收藏代码
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"   
  3.                        xmlns:s="library://ns.adobe.com/flex/spark"   
  4.                        xmlns:mx="library://ns.adobe.com/flex/mx">  
  5.     <fx:Script>  
  6.         <![CDATA[  
  7.             import mx.collections.ArrayCollection;  
  8.             import mx.controls.Alert;  
  9.             import mx.events.FlexEvent;  
  10.               
  11.             [Bindable]  
  12.             private var typeData:ArrayCollection = new ArrayCollection([   
  13.                 {"label":"加""data":1},   
  14.                 {"label":"减""data":2},   
  15.                 {"label":"乘""data":3},  
  16.                 {"label":"除""data":4}  
  17.             ]);  
  18.               
  19.             [Bindable]  
  20.             private var _result:String = "";  
  21.               
  22.             protected function button1_clickHandler(event:MouseEvent):void  
  23.             {  
  24.                 var b1:BigDecimal = new BigDecimal(t1.text);  
  25.                 var b2:BigDecimal = new BigDecimal(t2.text);  
  26.                 if(_type.selectedItem["data"]=="1"){  
  27.                     _result = b1.sum(b2).toString();  
  28.                 }else if(_type.selectedItem["data"]=="2"){  
  29.                     _result = b1.sub(b2).toString();  
  30.                 }else if(_type.selectedItem["data"]=="3"){  
  31.                     _result = b1.mul(b2).toString();  
  32.                 }else if(_type.selectedItem["data"]=="4"){  
  33.                     _result = b1.div(b2).toString();  
  34.                 }  
  35.             }  
  36.               
  37.             protected function button2_clickHandler(event:MouseEvent):void  
  38.             {  
  39.                 var b1:Number = new Number(t1.text);  
  40.                 var b2:Number = new Number(t2.text);  
  41.                 if(_type.selectedItem["data"]=="1"){  
  42.                     _result = (b1+b2).toString();  
  43.                 }else if(_type.selectedItem["data"]=="2"){  
  44.                     _result =( b1-b2).toString();  
  45.                 }else if(_type.selectedItem["data"]=="3"){  
  46.                     _result = (b1*b2).toString();  
  47.                 }else if(_type.selectedItem["data"]=="4"){  
  48.                     _result = (b1/b2).toString();  
  49.                 }  
  50.             }  
  51.               
  52.         ]]>  
  53.     </fx:Script>  
  54.     <fx:Declarations>  
  55.         <!-- 将非可视元素(例如服务、值对象)放在此处 -->  
  56.     </fx:Declarations>  
  57.     <mx:VBox>  
  58.         <s:TextInput id="t1"/>  
  59.         <s:ComboBox id="_type" labelField="label" dataProvider="{typeData}" selectedIndex="0"></s:ComboBox>  
  60.         <s:TextInput id="t2"/>  
  61.         <s:Label  text="值:{_result}"/>  
  62.         <s:Button id="BigDecimalAccount" label="使用BigDecimal运算" click="button1_clickHandler(event)"/>  
  63.         <s:Button id="NumberAccount" label="使用系统直接运算"  click="button2_clickHandler(event)"/>  
  64.     </mx:VBox>  
  65. </s:WindowedApplication>  

 

0 0
原创粉丝点击