全部分數均可以表示成小數,可是小數中只有有限小數、無限循環小數能夠表示成分數,無限不循環小數不能表示成分數。函數
有限小數改寫成分數:分子數小數部分的數,分母是10的分子長度的次冪;spa
純循環小數改寫成分數:分子是一個循環節的數字組成的數,分母各位數字都是9,9的個數與循環節中的數字的個數相同;code
混循環小數改寫成分數:分紅有限小數部分和循環節部分處理,各部分同上。rem
最後找到分子、分母的最大公約數,把分數化成最簡分數便可。字符串
#include <stdio.h> #include <string.h> /* 函數功能:解析字符串爲分數 * 參數表:strNum = 字符串,格式爲 *.*(*),括號內爲循環節 * intgr = 整數部分 * nmrtr = 分子 * dnmtr = 分母 * 返回值:0 = 輸入錯誤(括號未匹配) * 1 = 解析成功 */ char fraction(char *strNum, int *intgr, unsigned *nmrtr, unsigned *dnmtr) { char *pDot = strchr(strNum, '.'); // 小數點的位置 char *pLeftBracket = strchr(strNum, '('); // 左括號的位置 char *pRightBracket = strchr(strNum, ')'); // 右括號的位置 char *p; *intgr = 0; *nmrtr = 0; *dnmtr = 1; // 先處理整數部分 p = (strNum[0] == '-' ? strNum + 1 : strNum); while((NULL != pDot && p < pDot) || (NULL == pDot && *p)) *intgr = 10 * *intgr + *p++ - '0'; if(strNum[0] == '-') *intgr = -*intgr; // 再處理小數部分 if(NULL == pDot) return 1; p = pDot + 1; // 沒有括號 = 有限小數:轉換成10的倍數做爲分母的分數 if(NULL == pLeftBracket && NULL == pRightBracket) { while(*p) { *nmrtr = 10 * *nmrtr + *p++ - '0'; *dnmtr *= 10; } } // 有一對匹配的括號 = 無限循環小數 else if(NULL != pLeftBracket && NULL != pRightBracket) { unsigned temp1 = 0, temp2 = 0, temp3 = 1, temp4 = 1; // 有限小數部分:同有限小數 while(p < pLeftBracket) { temp1 = temp1 * 10 + *p++ - '0'; temp3 *= 10; } // 循環節部分:分子爲一個循環節,分母爲循環節長度個數的 9 p = pLeftBracket + 1; while(p < pRightBracket) { temp2 = temp2 * 10 + *p++ - '0'; temp4 *= 10; } temp4--; // 合併:t1/t3 + t2/(t3*t4) *nmrtr = temp1 * temp4 + temp2; *dnmtr = temp3 * temp4; } // 只有一個括號 = 輸入錯誤 else { return 0; } // 展轉相除法求分子、分母的最大公約數 unsigned temp, gcd = *dnmtr, remainder = *nmrtr; while(remainder) { temp = gcd % remainder; gcd = remainder; remainder = temp; } *nmrtr /= gcd; *dnmtr /= gcd; return 1; } int main(int argc, char **argv) { int intgr; unsigned nmrtr, dnmtr; if(argc == 2) { fraction(argv[1], &intgr, &nmrtr, &dnmtr); if(nmrtr > 0) printf("%s = %d %d/%d", argv[1], intgr, nmrtr, dnmtr); else printf("%s = %d", argv[1], intgr); } else { printf("Usage : %s *.*(*)", argv[0]); } return 0; }