读书人

浮点数精度有关问题(60分)

发布时间: 2013-03-10 09:38:39 作者: rapoo

浮点数精度问题(60分)
非常老的一个话题, 以为搞懂了,没想到在实战中 浮点数精度有关问题(60分)



case WM_PAINT:
{
HDC hdc = BeginPaint(hWnd, &ps);
RECT rc;
GetClientRect(hWnd,&rc);
SetViewportOrgEx(hdc,rc.right/2,rc.bottom/2,NULL);

float x=-360.0f;
float y=0.0f;

MoveToEx(hdc,x,0,NULL);
while(x<360.0f)
{
y=sin(x/57.3)*100;
LineTo(hdc,x,y);
MoveToEx(hdc,x,y,NULL);
x+=1.5f;
}
for(x=-360.0f;x<=360.0f;x+=90.0f)
{
TCHAR buf[20]={0};
y=sin(x/57.3)*100;
if(abs(y-0.0f)<0.00001f)
{
_stprintf(buf,_T("x=%d度;y=%f"),(int)x,y);
TextOut(hdc,x+4.0f,y+8.0f,buf,lstrlen(buf));
}
else if(abs(y-100.0f)<0.00001f)
{
_stprintf(buf,_T("x=%d度;y=%f"),(int)x,y);
TextOut(hdc,x+4.0f,y-8.0f,buf,lstrlen(buf));
}
}

EndPaint(hWnd, &ps);
return 0;
}
break;

需求:绘制一条正弦曲线,绘制后,在一些点的附近标注x,y的值。
(这些点为:y=0,y=+-100的点)

问题: 曲线绘正确了,但是 标注x,y的值不对,


截图吧:

浮点数精度有关问题(60分)

很明显,少了一些标注了,比如y=-100.0f的地方就没有标注,怎么回事呢?




[解决办法]
当 y== -100.0f的时候,

下面两条判断语句,走哪一条啊?呵呵。

if(abs(y-0.0f)<0.00001f)
{
。。。
}
else if(abs(y-100.0f)<0.00001f)//走这条吗?-100 - 100 =?
{
。。。
}

另外对于浮点数求绝对值最好用fabs

[解决办法]

引用:
引用:1. double 和 float ,天差地别。
-------
float x=0; //这里用double ,结果可是不一样多了。
int n=1000;
while(n--)
x+=0.1;
printf("%f\n",x);
----------

2。
1.5和0.5, 自然是不一样的精度。我也只是……


所有整数都是可以表示的 并不是所有小数都可以表示.
他不可能准确的存储0.1 只能接近0.1
2的-1 == 0.5 2的-2 == 0.25 2的-3 == 0.125.
你本身存储0.1的时候,无法表示0.1,只能无限接近,但若你存储1.5,则1.1(2进制)就可以表示,不会失真.

对于你的工程,PI本身就是无限循环小数,只能无限接近,然后你除去,所以得到的结果和真实的正弦值不一样.
对于没有点的输出,你可以把绝对值小于的数扩大点,0.5f,就可以输出所有的点了.


#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <math.h>


TCHAR szAppName[] = TEXT("Test");

LRESULT CALLBACK TestWinProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);

int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // command line
int nCmdShow // show state
)


{
WNDCLASS wndcls;
HWND hwnd;
BOOL bRet;
MSG msg;



hInstance = hInstance;


wndcls.cbClsExtra = 0;
wndcls.cbWndExtra = 0;
wndcls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndcls.hCursor = LoadCursor(NULL, IDC_ARROW);
wndcls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndcls.hInstance = hInstance;
wndcls.lpfnWndProc = TestWinProc;
wndcls.lpszClassName = szAppName;
wndcls.lpszMenuName = NULL;//无菜单
wndcls.style = CS_VREDRAW
[解决办法]
CS_HREDRAW;

if (!RegisterClass(&wndcls))
{
MessageBox(NULL, TEXT("此程序需要在WINDOWS NT操作系统下运行!"),
szAppName, MB_ICONERROR);
return 0;
}

hwnd = CreateWindow(szAppName, TEXT("Test"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);

while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (-1 == bRet)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}


return 0;
}

LRESULT CALLBACK TestWinProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
static int cxChar;


HDC hdc;
PAINTSTRUCT ps;
TEXTMETRIC tm;
RECT rc;

float x=-360.0f; float y=0.0f;// for draw sine line


switch(uMsg)
{
case WM_CREATE:
hdc = GetDC(hwnd);
SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));

GetTextMetrics(hdc, &tm);
cxChar = tm.tmAveCharWidth;
return 0;

case WM_PAINT:
{
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd,&rc);
SetMapMode(hdc, MM_LOENGLISH);
SetViewportOrgEx(hdc,rc.right/2,rc.bottom/2,NULL);

//draw y=100sin(x) sine line
MoveToEx(hdc,(int)(x),0,NULL);
while(x<360.0f)
{
y=(float)sin(x/57.3)*100;
LineTo(hdc,(int)(x),(int)y);
x+=1.5f;
}
for(x=-360.0f;x<=360.0f;x+=90.0f)
{
TCHAR buf[40] = {0};
y=(float)sin(x/57.3)*100;
if(fabs(y-0.0f)<0.05f)
{
_stprintf(buf,_T("x=%d度;y=%f"),(int)x,y);
TextOut(hdc,x,y,buf,lstrlen(buf));
}
else if(fabs(y-100.0f)<0.05f)
{
_stprintf(buf,_T("x=%d度;y=%f"),(int)x,y);
TextOut(hdc,x,y,buf,lstrlen(buf));
}
else if(fabs(y+100.0f)<0.05f)
{
_stprintf(buf,_T("x=%d度;y=%f"),(int)x,y);
TextOut(hdc,x,y,buf,lstrlen(buf));
}
}

EndPaint(hwnd, &ps);
return 0;
}

return 0;

case WM_CLOSE:


DestroyWindow(hwnd);
return 0;

case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);

}



浮点数精度有关问题(60分)

读书人网 >C语言

热点推荐