[英]Get float constant to be the same the runtime result (and VB.NET)
我试过相当于迈克尔梅多斯编辑2 ,但在VB.NET中得到了不同的结果。 (特别是Double
和Decimal
结果都是600000.0238418580。)
我已经确定区别在于存储在C#中的float
中的float
( Single
)除法的编译时精度(这似乎更符合VB.NET在存入Double
时的准确性)以及会发生什么(两者都有)当您强制在运行时进行除法时,语言并不令人惊讶。
因此, THREE_FIFTHS
和vTHREE_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"));
差异突出的结果是:
三分之五: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.