日期:2014-05-18  浏览次数:20871 次

[高手请进]-疑似算法精度的问题-梁哥 影子 石头等等 都快来吧
昨天有个朋友发的一个贴 求解
59(X + X平方 + X立方 + X四次方 + X五次方)+1250*X五次方=1000 求解X
我用2分查找的思路做了下来 
SQL code
-- =========================================
-- -----------t_mac 小编-------------
   ---希望有天成为大虾---- 
-- =========================================

create function f_pk(@n float)/*这个函数用来返回59*(@mid + power(@mid,2) + power(@mid,3) + power(@mid,4) + power(@mid,5))+1250* power(@mid,5)每次算出来的值*/
 returns float
 as
 begin 
 declare @mid float
 set @mid=@n
 return 59*(@mid + power(@mid,2) + power(@mid,3) + power(@mid,4) + power(@mid,5))+1250* power(@mid,5)
 end
 go
declare @n1 float, @n2 float, @mid float--实现2分查找(具体算法不说了)
set @n1=0/*答案一定在0和1之间 具体我已经在http://topic.csdn.net/u/20090624/21/e1a1bba4-3190-4908-aa8f-4f564693109d.html分析过了*/
set @n2=1
while (@n1< @n2)
begin 
 set @mid=(@n1+@n2)/2
  print dbo.f_pk(@mid)--调用函数,便于观察运行情况
  if( 59*(@mid + power(@mid,2) + power(@mid,3) + power(@mid,4) + power(@mid,5))+1250* power(@mid,5)=1000)
  break;
  if(59*(@mid + power(@mid,2) + power(@mid,3) + power(@mid,4) + power(@mid,5))+1250* power(@mid,5)<1000)
  set @n1=@mid + 0.0001;
  else
  set @n2=@mid - 0.0001;
 end
 print @mid--输出答案
/*
96.2188
431.749
842.627
1149.82
986.198
1065.38
1025.14
1005.51
995.816
1000.65
998.233
999.443
1000.05
0.909139/*--这个是最后X的值,上面的值是f_pk函数返回的值,可以看到最后判断到1000.05的时候跳出*/

*/

问题来了:
我把0.909139 放于计算式进行检验 发现
59(X + X平方 + X立方 + X四次方 + X五次方)+1250*X五次方=1300多
误差这么大 到底什么原因
我也试过将 @n1 float, @n2 float, @mid float都变成 decimal类型的 都差不多 
这个是不是SQL SERVER的一个精度缺失问题
我试过用C语言的方法进行同样得到方法(一模一样)但是答案确非常接近~~
高手不要在潜水 都来吧~


 
 

------解决方案--------------------
C/C++ code
#include<iostream>
#include<cmath>
using namespace std;

double T ( double n ) 
{
    return 59*(n + pow(n,2.0) + pow(n,3.0) + pow(n,4.0) + pow(n,5.0))+1250* pow(n,5.0);
}

int main()
{
    double low = 0, high = 1, mid;
    while ( low < high )
    {
        mid = ( low + high ) / 2;
        if ( fabs( T ( mid ) - 1000 ) < 0.000001 ) break;
        if ( T( mid ) < 1000 ) low = mid + 0.000001;
        else high = mid - 0.000001;
    }
    printf( "%5.6lf\n", mid );
    cout << T( mid ) << endl;
}

------解决方案--------------------
C# code

//C#出來的精度好像更好一些,
//看來二分法精度沒有迭代好?
        double x, y, x1, y1, abs;
        x = 1.0;
        abs = 1;
        while (abs > 0.00000001)
        {
            y = 59 * x + 59 * Math.Pow(x, 2) + 59 * Math.Pow(x, 3) + 59 * Math.Pow(x, 4) + 1309 * Math.Pow(x, 5) - 1000;
            y1 = 59 + 59 * 2 * x + 59 * 3 * Math.Pow(x, 2) + 59 * 4 * Math.Pow(x, 3) + 5 * 1309 * Math.Pow(x, 4);
            x1 = x - y / y1;
            abs = Math.Abs(x1-x);
            x = x1;
        }

        Response.Write(x.ToString());

//result:  0.909129599424195

------解决方案--------------------
to 楼主:
1、二分法的精度不够,一般编程的时候,与小数比较的时候,不是和0比较,而是和一个很小的数,一般是10的-6此方相比较,即小于0.000001,则可以认为为0
修改你的函数,增加精度以后:
if object_id('f_pk') is not null
 drop function f_pk
go
create function f_pk(@n float)/*这个函数用来返回59*(@mid + power(@mid,2) + power(@mid,3) + power(@mid,4) + power(@mid,5))+1250* power(@mid,5)每次算出来的值*/
 returns float
 as
 begin 
 declare @mid float
 set @mid=@n
 return 59*(@mid + power(@mid,2) + power(@mid,3) + power(@mid,4) + power(@mid,5))+1250* power(@mid,5)
 end
 go
declare @n1 float, @n2 float, @mid float--实现2分查找(具体算法不说了)
set @n1=0/*答案一定在0和1之间 具体我已经在http://topic.csdn.net/u/20090624/21/e1a1bba4-3190-4908-aa8f-4f564693109d.html分析过了*/
set @n2=1
while (@n1< @n2)