Flex 准确基于四舍五入的浮点运算
2014-01-20 16:47
435 查看
转自: 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代码
BigDecimal.as
Flex代码
package
{
/**
* 准确的计算浮点数 ,四舍五入方式是采用最后一位一直到保留小数位的判断。
* */
public class BigDecimal
{
/**
* 保留小数位
* */
private var _maxDecimalLength:int = 2;
/**
* 设置保留小数位 如doubleValue有值 设置之后会四舍五入
* */
public function set maxDecimalLength(i:int):void{
_maxDecimalLength = i;
_doubleValue = round(_doubleValue.toString());
}
private var _validateStringThrow:Boolean = true;
/**
* 设置验证字符串数据时如不是数字类型是否抛异常
* 如果不抛异常默认值为0
* */
public function set validateStringThrow(b:Boolean):void{
_validateStringThrow = b;
}
private var _doubleValue:Number = 0;
/**
* 设值
* @param value 可以是String、Number、BigDecimal的任意类型
* @throws Error 传入的String类型不是数字
* @throws Error 传入的类型不是String、Number、BigDecimal其中的一个类型
* */
public function set doubleValue(value:*):void{
_doubleValue = getNumber(value);
}
public function get doubleValue():Number{
return _doubleValue;
}
/**
* @param value 可以是String、Number、BigDecimal的任意类型
* @param arg1 保留小数位
* @param arg2 设置验证字符串数据时如不是数字类型是否抛异常,如果不抛异常默认值为0。
* @throws Error 传入的String类型不是数字
* @throws Error 传入的类型不是String、Number、BigDecimal其中的一个类型
* */
public function BigDecimal(value:*,arg1:int = 2,arg2:Boolean = true)
{
_maxDecimalLength = arg1;
_validateStringThrow = arg2;
_doubleValue = getNumber(value);
}
/**
* 获得String、Number、BigDecimal类型的值
* @param value 可以是String、Number、BigDecimal的任意类型
* @throws Error 传入的String类型不是数字
* @throws Error 传入的类型不是String、Number、BigDecimal其中的一个类型
* */
private function getNumber(value:*):Number{
var _num:Number = 0;
if(value is String){
if(new Number(value).toString()=="NaN"){
if(_validateStringThrow){
throw(new Error("值:"+value+" 不是正确的数字类型!"));
}else{
_doubleValue = 0;
}
}else{
_num = round(value);
}
}else if(value is Number){
_num = round(value.toString());
}else if(value is BigDecimal){
_num = round(value.doubleValue.toString());
}else{
throw(new Error("BigDecimal不支持此类型的数据:"+value));
}
return _num;
}
/**
* 将移除的小数点加上
* @throws _str 可以是String、Number的类型
* @throws _mDL 相乘后应该恢复的是双倍长度的保留小数长度 相除应该是0 加减就是保留小数长度
* */
private function getDecimalNumber(_str:*,_mDL:Number = NaN):Number{
var str:String = _str.toString();
if(_mDL.toString()=="NaN") _mDL = _maxDecimalLength;
var _retrunValue:String = "";
if(str.length>_mDL){
var _indexOf:Number = str.indexOf(".");
if(_indexOf==-1){
_retrunValue = str.substring(0,str.length-_mDL)+"."+str.substring(str.length-_mDL,str.length);
}else{
str = str.replace(".","");
_retrunValue = str.substring(0,_indexOf-_mDL)+"."+str.substring(_indexOf-_mDL,str.length);
}
}else{
_retrunValue = "0.";
for (var i:int = 0; i <_mDL-str.length; i++)
{
_retrunValue += "0";
}
_retrunValue += str;
}
return new Number(_retrunValue);
}
/**
* 将多出的小数点去掉
*
* */
private function getIntegerNumber(str:*):Number{
var _arr:Array = str.toString().split(".");
var _retrunValue:String = _arr[0].toString();
if(_arr.length>1){
_retrunValue += _arr[1].toString();
for (var i:int = _arr[1].toString().length; i < _maxDecimalLength; i++)
{
_retrunValue += "0";
}
}else{
for (var j:int = 0; j < _maxDecimalLength; j++)
{
_retrunValue += "0";
}
}
return new Number(_retrunValue);
}
/**
* 四舍五入
* */
private function round(value:String):Number{
var _arr:Array = value.split(".");
if(_arr.length>1&&_arr[1].toString().length>_maxDecimalLength){
var _arr0:String = _arr[0].toString();
var _arr1:String = _arr[1].toString();
var _v1:String = _arr0+_arr1.substring(0,_maxDecimalLength);
var _v2:String = _arr1.substring(_maxDecimalLength,_arr1.length);
while(true){
if(_v2.length == 1){
if(Number(_v2)>4){
_v1 = (new Number(_v1)+1).toString();
}
break;
}
if(Number(_v2.charAt(_v2.length-1))>4){
_v2 = (new Number(_v2.substring(0,_v2.length - 1))+1).toString();
}else{
_v2 = (new Number(_v2.substring(0,_v2.length - 1))).toString();
}
}
return getDecimalNumber(_v1);
}
return new Number(value);
}
/**
* 相加
* @param value 可以是String、Number、BigDecimal的任意类型
* */
public function sum(value:*):Number{
var n1:Number = getIntegerNumber(doubleValue);
var n2:Number = getIntegerNumber(getNumber(value));
_doubleValue = getDecimalNumber(n1 + n2);
return _doubleValue;
}
/**
* 相减
* @param value 可以是String、Number、BigDecimal的任意类型
* */
public function sub(value:*):Number{
var n1:Number = getIntegerNumber(doubleValue);
var n2:Number = getIntegerNumber(getNumber(value));
_doubleValue = getDecimalNumber(n1 - n2);
return _doubleValue;
}
/**
* 相乘
* @param value 可以是String、Number、BigDecimal的任意类型
* */
public function mul(value:*):Number{
var n1:Number = getIntegerNumber(doubleValue);
var n2:Number = getIntegerNumber(getNumber(value));
_doubleValue = round(getDecimalNumber((n1 * n2),_maxDecimalLength*2).toString());
return _doubleValue;
}
/**
* 相除
* @param value 可以是String、Number、BigDecimal的任意类型
* */
public function div(value:*):Number{
var n1:Number = getIntegerNumber(doubleValue);
var n2:Number = getIntegerNumber(getNumber(value));
if(n2==0){
_doubleValue = 0;
}else{
_doubleValue = round(getDecimalNumber((n1 / n2),0).toString());
}
return _doubleValue;
}
}
}
测试类
Flex代码
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.events.FlexEvent;
[Bindable]
private var typeData:ArrayCollection = new ArrayCollection([
{"label":"加", "data":1},
{"label":"减", "data":2},
{"label":"乘", "data":3},
{"label":"除", "data":4}
]);
[Bindable]
private var _result:String = "";
protected function button1_clickHandler(event:MouseEvent):void
{
var b1:BigDecimal = new BigDecimal(t1.text);
var b2:BigDecimal = new BigDecimal(t2.text);
if(_type.selectedItem["data"]=="1"){
_result = b1.sum(b2).toString();
}else if(_type.selectedItem["data"]=="2"){
_result = b1.sub(b2).toString();
}else if(_type.selectedItem["data"]=="3"){
_result = b1.mul(b2).toString();
}else if(_type.selectedItem["data"]=="4"){
_result = b1.div(b2).toString();
}
}
protected function button2_clickHandler(event:MouseEvent):void
{
var b1:Number = new Number(t1.text);
var b2:Number = new Number(t2.text);
if(_type.selectedItem["data"]=="1"){
_result = (b1+b2).toString();
}else if(_type.selectedItem["data"]=="2"){
_result =( b1-b2).toString();
}else if(_type.selectedItem["data"]=="3"){
_result = (b1*b2).toString();
}else if(_type.selectedItem["data"]=="4"){
_result = (b1/b2).toString();
}
}
]]>
</fx:Script>
<fx:Declarations>
<!-- 将非可视元素(例如服务、值对象)放在此处 -->
</fx:Declarations>
<mx:VBox>
<s:TextInput id="t1"/>
<s:ComboBox id="_type" labelField="label" dataProvider="{typeData}" selectedIndex="0"></s:ComboBox>
<s:TextInput id="t2"/>
<s:Label text="值:{_result}"/>
<s:Button id="BigDecimalAccount" label="使用BigDecimal运算" click="button1_clickHandler(event)"/>
<s:Button id="NumberAccount" label="使用系统直接运算" click="button2_clickHandler(event)"/>
</mx:VBox>
</s:WindowedApplication>
先说清楚为什么要做这个东西。
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代码
BigDecimal.as
Flex代码
package
{
/**
* 准确的计算浮点数 ,四舍五入方式是采用最后一位一直到保留小数位的判断。
* */
public class BigDecimal
{
/**
* 保留小数位
* */
private var _maxDecimalLength:int = 2;
/**
* 设置保留小数位 如doubleValue有值 设置之后会四舍五入
* */
public function set maxDecimalLength(i:int):void{
_maxDecimalLength = i;
_doubleValue = round(_doubleValue.toString());
}
private var _validateStringThrow:Boolean = true;
/**
* 设置验证字符串数据时如不是数字类型是否抛异常
* 如果不抛异常默认值为0
* */
public function set validateStringThrow(b:Boolean):void{
_validateStringThrow = b;
}
private var _doubleValue:Number = 0;
/**
* 设值
* @param value 可以是String、Number、BigDecimal的任意类型
* @throws Error 传入的String类型不是数字
* @throws Error 传入的类型不是String、Number、BigDecimal其中的一个类型
* */
public function set doubleValue(value:*):void{
_doubleValue = getNumber(value);
}
public function get doubleValue():Number{
return _doubleValue;
}
/**
* @param value 可以是String、Number、BigDecimal的任意类型
* @param arg1 保留小数位
* @param arg2 设置验证字符串数据时如不是数字类型是否抛异常,如果不抛异常默认值为0。
* @throws Error 传入的String类型不是数字
* @throws Error 传入的类型不是String、Number、BigDecimal其中的一个类型
* */
public function BigDecimal(value:*,arg1:int = 2,arg2:Boolean = true)
{
_maxDecimalLength = arg1;
_validateStringThrow = arg2;
_doubleValue = getNumber(value);
}
/**
* 获得String、Number、BigDecimal类型的值
* @param value 可以是String、Number、BigDecimal的任意类型
* @throws Error 传入的String类型不是数字
* @throws Error 传入的类型不是String、Number、BigDecimal其中的一个类型
* */
private function getNumber(value:*):Number{
var _num:Number = 0;
if(value is String){
if(new Number(value).toString()=="NaN"){
if(_validateStringThrow){
throw(new Error("值:"+value+" 不是正确的数字类型!"));
}else{
_doubleValue = 0;
}
}else{
_num = round(value);
}
}else if(value is Number){
_num = round(value.toString());
}else if(value is BigDecimal){
_num = round(value.doubleValue.toString());
}else{
throw(new Error("BigDecimal不支持此类型的数据:"+value));
}
return _num;
}
/**
* 将移除的小数点加上
* @throws _str 可以是String、Number的类型
* @throws _mDL 相乘后应该恢复的是双倍长度的保留小数长度 相除应该是0 加减就是保留小数长度
* */
private function getDecimalNumber(_str:*,_mDL:Number = NaN):Number{
var str:String = _str.toString();
if(_mDL.toString()=="NaN") _mDL = _maxDecimalLength;
var _retrunValue:String = "";
if(str.length>_mDL){
var _indexOf:Number = str.indexOf(".");
if(_indexOf==-1){
_retrunValue = str.substring(0,str.length-_mDL)+"."+str.substring(str.length-_mDL,str.length);
}else{
str = str.replace(".","");
_retrunValue = str.substring(0,_indexOf-_mDL)+"."+str.substring(_indexOf-_mDL,str.length);
}
}else{
_retrunValue = "0.";
for (var i:int = 0; i <_mDL-str.length; i++)
{
_retrunValue += "0";
}
_retrunValue += str;
}
return new Number(_retrunValue);
}
/**
* 将多出的小数点去掉
*
* */
private function getIntegerNumber(str:*):Number{
var _arr:Array = str.toString().split(".");
var _retrunValue:String = _arr[0].toString();
if(_arr.length>1){
_retrunValue += _arr[1].toString();
for (var i:int = _arr[1].toString().length; i < _maxDecimalLength; i++)
{
_retrunValue += "0";
}
}else{
for (var j:int = 0; j < _maxDecimalLength; j++)
{
_retrunValue += "0";
}
}
return new Number(_retrunValue);
}
/**
* 四舍五入
* */
private function round(value:String):Number{
var _arr:Array = value.split(".");
if(_arr.length>1&&_arr[1].toString().length>_maxDecimalLength){
var _arr0:String = _arr[0].toString();
var _arr1:String = _arr[1].toString();
var _v1:String = _arr0+_arr1.substring(0,_maxDecimalLength);
var _v2:String = _arr1.substring(_maxDecimalLength,_arr1.length);
while(true){
if(_v2.length == 1){
if(Number(_v2)>4){
_v1 = (new Number(_v1)+1).toString();
}
break;
}
if(Number(_v2.charAt(_v2.length-1))>4){
_v2 = (new Number(_v2.substring(0,_v2.length - 1))+1).toString();
}else{
_v2 = (new Number(_v2.substring(0,_v2.length - 1))).toString();
}
}
return getDecimalNumber(_v1);
}
return new Number(value);
}
/**
* 相加
* @param value 可以是String、Number、BigDecimal的任意类型
* */
public function sum(value:*):Number{
var n1:Number = getIntegerNumber(doubleValue);
var n2:Number = getIntegerNumber(getNumber(value));
_doubleValue = getDecimalNumber(n1 + n2);
return _doubleValue;
}
/**
* 相减
* @param value 可以是String、Number、BigDecimal的任意类型
* */
public function sub(value:*):Number{
var n1:Number = getIntegerNumber(doubleValue);
var n2:Number = getIntegerNumber(getNumber(value));
_doubleValue = getDecimalNumber(n1 - n2);
return _doubleValue;
}
/**
* 相乘
* @param value 可以是String、Number、BigDecimal的任意类型
* */
public function mul(value:*):Number{
var n1:Number = getIntegerNumber(doubleValue);
var n2:Number = getIntegerNumber(getNumber(value));
_doubleValue = round(getDecimalNumber((n1 * n2),_maxDecimalLength*2).toString());
return _doubleValue;
}
/**
* 相除
* @param value 可以是String、Number、BigDecimal的任意类型
* */
public function div(value:*):Number{
var n1:Number = getIntegerNumber(doubleValue);
var n2:Number = getIntegerNumber(getNumber(value));
if(n2==0){
_doubleValue = 0;
}else{
_doubleValue = round(getDecimalNumber((n1 / n2),0).toString());
}
return _doubleValue;
}
}
}
测试类
Flex代码
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.events.FlexEvent;
[Bindable]
private var typeData:ArrayCollection = new ArrayCollection([
{"label":"加", "data":1},
{"label":"减", "data":2},
{"label":"乘", "data":3},
{"label":"除", "data":4}
]);
[Bindable]
private var _result:String = "";
protected function button1_clickHandler(event:MouseEvent):void
{
var b1:BigDecimal = new BigDecimal(t1.text);
var b2:BigDecimal = new BigDecimal(t2.text);
if(_type.selectedItem["data"]=="1"){
_result = b1.sum(b2).toString();
}else if(_type.selectedItem["data"]=="2"){
_result = b1.sub(b2).toString();
}else if(_type.selectedItem["data"]=="3"){
_result = b1.mul(b2).toString();
}else if(_type.selectedItem["data"]=="4"){
_result = b1.div(b2).toString();
}
}
protected function button2_clickHandler(event:MouseEvent):void
{
var b1:Number = new Number(t1.text);
var b2:Number = new Number(t2.text);
if(_type.selectedItem["data"]=="1"){
_result = (b1+b2).toString();
}else if(_type.selectedItem["data"]=="2"){
_result =( b1-b2).toString();
}else if(_type.selectedItem["data"]=="3"){
_result = (b1*b2).toString();
}else if(_type.selectedItem["data"]=="4"){
_result = (b1/b2).toString();
}
}
]]>
</fx:Script>
<fx:Declarations>
<!-- 将非可视元素(例如服务、值对象)放在此处 -->
</fx:Declarations>
<mx:VBox>
<s:TextInput id="t1"/>
<s:ComboBox id="_type" labelField="label" dataProvider="{typeData}" selectedIndex="0"></s:ComboBox>
<s:TextInput id="t2"/>
<s:Label text="值:{_result}"/>
<s:Button id="BigDecimalAccount" label="使用BigDecimal运算" click="button1_clickHandler(event)"/>
<s:Button id="NumberAccount" label="使用系统直接运算" click="button2_clickHandler(event)"/>
</mx:VBox>
</s:WindowedApplication>
相关文章推荐
- hdu2552 (浮点数复杂运算的四舍五入)题解
- JavaScript 浮点数及运算精度调整总结,浮点数计算不准确怎么办
- JS中准确的浮点运算库
- 由于Java的简单类型不能够精确的对浮点数进行运算,这个工具类提供精 确的浮点数运算,包括加减乘除和四舍五入。
- 供精 确的浮点数运算,包括加减乘除和四舍五入
- [java]运算工具(提供精确的浮点数运算,包括加减乘除和四舍五入)
- java浮点数运算不准确问题的解决
- OPenCV下浮点数除法运算不准确问题
- 由于Java的简单类型不能够精确的对浮点数进行运算,这个工具类提供精 确的浮点数运算,包括加减乘除和四舍五入
- 基于ARM9的逻辑运算
- float 和 double 运算不准确的思考
- <2011 11 10> 编程中数据处理的问题(三)浮点数运算与精度误差
- 结队编程-基于gui的四则运算生成器
- 浮点数的运算
- 基于.net webservices和Flex LineChart组件的动态数据监控
- linux shell 实现 四则运算(整数及浮点) 简单方法
- flex 事件机制-基于Actionscript 3.0
- 基于Pipe的PureMVC Flex框架的多核共享消息技术
- 结对编程1 —— 基于GUI和Swing的四则运算题目生成器
- 基于异或(^)运算进行数值交换的可行性分析