获取浮点常量,使其与运行时结果(和VB.NET)相同 [英] Get float constant to be the same the runtime result (and VB.NET)
问题描述
我尝试了与 Michael Meadows EDIT 2 等效的方法,但是在VB.NET中得到了不同的结果. (具体来说,Double
和Decimal
结果均为600000.0238418580.)
I tried the equivalent of Michael Meadows EDIT 2, but in VB.NET and got a different result. (Specifically both the Double
and Decimal
results were 600000.0238418580.)
我已经确定差异在于C#中存储在float
中的float
(Single
)除法的编译时精度(当存储到float
中时,这似乎更等同于VB.NET的精度). Double
),以及当您强制在运行时进行除法时会发生两种语言(不足为奇).
I have determined the difference is with the compile-time accuracy of a float
(Single
) division stored into a float
in C#, (which seems to be more equivalent to VB.NET's accuracy when storing into a Double
) and what happens (in both languages unsurprisingly) when you force the division to occur at runtime.
因此,THREE_FIFTHS
和vTHREE_FIFTHS
为asDouble
求和提供不同的结果:
So, THREE_FIFTHS
and vTHREE_FIFTHS
provide different results for the asDouble
summation:
const int ONE_MILLION = 1000000;
float THREEsng = 3f;
float FIVEsng = 5f;
float vTHREE_FIFTHS = THREEsng / FIVEsng;
const float THREE_FIFTHS = 3f / 5f;
Console.WriteLine("Three Fifths: {0}", THREE_FIFTHS.ToString("F10"));
float asSingle = 0f;
double asDouble = 0d;
decimal asDecimal = 0M;
for (int i = 0; i < ONE_MILLION; i++)
{
asSingle += (float) THREE_FIFTHS;
asDouble += (double) THREE_FIFTHS;
asDecimal += (decimal) THREE_FIFTHS;
}
Console.WriteLine("Six Hundred Thousand: {0:F10}", THREE_FIFTHS * ONE_MILLION);
Console.WriteLine("Single: {0}", asSingle.ToString("F10"));
Console.WriteLine("Double: {0}", asDouble.ToString("F10"));
Console.WriteLine("Decimal: {0}", asDecimal.ToString("F10"));
Console.WriteLine("vThree Fifths: {0}", vTHREE_FIFTHS.ToString("F10"));
asSingle = 0f;
asDouble = 0d;
asDecimal = 0M;
for (int i = 0; i < ONE_MILLION; i++)
{
asSingle += (float) vTHREE_FIFTHS;
asDouble += (double) vTHREE_FIFTHS;
asDecimal += (decimal) vTHREE_FIFTHS;
}
Console.WriteLine("Six Hundred Thousand: {0:F10}", vTHREE_FIFTHS * ONE_MILLION);
Console.WriteLine("Single: {0}", asSingle.ToString("F10"));
Console.WriteLine("Double: {0}", asDouble.ToString("F10"));
Console.WriteLine("Decimal: {0}", asDecimal.ToString("F10"));
具有突出显示的结果是:
五分之三:0.6000000000
60万:600000.0000000000
单身:599093.4000000000
双人间:599999.9999886850
十进制:600000.0000000000
v五分之三:0.6000000000
60万:600000.0000000000
单身:599093.4000000000
双人间:600000.0238418580
十进制:600000.0000000000
Three Fifths: 0.6000000000
Six Hundred Thousand: 600000.0000000000
Single: 599093.4000000000
Double: 599999.9999886850
Decimal: 600000.0000000000
vThree Fifths: 0.6000000000
Six Hundred Thousand: 600000.0000000000
Single: 599093.4000000000
Double: 600000.0238418580
Decimal: 600000.0000000000
我的问题是,您能用C#获得与运行时(和VB.NET)结果等效的const float
表达式吗? (即生成与vTHREE_FIFTHS
相同结果的THREE_FIFTHS
.)
My question is, can you get C# to get a const float
expression with the equivalent of the runtime (and VB.NET) result? (I.e. produce a THREE_FIFTHS
with the same results as vTHREE_FIFTHS
.)
推荐答案
THREE_FIFTHS
与示例中的vTHREE_FIFTHS
具有相同的值(您可以在BitConverter.GetBytes
中看到此值).唯一不同的是,它被添加到代码中的double中.
THREE_FIFTHS
has the same value as vTHREE_FIFTHS
in your example (you can see this with BitConverter.GetBytes
). It only differs in the way it is added to a double in your code.
我认为您的与众不同之处是C#编译器在某些方面将const
视为文字的方式.例如.尽管通常不允许不进行强制转换,但此操作是可以的,因为const
可使编译器看到int
足够小以解决该问题:
I think your difference is due to the way that the C# compiler handles const
s as if they were literals, in some ways. E.g. this operation, though it's normally not allowed without a cast, is ok because the const
lets the compiler see that the int
is small enough to work out:
const int i = 5;
byte b = i;
在您的情况下,这意味着它不会将单精度值3/5与双精度值相加,而是会计算双精度值3/5并将其相加.不幸的是,这种额外的智能"具有副作用.您可以通过将const float
首先存储为float
来解决它,例如:
In your case, this means that it doesn't add the single-precision value 3/5 to the double, but calculates the double value 3/5 and adds that. Unfortunately this extra "intelligence" has a side effect. You can get around it by storing the const float
as a float
first, e.g.:
float f = THREE_FIFTHS;
asDouble += (double) f;
通过这种方式,两种方法都将double计算为600000.0238418580
.
With this, both ways calculate the double as 600000.0238418580
.
通过这些输出,您可以看到有关怪异的更多详细信息:
You can see more detail on the weirdness with these outputs:
string GetByteString(double d)
{
return string.Join("", BitConverter.GetBytes(d).Select(b=>b.ToString("X2")));
}
string GetByteString(float f)
{
return string.Join("", BitConverter.GetBytes(f).Select(b=>b.ToString("X2")));
}
double vd = vTHREE_FIFTHS;
double d = THREE_FIFTHS;
const double cd = THREE_FIFTHS;
float f = THREE_FIFTHS;
const double cd2 = 3d / 5d;
double d2 = 3d / 5d;
double df = f;
// doubles
Console.WriteLine(GetByteString((double)THREE_FIFTHS));
Console.WriteLine(GetByteString(vd));
Console.WriteLine(GetByteString(df));
Console.WriteLine(GetByteString(d));
Console.WriteLine(GetByteString(cd));
Console.WriteLine(GetByteString(cd2));
Console.WriteLine(GetByteString(d2));
// floats
Console.WriteLine(GetByteString(f));
Console.WriteLine(GetByteString(vTHREE_FIFTHS));
Console.WriteLine(GetByteString(THREE_FIFTHS));
prints this:
333333333333E33F
000000403333E33F <-- these are the only ones that were actually
000000403333E33F <-- converted from 32-bit float values to doubles
333333333333E33F
333333333333E33F
333333333333E33F
333333333333E33F
9A99193F
9A99193F
9A99193F
这篇关于获取浮点常量,使其与运行时结果(和VB.NET)相同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!