gpt4 book ai didi

c# - 为什么当甚至 VS 说它是多余的时,这个转换会改变结果?

转载 作者:太空狗 更新时间:2023-10-29 23:05:20 25 4
gpt4 key购买 nike

------ 请跳到上次更新--------------

我发现了一个错误(在我的代码中),我正在努力找到对它的正确理解。

这一切都归结为调试时从即时窗口中获取的这个特定示例:

x
0.00023569075
dx
-0.000235702712
x+dx+1f < 1f
true

(float) (x+dx+1f) < 1f
false

x 和 dx 都是 float 类型。那么为什么当我进行强制转换时 bool 值不同呢?

在我的实际代码中:
x+=dx
if( x+1f < 1f) // Add a one to truncate really small negative values (originally testing x < 0)
{
// do actions accordingly

// Later doing
x+=1; // Where x<1 has to be true, therefore we have to get rid of really small negatives where x+=1 will give x==1 as true and x<1 false.
}

但我现在正在尝试 Actor 阵容
x+=dx;
if( (float)( x+1f) < 1f) // Add a one to truncate really small negative values (originally testing x < 0)
{
// do actions accordingly
// Later doing
x+=1; // Where x<1 has to be true, therefore we have to get rid of really small negatives where x+=1 will give x==1 as true and x<1 false.
}

Visual Studio 说类型转换是多余的,但如果没有它,它确实会得到一个错误的肯定,因为直接窗口还告诉我什么时候:
x+dx+1f < 1f
true

我目前正在运行我的代码,看看我是否再次遇到类型转换的错误,一旦我被说服,我会立即更新。

与此同时,我希望有人能弄清楚这里发生了什么?我可以期待 Actor 做些什么吗?

更新 - 变量
我的变量 x 和 dx 是 Vector2 (Xna/monogame) 的组件。
所以在代码中你应该阅读
Vector2 coord; // the x (and y) components are floats.
Vector2 ds;
coord.X // where it says x
ds.X // where it says dx

我认为这无关紧要,但也许确实如此。

更新 2 - 删除上面的例子

看到 Actor 确实改变了结果我做了这个简单的演示
class Program
{
static void Main(string[] args)
{
float a = -2.98023224E-08f; // Just a small negative number i picked...

Console.WriteLine(((a + 1f) < 1f) ? "true" : "false"); //true

Console.WriteLine(((float)(a + 1f) < 1f) ? "true":"false"); //false

// Visual Studio Community 2015 marks the above cast as redundant
// but its clearly something fishy going on!

Console.Read();
}
}

那么,即使 VS 说它是多余的,为什么这个转换会改变结果?

最佳答案

我不知道你是如何声明变量的,但是分配发布到变量的静态值会使这些变量成为 double类型,不是 float .如您所知,double类型具有比 float 更大的精度.

这是一个测试:

var x = 0.00023569075;
var dx = -0.000235702712;
Console.WriteLine(x.GetType()); //result: System.Double
Console.WriteLine(dx.GetType()); //result: System.Double

当然,当添加两个 double 时s 和 float ,结果是 double ,这就是为什么第一个条件返回 true :
Console.WriteLine(x+dx+1f < 1f); //returns true
Console.WriteLine(x+dx+1f); //returns 0.999999988038

但是当你把它转换到 float ,发生截断并且结果不再正确,这就是您的第二个条件返回 false 的原因:
Console.WriteLine((float)(x+dx+1f) < 1f); //returns false
Console.WriteLine((float)(x+dx+1f)); //returns 1

更新:当你的变量是 float ,截断在这里起作用。请记住 float 的最大精度只有 7 位数字,并且您分配的数字要多得多,因此会发生截断并导致您看到的结果不准确。

在您的原始问题中,以下是截断值的方式:
float x = 0.00023569075f;
float dx = -0.000235702712f;
Console.WriteLine(x); //0.0002356907 last digit lost
Console.WriteLine(dx); //-0.0002357027 last two digits lost
Console.WriteLine((x + dx)); //-1.196167E-08
Console.WriteLine((x + dx + 1f)); //1

最后结果是 1的原因应该是显而易见的。添加 x的结果和 dx-1.196167E-08 ( -0.00000001196167 ) 有 7 位数字,可以放入 float .现在添加 1使它 0.99999998803833有 14 位数字,不能放入 float所以它被截断并四舍五入为 1当存储在 float 中时.

同样的事情发生在您的更新 2 中。值 -2.98023224E-08f有 9 位数字,所以它被截断为 -2.980232E-08 ( -0.00000002980232 )。再次添加 1做到这一点 0.99999997019768它被截断并四舍五入为 1 :
float a = -2.98023224E-08f;
Console.WriteLine(a); //-2.980232E-08 last two digits lost
Console.WriteLine(a + 1f); //1

更新 2 Chris 评论说计算是以更高的精度完成的,这是绝对正确的,但这并不能解释不应受其影响的结果。是 a + 1f计算以更高的精度完成,但因为两个操作数都是 float ,计算结果会自动转换为 float .手动将结果转换为 float应该是多余的,不应该改变结果。更重要的是,它不会强制在 float 处进行计算。精确。是的,我们仍然得到这些结果:
Console.WriteLine(a + 1f); //1
Console.WriteLine(a + 1f < 1f); //True
Console.WriteLine((float)(a + 1f) < 1f); //False

由于与 Chris 进行了很好的辩论以及在各种机器上进行了大量测试,我想我对正在发生的事情有了更好的了解。

当我们读到:

Floating-point operations may be performed with higher precision than the result type of the operation



这里的操作一词不仅是计算(在我们的示例中为加法),还包括比较(在我们的示例中为小于)。所以在上面的第二行中,整个 a + 1f < 1f以更高的精度完成:添加值 -2.98023224E-08f ( -0.0000000298023224 ) 到 1结果 0.9999999701976776然后将其与 1f 进行比较显然返回 true :
Console.WriteLine(a + 1f < 1f); //True

在任何时候都没有任何类型转换到 float ,因为比较的结果是 bool .

然而,在第一行,我们只是简单地打印了计算结果 a+1f ,并且因为两个操作数都是 float ,结果会自动转换为 float这导致它被截断并四舍五入为 1 :
Console.WriteLine(a + 1f); //1

现在最大的问题是关于第三行。这次的不同之处在于,强制转换强制将计算结果向下转换为浮点数,从而将其截断并四舍五入为 1然后将其与 1f 进行比较.比较仍然以更高的精度进行,但现在没有关系,因为类型转换已经改变了计算结果:
Console.WriteLine((float)(a + 1f) < 1f); //False

所以这里的转换导致两个操作(加法和比较)分开进行。没有强制转换,步骤是:添加、比较、打印。使用强制转换,步骤是:添加、强制转换、比较、打印。这两个操作仍然以更高的精度完成,因为类型转换不会影响它。

也许 Visual Studio 说转换是多余的,因为它没有考虑操作是否会以更高的精度完成。

关于c# - 为什么当甚至 VS 说它是多余的时,这个转换会改变结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45255199/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com