繁体   English   中英

获取浮点常量与运行时结果相同(和VB.NET)

[英]Get float constant to be the same the runtime result (and VB.NET)

我试过相当于迈克尔梅多斯编辑2 ,但在VB.NET中得到了不同的结果。 (特别是DoubleDecimal结果都是600000.0238418580。)

我已经确定区别在于存储在C#中的float中的floatSingle )除法的编译时精度(这似乎更符合VB.NET在存入Double时的准确性)以及会发生什么(两者都有)当您强制在运行时进行除法时,语言并不令人惊讶。

因此, THREE_FIFTHSvTHREE_FIFTHSasDouble求和提供了不同的结果:

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"));

差异突出的结果是:

三分之五:60亿
六十万:600000.0000000000
单身:599093.4000000000
双人间:599999.9999886850
十进制:600000.0000000000
vThree Fifths:0.6000000000
六十万:600000.0000000000
单身:599093.4000000000
双倍:600000.0238418580
十进制:600000.0000000000

我的问题是,你能得到C#来获得一个const float表达式,其表达式与运行时(和VB.NET)相当吗? (即产生一个THREE_FIFTHS ,结果与vTHREE_FIFTHS相同。)

THREE_FIFTHS具有相同的值vTHREE_FIFTHS在你的例子(你可以看到这与BitConverter.GetBytes )。 它只是在代码中添加到double的方式不同。

我认为你的不同之处在于C#编译器在某些方面处理const的方式,就像它们是文字一样。 例如,这个操作虽然通常在没有强制转换的情况下是不允许的,但是可以,因为const让编译器看到int足够小就可以解决:

const int i = 5;
byte b = i;

在您的情况下,这意味着它不会将单精度值3/5添加到double,而是计算双精度值3/5并添加它。 不幸的是,这种额外的“情报”有副作用。 您可以通过将const float作为float存储来解决它,例如:

float f = THREE_FIFTHS;
asDouble += (double) f;

有了这个,两种方法都计算双倍为600000.0238418580

您可以通过这些输出查看有关奇怪性的更多详细信息:

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

看起来答案似乎是“它无法完成”,因为正如Tim S.指出的那样,编译时常量并不是真正的常量,而是在每次使用时实际重新解释。 具体而言,常量的(double)强制转换版本会对运行时结果产生不同的结果。

void Main()
{
        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(GetByteString((float) THREE_FIFTHS));
        Console.WriteLine(GetByteString((double) THREE_FIFTHS));
        Console.WriteLine(GetByteString((decimal) THREE_FIFTHS));

        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"));
        Console.WriteLine(GetByteString((float) vTHREE_FIFTHS));
        Console.WriteLine(GetByteString((double) vTHREE_FIFTHS));
        Console.WriteLine(GetByteString((decimal) vTHREE_FIFTHS));

}

// Define other methods and classes here
string GetByteString(double d)
{
    return "#" + string.Join("", BitConverter.GetBytes(d).Select(b=>b.ToString("X2")));
}
string GetByteString(decimal d)
{
    return "D" + string.Join("", Decimal.GetBits(d).Select(b=>b.ToString("X8")));
}
string GetByteString(float f)
{
    return "S" + string.Join("", BitConverter.GetBytes(f).Select(b=>b.ToString("X2")));
}

输出:

三分之五:60亿
六十万:600000.0000000000
单身:599093.4000000000
双人间:599999.9999886850
十进制:600000.0000000000
S9A99193F
#333333333333E33F
D00000006000000000000000000010000
vThree Fifths:0.6000000000
六十万:600000.0000000000
单身:599093.4000000000
双倍:600000.0238418580
十进制:600000.0000000000
S9A99193F
#000000403333E33F
D00000006000000000000000000010000

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM