Apache flex 如何处理Actionscript中的数字精度?
我用BlazeDS将BigDecimal对象序列化为Actionscript。一旦它们作为数字对象点击Actionscript,它们的值如下:Apache flex 如何处理Actionscript中的数字精度?,apache-flex,actionscript-3,actionscript,Apache Flex,Actionscript 3,Actionscript,我用BlazeDS将BigDecimal对象序列化为Actionscript。一旦它们作为数字对象点击Actionscript,它们的值如下: 140475.32变为140475.3199999998 我该怎么处理?问题是,如果使用精度为2的a,则该值将被截断为140475.31。有什么想法吗?如果您事先知道所需的精度,您可以存储按比例缩放的数字,以便所需的最小数量是一个整数值。例如,将数字存储为美分而不是美元 如果这不是一个选项,那么像这样的东西怎么样: function printTwoDe
140475.32
变为140475.3199999998
我该怎么处理?问题是,如果使用精度为2的a,则该值将被截断为
140475.31
。有什么想法吗?如果您事先知道所需的精度,您可以存储按比例缩放的数字,以便所需的最小数量是一个整数值。例如,将数字存储为美分而不是美元
如果这不是一个选项,那么像这样的东西怎么样:
function printTwoDecimals(x)
{
printWithNoDecimals(x);
print(".");
var scaled = Math.round(x * 100);
printWithNoDecimals(scaled % 100);
}
(无论如何,打印时没有小数。)
不过,这对真正大的数字不起作用,因为仍然可能会失去精度 这是我针对这个问题的通用解决方案(我有): 例如:
- 将
乘以0.12345678
;这给了我们10
1.2345678
- 当我们取整
时,我们得到1.2345678
1.0
- 最后,
除以1.0
等于10
0.1
- 将
乘以1.7302394309234435
;这给我们提供了10000
17302.394309234435
- 当我们取整
17302.394309234435时,我们得到
17302
- 最后,
除以17302
等于10000
1.7302
编辑 基于匿名答案,对该方法的参数进行了很好的简化,使精度更加直观。e、 g:
注意:我在这里添加了这个,以防有人将此视为答案而不向下滚动…这似乎更像是一个交通问题,数字是正确的,但比例忽略了。如果必须将数字存储为服务器上的BigDecimal,则在发送之前,您可能希望将其转换为服务器端不太含糊的格式(数字、双精度、浮点)。您可以使用property:rounding=“nearest” 在NumberFormatter中,舍入有4个值可供选择:舍入=“无|向上|向下|最近”。我想根据你的情况,你可以选择“最近的”
--chary--我在ActionScript3中使用了
Number.toFixed(precision)
来执行此操作:
它正确处理舍入并指定小数点后要显示的位数,这与限制要显示的总位数而不考虑小数点位置的number.toPrecision()
不同
var roundDown:Number = 1.434;
// will print 1.43
trace(roundDown.toFixed(2));
var roundUp:Number = 1.436;
// will print 1.44
trace(roundUp.toFixed(2));
我将BigDecimal的Java转换为ActionScript。 我们没有选择,因为我们计算的是财务应用
对于任何感兴趣的人来说,这只是功能上的细微变化
function setPrecision(number:Number, precision:int) {
precision = Math.pow(10, precision);
return (Math.round(number * precision)/precision);
}
因此,使用:
var number:Number = 10.98813311;
trace(setPrecision(number,1)); //Result is 10.9
trace(setPrecision(number,2)); //Result is 10.98
trace(setPrecision(number,3)); //Result is 10.988 and so on
我发现BlazeDS还支持将Java BigDecimal对象序列化为ActionScript字符串。因此,如果您不需要ActionScript数据是数字(您在Flex/ActionScript方面没有做任何数学运算),那么字符串映射工作得很好(没有四舍五入的奇怪之处)。有关BlazeDS映射选项,请参见此链接:您可以在Flash PLayer Jira bug跟踪系统中投票并观看增强请求,网址为 同时使用Number.toFixed()解决问题请参见: () 或者使用开源实现:()或()
至于序列化工作,如果您使用Blazeds或LCD,它将很小,因为它们支持Java BigDecimal序列化(到字符串)cf.()GraniteDS 2.2在ActionScript3中有BigDecimal、BigInteger和Long实现,Java/Flex之间的序列化选项用于这些类型,甚至还有代码生成工具选项,以便为相应的Java变量生成3个大数字变量
请参阅此处的更多信息:。我们能够通过从AMF3Output中进行子类化,重用web上的一个可用BigDecimal.as类和扩展blazeds,您需要在flex xml文件中指定自己的端点类,在该自定义端点中,您可以插入自己的序列化程序来实例化AMF3Output子类
public class EnhancedAMF3Output extends Amf3Output {
public EnhancedAMF3Output(final SerializationContext context) {
super(context);
}
public void writeObject(final Object o) throws IOException {
if (o instanceof BigDecimal) {
write(kObjectType);
writeUInt29(7); // write U290-traits-ext (first 3 bits set)
writeStringWithoutType("java.math.BigDecimal");
writeAMFString(((BigDecimal)o).toString());
} else {
super.writeObject(o);
}
}
}
就这么简单!然后您就可以使用blazeds获得本机的BigDecimal支持,哇哦!
确保BigDecimal as3类实现IExternalizable
干杯,jb伙计们,检查一下解决方案:
protected function button1_clickHandler(event:MouseEvent):void { var formatter:NumberFormatter = new NumberFormatter(); formatter.precision = 2; formatter.rounding = NumberBaseRoundType.NEAREST; var a:Number = 14.31999999999998; trace(formatter.format(a)); //14.32 } 受保护的功能按钮1\u clickHandler(事件:MouseeEvent):无效 { var格式化程序:NumberFormatter=newnumberformatter(); formatter.precision=2; formatter.rounding=NumberBaseRoundType.NEAREST; 变量a:数字=14.319999998; 跟踪(formatter.format(a));//14.32 }
我为Actionscript客户端移植了BigDecimal的IBM ICU实现。我们的版本添加了一些方便的比较方法 您可以扩展Blaze AMF端点以添加对BigDecimal的序列化支持。请注意,另一个答案中的代码似乎不完整,根据我们的经验,它在生产中无法工作 AMF3假设重复的对象、特征和字符串通过引用发送。序列化时,对象引用表需要保持同步,否则客户端将在反序列化期间丢失这些表的同步,并开始抛出类强制转换错误,或损坏不匹配但强制转换为ok的字段中的数据 以下是更正后的代码:
public void writeObject(final Object o) throws IOException {
if (o instanceof BigDecimal) {
write(kObjectType);
if(!byReference(o)){ // if not previously sent
String s = ((BigDecimal)o).toString();
TraitsInfo ti = new TraitsInfo("java.math.BigDecimal",false,true,0);
writeObjectTraits(ti); // will send traits by reference
writeUTF(s);
writeObjectEnd(); // for your AmfTrace to be correctly indented
}
} else {
super.writeObject(o);
}
}
还有另一种发送类型化对象的方法,它不需要在客户端上外部化。客户端将改为在对象上设置textValue属性:
TraitsInfo ti = new TraitsInfo("java.math.BigDecimal",false,false,1);
ti.addProperty("textValue");
writeObjectTraits(ti);
writeObjectProperty("textValue",s);
无论哪种情况,Actionscript类都需要以下标记:
[RemoteClass(alias="java.math.BigDecimal")]
Actionscript类还需要一个文本属性来匹配您选择发送的将初始化BigDecimal值的文本属性,或者在可外部化对象的情况下,需要两个如下方法:
public function writeExternal(output:IDataOutput):void {
output.writeUTF(this.toString());
}
public function readExternal(input:IDataInput):void {
var s:String = input.readUTF();
setValueFromString(s);
}
public class BigNumberWrapper implements Externalizable {
String stringValue;
String className;
public void readExternal(ObjectInput arg0) throws IOException, ClassNotFoundException {
stringValue = arg0.readUTF();
}
public void writeExternal(ObjectOutput arg0) throws IOException {
arg0.writeUTF(stringValue);
}
public String getStringValue() {
return stringValue;
}
public void setStringValue(String stringValue) {
this.stringValue = stringValue;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
}
TraitsInfo ti = new TraitsInfo("java.math.BigDecimal",false,false,1);
ti.addProperty("textValue");
writeObjectTraits(ti);
writeObjectProperty("textValue",s);
[RemoteClass(alias="java.math.BigDecimal")]
public function writeExternal(output:IDataOutput):void {
output.writeUTF(this.toString());
}
public function readExternal(input:IDataInput):void {
var s:String = input.readUTF();
setValueFromString(s);
}
public class BigNumberProxy extends AbstractProxy {
public BigNumberProxy() {
this(null);
}
public BigNumberProxy(Object defaultInstance) {
super(defaultInstance);
this.setExternalizable(true);
if (defaultInstance != null)
alias = getClassName(defaultInstance);
}
protected String getClassName(Object instance) {
return((BigNumberWrapper)instance).getClassName();
}
public Object createInstance(String className) {
BigNumberWrapper w = new BigNumberWrapper();
w.setClassName(className);
return w;
}
public Object instanceComplete(Object instance) {
String desiredClassName = ((BigNumberWrapper)instance).getClassName();
if(desiredClassName.equals("java.math.BigDecimal"))
return new BigDecimal(((BigNumberWrapper)instance).stringValue);
return null;
}
public String getAlias(Object instance) {
return((BigNumberWrapper)instance).getClassName();
}
}
PropertyProxyRegistry.getRegistry().register(
java.math.BigDecimal.class, new BigNumberProxy());
public class BigNumberWrapper implements Externalizable {
String stringValue;
String className;
public void readExternal(ObjectInput arg0) throws IOException, ClassNotFoundException {
stringValue = arg0.readUTF();
}
public void writeExternal(ObjectOutput arg0) throws IOException {
arg0.writeUTF(stringValue);
}
public String getStringValue() {
return stringValue;
}
public void setStringValue(String stringValue) {
this.stringValue = stringValue;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
}
public function setPrecision(number:Number, precision:int):Number {
precision = Math.pow(10, precision);
const excelFactor : Number = 0.00000001;
number += excelFactor;
return (Math.round(number * precision)/precision);
}