请各位大哥帮帮我吧
分析分析是什么原因引起二种方法结果不相同float k1;
int k;//方法一
k1=4.6f;
k1 =(int)(k1 * 10);
MessageBox.Show(k+""); //显示结果为45//方法二
k1=4.6f;
k1 = (k1 * 10);
k = (int)k1;
MessageBox.Show(k+""); //显示结果为46
分析分析是什么原因引起二种方法结果不相同float k1;
int k;//方法一
k1=4.6f;
k1 =(int)(k1 * 10);
MessageBox.Show(k+""); //显示结果为45//方法二
k1=4.6f;
k1 = (k1 * 10);
k = (int)k1;
MessageBox.Show(k+""); //显示结果为46
应该是MessageBox.Show(k1+""); 吗
MessageBox.Show(k.ToString());
没问题了,46
也可以理解,不过为什么一步会出错,就二步就没问题呢,一步到位:k1 =(int)(k1 * 10);
二步实现:k1 = (k1 * 10);
k = (int)k1;
一步到位:k =(int)(k1 * 10);
二步实现:k1 = (k1 * 10);
k = (int)k1;
如果精确,应当返回 2.0000000~ (向偶数舍入)
如果因为精度问题 2.50稍微大了一点,3.000000~
如果小了一点,2.000000~
我是想问为什么结果会不一样
是进行的一样的操作啊一步到位:k =(int)(k1 * 10); //结果K等于45,这个就算是精度问题
二步实现:k1 = (k1 * 10);
k = (int)k1; //结果K等于46,这个和上一种方法有什么不同吗,只不过是把一句写成了二句,结果应该一样啊
没有发现溢出 10改为7、8或者11这样都是一样的
而//方法一
k1=4.6f;
k1 =(int)(k1 * 10);k1*10之后是45.55555 然后在类型转换 当然是45了
MessageBox.Show(k+""); //显示结果为45//方法二
k1=4.6f;
k1 = (k1 * 10);
k = (int)k1;
MessageBox.Show(k+""); //显示结果为46
主要看数据类型的精度和在内存中的存储原理
float k1=4.6f float类型的变量存储的是它的近似值,应该是4.55555555什么之类的(比如是8位)
按你的说法 类型转化会四舍五入才对 为什么是45?
k1 = (k1 * 10); k1*10之后是45.999999 然后在赋值给k1,k1的值是46
k = (int)k1; 对k1进行强制int转换后,取整46
所以输出结果出现不同
发现4.7>46 ,4.8>48,4.5>45
k1*5时4.2〉21,4.8〉29
得出结论:尾数为0,3,4,5,8,9时存为n+0.000000000000001
尾数为1,2,6,7时存为n-0.00000000000000000001。(n为尾数)
等大家检验 。
也就是说,浮点运算之后得到的结果如果赋值给浮点数或者以浮点方式处理(自动或人为指定的),则能够保证精度(当然不能是绝对的精确),如果进行 float 到 int 的强制转换操作则会直接截断小数点后面的部分(小数点后面的数被抛弃了),故如果是 X.99999999999 就是产生严重误差。
float k1;
int k;
请注意你的定义,k1为float,k为int
当执行k=(int)(k1 * 10);时,由于k为int,10会作int处理,会自动先把k1进行转换(由于变量类型的字节数不同,造成转换溢出),然后与10进行运算,最后的结果造成误差。而
k1 = (k1 * 10);
因K1是float,这时会把10示作float类型,不用转换k1后再运算,不会造成溢出误差,其结果是46.0,当把46.0转成整数时,不会造成去尾丢失,所以结果是46.这说明了一个问题,当一个变量和一个像10这个无法直接识别为何数据类型的常数(10可以是int,也可以是float,也可以是double,你说10是什么类型呢?无法确定)进行运算时,系统会先对它们进行类型转换,把它们转成相同类型后再进行运算,到底对哪个进行转换,示目标变量的类型而定.你可以这样测试:
k =(int)(k1 * (float)10);
或k =(int)(k1 * 10.0); 大家说结果会是多少呢?
说对了就来我们微软工作吧!
刚看楼主的贴子9测试过了
float k1;
int k;
请注意你的定义,k1为float,k为int
当执行k=(int)(k1 * 10);时,由于k为int,10会作int处理,会自动先把k1进行转换(由于变量类型的字节数不同,造成转换溢出),然后与10进行运算,最后的结果造成误差。而
k1 = (k1 * 10);
因K1是float,这时会把10示作float类型,不用转换k1后再运算,不会造成溢出误差,其结果是46.0,当把46.0转成整数时,不会造成去尾丢失,所以结果是46.这说明了一个问题,当一个变量和一个像10这个无法直接识别为何数据类型的常数(10可以是int,也可以是float,也可以是double,你说10是什么类型呢?无法确定)进行运算时,系统会先对它们进行类型转换,把它们转成相同类型后再进行运算,到底对哪个进行转换,示目标变量的类型而定.你可以这样测试:
k =(int)(k1 * (float)10);
或k =(int)(k1 * 10.0); 大家说结果会是多少呢?
说对了就来我们微软工作吧!============================================================程序员最忌讳的就是想当然……当执行k=(int)(k1 * 10);时,由于k为int,10会作int处理,会自动先把k1进行转换(由于变量类型的字节数不同,造成转换溢出),然后与10进行运算,最后的结果造成误差。这个纯粹就是胡说八道……
当一个浮点型的数字乘以整型的数字的时候,会自动把整型的转换成浮点型。一般来说:int * int = int;
long * long = long;
long * int = int * long = long;
float * int = int * float = float;
float * float = float;
double * float = float * double = double;而不可能是将浮点型转换成整型,然后按整型计算乘法。你自己一试便知:
float f = 5;
iny k = f * 10;//编译错误,这里需要强制类型转换,因为后面的表达式是浮点型的。
至于这个:k =(int)(k1 * (float)10);
或k =(int)(k1 * 10.0); 你根本就没搞清楚10.0是double!
我确实有没有看清楚就乱说。为消除影响,作下面的更正:附测试代码:float k1;
k1=4.6f;this.Response.Write("1: "+k1.ToString("0.00000000000000000000000000")+"<br>");
this.Response.Write("2: "+((double)k1).ToString("0.00000000000000000000000000")+"<br>");
this.Response.Write("3: "+((k1*10)).ToString("0.0000000000000000000000000000000")+"<br>");
this.Response.Write("4: "+((k1*10d)).ToString("0.0000000000000000000000000000000")+"<br>");
this.Response.Write("5: "+((int)(k1*10)).ToString("0.00000000000000000000")+"<br>");
this.Response.Write("6: "+((int)(k1*10f)).ToString("0.0000000000000000")+"<br>");
this.Response.Write("7: "+((int)(float)(k1*10)).ToString("0.0000000000000000")+"<br>");
this.Response.Write("8: "+((double)(float)(k1*10)).ToString("0.00000000000000000000000000")+"<br>");this.Response.Write("<br>");this.Response.Write("9: "+(k1-0.1).ToString("0.000000000000000000000")+"<br>");
this.Response.Write("10: "+(k1-0.1f).ToString("0.000000000000000000000")+"<br>");
this.Response.Write("11: "+((float)(k1-0.1)).ToString("0.0000000000000000000000")+"<br>");this.Response.Write("<br>");this.Response.Write("12: "+((int)(float)5.999999).ToString("0.00000000000000000000000000")+"<br>");
this.Response.Write("13: "+((int)(float)5.9999999).ToString("0.00000000000000000000000000")+"<br>");
this.Response.Write("14: "+((int)5.9999999).ToString("0.00000000000000000000000000")+"<br>");
this.Response.Write("15: "+((double)(float)5.9999999).ToString("0.00000000000000000000000000")+"<br>");
以上代码的运行结果:1: 4.60000000000000000000000000
2: 4.59999990463257000000000000
3: 46.0000000000000000000000000000000
4: 45.9999990463257000000000000000000
5: 45.00000000000000000000
6: 45.0000000000000000
7: 46.0000000000000000
8: 46.000000000000000000000000009: 4.499999904632570000000
10: 4.500000000000000000000
11: 4.500000000000000000000012: 5.00000000000000000000000000
13: 6.00000000000000000000000000
14: 5.00000000000000000000000000
15: 6.00000000000000000000000000
为什么会是这样的呢?
原因就是由于float的精度,把float转成double后,可以看出它只是近似等于4.6,而为4.59999990463257000000000000,当它*10显式转为int时,会以double的形式转换,即:(int)45.9999990463257,当然是45了。但是,用(int)(float)(k1*10)或k1=k1*10后转换,将会以float的形式显式转为int,结果是46。float的精度问题不但在乘法中存在,在其他运算中也是存的。以上的代码也证实了这点。所以,如果没有特别要求的话,数据运算还是用double类型为好。对于浮点数运算的结果是double,还是float,微软是这样说的:
可在一个表达式中兼用数值整型和浮点型。在此情况下,整型将转换为浮点型。根据以下规则计算表达式:
如果一种浮点型为 double,表达式计算为 double 类型(在关系表达式或布尔表达式情况下为 bool)。
如果表达式中不存在 double,它将计算为 float 类型(在关系表达式或布尔表达式中为 bool)。
首先,我被你骂是我活该!
但
float * float = float;
float * int = int * float = float;
好像也不一定呀!
有时好像会是double的。但“至少”会是float。你如何解释(int)(4.6f*10)=45,而(int)(float)(4.6f*10)=46呢?
而且,即使(int)(4.6f*10f)也是等于45,如何解释呢???请看下面的说法:
如果二元运算符的一个操作数为浮点型,则另一个操作数必须为整型或浮点型,并且运算按下面这样计算:如果一个操作数为整型,则该操作数转换为另一个操作数的浮点型。然后,如果任一操作数的类型为 double,则另一个操作数转换为 double。至少用 double 范围和精度执行运算,结果的类型为 double(对于关系运算符则为 bool)。 否则,至少用 float 范围和精度执行运算,结果的类型为 float(对于关系运算符则为 bool)。
在C#里(其实是微软所有的语言里,其它公司的语言不太清楚)
四舍五入实际上是按照国际标准的“四舍六入五成双”原则来进行的
也就是说舍或者入以后,要保证最后一位是偶数
所以
Math.Round(2.5, 0) = 2
Math.Round(3.5, 0) = 4
嘿嘿..............
微软将(4.6f*10)的结果作了优化。而(int)(4.6f*10)被当作一个表达式处理,还没来得及优化就转换成int了。
微软将(4.6f*10)的结果作了优化。而(int)(4.6f*10)被当作一个表达式处理,还没来得及优化就转换成int了。==========================================================这样也不能说明楼主的情况。
有两个猜测:猜测一,是生成的IL不同,IL的JIT编译优化上面也许出了问题即:k1 = (k1 * 10);
优化成了:
k1 *= 10f;而
k1 =(int)(k1 * 10);
也许是优化成:
kk = k1 * 10;
k1 = (int) kk;
这样两个运算的二进制代码是不同的。不过下面这个猜测也许更可靠:在float在进行计算的时候,.NET为了保持较高的计算精度,会自动将他们转成double来计算,在计算完后再转换回去。
即:
k1 = (k1 * 10);
实际上是:
k1 = (float) ( (double) k1 * (double) 10 );而
k1 =(int)(k1 * 10);
则会优化成:
k1 = (int) ( (double) k1 * (double) 10 );从double->float->int之间的转换导致了这个问题。
首先,我被你骂是我活该!
但
float * float = float;
float * int = int * float = float;
好像也不一定呀!
有时好像会是double的。但“至少”会是float。========================================================
这个我想过,但是如果是double:
k1 = k1 * 10就会是语法错误,因为float不能隐式的转换成double。
this.Response.Write("3: "+((k1*10)).ToString("0.0000000000000000000000000000000")+"<br>");
它的结果是:3: 46.0000000000000000000000000000000,可见,(4.6f*10)的结果是46,即这个结果是float,但是(int)(4.6f*10)的结果是45,即这种情况下)(4.6f*10)的结果是double的,为什么会这样呢???
C# 代码(方法 Main() )
static void Main()
{
float k1;
int k;
k1 = 4.6f;
k = (int)(k1 * 10);
Console.WriteLine(k);
k1 = 4.6f;
k1 = k1 * 10;
k = (int)k1;
Console.WriteLine(k);
Console.ReadLine();
}IL 代码(方法 Main).method private hidebysig static void Main() cil managed
{
.entrypoint
// 代码大小 54 (0x36)
.maxstack 2
.locals init (float32 V_0, // 这里应该是变量声明吧?
int32 V_1)
IL_0000: nop
IL_0001: ldc.r4 4.5999999 // 4.6f; 看看存成什么了
IL_0006: stloc.0 // 保存变量到 k1
IL_0007: ldloc.0 // 读取变量 k1
IL_0008: ldc.r4 10. // 将 10 转换为实形 10 -> 10.
IL_000d: mul // 乘法 4.59999 × 10. -> 45.999
IL_000e: conv.i4 // 结果直接转换为整型 -> 45
IL_000f: stloc.1 // 保存变量到 k
IL_0010: ldloc.1 // 读取变量 k
IL_0011: call void [mscorlib]System.Console::WriteLine(int32) // 输出
IL_0016: nop
IL_0017: ldc.r4 4.5999999 // 4.6f; 看看到底是什么
IL_001c: stloc.0 // 保存到变量 k1
IL_001d: ldloc.0 // 读取变量 k1
IL_001f: ldc.r4 10. // 将 10 转换为实形 10.
IL_0023: mul // 乘法 45.9999
IL_0024: stloc.0 // 保存变量到 k1 45.9999
IL_0025: ldloc.0 // 读取变量 k1
IL_0026: conv.i4 // 转换为整型
IL_0028: stloc.1 // 保存到 k
IL_0029: ldloc.1 // 读取 k
IL_0029: call void [mscorlib]System.Console::WriteLine(int32) // 输出
IL_002e: nop
IL_002f: call string [mscorlib]System.Console::ReadLine()
IL_0034: pop
IL_0035: ret
} // end of method Tester::Main系统处理浮点数时,会处理精度问题,例如调用 System.Console::WriteLine(float32) 所以输出 46;转换为整型时,精度丢失,所以为 45