获取浮点常量,使其与运行时结果(和VB.NET)相同 [英] Get float constant to be the same the runtime result (and VB.NET)

查看:176
本文介绍了获取浮点常量,使其与运行时结果(和VB.NET)相同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试了与 Michael Meadows EDIT 2 等效的方法,但是在VB.NET中得到了不同的结果. (具体来说,DoubleDecimal结果均为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_FIFTHSvTHREE_FIFTHSasDouble求和提供不同的结果:

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 consts 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆