关于数据类型转换的一个奇怪问题,有人知道原因吗?

webdiyer 2006-02-25 04:48:31
我在程序中用到了Math.Log()这个求对数的方法,现在出现一个无法理解的问题:

Math.Log(8,2); //结果是正确的值:3
(int)Math.Log(8,2); //结果竟是2 ???
Math.Floor(Math.Log(8,2)); //也是2 ??

用其它数值测试均没有上面碰到的这种问题,比如

(int)Math.Log(4,2)和Math.Log(4,2)结果都是2,Math.Log(16,2)和 (int)Math.Log(16,2) 结果都是4,Math.Log(32,2)和(int)Math.Log(32,2)结果都是5,只有(int)Math.Log(8,2)或Math.Floor(Math.Log(8,2));输出的值不正确,百思不得其解,在同事的机器上测试结果也一样,应该不是机器的问题了,难道是.net的bug?或是别的什么原因?有谁碰到过这个问题吗?
...全文
376 26 打赏 收藏 转发到动态 举报
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
Ivony 2006-02-26
  • 打赏
  • 举报
回复
Bug肯定是谈不上了,因为没有谁对浮点数有什么保证。
FrankWin 2006-02-26
  • 打赏
  • 举报
回复
为什么有的机器可以重现,有的却重现不了?
webdiyer 2006-02-26
  • 打赏
  • 举报
回复
to Sunmast(速马>WPF>WCF>WWF):
Math.Floor()试过,和显式转换为int是一样的

to tiaoci(我挑刺,我快乐):
小弟非科班出身,初中毕业而已,编程技术是自学的,也没研究过计算机太基础的东西,露拙了别见笑:)

谢谢各位参与,现在只有用raulredondo() 所说的先转为decimal然后再转为int的方法了,结帖!
ruodeer 2006-02-26
  • 打赏
  • 举报
回复
函数本身写的毛病?
yeerh 2006-02-25
  • 打赏
  • 举报
回复
Win2003(64位)....VS2003 下测试...

Math.Log(8,2); //结果3.0
(int)Math.Log(8,2); //结果3
Math.Floor(Math.Log(8,2)); //结果3.0

莫得楼主说的问题啊....

chentianfen 2006-02-25
  • 打赏
  • 举报
回复
Math.Log(double a, double newBase)是调用这个方法的:
public static double Log(double a, double newBase)
{
return (Math.Log(a) / Math.Log(newBase));
}
大家一看问题出在哪了,我们其实可以这样做:
Decimal m = Convert.ToDecimal(Math.Log( 8 ));
Decimal n = Convert.ToDecimal(Math.Log( 2 ));
Console.WriteLine( Convert.ToDecimal(m / n ));
Console.WriteLine( (Math.Log(8) / Math.Log(2)));
^-^
tiaoci 2006-02-25
  • 打赏
  • 举报
回复
这儿给一毛,那儿给一毛,

老太太,给钱吧,你呐 :)
raulredondo 2006-02-25
  • 打赏
  • 举报
回复
我在2005上面试了一下
double d = 2.999999999999999; 一共16位,也就是double的精度极限
int i = (int)d;
int j = Convert.ToInt32(d);
MessageBox.Show(d.ToString() + "\n" + i.ToString() + "\n" + j.ToString());

显示的是3 2 3

再多一个9就是3 3 3了
tiaoci 2006-02-25
  • 打赏
  • 举报
回复
floor操作是返回不超过当前值得整数,自然返回2

而VS2005中显示也一定是调用了ToString,所以有四舍五入,可以显示3.0

不过3.0浮点数的几内表示到是 3.00000....1这样

只是Log函数有点精度误差,所以得到了 2.99....
tiaoci 2006-02-25
  • 打赏
  • 举报
回复
也就是说 (int) 操作是做截断转换,

而函数调用 ToInt32() 是做四舍五入处理
tiaoci 2006-02-25
  • 打赏
  • 举报
回复
晕,这么多的星竟然无法理解计算机最基本的问题

首先 Log(8,2) 的几内表示的值大概是 2.999999999999999.....

如果使用 (int)Math.Log(8,2), 那么是做double到int的截断转换

也就是是说2后面所有的小数都会被截掉

如果是用Convert.ToInt32/ToString()或者其他的转换函数,

那么会先做四舍五入处理,然后做格式化处理

也就是说 2.999999... 变成 3
速马 2006-02-25
  • 打赏
  • 举报
回复
>>> 取小于这个值的最大整数
可以用Math.Floor ...
raulredondo 2006-02-25
  • 打赏
  • 举报
回复
你那个b=2.9999999999999999999999999999999999999999999999999999999999999999999999999999999999999;
不对的,double最多精度是16位

double
±5.0 × 10−324 到 ±1.7 × 10308
15 到 16 位
System.Double
webdiyer 2006-02-25
  • 打赏
  • 举报
回复
to raulredondo() :

不能用Math.Round()方法,因为我要取小于这个值的最大整数,转为decimal后再转为int确实对了!这怎么回事??不过这样对性能会有副作用,因为我是在一个循环中用这个方法的,刚才又试了一下,下面的测试竟然通过了,看来确实是数值精度的问题:

[Test]
public void ATest()
{
double b=2.9999999999999999999999999999999999999999999999999999999999999999999999999999999999999;
Assert.AreEqual((int)b,3);
}

1 succeeded, 0 failed, 0 skipped, took 0.09 seconds.
webdiyer 2006-02-25
  • 打赏
  • 举报
回复
在vs.net 2003中调试了,也是3.0,这是单元测试代码:


[Test]
public void ATest()
{
double b=Math.Log(8,2); //这里设了断点
Assert.AreEqual((int)b,3);
}

在断点中能看出变量b=3.0,但测试结果却失败了:
expected: <2>
but was: <3>
raulredondo 2006-02-25
  • 打赏
  • 举报
回复
你只好改用Math.Round了,四舍五入
不过浮点数转int最好不用(int),因为就算最简单的1+1做多了,结果也会变成不是整数的,总会多一点或者少一点

突然想到一点,你先转decimal再转int看看
ztqye 2006-02-25
  • 打赏
  • 举报
回复
double i=Math.Log(8,2);
int k=(int)Math.Log(8,2);
double l=Math.Floor(Math.Log(8,2));
Console.Read();
我在VS2003里面得到的是正确答案啊,都是3.怎么回事哦?!
我是丁学 2006-02-25
  • 打赏
  • 举报
回复
这是计算机系统的问题,十进制转二进制再反转回来时出现的问题
和1-0.9-0.1<>1-0.1-0.9一样
记得以前VB6里 cint(0.5)=0 cint(1.5)=2 cint(2.5)=2,也是同样的问题
计算机本身的问题,VS里没有很好的处理,尽量避免这样使用吧
webdiyer 2006-02-25
  • 打赏
  • 举报
回复
to raulredondo() :
试过了,完全一样,就是这个:
(int)((double)Math.Log(8,2))

结果还是2
raulredondo 2006-02-25
  • 打赏
  • 举报
回复
如果你先用double把结果接住,然后再转换Int,结果是不是还是2呢
加载更多回复(6)

110,535

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧