Actionscript 3 如何修复浮点不精确的输出?

Actionscript 3 如何修复浮点不精确的输出?,actionscript-3,algorithm,language-agnostic,math,floating-point,Actionscript 3,Algorithm,Language Agnostic,Math,Floating Point,我正在进行一些浮点运算,最终得到以下数字: -0.5 -0.4 -0.3000000000000000004 -0.2000000000000000004 -0.1000000000000000003 1.10E-16 0.1 0.2 0.30000000000000000004 0.4 0.5 算法如下所示: var inc:Number = nextMultiple(min, stepSize); trace(String(inc)); private function nextMult

我正在进行一些浮点运算,最终得到以下数字:

-0.5
-0.4
-0.3000000000000000004
-0.2000000000000000004
-0.1000000000000000003
1.10E-16
0.1
0.2
0.30000000000000000004
0.4
0.5
算法如下所示:

var inc:Number = nextMultiple(min, stepSize);
trace(String(inc));

private function nextMultiple(x:Number, y:Number) {
    return Math.ceil(x/y)*y;
}
我理解浮点不能总是用一个字节准确地表示。e、 g 1/3。我还知道我的步长为0.1。如果我有步长,我怎样才能得到正确的输出

奇怪的是,这是我第一次遇到这种问题。
也许我玩浮点数不够。

正如你所认识到的,二进制数的有限浮点数精度是你的问题。解决这个问题的一种方法是不做浮点运算。将问题转换为整数,然后再转换回输出。

如果您使用的是具有舍入函数的语言,则可以使用该语言

编辑

为了回应关于舍入的评论,这里有一个c#的示例:

float值=1.0F;
对于(int i=0;i<20;i++)
{
数值-=0.1F;
Console.WriteLine(Math.Round(value,1.ToString()+”:“+value.ToString());
}
结果是:

0.9:0.9

0.8:0.8

0.7:0.699999

0.6:0.599999

(等)


舍入确实解决了精度问题。我并不是说它比做整数然后除以10好,只是说它行得通。

对于你的具体问题,先从-5数到5,再除以10,然后再实际使用该值进行计算。

一个语言不可知的解决方案是将你的数字存储为整数步数,考虑到你知道你的步长,而不是浮点数

一个非语言不可知的解决方案是找出您的语言的实现是什么


要么使用整数而不是浮点类型,要么使用浮点类型,其中“点”是小数点(例如在.NET中)。

我做了以下操作

var digitsNbr:Number = Math.abs(Math.ceil(((Math.log(stepSize) / Math.log(10))) + 1));      
tickTxt.text = String(inc.toPrecision(digitsNbr));
这不是很有效,但我没有很多步骤

======
我应该将步数的nbr作为int,然后乘以步数…

如果您没有printf,或者如果步数不只是10的幂(例如,如果您想四舍五入到最接近的0.2),那么听起来您需要一个量化器:

q(x,u)=u*地板(x/u+0.5)

“u”是步长(在您的情况下为0.1),floor()查找不大于其输入的最大整数,“+0.5”将四舍五入到最接近的整数

基本上,你除以步长,四舍五入到最接近的整数,然后乘以步长


编辑:哦,没关系,你基本上是这样做的&它乘以u的步骤是引入舍入误差。

简单地缩放数字以获得整数,然后进行数学运算并将其缩放回浮点数显示:

//this will round to 3 decimal places var NUM_SCALE = 1000; function scaleUpNumber(n) { return (Math.floor(n * NUM_SCALE)); } function scaleDnNumber(n) { return (n / NUM_SCALE); } var answ = scaleUpNumber(2.1) - scaleUpNumber(3.001); alert(scaleDnNumber(answ)); // displays: -0.901 //这将四舍五入到小数点后3位 var NUM_SCALE=1000; 函数scaleUpNumber(n){ 返回值(数学下限(n*NUM_刻度)); } 函数scaleDnNumber(n){ 返回(n/NUM\u刻度); } var answ=比例编号(2.1)-比例编号(3.001); 警报(缩放编号(answ));//显示:-0.901 更改NUM_比例以增加/减少decimap位置


|/|ax

这有点违反直觉,但我测试了它,它工作正常(AS3中的示例):

所以我加上的唯一一件事就是把
y
乘以10,然后除以10。不是通用的解决方案,但适用于您的步长


[编辑:]这里的逻辑似乎是,你乘以一个足够大的数字,这样最后的小数位数就“从刻度上掉下来”,然后再除以得到一个四舍五入的数字。也就是说,上面使用Math.round()的示例可读性更好,因为代码明确说明了传入的数字将发生什么。

如果您的语言支持,最好使用十进制数据类型。许多语言中都添加了小数来解决这个问题。

我听说它速度较慢(但我没有使用-1)。你能把一个浮点数四舍五入到一个浮点数吗?我经常看到int-round(float)。你当然可以在.NET中看到(从技术上讲,是双精度的)。您可以指定要舍入到的小数位数。舍入没有帮助-得到的舍入值仍然具有与浮点或双精度相同的不精确性。@Adam-不是这样(代表.NET)。Math.Round(0.6999999,1)将返回0.7。但是,每种语言都有一个合适的浮点格式。是的,任何语言都应该有一个。我要指定,有理数没有任何东西可以准确地表示1/3。i、 e.3*(1/3)=0.99999…在基数2中,不可能完美地表示0.1。@BradGilbert基数3可以。
var digitsNbr:Number = Math.abs(Math.ceil(((Math.log(stepSize) / Math.log(10))) + 1));      
tickTxt.text = String(inc.toPrecision(digitsNbr));
//this will round to 3 decimal places var NUM_SCALE = 1000; function scaleUpNumber(n) { return (Math.floor(n * NUM_SCALE)); } function scaleDnNumber(n) { return (n / NUM_SCALE); } var answ = scaleUpNumber(2.1) - scaleUpNumber(3.001); alert(scaleDnNumber(answ)); // displays: -0.901
var inc:Number = nextMultiple(min, stepSize);
trace(String(inc));

private function nextMultiple(x:Number, y:Number) {
    return Math.ceil(x/y)*(y*10)/10;
}