簡體   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