ActionScript 2英寸转毫米计算出现异常结果求助
问题背景
需求是实现英寸转毫米的转换:输入变量k(测试值为1、10、100、1000等),dp表示保留的小数精度(取值为0.00至0.0000000,对应2到7位小数),k19为最终计算结果。在影片剪辑中编写的ActionScript 2代码如下:
k19 = k * 25.4; trace(k19); k19 = int(k19*dp)/dp; trace(k19);
运行后发现,第一次trace结果始终正确,但dp的小数位越多,第二次trace结果越异常,测试案例如下:
k为10,dp为0.00时,k19显示25.4; k为100,dp为0.0000时,k19显示2540; k为100,dp为0.00000时,k19显示-17549.67296; k为1000,dp为0.00000时,k19显示-17549.67296; k为10000,dp为0.00000时,k19显示-3698.03776; k为100000,dp为0.00000时,k19显示5969.29536; k为10,dp为0.0000000时,k19显示-175.4967296。
错误原因
int()函数的32位整数溢出问题
ActionScript 2中的int()函数处理的是32位有符号整数,最大值为2^31-1=2147483647。当dp小数位越多,k19*dp的计算值会急剧增大:比如dp=0.00000(对应5位小数),k19*dp实际是k*25.4 / 0.00000 = k*2540000。当k=100时,这个值是254000000,已经超过32位有符号整数的最大值,导致整数溢出,数值变成负数,后续除以dp自然得到错误结果。精度处理逻辑倒置
你用dp表示保留的小数精度,但代码中k19*dp的逻辑是错误的。正确的精度处理应该是将数值乘以10的n次方(n为保留小数位数),取整后再除以10的n次方,而不是乘以0.0...1。比如保留2位小数,应该乘以100而非0.00。
修正方案
方案1:直接指定保留的小数位数
如果可以直接传入需要保留的小数位数(而非dp参数),代码可写为:
var decimalPlaces:Number = 5; // 要保留的小数位数,例如5位 var multiplier:Number = Math.pow(10, decimalPlaces); k19 = k * 25.4; trace(k19); // 用Math.round替代int,既避免溢出,又实现四舍五入 k19 = Math.round(k19 * multiplier) / multiplier; trace(k19);
方案2:兼容原有的dp参数
如果必须使用dp参数(比如dp=0.00000),可以先计算精度倍数,同时处理浮点数误差:
k19 = k * 25.4; trace(k19); // 计算精度倍数,用Math.round避免浮点数精度问题 var multiplier:Number = Math.round(1 / dp); // 用Math.round替代int,解决溢出和取整逻辑问题 k19 = Math.round(k19 * multiplier) / multiplier; trace(k19);
关键说明:使用Math.round()替代int(),因为Math.round()返回的是64位浮点数类型(ActionScript 2的Number类型),不会有32位整数的溢出问题,同时能实现符合预期的四舍五入取整,而非int()的截断取整。
内容的提问来源于stack exchange,提问作者user20220056

