作者 主題: 不限位數四則運算程式原碼  (閱讀 20131 次)

0 會員 與 1 訪客 正在閱讀本文。

stlee

  • 鑽研的研究生
  • *****
  • 文章數: 817
    • 檢視個人資料
不限位數四則運算程式原碼
« 於: 2007-01-14 13:23 »
代碼: [選擇]

rm *.o
rm go
make
gdb go

請先將這裡程式代碼的部份存成go.sh
在編譯程式時執行./go.sh即可
程式是人寫的,別讓工具的限制成為您想像力的極限
~程式中最重要的部份應該是註解而不是程式碼,這是因為解讀註解一定比解讀程式碼簡單
~程式寫好後約一個月就會忘的差不多了,所以花點時間把註解寫好至少能讓自己(或別人)看的懂當初在寫什麼

stlee

  • 鑽研的研究生
  • *****
  • 文章數: 817
    • 檢視個人資料
不限位數四則運算程式原碼
« 回覆 #1 於: 2007-01-14 13:35 »
代碼: [選擇]

#-lcurses為系統內定的函數庫(存放在/usr/lib目錄之函數庫皆為系統內定)
#-lefence是在gdb下一個很好用的除錯模組,主要能檢查出陣列溢位如abc[-1]的狀況
#-lefence可不用(刪除)
#第二行前面空白的部份是一個Tab不是8個空白
go:hbpfs.o
gcc -g -o go hbpfs.c -lcurses -lefence


請將程式代碼的部份以makefile的檔名建立(make內定名稱)
程式是人寫的,別讓工具的限制成為您想像力的極限
~程式中最重要的部份應該是註解而不是程式碼,這是因為解讀註解一定比解讀程式碼簡單
~程式寫好後約一個月就會忘的差不多了,所以花點時間把註解寫好至少能讓自己(或別人)看的懂當初在寫什麼

stlee

  • 鑽研的研究生
  • *****
  • 文章數: 817
    • 檢視個人資料
不限位數四則運算程式原碼
« 回覆 #2 於: 2007-01-14 13:43 »
代碼: [選擇]

/*
struct hbpfs2ans{
 char *ans;
 char *quot;
 char *rem;
};
*/
#include <unistd.h>

#include <ctype.h>
#include <curses.h>
#include <dirent.h>
#include <fcntl.h>
#include <grp.h>
#include <pwd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <term.h>
#include <termios.h>
#include <sys/time.h>
#include <unistd.h>
#include <errno.h>


#define ISNULL '\0'
#define INFO   0
#define FROM   1

/*................................................................................*/
/*..............................      hbpfs.c       ..............................*/
/*................................................................................*/
void lee_getscrxy(int *x,int *y);

/*不限位元精確度四則運算窗口函數*/
char *lee_hbpfs(char *a,int op,char *b);

/*除錯函數*/
void lee_hbpfs_debug(char *numa,int op,char *numb,int maxlen,
                     char *ans,int anslen,int cx,int cy);

/*參考numa,numb將tmpaa,tmpb字串標齊為直列算式小數點標齊的格式;tmp_與num_位址可重疊*/
void lee_hbpfs_primdec(char *tmpa,char *tmpb,int tmplen,char *numa,char *numb);

/*將不限位元精確度四則運算求出的ans字串修飾(加上正負號或決定乘法小數點位置的處理)*/
void lee_hbpfs_ansbedeck(char *ans,char *numa,char *numb,int maxlen);

/*將被標齊或運算結果的str字串前面的'\0'或'0'字元取消並令其左靠使str成為正常的字串*/
void lee_hbpfs_delzero(char *str,int anslen);

/*比較兩數字字串的大小:標準字串比較函數999會比10000大但此函數可比較出999比10000小*/
int lee_hbpfs_numcmp(char *tmpa,char *tmpb,int tmplen);

/*只取num字串數字的部份(含小數點)複製到tmp所指位置*/
void lee_hbpfs_digit(char *tmp,char *num);

void lee_hbpfs_chadd(char *ans,char *tmpa,char *tmpb,int maxlen);
void lee_hbpfs_chmul(char *ans,int anslen,char *numa,char *numb);
int lee_hbpfs_chsub(char *ans,char *tmpa,char *tmpb,int maxlen);
int lee_hbpfs_quot(char *multmp,char *divisor,char *rem,int maxlen);

/*以下四個函數的參數numa,numb都可含描述詞如abc=123.45或xyz  456.678
這樣函數會取得123.45或456.678進行運算;但描述詞儘量不要用中文,這是因為中文是雙位元組合而成其中可能有包含小數點字元'.'的組合字,如此一來將使得正整數變成浮點數或有兩個小數點的錯誤數值表示而使得運算失敗(或算出錯誤的值)但修改lee_hbpfs_digit()則可避免不能用中文描述的狀況
2007.01.11 程式設計:李湘台於台灣,台南永康*/

/*不限位元精確度加法運算窗口函數,numa,numb字串長度可不同且含描述詞*/
char *lee_hbpfs_add(char *numa,char *numb);

/*不限位元精確度減法運算窗口函數,numa,numb字串長度可不同且含描述詞*/
char *lee_hbpfs_sub(char *numa,char *numb);

/*不限位元精確度乘法運算窗口函數,numa,numb字串長度可不同且含描述詞*/
char *lee_hbpfs_mul(char *numa,char *numb);

/*不限位元精確度除法運算窗口函數,numa,numb字串長度可不同且含描述詞*/
char *lee_hbpfs_div(char *numa,char *numb,int precision);

/*找出第一個是fill字元的旗標值,參數dir控制要從前面INFO或後面FROM開始*/
int lee_memcycfg(char *s,int sz,int dir,int fill);



請將此檔存成hbpfs.h
前面註解的部分本來想宣告一個結構可在除法算完後填入商數及餘數的
不過一直沒通過gcc
含引檔可能不用那麼多....請自行刪除不必要的
程式是人寫的,別讓工具的限制成為您想像力的極限
~程式中最重要的部份應該是註解而不是程式碼,這是因為解讀註解一定比解讀程式碼簡單
~程式寫好後約一個月就會忘的差不多了,所以花點時間把註解寫好至少能讓自己(或別人)看的懂當初在寫什麼

stlee

  • 鑽研的研究生
  • *****
  • 文章數: 817
    • 檢視個人資料
不限位數四則運算程式原碼
« 回覆 #3 於: 2007-01-14 13:52 »
代碼: [選擇]

#include "/home/tst/hbpfs.h"

main()
{
  char pi[100008]={"3.\
14159265358979323846264338327950288419716939937510\
58209749445923078164062862089986280348253421170679\
82148086513282306647093844609550582231725359408128\
48111745028410270193852110555964462294895493038196\
44288109756659334461284756482337867831652712019091\
45648566923460348610454326648213393607260249141273\
72458700660631558817488152092096282925409171536436\
78925903600113305305488204665213841469519415116094\
33057270365759591953092186117381932611793105118548\
07446237996274956735188575272489122793818301194912\
98336733624406566430860213949463952247371907021798\
60943702770539217176293176752384674818467669405132\
00056812714526356082778577134275778960917363717872\
14684409012249534301465495853710507922796892589235\
42019956112129021960864034418159813629774771309960\
51870721134999999837297804995105973173281609631859\
50244594553469083026425223082533446850352619311881\
71010003137838752886587533208381420617177669147303\
59825349042875546873115956286388235378759375195778\
18577805321712268066130019278766111959092164201989\
38095257201065485863278865936153381827968230301952\
03530185296899577362259941389124972177528347913151\
55748572424541506959508295331168617278558890750983\
81754637464939319255060400927701671139009848824012\
85836160356370766010471018194295559619894676783744\
94482553797747268471040475346462080466842590694912\
93313677028989152104752162056966024058038150193511\
25338243003558764024749647326391419927260426992279\
67823547816360093417216412199245863150302861829745\
55706749838505494588586926995690927210797509302955\
32116534498720275596023648066549911988183479775356\
63698074265425278625518184175746728909777727938000\
81647060016145249192173217214772350141441973568548\
16136115735255213347574184946843852332390739414333\
45477624168625189835694855620992192221842725502542\
56887671790494601653466804988627232791786085784383\
82796797668145410095388378636095068006422512520511\
73929848960841284886269456042419652850222106611863\
06744278622039194945047123713786960956364371917287\
46776465757396241389086583264599581339047802759009\
94657640789512694683983525957098258226205224894077\
26719478268482601476990902640136394437455305068203\
49625245174939965143142980919065925093722169646151\
57098583874105978859597729754989301617539284681382\
68683868942774155991855925245953959431049972524680\
84598727364469584865383673622262609912460805124388\
43904512441365497627807977156914359977001296160894\
41694868555848406353422072225828488648158456028506\
01684273945226746767889525213852254995466672782398\
64565961163548862305774564980355936345681743241125\
15076069479451096596094025228879710893145669136867\
22874894056010150330861792868092087476091782493858\
90097149096759852613655497818931297848216829989487\
22658804857564014270477555132379641451523746234364\
54285844479526586782105114135473573952311342716610\
21359695362314429524849371871101457654035902799344\
03742007310578539062198387447808478489683321445713\
86875194350643021845319104848100537061468067491927\
81911979399520614196634287544406437451237181921799\
98391015919561814675142691239748940907186494231961\
56794520809514655022523160388193014209376213785595\
66389377870830390697920773467221825625996615014215\
03068038447734549202605414665925201497442850732518\
66600213243408819071048633173464965145390579626856\
10055081066587969981635747363840525714591028970641\
40110971206280439039759515677157700420337869936007\
23055876317635942187312514712053292819182618612586\
73215791984148488291644706095752706957220917567116\
72291098169091528017350671274858322287183520935396\
57251210835791513698820914442100675103346711031412\
67111369908658516398315019701651511685171437657618\
35155650884909989859982387345528331635507647918535\
89322618548963213293308985706420467525907091548141\
65498594616371802709819943099244889575712828905923\
23326097299712084433573265489382391193259746366730\
58360414281388303203824903758985243744170291327656\
18093773444030707469211201913020330380197621101100\
44929321516084244485963766983895228684783123552658\
21314495768572624334418930396864262434107732269780\
28073189154411010446823252716201052652272111660396\
66557309254711055785376346682065310989652691862056\
47693125705863566201855810072936065987648611791045\
33488503461136576867532494416680396265797877185560\
84552965412665408530614344431858676975145661406800\
70023787765913440171274947042056223053899456131407\
11270004078547332699390814546646458807972708266830\
63432858785698305235808933065757406795457163775254\
20211495576158140025012622859413021647155097925923\
09907965473761255176567513575178296664547791745011\
29961489030463994713296210734043751895735961458901\
93897131117904297828564750320319869151402870808599\
04801094121472213179476477726224142548545403321571\
85306142288137585043063321751829798662237172159160\
77166925474873898665494945011465406284336639379003\
97692656721463853067360965712091807638327166416274\
88880078692560290228472104031721186082041900042296\
61711963779213375751149595015660496318629472654736\
42523081770367515906735023507283540567040386743513\
62222477158915049530984448933309634087807693259939\
78054193414473774418426312986080998886874132604721\
56951623965864573021631598193195167353812974167729\
47867242292465436680098067692823828068996400482435\
40370141631496589794092432378969070697794223625082\
21688957383798623001593776471651228935786015881617\
55782973523344604281512627203734314653197777416031\
99066554187639792933441952154134189948544473456738\
31624993419131814809277771038638773431772075456545\
32207770921201905166096280490926360197598828161332\
31666365286193266863360627356763035447762803504507\
77235547105859548702790814356240145171806246436267\
94561275318134078330336254232783944975382437205835\
31147711992606381334677687969597030983391307710987\
04085913374641442822772634659470474587847787201927\
71528073176790770715721344473060570073349243693113\
83504931631284042512192565179806941135280131470130\
47816437885185290928545201165839341965621349143415\
95625865865570552690496520985803385072242648293972\
85847831630577775606888764462482468579260395352773\
48030480290058760758251047470916439613626760449256\
27420420832085661190625454337213153595845068772460\
29016187667952406163425225771954291629919306455377\
99140373404328752628889639958794757291746426357455\
25407909145135711136941091193932519107602082520261\
87985318877058429725916778131496990090192116971737\
27847684726860849003377024242916513005005168323364\
35038951702989392233451722013812806965011784408745\
19601212285993716231301711444846409038906449544400\
61986907548516026327505298349187407866808818338510\
22833450850486082503930213321971551843063545500766\
82829493041377655279397517546139539846833936383047\
46119966538581538420568533862186725233402830871123\
28278921250771262946322956398989893582116745627010\
21835646220134967151881909730381198004973407239610\
36854066431939509790190699639552453005450580685501\
95673022921913933918568034490398205955100226353536\
19204199474553859381023439554495977837790237421617\
27111723643435439478221818528624085140066604433258\
88569867054315470696574745855033232334210730154594\
05165537906866273337995851156257843229882737231989\
87571415957811196358330059408730681216028764962867\
44604774649159950549737425626901049037781986835938\
14657412680492564879855614537234786733039046883834\
36346553794986419270563872931748723320837601123029\
91136793862708943879936201629515413371424892830722\
01269014754668476535761647737946752004907571555278\
19653621323926406160136358155907422020203187277605\
27721900556148425551879253034351398442532234157623\
36106425063904975008656271095359194658975141310348\
22769306247435363256916078154781811528436679570611\
08615331504452127473924544945423682886061340841486\
37767009612071512491404302725386076482363414334623\
51897576645216413767969031495019108575984423919862\
91642193994907236234646844117394032659184044378051\
33389452574239950829659122850855582157250310712570\
12668302402929525220118726767562204154205161841634\
84756516999811614101002996078386909291603028840026\
91041407928862150784245167090870006992821206604183\
71806535567252532567532861291042487761825829765157\
95984703562226293486003415872298053498965022629174\
87882027342092222453398562647669149055628425039127\
57710284027998066365825488926488025456610172967026\
64076559042909945681506526530537182941270336931378\
51786090407086671149655834343476933857817113864558\
73678123014587687126603489139095620099393610310291\
61615288138437909904231747336394804575931493140529\
76347574811935670911013775172100803155902485309066\
92037671922033229094334676851422144773793937517034\
43661991040337511173547191855046449026365512816228\
82446257591633303910722538374218214088350865739177\
15096828874782656995995744906617583441375223970968\
34080053559849175417381883999446974867626551658276\
58483588453142775687900290951702835297163445621296\
40435231176006651012412006597558512761785838292041\
97484423608007193045761893234922927965019875187212\
72675079812554709589045563579212210333466974992356\
30254947802490114195212382815309114079073860251522\
74299581807247162591668545133312394804947079119153\
26734302824418604142636395480004480026704962482017\
92896476697583183271314251702969234889627668440323\
26092752496035799646925650493681836090032380929345\
95889706953653494060340216654437558900456328822505\
45255640564482465151875471196218443965825337543885\
69094113031509526179378002974120766514793942590298\
96959469955657612186561967337862362561252163208628\
69222103274889218654364802296780705765615144632046\
92790682120738837781423356282360896320806822246801\
22482611771858963814091839036736722208883215137556\
00372798394004152970028783076670944474560134556417\
25437090697939612257142989467154357846878861444581\
23145935719849225284716050492212424701412147805734\
55105008019086996033027634787081081754501193071412\
23390866393833952942578690507643100638351983438934\
15961318543475464955697810382930971646514384070070\
73604112373599843452251610507027056235266012764848\
30840761183013052793205427462865403603674532865105\
70658748822569815793678976697422057505968344086973\
50201410206723585020072452256326513410559240190274\
21624843914035998953539459094407046912091409387001\
26456001623742880210927645793106579229552498872758\
46101264836999892256959688159205600101655256375678"};


  WINDOW *winptr;
  int scrx,scry,wtcx,wtcy,wxwit,wywit,op;
  char *ans,*tmp;
  char numa[10240],numb[10240];
  struct timeval tv;
  struct timezone tz;
  long foot_sec,foot_usec,end_sec,end_usec;
  int anslen,i,n,k;
 

  initscr();/*營幕顯示控制起始化*/
  lee_getscrxy(&scrx,&scry);
  wtcx=0;
  wtcy=1;
  wxwit=scrx-wtcx;
  wywit=scry-wtcy;
  winptr=newwin(wywit,wxwit,wtcy,wtcx);/*取得視窗*/

memset(numa,ISNULL,10240);
memset(numb,ISNULL,10240);
/*strcpy(numa,"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
strcpy(numb,"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");

strcpy(numa,"123456789");
strcpy(numb,"9876543");
*/

op='*';
gettimeofday(&tv,&tz);
foot_sec=tv.tv_sec;
foot_usec=tv.tv_usec;
/*測試前的時間取得*/

/*一般測試用此行及改變op即可*/
/*ans=lee_hbpfs(numa,op,numb);*/


/*2的升幕次(k的值即為要求多少次方)輸入到512次方(155位數)時才有用到一秒
當k改到1024(2的1024次方共309位數)用了2秒但程式尚未調整到最佳化
使用配備:CPU=IntelP3-1GMHZ,DRAM=512MB,作業系統:RedHat9 Linux2.4
2007.01.14....微秒的部份不知怎麼計算,居然有負的值?*/
/*k=512;
for(i=0,n=2;i<k;i++)
{
strcpy(numb,"2");
if(i==0)
strcpy(numa,"1");
else
{
memset(numa,ISNULL,10240);
strcpy(numa,ans);
if(i<k-1)
free(ans);
}
ans=lee_hbpfs(numa,op,numb);
}
*/

/*圓週率小數點後一萬位測試:將網路上抓下來的資料排列後成為一個字串,將該值乘任一
數x得出n再以n除x如果可被整除表示成功
2007.01.14-02:40測試成功共用了76秒達成乘法與除法再測過乘法後即可算出除法的秒數了
乘法共用了37秒所以除法用了39秒,不過這是假設兩數相除可被整除的情況下用圓週率來比對
除法是否正確的測試並不代表本程式能在39秒內算出圓週率小數點後一萬位
*/
strcpy(numa,"123456789");/*用"987654321"是107秒*/

tmp=lee_hbpfs(numa,'*',pi);/*以任一值x乘pi為tmp,該tmp可被x整除*/
ans=lee_hbpfs(tmp,'/',numa);/*將此行註解可測出乘法的時間*/

/*測試後的時間取得*/
gettimeofday(&tv,&tz);
end_sec=tv.tv_sec;
end_usec=tv.tv_usec;

/*if( (anslen=strlen(tmp)) > 1000)/*測圓週率註解ans以求除法時間時用此行取代下面那行*/
if( (anslen=strlen(ans)) > 1000)
{
  mvprintw(0,0,"ans字串長度(位數)anslen=%d 使用秒數=%ld (微秒)=%d *",
                anslen,(end_sec-foot_sec),(end_usec-foot_usec));
}
else
{
  mvprintw(0,0,"%s%c%s=%s *",numa,op,numb,ans);
  mvprintw(wywit-1,0,"ans字串長度(位數)anslen=%d 使用秒數=%ld (微秒)=%d *",
                anslen,(end_sec-foot_sec),(end_usec-foot_usec));
}
free(ans);
refresh();
getch();

  delwin(winptr);/*消除視窗*/
  touchwin(stdscr);/*還原scr終端機的畫面*/
  wrefresh(stdscr);/*刷新scr*/
  endwin();/*營幕顯示控制終止*/
}
/*
*/
void lee_getscrxy(int *x,int *y)
{

  setupterm(NULL,fileno(stdout),(int *)0);
  *y = tigetnum("lines");/*列=y*/
  *x = tigetnum("cols");/*行=x*/
}

從這裡開始都給他存到hbpfs.c內
其中有一些昨天晚上測試的程式碼...有興趣的人可以測看看
主要是填入兩個字串陣列交給lee_hbpfs()做運算所以您可以自行寫一個
main函數呼叫lee_hbpfs()即可

程式請在終端機模式(視窗)下執行
程式是人寫的,別讓工具的限制成為您想像力的極限
~程式中最重要的部份應該是註解而不是程式碼,這是因為解讀註解一定比解讀程式碼簡單
~程式寫好後約一個月就會忘的差不多了,所以花點時間把註解寫好至少能讓自己(或別人)看的懂當初在寫什麼

stlee

  • 鑽研的研究生
  • *****
  • 文章數: 817
    • 檢視個人資料
不限位數四則運算程式原碼
« 回覆 #4 於: 2007-01-14 13:59 »
代碼: [選擇]

/*
不限位數的四則運算
程式設計:李湘台於台灣台南永康-2007.01.14
*/
char *lee_hbpfs(char *numa,int op,char *numb)
{
 
  char *ans,*tmpa,*tmpb;
  char tmp[2];
  int maxlen;
  int i,n,k,x,y,p;  

  switch(op)
  {
    case '+':      
      ans=lee_hbpfs_add(numa,numb);
    break;
    case '-':
      ans=lee_hbpfs_sub(numa,numb);
    break;
    case '*':      
      ans=lee_hbpfs_mul(numa,numb);  
    break;
    case '/':    
    case '%':
      ans=lee_hbpfs_div(numa,numb,-1);
    break;
    default:
      return(NULL);
  }
/*
mvprintw(0,0,"sa op sb=%s%c%s ans=%s *",numa,op,numb,ans);
refresh();
*/
  return(&*ans);

}

這個函數請存到hbpfs.c內
程式是人寫的,別讓工具的限制成為您想像力的極限
~程式中最重要的部份應該是註解而不是程式碼,這是因為解讀註解一定比解讀程式碼簡單
~程式寫好後約一個月就會忘的差不多了,所以花點時間把註解寫好至少能讓自己(或別人)看的懂當初在寫什麼

stlee

  • 鑽研的研究生
  • *****
  • 文章數: 817
    • 檢視個人資料
不限位數四則運算程式原碼
« 回覆 #5 於: 2007-01-14 14:06 »
代碼: [選擇]

/*除錯函數
*/
void lee_hbpfs_debug(char *numa,int op,char *numb,int maxlen,
                     char *ans,int anslen,int cx,int cy)
{
  int i,x,y;
return;

  if(op=='/')
  {
    for(i=0,x=strlen(numb)+cx+1;i<anslen;i++,x++)
    {
      if(*(ans+i)==ISNULL)
        mvprintw(cy,x,"x");
      else
        mvprintw(cy,x,"%c",*(ans+i));
    }  
    for(i=0,x=strlen(numb)+cx+1;i<strlen(numa)+1;i++,x++)
      mvprintw(cy+1,x,"_");
    mvprintw(cy+2,cx,"%s/%s ",numb,numa);
    refresh();    
    return;
  }
 
  y=cy;

  for(i=0,x=cx;i<maxlen;i++,x++)
  {
    if(*(numa+i)==ISNULL)
      mvprintw(y,x,"a");
    else
      mvprintw(y,x,"%c",*(numa+i));
    if(*(numb+i)==ISNULL)
      mvprintw(y+1,x,"b");
    else
      mvprintw(y+1,x,"%c",*(numb+i));
  }

  mvprintw(y+1,cx-2,"%c",op);
  for(i=0,x=cx-2;i<=maxlen+2;i++,x++)
    mvprintw(y+2,x,"-");

  for(i=0,x=cx;i<anslen;i++,x++)
  {
    if(*(ans+i)==ISNULL)
      mvprintw(y+3,x,"x");
    else
      mvprintw(y+3,x,"%c",*(ans+i));
  }  
  refresh();

getchar();
}


這個函數存到hbpfs.c

在函數一開始有用return返回是因為要測試所以不執行本函數
有興趣的人可以將那一行拿掉,這樣程式會一個動作一個動作的顯示...
按任一鍵可執行一個動作以觀察程式執行時的除錯用
程式是人寫的,別讓工具的限制成為您想像力的極限
~程式中最重要的部份應該是註解而不是程式碼,這是因為解讀註解一定比解讀程式碼簡單
~程式寫好後約一個月就會忘的差不多了,所以花點時間把註解寫好至少能讓自己(或別人)看的懂當初在寫什麼

stlee

  • 鑽研的研究生
  • *****
  • 文章數: 817
    • 檢視個人資料
不限位數四則運算程式原碼
« 回覆 #6 於: 2007-01-14 14:09 »
代碼: [選擇]

/*找出第一個是fill字元的旗標值,參數dir控制要從前面INFO或後面FROM開始
程式設計:李湘台於台灣台南永康-2007.01.14
*/
int lee_memcycfg(char *s,int sz,int dir,int fill)
{
  int i;

  if(sz<1)
    return(-1);
  if(dir==INFO)/*從前面(順向,右邊)找第一個fill字元*/
  {
    for(i=0;i<sz;i++)
      if(*(s+i)==fill)
        return(i);
  }
  else/*if(ori==FROM)從後面(逆向,左邊)找最後一個fill字元*/
  {
    for(i=sz-1;i>=0;i--)
      if(*(s+i)==fill)
        return(i);
  }
  /*找不到fill字元時傳回-1*/
  return(-1);
}


這個函數是我在寫文書處理器的字串搜尋函數改來的
程式是人寫的,別讓工具的限制成為您想像力的極限
~程式中最重要的部份應該是註解而不是程式碼,這是因為解讀註解一定比解讀程式碼簡單
~程式寫好後約一個月就會忘的差不多了,所以花點時間把註解寫好至少能讓自己(或別人)看的懂當初在寫什麼

stlee

  • 鑽研的研究生
  • *****
  • 文章數: 817
    • 檢視個人資料
不限位數四則運算程式原碼
« 回覆 #7 於: 2007-01-14 14:14 »
代碼: [選擇]

/*............................................................................
程式設計:李湘台於台灣台南永康-2007.01.14
小數點標齊
此函數只處理小數點應標齊位置不處理正負值的問題
例如要標齊兩個字串*a為"123.12"及*b為123456.123
abc(char *a,char *b)
{
  char *ta,*tb;
  int maxlen;

  maxlen=strlen(a)+strlen(b)+1;
  lee_hbpfs_primdec(ta,tb,maxlen,a,b);
}
這樣ta,tb就是被標齊後的結果(可供加,減法的運算)

可處理重疊的問題如ta,a或tb,b所指位置重疊
  lee_hbpfs_primdec(ta,tb,maxlen,ta,tb);
  lee_hbpfs_primdec(ta,tb,maxlen,a,tb);
  lee_hbpfs_primdec(ta,tb,maxlen,ta,b);
以上狀況也可正確的將ta,tb標齊
.............................................................................*/

void lee_hbpfs_primdec(char *tmpa,char *tmpb,int tmplen,char *numa,char *numb)
{
  int i,n,alen,blen,ad,bd,aii,bii,deci;

  alen=strlen(numa);/*計算a字串的長度*/
  if(alen<1)/*已標齊或空字串則不再做標齊動作*/
    return;
  ad=lee_memcycfg(numa,alen,INFO,'.');/*找出a字串小數點位置*/
  if(ad<0)/*a是整數則將小數點放在個位數後一位的虛擬位置供正整數與浮點數運算時的參考點*/
    ad=alen;  
  blen=strlen(numb);/*計算b字串的長度*/
  if(blen<1)/*已標齊或空字串則不再做標齊動作*/
    return;
  bd=lee_memcycfg(numb,blen,INFO,'.');/*找出b字串小數點位置*/
  if(bd<0)/*b是整數則將小數點放在個位數後一位的虛擬位置供正整數與浮點數運算時的參考點*/
    bd=blen;  
   
  /*小數點應標齊的位置deci應為ad,bd兩值中最大的那一個*/
  if(ad>bd)
    deci=ad;
  else
    deci=bd;
/*
mvprintw(0,0,"&*tmpa=%p &tmpa=%p &*numa=%p &numa=%p*",
              &*tmpa,&tmpa,&*numa,&numa);
mvprintw(1,0,"tmplen=%d deci=%d  alen=%d ad=%d aii=%d --- blen=%d bd=%d bii=%d _primdec()*",
              tmplen,deci,alen,ad,aii,blen,bd,bii);
refresh();
*/
  if(ad>bd)
  {    
    /*numa的小數點位置ad在比較右邊:迴路將tmpb往後推到小數點標齊處*/
    for(i=deci+(blen-bd)-1,n=blen-1;i>=0;i--,n--)
    {
      if(n>=0)
        *(tmpb+i)=*(numb+n);
      else
        *(tmpb+i)=ISNULL;
    }
    /*if(&*tmpa != &*numa)/*tmpa與numa所指記憶體區域無重疊需覆製num到tmp*/
      /*memcpy(tmpa,numa,alen);*/
  }
  else if(bd>ad)
  {
    /*numb的小數點位置bd在比較右邊:迴路將tmpa往後推到小數點標齊處*/
    for(i=deci+(alen-ad)-1,n=alen-1;i>=0;i--,n--)
    {
      if(n>=0)
        *(tmpa+i)=*(numa+n);
      else
        *(tmpa+i)=ISNULL;
    }

    /*if(&*tmpb != &*numb)/*tmpb與numb所指記憶體區域無重疊需覆製num到tmp*/
      /*memcpy(tmpb,numb,blen);*/
  }
  else
  {;}

}

這個函數主要就是將數字字串標齊小數點用的
請存到hbpfs.c
程式是人寫的,別讓工具的限制成為您想像力的極限
~程式中最重要的部份應該是註解而不是程式碼,這是因為解讀註解一定比解讀程式碼簡單
~程式寫好後約一個月就會忘的差不多了,所以花點時間把註解寫好至少能讓自己(或別人)看的懂當初在寫什麼

stlee

  • 鑽研的研究生
  • *****
  • 文章數: 817
    • 檢視個人資料
不限位數四則運算程式原碼
« 回覆 #8 於: 2007-01-14 14:19 »
代碼: [選擇]

/*只取num字串數字的部份(含小數點)複製到tmp所指位置
程式設計:李湘台於台灣台南永康-2007.01.14
*/
void lee_hbpfs_digit(char *tmp,char *num)
{  
  int x,n,numlen;
 
  numlen=strlen(num);  
  for(x=0,n=0;x<numlen;x++)  
    if(isdigit(*(num+x)) || *(num+x)=='.')
    {
      *(tmp+n)=*(num+x);
      n+=1;
    }
}


/*比較兩數字字串的大小
數字999並沒比1000大但以標準函數的字串比較函數來說的話字串999是比字串1000大的
此函數的目地即是比出這種數字字串所表示的數字大小
程式設計:李湘台於台灣台南永康-2007.01.14
*/
int lee_hbpfs_numcmp(char *tmpa,char *tmpb,int tmplen)
{
  int i;

  /*標齊tmpa與tmpb,字串較短或小數點位置較左的那一個字串前面會被補'\0'字元*/
  lee_hbpfs_primdec(tmpa,tmpb,tmplen,tmpa,tmpb);
  i=memcmp(tmpa,tmpb,tmplen);
  lee_hbpfs_delzero(tmpa,tmplen);
  lee_hbpfs_delzero(tmpb,tmplen);
  return(i);
}

/*消除前面的'\0'及'0'字元使*ans字串符合一般以'\0'結尾格式的字串
程式設計:李湘台於台灣台南永康-2007.01.14
*/
void lee_hbpfs_delzero(char *ans,int anslen)
{
  int i,x,n;

  /*先找出第一個不是'\0'及'0'字元所在旗標*/        
  for(x=0;x<anslen;x++)
    if(*(ans+x)!=ISNULL && *(ans+x)!='0')
      break;
  if(x==0)
    return;  
  /*將ans字串往前推x位元*/
  for(i=0,n=x;i<anslen;i++,n++)
    if(n<anslen)
      *(ans+i)=*(ans+n);
    else
      *(ans+i)=ISNULL;
}


這3個工具函數關係效能甚巨,希望有高手能把它改的快一點
存到hbpfs.c
程式是人寫的,別讓工具的限制成為您想像力的極限
~程式中最重要的部份應該是註解而不是程式碼,這是因為解讀註解一定比解讀程式碼簡單
~程式寫好後約一個月就會忘的差不多了,所以花點時間把註解寫好至少能讓自己(或別人)看的懂當初在寫什麼

stlee

  • 鑽研的研究生
  • *****
  • 文章數: 817
    • 檢視個人資料
不限位數四則運算程式原碼
« 回覆 #9 於: 2007-01-14 14:27 »
代碼: [選擇]

/*ans字串修飾
*/
void lee_hbpfs_ansbedeck(char *ans,char *numa,char *numb,int maxlen)
{
  int i,n,d,x,dec;
 
  dec=0;
  d=lee_memcycfg(numa,/*alen*/strlen(numa),INFO,'.');/*找出a字串小數點位置*/
  if(d>=0)
    n=/*alen-ad-1*/strlen(numa)-d-1;/*算出a字串小數點後所佔位數*/
  else
    n=0;
  dec+=n;    
  d=lee_memcycfg(numb,/*blen*/strlen(numb),INFO,'.');/*找出b字串小數點位置*/
  if(d>=0)
    n=/*blen-bd-1*/strlen(numb)-d-1;/*算出b字串小數點後所佔位數*/
  else
    n=0;
  dec+=n;

/*mvprintw(5,0,"alen=%d ad=%d--blen=%d bd=%d--dec=%d ",alen,ad,blen,bd,dec);
*/
 
  if(dec>0)
  {
    d=0;
    for(i=maxlen;i>=0;i--)
    {  
      if(d>=1 && *(ans+i)==ISNULL)/*浮點數計算的結果不足小數點右d位補d個0*/
        *(ans+i)='0';    

      if( *(ans+i) != ISNULL)
      {
        d+=1;
        if(d==dec)
        {
          for(x=maxlen,n=maxlen-1; x>i ;x--,n--)
            *(ans+x)=*(ans+n);          
          *(ans+x)='.';

          if(d+x>=/*alen+blen*/strlen(numa)+strlen(numb) && *(ans+x-1)==ISNULL)
            *(ans+x-1)='0';/*浮點數計算結果小於1在小數點左一位補一個0*/

/*mvprintw(6,0,"alen=%d blen=%d d=%d x=%d i=%d ",alen,blen,d,x,i);
*/
          break;
        }
      }
    }
  }
 
  /*底下是修飾*ans的程式碼,如果發現有計算錯誤可將其註解後以lee_hbpfs_debug()查看*ans
    實際的內容看是否真的算錯(如果發生錯誤應該是進位的問題)*/

  /*消除前面的'\0'使*ans字串符合一般以'\0'結尾的字串格式*/
  for(x=0;x<maxlen;x++)
    if(*(ans+x)!=ISNULL && (*(ans+x)!='0' || *(ans+x+1)=='.'))
      break;
  for(i=0,n=x;n<=maxlen;i++,n++)
    *(ans+i)=*(ans+n);

  /*消除小數點後尾部的0*/  
  d=lee_memcycfg(ans,strlen(ans),INFO,'.');/*找出ans字串是否有小數點*/
  if(d!=-1)
  {
    for(x=maxlen;x>=0;x--)
    {
      if(isdigit(*(ans+x)) && *(ans+x)!='0')
        break;      
      *(ans+x)=ISNULL;    
    }    
  }
}


基本上這個函數不能用因為我還沒把它寫好
不過裡面有一些是我在寫加法及乘法時所使用到的辦法
用除錯函數觀察只呼叫加法及乘法函數時您會發現字串仍需處理才能做為ans
所以有興趣的人可自行撰寫本函數將之加在窗口函數後面
程式是人寫的,別讓工具的限制成為您想像力的極限
~程式中最重要的部份應該是註解而不是程式碼,這是因為解讀註解一定比解讀程式碼簡單
~程式寫好後約一個月就會忘的差不多了,所以花點時間把註解寫好至少能讓自己(或別人)看的懂當初在寫什麼

stlee

  • 鑽研的研究生
  • *****
  • 文章數: 817
    • 檢視個人資料
不限位數四則運算程式原碼
« 回覆 #10 於: 2007-01-14 14:32 »
代碼: [選擇]

/*兩數字字串直列式相加
ans,tmpa,tmpb三個字串的長度必須是maxlen的相同長度否則會溢位
tmpa與tmpb須是經由lee_hbpfs_primdec()標齊小數點及個位數的字串否則會計算錯誤
程式設計:李湘台於台灣台南永康-2007.01.14
*/
void lee_hbpfs_chadd(char *ans,char *tmpa,char *tmpb,int maxlen)
{
  char buf[2],bfa[2],bfb[2];
  int i,n,q,r,x,y,p;

  memset(buf,ISNULL,2);/*進位暫存區清空*/
  for(i=maxlen-1,p=maxlen;i>=0;i--)
  {
    if(isdigit(*(tmpa+i)) || isdigit(*(tmpb+i)))
    {      
      memset(bfa,ISNULL,2);
      if(isdigit(*(tmpa+i)))/*排除非數字0~9的其它ascii字元*/
        bfa[0]=*(tmpa+i);
      memset(bfb,ISNULL,2);
      if(isdigit(*(tmpb+i)))/*排除非數字0~9的其它ascii字元*/
        bfb[0]=*(tmpb+i);
      n=atoi(bfa)+atoi(bfb)+atoi(buf);
      if(n>9)/*發生進位*/
      {        
        q = n/10;
        r = n%10;
        buf[0]=q+48;/*ascii的數字從0,1,2,3,4,5,6,7,8,9以10進位表示為48,49,50....57*/

        p=i-1;/*進位旗標是目前這一位數的左邊一位*/
      }  
      else
      {
        memset(buf,ISNULL,2);/*進位暫存區清空*/
        r=n;
      }
      *(ans+i)=r+48;/*ascii的數字從0,1,2,3,4,5,6,7,8,9以10進位表示為48,49,50....57*/      

    }  
    else if(*(tmpa+i)=='.' || *(tmpb+i)=='.')
    {
      *(ans+i)='.';
      /*進位旗標遇到小數點要再往左進一位這在加法.999+.124的兩個小於1且以.號開始的字串相加
      時如沒令p-1會發生兩值的合大於1時其最終進位的1被擺到小數點後面成為.1123(正確為1.123)
      但在0.999+0.124的情況時則此值將不會被取用(最終進位值buf[0]為NULL)*/
      p-=1;
    }
    else
    {;}
  }  

/**/mvprintw(7,0,"(加,乘法)maxlem=%d buf=%s p=%d ",maxlen,buf,p);

  /*將最高位數的進位插入ans字串內*/
  if(p<0 && strlen(buf)>0 )/*已無空間可供放置進位的數字(進位旗標已達-1)*/
  {
    p=0;
    for(i=maxlen,n=maxlen-1; i>p ;i--,n--)/*將字串後推一個位元*/
      *(ans+i)=*(ans+n);    
    *(ans+p)=buf[0];
  }
  else if(strlen(buf)>0)/*最終有進位則將該數字放入p旗標所指位置(乘法的乘積加必用到)*/
    *(ans+p)=buf[0];
  else
  {;}
 
/**/lee_hbpfs_debug(tmpa,'p',tmpb,maxlen,ans,maxlen+1,15,3);

}


以前剛學c語言時很多老師(我去補習的,不是在學校學的)都說c的字串不能運算
...............
...............
小弟把它加起來了
程式是人寫的,別讓工具的限制成為您想像力的極限
~程式中最重要的部份應該是註解而不是程式碼,這是因為解讀註解一定比解讀程式碼簡單
~程式寫好後約一個月就會忘的差不多了,所以花點時間把註解寫好至少能讓自己(或別人)看的懂當初在寫什麼

stlee

  • 鑽研的研究生
  • *****
  • 文章數: 817
    • 檢視個人資料
不限位數四則運算程式原碼
« 回覆 #11 於: 2007-01-14 14:37 »
代碼: [選擇]

/*兩數字字串直列式相減
ans,tmpa,tmpb三個字串的長度必須是maxlen的相同長度否則會溢位
傳入該函數的tmpa必須大於tmpb否則運算會失敗(無法借位會傳回'-')
除法餘數小於除數的問題由除法函數自行處理,,因為補位如果在減法以遞迴進行則可能狀況是不知道該補多少位所以遞迴的深度將無法預測而造成可能的堆疊溢位,所以乾脆運算失敗將控制權交回除法函數(除法已可判斷餘數與除數字串所表示的數值大小所以發生此狀況可判定為程式錯誤)
程式設計:李湘台於台灣台南永康-2007.01.14
*/
int lee_hbpfs_chsub(char *ans,char *tmpa,char *tmpb,int maxlen)
{
  int i,n,x,j;
  char bfa[2],bfb[2];

/**/lee_hbpfs_debug(tmpa,'1',tmpb,maxlen,ans,maxlen+1,15,3);

  for(i=maxlen-1;i>=0;i--)
  {
    if(isdigit(*(tmpa+i)) || isdigit(*(tmpb+i)))
    {      
      memset(bfa,ISNULL,2);
      if(isdigit(*(tmpa+i)))/*排除非數字0~9的其它ascii字元*/
        bfa[0] = *(tmpa+i);
      memset(bfb,ISNULL,2);
      if(isdigit(*(tmpb+i)))/*排除非數字0~9的其它ascii字元*/
        bfb[0] = *(tmpb+i);

      if(atoi(bfa) < atoi(bfb))/*需要借位*/
      {
        if(i==0)/*已在最高位,左邊沒有可以借位的數字*/
          return(-1);/*減法失敗傳回-1*/        
         
        for(n=i-1;n>=0;n--)/*先往左找到可借位的數字所在旗標n*/
          if(isdigit(*(tmpa+n)) &&  *(tmpa+n)!='0')/*非0的數字即可借位*/
            break;
        if(n<0)/*左邊沒有可以借位的數字*/
          return(-1);/*減法失敗傳回-1*/
        else
        {
          *(tmpa+n) -= 1;/*可借位的數字需減1*/          
          /*此迴路主要用在如一整數減一個帶小數的數值,因為此整數沒有小數點後的值所以當
          前面找到被借位的數字並將其減1後其被借位右邊的值原本是'\0'此時也被借位所以直接
          將其改為'9'這樣一來即可在本次借位後設好該整數小數點右邊的狀態為.9999...n;而n
          是最終借位值以j=10代替;這樣在算式中能加回到正確的值*/
          for(x=n+1;x<i;x++)
            if(*(tmpa+x)!='.' && *(tmpb+x)!='.')/*tmpa不一定有小數點字元所以也要找tmpb*/          
              *(tmpa+x) = '9';
        }        
        j=10;
      }
      else
        j=0;        
     
      n=atoi(bfa)-atoi(bfb)+j;/*有借位j=10則a-b是負數時加回10即為a+(10-b)的意思*/
      *(ans+i)=n+48;/*ascii的數字從0,1,2,3,4,5,6,7,8,9以10進位表示為48,49,50....57*/

/**/mvprintw(7,0,"(減法)n=%d j=%d bfa=%s bfb=%s x=%d i=%d  *",n,j,bfa,bfb,x,i);
/**/lee_hbpfs_debug(tmpa,'2',tmpb,maxlen,ans,maxlen+1,15,3);
 
    }  
    else if(*(tmpa+i)=='.' || *(tmpb+i)=='.')
      *(ans+i)='.';
    else
    {;}
  }

/**/lee_hbpfs_debug(tmpa,'3',tmpb,maxlen,ans,maxlen+1,15,3);
   lee_hbpfs_delzero(ans,maxlen);/*消除前面的'\0'及'0'使*ans字串符合一般以'\0'結尾的格式*/
/**/lee_hbpfs_debug(tmpa,'4',tmpb,maxlen,ans,maxlen+1,15,3);

  return(1);/*成功傳回1*/
}

曾被減法的借位問題困擾所以寫了lee_hbpfs_debug()函數以觀察程式每一步的動作後終於把減法寫好
程式是人寫的,別讓工具的限制成為您想像力的極限
~程式中最重要的部份應該是註解而不是程式碼,這是因為解讀註解一定比解讀程式碼簡單
~程式寫好後約一個月就會忘的差不多了,所以花點時間把註解寫好至少能讓自己(或別人)看的懂當初在寫什麼

stlee

  • 鑽研的研究生
  • *****
  • 文章數: 817
    • 檢視個人資料
不限位數四則運算程式原碼
« 回覆 #12 於: 2007-01-14 14:40 »
代碼: [選擇]

/*兩數字字串直列式相乘
numa字串與numb字串的長度可以不必相同
anslen長度必須最少是numa+numb+1的長度,否則在處理浮點數相乘時會有溢位的錯誤
*/
void lee_hbpfs_chmul(char *ans,int anslen,char *numa,char *numb)
{
  char buf[2],bfa[2],bfb[2];  
  int i,n,x,q,r;  
  int alen,blen,ai,bi,alp,blp;
  char *anstmp,*temp;
 
  alen=strlen(numa);
  blen=strlen(numb);
  anstmp=(char *)malloc(anslen);
  /*memset(anstmp,ISNULL,anslen+1);*/
  temp=(char *)malloc(anslen);

  memset(buf,ISNULL,2);/*進位暫存區清空*/
  /*一般如果以橫式12345*678換成直式會寫成  12345
                                          *  678
  所以雙層迴路的外圈應是從678的8開始逐一與12345的54321順序乘過去,故外層控制678的876順序
  ,內層則控制12345的54321順序*/
  /*ans已多宣告了1Byte所以blp從maxlen-2開始以保留插入小數點時須右推一位的空間*/
  for(bi=blen-1,blp=anslen-2;bi>=0;bi--)
  {
    memset(temp,ISNULL,anslen);
    memset(buf,ISNULL,2);/*進位暫存區清空*/
    if(isdigit(*(numb+bi)))/*排除非數字0~9的 +.-號*/
    {
      for(ai=alen-1,alp=blp;ai>=0;ai--)
      {        
        if(isdigit(*(numa+ai)))/*排除非數字0~9的其它ascii字元*/
        {
          memset(bfa,ISNULL,2);
          if(isdigit(*(numa+ai)))/*排除非數字0~9的其它ascii字元*/
            bfa[0]=*(numa+ai);
          memset(bfb,ISNULL,2);
          if(isdigit(*(numb+bi)))/*排除非數字0~9的其它ascii字元*/
            bfb[0]=*(numb+bi);
          n=(atoi(bfa)*atoi(bfb))+atoi(buf);
          if(n>9)/*發生進位*/
          {                      
            q = n/10;
            r = n%10;            
            buf[0]=q+48;/*ascii的數字從0,1,2,3,4,5,6,7,8,9以10進位表示為48,49,50....57*/
          }  
          else
          {
            memset(buf,ISNULL,2);/*進位暫存區清空*/
            r=n;
          }
          *(temp+alp)=r+48;/*ascii的數字從0,1,2,3,4,5,6,7,8,9以10進位表示為48,49,50....57*/
          alp-=1;
        }
        else
        {;}
      }

/*mvprintw(21,0,"anslen=%d alp=%d blp=%d ",anslen,alp,blp-1);
/*refresh();
/**/

      *(temp+alp)=buf[0];/**tmpa接收最終進位值成為完整字串使之可與上一位數的相乘結果相加*/      
      /*將上一位數的乘積複製到buff供lee_hbpfs_chadd()運算出本位數的乘積到ans*/      
      memcpy(anstmp,ans,anslen);
      lee_hbpfs_chadd(ans,temp,anstmp,anslen);/*此行buff,tmpa可對調但以tmpa,buff則除錯較清楚*/
      blp-=1;/*blp-=1必須在if(isdigit(*(numb+bi)))的裡面否則遇到小數點會令tmpa多進一位造成錯誤*/
    }
  }

  lee_hbpfs_delzero(ans,anslen);/*消除前面的'\0'及'0'使*ans字串符合一般以'\0'結尾的格式*/

  free(anstmp);
  free(temp);
}

觀察乘法的除錯步驟滿好玩的
程式是人寫的,別讓工具的限制成為您想像力的極限
~程式中最重要的部份應該是註解而不是程式碼,這是因為解讀註解一定比解讀程式碼簡單
~程式寫好後約一個月就會忘的差不多了,所以花點時間把註解寫好至少能讓自己(或別人)看的懂當初在寫什麼

stlee

  • 鑽研的研究生
  • *****
  • 文章數: 817
    • 檢視個人資料
不限位數四則運算程式原碼
« 回覆 #13 於: 2007-01-14 14:47 »
代碼: [選擇]

/*求商值 ;如果rem<divisor傳回0否則找出divisor應乘n才會最接進rem而不超過rem後傳回n
程式設計:李湘台於台灣台南永康-2007.01.14
*/
int lee_hbpfs_quot(char *multmp,char *divisor,char *rem,int maxlen)
{
  /*lee_hbpfs_chmul()的參數是字串乘字串所以dividen應宣告為字串陣列而不是字元陣列*/
  char dividen[10][2]={"0","1","2","3","4","5","6","7","8","9"};
  char buf[2],bfa[2],bfb[2];
  int i,n,x,loopmax;
  int bigrem;
   
  /*bigrem有特殊需求但又不要在判斷後再執行一次lee_hbpfs_numcmp()所以在if內將
  函數的傳回值指定給bigrem當rem<divisor則傳回負值給bigrem又小於0即可傳回0但
  當bigrem>=0則可繼續後面的程式又不用再叫用lee_hbpfs_numcmp()一次*/
  if( (bigrem=lee_hbpfs_numcmp(rem,divisor,maxlen)) < 0)
  {
/**/mvprintw(10,0,"餘數比除數小,返回呼叫者函數處理補位或補0作業");
    return(0);
  }

  memset(buf,ISNULL,2);  
  if(bigrem>0)
  {        
    /*程式進行到這裡時可確定rem一定是不小於divisor的值,所以當rem字串長度等於divisor
    字串長度表示rem是等於divisor的所以直接設為1即可,而rem在lee_hbpfs_numcmp()判斷完
    小於divisor已返回呼叫者函數進行補位或補0才能再次叫用本函數;所以進行到這裡時前rem
    字串原先可能是一個"很接近divisor"的值或"接近整除"的值,由於兩者範圍有可能是除數
    乘1~9的任何一個可能範圍內所以設為9...例如100/99則餘數1是一個"接近整除"的值所以
    在補0後將造成須執行9次乘法才能取得商數;但以100/101來說被除數在rem3次借位後使rem
    變成100則是一個"接近divisor"的值在補了0後變成1000則只要執行一次乘法就可以求出
    商數了*/    
    if(*(divisor+0) >= *(rem+0))/*除數最高位元>=餘數最高位元*/
    {
      if(strlen(rem) == strlen(divisor))
        buf[0]='1';
      else
      {
    /*可能有更好的方法令"接近整除"的餘數在補位或補0後不用執行9次的乘法;如果有則加在這*/
        buf[0]='9';
      }
    }
    else /*if(*(divisor+0) < *(rem+0))*/
    {
    /*如果餘數的最高位元大於除數最高位元時則直接將兩值相除的商數做為商在最差情況下只
    會執行兩次:例如餘數是789除數是299以7除2得到3則在進行到2時299的乘積就會小於餘數了
    ;當除數第二位以後是較小的數如244則在商值為3時則只要進行一次乘法乘積就比餘數小了*/
      memset(bfa,ISNULL,2);
      memset(bfb,ISNULL,2);
      bfa[0]=*(rem+0);
      bfb[0]=*(divisor+0);
      buf[0]=atoi(bfa)/atoi(bfb)+48;
    }
  }
  else /*bigrem==0 餘數等於除數*/
    buf[0]='1';

  loopmax=atoi(buf);
  for(i=loopmax;i>0;i--)
  {
    memset(multmp,ISNULL,maxlen);
    lee_hbpfs_chmul(multmp,maxlen,divisor,dividen[i]);    
 
/**/lee_hbpfs_debug(rem,'Q',multmp,maxlen,rem,maxlen,15,3);
   
    /*除數與該位數商值的乘積最接進餘數且不大於餘數時傳回i*/
    if(lee_hbpfs_numcmp(multmp,rem,maxlen) <= 0)
      return(i);

  }
  return(-1);
}

有沒有不要算到9次乘法就能取得商數呢
如果以較大值除較小值那餘數3除數8時會得到2但8乘3得24也還小於30的啊
所以應該還有改進的空間吧
程式是人寫的,別讓工具的限制成為您想像力的極限
~程式中最重要的部份應該是註解而不是程式碼,這是因為解讀註解一定比解讀程式碼簡單
~程式寫好後約一個月就會忘的差不多了,所以花點時間把註解寫好至少能讓自己(或別人)看的懂當初在寫什麼

stlee

  • 鑽研的研究生
  • *****
  • 文章數: 817
    • 檢視個人資料
不限位數四則運算程式原碼
« 回覆 #14 於: 2007-01-14 14:51 »
代碼: [選擇]

/*............................................................................
不限位數的加法
可作出"abc=123"與"xyz=456"的123*456的運算但前面的修飾詞儘量不要用中文因為'.'號也可能是中文組字的一部份而使得正整數變成浮點數
程式設計:李湘台於台灣台南永康-2007.01.14
............................................................................*/
char *lee_hbpfs_add(char *numa,char *numb)
{
  char *ans,*tmpa,*tmpb;
  int maxlen;
  int i,d,n,x,y;  

  /*加法最多只進一位所以應找出最長字串長度+1即可,
  但是如123+0.456的算式應標齊小數點位置所以應為兩字串長度相加+1;這樣看起來有點浪費記憶體
  空間,但以兩個100位數的值相加來看也只不過多宣告了100/2Byte以下而且不用再搜尋a,b字串是否
  有小數點這樣對效能也有所幫助;所以用最多n/2Byte即可以換取效能來說是很划算的*/
 
  maxlen=strlen(numa)+strlen(numb)+1;
  ans=(char *)malloc(maxlen+1);
  memset(ans,ISNULL,maxlen+1);
  tmpa=(char *)malloc(maxlen);
  memset(tmpa,ISNULL,maxlen);
  tmpb=(char *)malloc(maxlen);  
  memset(tmpb,ISNULL,maxlen);

/**/mvprintw(14,0,"無限位數加法");
/**/lee_hbpfs_debug(numa,'+',numb,maxlen,ans,maxlen+1,5,10);

  /*排除numa的正負號及非數字字元*/  
  lee_hbpfs_digit(tmpa,numa);
  /*排除numb的正負號及非數字字元*/
  lee_hbpfs_digit(tmpb,numb);
  lee_hbpfs_primdec(tmpa,tmpb,maxlen,numa,numb);/*將tmpa,tmpb標齊為直列算式格式的字串*/
  lee_hbpfs_chadd(ans,tmpa,tmpb,maxlen);

/**/lee_hbpfs_debug(tmpa,'+',tmpb,maxlen,ans,maxlen+1,5,10);


  free(tmpa);
  free(tmpb);  
  return(&*ans);  
 
}

/*............................................................................
不限位數的乘法
可作出"abc=123"與"xyz=456"的123*456的運算但前面的修飾詞儘量不要用中文因為'.'號也可能是中文組字的一部份而使得正整數變成浮點數
程式設計:李湘台於台灣台南永康-2007.01.14
............................................................................*/
char *lee_hbpfs_mul(char *numa,char *numb)
{
  char *ans,*tmpa,*tmpb;
  int maxlen;

  maxlen=strlen(numa)+strlen(numb)+1;    
  /*乘法須從乘數的最低位數逐一與被乘數相乘,所以先找出兩字串的長度並從後面以雙層迴路達到此需求*/
  ans=(char *)malloc(maxlen+1);/*n數與x數相乘須做x次的加法此空間會隨時變動,但仍是最後的計算結果*/
  memset(ans,ISNULL,maxlen+1);
  tmpa=(char *)malloc(maxlen);
  memset(tmpa,ISNULL,maxlen);
  tmpb=(char *)malloc(maxlen);  
  memset(tmpb,ISNULL,maxlen);

  /*排除numa的正負號及非數字字元*/  
  lee_hbpfs_digit(tmpa,numa);
  /*排除numb的正負號及非數字字元*/
  lee_hbpfs_digit(tmpb,numb);

/**/lee_hbpfs_debug(numa,'*',numb,maxlen,ans,maxlen+1,5,17);

  lee_hbpfs_chmul(ans,maxlen,/*numa,numb*/tmpa,tmpb);

/**/lee_hbpfs_debug(numa,'*',numb,maxlen,ans,maxlen+1,5,17);

  return(&*ans);
 
}

/*............................................................................
不限位數的減法
可作出"abc=123"與"xyz=456"的123*456的運算但前面的修飾詞儘量不要用中文因為'.'號也可能是中文組字的一部份而使得正整數變成浮點數
程式設計:李湘台於台灣台南永康-2007.01.14
............................................................................*/
char *lee_hbpfs_sub(char *numa,char *numb)
{
  char *ans,*tmpa,*tmpb;
  int subret,maxlen;
   
  maxlen=strlen(numa)+strlen(numb)+1;
  ans=(char *)malloc(maxlen+1);
  memset(ans,ISNULL,maxlen+1);
  tmpa=(char *)malloc(maxlen);
  memset(tmpa,ISNULL,maxlen);
  tmpb=(char *)malloc(maxlen);
  memset(tmpb,ISNULL,maxlen);


/**/lee_hbpfs_debug(numa,'-',numb,maxlen,ans,maxlen+1,5,24);
 
  /*排除numa的正負號及非數字字元*/  
  lee_hbpfs_digit(tmpa,numa);
  /*排除numb的正負號及非數字字元*/
  lee_hbpfs_digit(tmpb,numb);

  lee_hbpfs_primdec(tmpa,tmpb,maxlen,numa,numb);/*將tmpa,tmpb標齊為直列算式格式的字串*/
  subret=lee_hbpfs_chsub(ans,tmpa,tmpb,maxlen);
  if(subret==-1)/*numa-numb是負值*/
  {
/**/mvprintw(28,0,"numa-numb是負值:傳回值buf= %d ",subret);
    memset(ans,ISNULL,maxlen+1);
    subret=lee_hbpfs_chsub(ans,tmpb,tmpa,maxlen);
  }

/**/mvprintw(29,0,"numa-numb是正值:傳回值buf= %d ",subret);
/**/lee_hbpfs_debug(tmpa,'-',tmpb,maxlen,ans,maxlen+1,5,24);

  free(tmpa);
  free(tmpb);
  return(&*ans);
}

這三個函數是窗口函數供程式有需要時各別叫用
除法也是窗口函數但比較複雜一點所以分開來
程式是人寫的,別讓工具的限制成為您想像力的極限
~程式中最重要的部份應該是註解而不是程式碼,這是因為解讀註解一定比解讀程式碼簡單
~程式寫好後約一個月就會忘的差不多了,所以花點時間把註解寫好至少能讓自己(或別人)看的懂當初在寫什麼

stlee

  • 鑽研的研究生
  • *****
  • 文章數: 817
    • 檢視個人資料
不限位數四則運算程式原碼
« 回覆 #15 於: 2007-01-14 14:56 »
代碼: [選擇]

/*............................................................................
不限位數的除法
可作出"abc=123"與"xyz=456"的123*456的運算但前面的修飾詞儘量不要用中文因為'.'號
也可能是中文組字的一部份而使得正整數變成浮點數
程式設計:李湘台於台灣台南永康-2007.01.14
............................................................................*/
char *lee_hbpfs_div(char *numa,char *numb,int precision)
{  
  char qch[10]={'0','1','2','3','4','5','6','7','8','9'};
  char *quot,*rem;
  char *multmp,*remtmp;
  char *divisor,*dividen;
  int maxlen,quotlen;
  int sorlen,denlen,remlen,sd,dd,szi,rln,mln,sln,qln;  
  int i,d,n,x,y;
  int subret,sordr,qxi,dxi,pxi;
  char buf[2],bfa[2],bfb[2];
 
  /*一般來說除法的商及餘數都不會比被除數numa來得長,除非是除不盡才有求到小數後n位的
  精確度需求當兩值相除不知是否可整除時precision可傳入-1此時字串長度是以內定的
  (a+b+1)*2則精確度應有(a+b)*2所以當precision傳入-1則會儘可能求到參數所能滿足的最大
  範圍而傳入非負值則求到小數點後precision位為止*/
  denlen=strlen(numa);
  sorlen=strlen(numb);
  if(denlen<1 || sorlen<1)/*運算結果必為0*/
  {
  ;
  }

  maxlen=denlen+sorlen+1;
  if(precision<0)  
    quotlen=maxlen*2;
  else
    quotlen=maxlen+precision+1;
 
  dividen=(char *)malloc(maxlen);/*被除數*/  
  divisor=(char *)malloc(maxlen);/*除數*/    
  multmp=(char *)malloc(maxlen);/*乘積暫存區*/    
  remtmp=(char *)malloc(maxlen);/*餘補暫存區*/
  rem=(char *)malloc(maxlen);/*餘數*/
  quot=(char *)malloc(quotlen+1);/*商數*/  
  memset(dividen,ISNULL,maxlen);
  memset(divisor,ISNULL,maxlen);
  memset(multmp,ISNULL,maxlen);
  memset(remtmp,ISNULL,maxlen);
  memset(rem,ISNULL,maxlen);
  memset(quot,ISNULL,quotlen+1);

  /*被除數排除正負號及非數字字元*/  
  lee_hbpfs_digit(dividen,numa);
  /*除數排除正負號及非數字字元*/
  lee_hbpfs_digit(divisor,numb);

/**/mvprintw(7,0,"(除法)quotlen=%d maxlen=%d denlen=%d sorlen=%d  *",
             quotlen,maxlen,denlen,sorlen);
/*lee_hbpfs_debug(dividen,'/',divisor,maxlen,quot,quotlen,5,20);



  /*找出小數點所在位置*/  
  dd=lee_memcycfg(dividen,maxlen,INFO,'.');/*找出a字串小數點位置(被除數)*/
  sd=lee_memcycfg(divisor,maxlen,INFO,'.');/*找出b字串小數點位置(除數)*/
  if(sd>=0)/*除數有小數點*/
  {
    /*除數的小數點去除,並找出小數點共右移d位元而成為正整數*/
    for(x=sd,n=sd+1,d=0;x<sorlen;x++,n++,d++)
    {
      *(divisor+x)=*(divisor+n);
      if(*(divisor+n)==ISNULL)
        break;
    }  
    /*被除數也有小數點則將其小數點也右移d個位元;右移方式是透過字元的交換達成;
    條件式內的迴路變數i為計步器,x為小數點所在旗標,n為小數點右一位數字所在旗標,
    如此在執行交換到d次時即可將小數點右移,補0也在迴路內進行,原則是當n旗標所指
    字元是字串結束字元'\0'時就開始補0*/
    if(dd>=0)
    {      
      memset(buf,ISNULL,2);/*清除暫存區*/
      for(i=0,x=dd,n=dd+1; i<d ;i++,x++,n++)
      {        
        buf[0]=*(dividen+x);/*將小數點字元'.'保存到暫存區*/
        if(*(dividen+n)==ISNULL)/*小數點右邊一位是字串結束字元'\0'則補0*/
        {
          buf[0]=ISNULL;/*開始補0後將buf[0]設為'\0'可防止"尾巴"沒清掉的錯誤*/
          *(dividen+n)='0';
        }
        /*下兩行是做字元交換工作,但在之前的判斷(小數點右邊是結束字元'\0')可令其
        做到補0與清尾的工作(清尾就是將字串尾加上'\0'的工作)*/
        *(dividen+x)=*(dividen+n);
        *(dividen+n)=buf[0];        
      }
    }
    else/*被除數是正整數則補d個0*/
      for(i=denlen;i<denlen+d;i++)
        *(dividen+i)='0';
  }


/**/mvprintw(12,0,"d=%d sd=%d dd=%d 原長度:sorlen=%d denlen=%d maxlen=%d quotlen=%d ",
                    d,sd,dd,sorlen,denlen,maxlen,quotlen);

  lee_hbpfs_delzero(divisor,maxlen);/*消除前面的'\0'及'0'使字串符合一般以'\0'結尾的格式*/
  lee_hbpfs_delzero(dividen,maxlen);/*消除前面的'\0'及'0'使字串符合一般以'\0'結尾的格式*/

  /*重設sorlen為除數去除小數點後的divisor字串長度;denlen為補0後的dividen字串長度
  sorle,及denlen在以下的運算極重要,未去小數點的除數及未補0的被除數字串長度無實際
  運算價值(除數字串長度含小數點則過長且無意義,被除數沒補0則過短);所以在除數去小
  數點及被除數補0後重設sorlen及denlen是必須的動作*/
  denlen=strlen(dividen);
  sorlen=strlen(divisor);  
  qxi=0;/*商數值填入的旗標起始值*/
  dxi=0;;/*餘數在dividen借位的起始旗標;超過denlen位時開始補0*/
  rln=0;/*餘數字串長度啟始值;還沒開始運算當然是沒有餘數的所以設為0*/
  pxi=-1;/*遇到dividen字串的小數點或無位可借才將pxi設為0並開始累加pxi到達precision精確度*/  
  do
  {
   
    if(pxi>=0 && pxi==precision)/*已達精確度要求*/
      break;
   
    rln=strlen(rem);
    if(lee_hbpfs_numcmp(rem,divisor,maxlen) < 0)/*餘數小於除數則須補位或補0*/
    {  
      /*借位前發現'.'字元*/    
      if(*(dividen+dxi)=='.')/*dividen字串是一個浮點數*/
      {
        *(quot+qxi)='.';
        qxi+=1;
        /*遇到小數點已可確定的將pxi設為0但如"10.110.2"(應是"10.1","10.2"但遺失10.1的'\0'字元)
        這樣的字串則可能會令迴路沒完沒了所以還是再加上if(pxi<0)的判斷*/
        if(pxi<0)
          pxi=0;
       
        /*這裡註解的部份可在"10.110.2"這種有兩個小數點的字串發生時提出錯誤或跳出迴路
        else if(pxi>=0)
          break;
        else
        {;}        
        */
        dxi+=1;/*小數點位置可能在最後面如"102."所以遇到小數點就要令dxi+1*/
      }

      if(dxi<denlen)/*dividen有位可借*/
      {        
        *(rem+rln)=*(dividen+dxi);          
        dxi+=1;


        /*借位後發現'.'字元*/    
        if(*(dividen+dxi)=='.')/*dividen字串是一個浮點數*/
        {
          *(quot+qxi)='.';
          qxi+=1;
          /*遇到小數點已可確定的將pxi設為0但如"10.110.2"(應是"10.1","10.2"但遺失10.1的'\0'字元)
          這樣的字串則可能會令迴路沒完沒了所以還是再加上if(pxi<0)的判斷*/
          if(pxi<0)
            pxi=0;
       
          /*這裡註解的部份可在"10.110.2"這種有兩個小數點的字串發生時提出錯誤或跳出迴路
          else if(pxi>=0)
            break;
          else
          {;}        
          */
          dxi+=1;/*小數點位置可能在最後面如"102."所以遇到小數點就要令dxi+1*/
        }


      }
      else/*無位可借則補0*/
      {
        *(rem+rln)='0';        
        /*pxi的初始值-1未變動過(被除數為一整數)*/
        if(pxi<0 && qxi>=denlen+(sorlen-1))
        {
          pxi=0;          
         *(quot+qxi)='.';
         qxi+=1;          
        }        
      }

    }        
    if(pxi>=0)/*精確度計算變數已啟動*/
      pxi+=1;
       
/**/mvprintw(15,0,"dxi=%d qxi=%d pxi=%d *",dxi,qxi,pxi);

    /*取得本位數乘以除數divisor的乘積multmp;傳回的值n就是本位數應填入的商數*/
    n=lee_hbpfs_quot(multmp,divisor,rem,maxlen);
    if(n<0)
    {
/**/mvprintw(10,0,"程式錯誤:除數乘到0仍小於餘數");
/**/refresh();
      break;
    }
    /*lee_hbpfs_quot()傳回的是數值n如此一來可將本位數的商值設為qch[n]字元陣列
    內對應n所代表的字元*/
    *(quot+qxi)=qch[n];/*填入本位數的商數*/
/**/
/**/
/*    if(qxi>=denlen+(sorlen-1) && rln<1 && n==0)/*已整除*/
/*      break;  
*/
    qxi+=1;/*將商數字串旗標右移一位*/


/**/lee_hbpfs_debug(dividen,'/',divisor,maxlen,quot,quotlen,5,20);
/**/lee_hbpfs_debug(rem,'W',multmp,maxlen,quot,quotlen,5+sorlen+1,23);

    /*當本位數的商值大於0表示本位數商值與除數的乘積要和現有的餘數做減法運算以求出新的餘數*/
    if(n>0)
    {        
      memcpy(remtmp,rem,maxlen);/*將rem複製到remtmp*/
      memset(rem,ISNULL,maxlen);/*清空rem以接收新的餘數*/    
      lee_hbpfs_primdec(remtmp,multmp,maxlen,remtmp,multmp);/*標齊為直列算式格式的字串*/
      subret=lee_hbpfs_chsub(rem,remtmp,multmp,maxlen);/*執行不限位數減法運算出新的餘數rem*/
      if(subret<0)
      {
/**/mvprintw(10,0,"程式錯誤:餘數小於本位數商值與除數的乘積卻執行了減法運算");
/**/refresh();
        break;
      }      
    }    
  }while(qxi<quotlen);

  free(dividen);
  free(divisor);
  free(multmp);
  free(remtmp);

  /*if(op=='%')
  {
    free(quot);
    return(&*rem);
  }
  else
  {
    free(rem);
    return(&*quot);
  }
  */
/*  free(rem);
  return(&*quot);
*/
/*這裡是測試圓週率時判斷是否為整除如整除則rem不會留任何字元
長度為0所以填入一個0;或不填0則測試函數將無字元可顯示*/
  free(quot);
  if(strlen(rem)<1)
    strcat(rem,"0");
  return(&*rem);

}


功德圓滿
程式是人寫的,別讓工具的限制成為您想像力的極限
~程式中最重要的部份應該是註解而不是程式碼,這是因為解讀註解一定比解讀程式碼簡單
~程式寫好後約一個月就會忘的差不多了,所以花點時間把註解寫好至少能讓自己(或別人)看的懂當初在寫什麼

stlee

  • 鑽研的研究生
  • *****
  • 文章數: 817
    • 檢視個人資料
不限位數四則運算程式原碼
« 回覆 #16 於: 2007-01-14 15:45 »
以前就很想寫一個字串運算的函數庫了,因為曾在轉型及精確度方面吃了很大的虧
...把客戶的獲利算出他一輩子也賠不起的數字><
原因在於將小數點後2位的浮點數做了4次以上的乘法然後轉型再運算結果就是沒頭路
其實我一直都是一個業餘的程式開發者,只是朋友知道我會寫程式便委託我幫他們寫一些簡單的程式以
幫助他們做一些資料運算的死工作(每天重覆人工計算的工作)要計算的金額說大不大說小的話我也要賺個好幾年
本來以為透過轉型便能把事情搞定結果往往不是如此,所以一賭..爛掉的名聲就把所有要計算的數字通通宣告成
字串給他輸入然後統一由一個函數負責接收該字串計算ans候傳回字串ans
....之後花就開了(不是菊花)鳥叫了春天來了人生變彩色了程式也正常了
不過以一個程式開發人員來說是不能就此滿足的,因為還有型別最大表示值的問題
當初以為這只能靠電腦硬體的進步或購買昂貴的機器或軟體才能達到大數值運算的最大滿足,但事情就是這樣發生的
........晚上睡不著拿了一本書隨便翻翻...
C名提精選百則技巧篇-使用C語言-儒林出版,作者:先鏡光
看到裡面有個題目[無限位數算數-第七部份第四題]
原來在1989年就有人寫了無限位數的加法及乘法了(我沒用到裡面的程式但有用到觀念)
所以馬上拿出筆和紙在紙上做了任一數的減法和除法的運算發現這些技巧原來
我們小學就學過了...只要我能將小學時學到的四則運算的技巧搬到電腦上不就
能達到不限位數四則運算的程式了嗎!!!!

程式還有很多需要改進的地方希望各位先進能給予批評和指教,謝謝大家
2007.01.14李湘台於台灣台南永康
程式是人寫的,別讓工具的限制成為您想像力的極限
~程式中最重要的部份應該是註解而不是程式碼,這是因為解讀註解一定比解讀程式碼簡單
~程式寫好後約一個月就會忘的差不多了,所以花點時間把註解寫好至少能讓自己(或別人)看的懂當初在寫什麼

ricky

  • 實習板主
  • 鑽研的研究生
  • *****
  • 文章數: 669
    • 檢視個人資料
    • Ricky 碎碎唸
不限位數四則運算程式原碼
« 回覆 #17 於: 2007-01-19 10:32 »
其實gnu 本身就有一套 gmp函式庫
可以用來處理不限位數的運算(特別是應用在像RSA這類需要大位數的加解密運算)
http://www.swox.com/gmp/
官方網站上還附有一個sample code
可以用來計算到百萬位以上的圓周率
參考一下吧
我的symfony作品:YOMOpets 寵物誌
有興趣可以一起來討論symfony喔
我的部落格:http://ricky.ez2.us/

stlee

  • 鑽研的研究生
  • *****
  • 文章數: 817
    • 檢視個人資料
不限位數四則運算程式原碼
« 回覆 #18 於: 2007-01-19 15:27 »
晴天霹靂><
把兩個禮拜的青春還我
...
...
...
可是目前市面上有關GNU函數庫的書還有點不好找
可是把它當練功吧^^
謝謝您的告知!!
程式是人寫的,別讓工具的限制成為您想像力的極限
~程式中最重要的部份應該是註解而不是程式碼,這是因為解讀註解一定比解讀程式碼簡單
~程式寫好後約一個月就會忘的差不多了,所以花點時間把註解寫好至少能讓自己(或別人)看的懂當初在寫什麼