中國剩餘定理及其C語言實現、WIn32實現

一 中國剩餘定理

孫子定理是中國古代求解一次同餘式組(見同餘)的方法。是數論中一個重要定理。又稱中國餘數定理。

原文    《孫子算經》    叫做“物不知數”問題,如下:
有物不知其數,三三數之剩二,五五數之剩三,七七數之剩二。問物幾何?

即,一個整數除以三餘二,除以五餘三,除以七餘二,求這個整數。

數論是純粹數學的分支之一,主要研究整數的性質。

如果是要自己實現各種加密算法,這個是必須會的;否則瞭解一下也行;

 

二 部分手算答案

例一
一個數,除以5餘1,除以3餘2。問這個數最小是多少?
答案:11

例二
一個數除以5餘1,除以3也餘1。問這個數最小是多少?(1除外)
答案:16

例三
一個數除以5餘4,除以3餘2。問這個數最小是多少?
答案:14

例五
三三數之剩二,五五數之剩三,七七數之剩二。問物幾何?
即,一個整數除以三餘二,除以五餘三,除以七餘二,求這個整數。
答案:23
 

    見百度百科 孫子定理;孫子定理原文所問,其答案爲:23

   下面用程序來驗證;使用CFree;

 

三 簡單C實現

“有物不知幾何,三三數餘一,五五數餘二,七七數餘三,問:物有幾何?”。編程求1000以內所有解。

這是除以3餘1,除以5餘2,除以7餘3;

 

如果是 除以三餘二,除以五餘三,除以七餘二;則如下;

#include <stdio.h>

int main(int argc, char *argv[])
{
	int m,count=0;
	for(m=1;m<=1000;m++)
		if(m%3==1&&m%5==2&&m%7==3) 
		{
			printf("%5d",m);
			count++;
			if(count%5==0) printf("\n");
		}
	return 0;
}

四 C函數實現

/*long long gcd(LL a,LL b)
{
    return b==0?a:gcd(b,a%b);
}*/
#include<cstdio>
#define ll long long
//擴展歐幾里得算法 
void gcd(ll a,ll b,ll &d,ll &x,ll &y)
{
    if(b==0){
        d=a;
        x=1,y=0;
    }
    else{//else不能省略 
        gcd(b,a%b,d,y,x);
        y-=(a/b)*x;
    }
}
//中國剩餘定理 
ll China(int n,ll *m,ll *a)
{
    ll M=1,d,y,x=0;
    for(int i=0;i<n;i++) M*=m[i];
    for(int i=0;i<n;i++){
        ll w=M/m[i];
        gcd(m[i],w,d,d,y);
        x=(x+y*w*a[i])%M;
    }
    return (x+M)%M;
}
ll m[15],a[15];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%lld%lld",&m[i],&a[i]);
    printf("%lld",China(n,m,a));
}

China()調用gcd();

輸入數據:

    n爲方程數目;

    除數放入m數組,餘數放入a數組;

運行數次,情況如下;

第二次準確答案爲16,應該排除結果爲1的情況;程序還有些地方需要完善;

五 Win32 版本實現中國剩餘定理

#include <windows.h>
#include "resource.h"

typedef long long ll;

LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
ll China(int ,ll *,ll *);
void gcd(ll ,ll ,ll &,ll &,ll &);

HINSTANCE hInst;
TCHAR szClassName[] = TEXT("sunziDemo");

int WINAPI
WinMain (HINSTANCE hThisInstance,
         HINSTANCE hPrevInstance,
         LPSTR lpszArgument,
         int nFunsterStil)
{
    HWND hwnd;
    MSG messages;
    WNDCLASSEX wincl;

	hInst = hThisInstance;
	
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;
    wincl.style = CS_DBLCLKS;
    wincl.cbSize = sizeof (WNDCLASSEX);

    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = MAKEINTRESOURCE (IDC_SUNZIDEMO2);
    wincl.cbClsExtra = 0;
    wincl.cbWndExtra = 0;
    wincl.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

    if (!RegisterClassEx (&wincl))
        return 0;

    hwnd = CreateWindowEx (
           0,
           szClassName,
           TEXT("sunziDemo2"),
           WS_OVERLAPPEDWINDOW,
           CW_USEDEFAULT,
           0,
           CW_USEDEFAULT,
           0,
           HWND_DESKTOP,
           NULL,
           hThisInstance,
           NULL
           );

    ShowWindow (hwnd, nFunsterStil);

    while (GetMessage (&messages, NULL, 0, 0))
    {
        TranslateMessage(&messages);
        DispatchMessage(&messages);
    }

    return messages.wParam;
}

LRESULT CALLBACK
WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT ps;
	HDC hdc;
	RECT rt;
	TCHAR szHello[] = TEXT("Hello, C-Free!");
	char szBuffer[100];
	ll m[3],a[3];	
	int n=3; //方程數 
	ll sunziAnswer;  //結果存放 
	m[0]=3;m[1]=5;m[2]=7;
	a[0]=2;a[1]=3;a[2]=2;
	
    switch (message)
    {
			case WM_COMMAND:
    		switch (LOWORD(wParam))
    		{
		    case IDM_ABOUT:
				MessageBox (hwnd, TEXT ("sunziDemo v1.0\nCopyright (C) 2020\n by bo"),
                        TEXT ("sunziDemo"), MB_OK | MB_ICONINFORMATION);
				break;
			case IDM_EXIT:
				DestroyWindow(hwnd);
				break;
			default:
				return DefWindowProc(hwnd, message, wParam, lParam);	    		
		    }
    		break;
    	case WM_PAINT:
			hdc = BeginPaint(hwnd, &ps);					
			GetClientRect(hwnd, &rt);
			sunziAnswer = China(n,m,a);
			wsprintf(szBuffer, "%d",sunziAnswer);
			DrawText(hdc, szBuffer, lstrlen(szBuffer), &rt, DT_LEFT);
			EndPaint(hwnd, &ps);
			break;
        case WM_DESTROY:
            PostQuitMessage (0);
            break;
        default:
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

//擴展歐幾里得算法 
void gcd(ll a,ll b,ll &d,ll &x,ll &y)
{
    if(b==0){
        d=a;
        x=1;y=0;
    }
    else{//else不能省略 
        gcd(b,a%b,d,y,x);
        y-=(a/b)*x;
    }
}
//中國剩餘定理 
ll China(int n,ll *m,ll *a)
{
    ll M=1,d,y,x=0;
    for(int i1=0;i1<n;i1++) M*=m[i1];
    for(int i=0;i<n;i++){
        ll w=M/m[i];
        gcd(m[i],w,d,d,y);
        x=(x+y*w*a[i])%M;
    }
    return (x+M)%M;
}
/*long long gcd(LL a,LL b)
{
    return b==0?a:gcd(b,a%b);
}*/

定義方程數目3,預先給好除數和餘數;然後調用China();在窗口上輸出結果sunziAnswer;

工程如下;

開發環境生成的resource.h和.rc文件;

resource.h:

#define 	IDM_EXIT		10001
#define 	IDM_ABOUT		10002
#define 	IDC_SUNZIDEMO2		10101
#define 	IDD_ABOUTBOX	10102

sunziDemo2.rc:

#include "resource.h"
#include <windows.h>

/////////////////////////////////////////////////////////////////////////////
//
// Menu
//

IDC_SUNZIDEMO2 MENU 
BEGIN
    POPUP "&File"
    BEGIN
        MENUITEM "E&xit",                	IDM_EXIT
    END
    POPUP "&Help"
    BEGIN
        MENUITEM "&About ...",           	IDM_ABOUT
    END
END

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章