我在程序中用到了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?或是别的什么原因?有谁碰到过这个问题吗?

解决方案 »

  1.   

    Math.Log(8,2) = 3
    (int)Math.Log(8,2) = 2
    Convert.ToInt32(Math.Log(8,2)) = 3 还真奇怪了,呵呵,关注
      

  2.   

    Math.Log方法肯定不是按我们想法来做的:8=2*2*2计算机求算使用的是数值逼近算法。(比如:牛顿上山法,样条法)求出来不是整数,估计是不到3的浮点数。强转之后精度丢失了。
      

  3.   

    我在2005上面试了一下,结果都是3,可能是bug可能是浮点数的误差,Log的结果变成了2.99999999,做了int就变成2了,floor也是一样的道理,直接显示的时候做了四舍五入,就变成3了
      

  4.   

    谢谢各位,如果Math.Log(8,2)的结果是2.99999999,那么
    int.Parse(Math.Log(8,2).ToString())却返回正确的3又该如何解释呢?
      

  5.   

    你进中断看看Log出来的到底是什么,我在2005里面看结果很清楚是3.0,一点也没有“毛刺”
      

  6.   

    如果你先用double把结果接住,然后再转换Int,结果是不是还是2呢
      

  7.   

    to raulredondo() :
    试过了,完全一样,就是这个:
    (int)((double)Math.Log(8,2))结果还是2
      

  8.   

    这是计算机系统的问题,十进制转二进制再反转回来时出现的问题
    和1-0.9-0.1<>1-0.1-0.9一样
    记得以前VB6里 cint(0.5)=0 cint(1.5)=2 cint(2.5)=2,也是同样的问题
    计算机本身的问题,VS里没有很好的处理,尽量避免这样使用吧
      

  9.   

    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.怎么回事哦?!
      

  10.   

    你只好改用Math.Round了,四舍五入
    不过浮点数转int最好不用(int),因为就算最简单的1+1做多了,结果也会变成不是整数的,总会多一点或者少一点突然想到一点,你先转decimal再转int看看
      

  11.   

    在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>
      

  12.   

    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.
      

  13.   

    你那个b=2.9999999999999999999999999999999999999999999999999999999999999999999999999999999999999;
    不对的,double最多精度是16位double 
     ±5.0 × 10&#8722;324 到 ±1.7 × 10308
     15 到 16 位
     System.Double 
      

  14.   

    >>> 取小于这个值的最大整数
    可以用Math.Floor ...
      

  15.   

    晕,这么多的星竟然无法理解计算机最基本的问题首先 Log(8,2) 的几内表示的值大概是 2.999999999999999.....如果使用 (int)Math.Log(8,2), 那么是做double到int的截断转换也就是是说2后面所有的小数都会被截掉如果是用Convert.ToInt32/ToString()或者其他的转换函数,那么会先做四舍五入处理,然后做格式化处理也就是说 2.999999... 变成 3
      

  16.   

    也就是说 (int) 操作是做截断转换,而函数调用 ToInt32() 是做四舍五入处理
      

  17.   

    floor操作是返回不超过当前值得整数,自然返回2而VS2005中显示也一定是调用了ToString,所以有四舍五入,可以显示3.0不过3.0浮点数的几内表示到是 3.00000....1这样只是Log函数有点精度误差,所以得到了 2.99....
      

  18.   

    我在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了
      

  19.   

    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)));
    ^-^
      

  20.   

    Win2003(64位)....VS2003 下测试...Math.Log(8,2);  //结果3.0
    (int)Math.Log(8,2); //结果3
    Math.Floor(Math.Log(8,2)); //结果3.0莫得楼主说的问题啊....
      

  21.   

    Bug肯定是谈不上了,因为没有谁对浮点数有什么保证。
      

  22.   

    to Sunmast(速马>WPF>WCF>WWF):
    Math.Floor()试过,和显式转换为int是一样的to tiaoci(我挑刺,我快乐):
    小弟非科班出身,初中毕业而已,编程技术是自学的,也没研究过计算机太基础的东西,露拙了别见笑:)谢谢各位参与,现在只有用raulredondo() 所说的先转为decimal然后再转为int的方法了,结帖!