2013-10-25 86 views
1

我试过相当于Michael Meadows EDIT 2,但在VB.NET中得到了不同的结果。 (具体来说两者DoubleDecimal结果600000.0238418580。)获取浮点常量与运行时结果(和VB.NET)相同

我已确定的差与存储到float在C#floatSingle)除法的编译时的精度,(这似乎是更相当于VB.NET在存储到Double时的准确性)以及当您在运行时强制执行分区时会发生什么(这两种语言都毫不意外)。

所以,THREE_FIFTHSvTHREE_FIFTHS提供了asDouble求和不同的结果:

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
六十万:600000.0000000000
Single:599093.4000000000
双:599999.9999886850
十进制:600000.0000000000
vThree五分之二:0.6000000000
六十万:600000.0000000000
单:599093.4000000000
双:600000.0238418580
十进制:600000.0000000000

我的问题是,你能让C#得到一个const float表达式与运行时(和VB.NET)结果的等价物? (即产生相同的结果作为一个vTHREE_FIFTHSTHREE_FIFTHS。)

+0

为什么d这很重要吗?这是一个小小的差异,“float”和“double”意味着代表不精确的事情。 –

回答

3

THREE_FIFTHS具有相同的值,在你的榜样vTHREE_FIFTHS(你可以看到这与BitConverter.GetBytes)。它只是添加到代码中的一个不同之处。

我认为你的区别是由于C#编译器在某些方面处理const s的方式,就好像它们是文字一样。例如。这种操作,但它通常不是没有投不准,是可以的,因为const让编译器看到int小到足以制定出:

const int i = 5; 
byte b = i; 

在你的情况,这意味着它不添加单精度值为双精度值的3/5,但计算双精度值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 
0

它看起来像答案是“不能做”,因为,正如蒂姆·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"))); 
} 

输出:

五分之三:0.6000000000
六十万:600000.0000000000
单:599093.4000000000
双:599999.9999886850
十进制:600000.0000000000
S9A99193F
#333333333333E33F
点 D00000006000000000000000000010000
vThree五分之二:0.6000000000
六十万:600000.0000000000
单:599093.4000000000
双:600000.0238418580
十进制:600000.0000000000
S9A99193F
#000000403333E33F
D00000006000000000000000000010000