SOGO論壇

標題: 請問這C++程式碼有改進的地方嗎? [列印本頁]

作者: alan1573    時間: 2010-3-26 15:13:29     標題: 請問這C++程式碼有改進的地方嗎?

小的做了一個有關進制轉換的程式,可是怎樣看就是有一種美中不足的感覺
請問大大們這個程式有可以改進地方嗎? 或是使電腦執行時更有效率的方法嗎?

(以下為程式碼內容:)
#include <stdio.h>
#include <math.h>

long double ToSum10(int Num[] , int base , int T , int TT); //把輸入字元計算成十進位數字
void To_2_8_10_16(long double Sum10,int base,int check2); //=====數字型態10進位,轉成4種型態輸出
int CheckFunction(int Num[] , int base , int T); //===檢查輸入字元是否符合選擇的base

void main(void)
{
int debug=1; //=================對付getchar無法重複執行的缺點=>執行後+1,奇數時執行,偶數時跳過BUG
int T=0 , TT=-1 , check , check2; //======輸入字元數量,小數點位置,小數點數量,正負號
int Num[30]={0} , N , base  ; //=存入字元的陣列,N=暫存器,base=進制
long double Sum10=0; //==========10進制總和

printf("======如輸入為16進制,﹝A-F﹞使用大寫才是有效輸入!======\n");

while(1)  { //使程式無限重複執行
do {
         check=check2=T=base=Sum10=0; //================給初始值       
         TT=-1; //===============================給初始值
         if (debug%2==1) //======================偶數跳過不處理
         printf("請輸入一個數字(整數最多10位,小數3位!!):");
     do { //=================================debug偶數時照樣執行,使錯誤消失
         N=getchar();
         if (N!='\n')
            Num[T++]=N; //===================累計輸入數量,存入陣列
         if (N=='.')       
                    {
             TT=T; //========================記下小數點的位置
             check++;
                    }  
            } while(N!='\n');
         if (TT==-1)
                 TT=T+1; //==========================沒有小數點的情況,給值方便後面計算
     while (Num[0]=='-') //如果Num[0]為負號,陣列往前取代一格,直到Num[0]不為負號,方便計算
       {
        for (int d=0;d<T;d++)     
            Num[d]=Num[d+1];
                T--; //字元數量扣1
                TT--; //小數點位置扣1
        check2=1; //為負值,使後面輸出負號
       }
         if (check==1)
         while ( Num[T-1]=='0') //===========小數點後無效的0去掉,T扣回來
                 T--;
    } while (check>1 || TT>11 || T-TT>3); //避免多個小數點,避免整數超過10位,避免小數超過3位
if (debug%2==1) //偶數跳過不處理
     do {
         printf("請輸入進制 <2、8、10、16>:");               
         scanf("%d",&base);       
        } while(base!=2 && base!=8 && base!=10 && base!=16 ); //確保輸入為(2 8 10 16)其中之一
/*==========================================輸入部分完成========================================*/
debug++;        
if ( CheckFunction(Num,base,T) == 0 ) //呼叫函式,確認輸入是否符合進制
          continue;
Sum10 = ToSum10(Num ,base ,T ,TT); //===呼叫函式,求得10進位總數
switch(base)
           {
            case 2: //==================呼叫函式轉換其他三種進制
                           To_2_8_10_16(Sum10,8,check2);
                           To_2_8_10_16(Sum10,10,check2);
                           To_2_8_10_16(Sum10,16,check2);
                           break;
            case 8: //==================呼叫函式轉換其他三種進制
                           To_2_8_10_16(Sum10,2,check2);
                           To_2_8_10_16(Sum10,10,check2);
                           To_2_8_10_16(Sum10,16,check2);
                           break;   
                case 10: //==================呼叫函式轉換其他三種進制
                           To_2_8_10_16(Sum10,2,check2);
                           To_2_8_10_16(Sum10,8,check2);
                           To_2_8_10_16(Sum10,16,check2);
                           break;            
                case 16: //==================呼叫函式轉換其他三種進制
                           To_2_8_10_16(Sum10,2,check2);
                           To_2_8_10_16(Sum10,8,check2);
                           To_2_8_10_16(Sum10,10,check2);
                           break;
       } //switch(base)結束
  printf("===================================================\n");
} //重複執行的while結束
} /*end function main*/

void To_2_8_10_16(long double Sum10,int base,int check2) //傳入(總數,進制,正負號)
{
long S = Sum10 ; //========S====>整數部分
double Sp = Sum10 - S; //==Sp===>小數部份
int a[40]={0};
int t=0,tt=0;

printf("\n轉換成<%d>進制\n",base);
do {
         if ( S%base < 10 )
          a[t++] = S % base + 48 ; //==以字元方式存入陣列
         else
          a[t++] = S % base + 55 ; //==存入A~F
     S=S/base;
    }while ( S>0 );
if (t>=11) //=========================如整數超過10位 輸出溢位
         printf("發生溢位!!\n需要的位數為:%d\n",t);
else
     {
          printf("不會發生溢位!!,轉換的數值如下:");
          if (check2==1) //若為負值先輸出負號
                  printf("-");
      for (int ss=t-1 ; ss>=0 ; ss--)
               printf("%c",a[ss]); //======整數部份輸出結束
      if (Sp!=0.0) //小數點後面
         {
              printf(".");
          while (Sp!=0.0 && tt<3)
                {
                             int Spp=0;
                 Sp=Sp*base;
                 Spp=Sp; //擷取整數部份
                             Sp=Sp-Spp; //留下小數部份
                             if (Spp<10)
                     printf("%c",Spp+48); //1~9
                             else
                     printf("%c",Spp+55); //A~F                       
                             tt++; //計數器++,控制小數點後面輸出位數
                    } //while結束            
         } //if(Sp)結束
      printf("\n");
     } //else結束
} //函式結束

int CheckFunction(int Num[] , int base ,int T) //傳入(陣列,進制,字元數量)
{
int base2[3] = {'0','1','.'}; //給各進制範圍
int base8[9] = {'0','1','2','3','4','5','6','7','.'};
int base10[11]={'0','1','2','3','4','5','6','7','8','9','.'};
int base16[17]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','.'};

for (int f=0 ; f<T ; f++) //陣列字元一個個比對,檢查是否有錯誤輸入
         {
      int x=0;
          for(int ff=0 ; ff < base+1 ; ff++)
             {
          if(base==2)
                     if(Num[f]==base2[ff])
                        x=1;
                  if(base==8)
                     if(Num[f]==base8[ff])
                        x=1;
                  if(base==10)
                     if(Num[f]==base10[ff])
                        x=1;
                  if(base==16)
                     if(Num[f]==base16[ff])
                        x=1;
             } //for(ff)結束
          if(x==0) //某輸入字元不在設定範圍內
                {
             printf("輸入錯誤,請重新來過!!\n\n");
             return 0; //回傳錯誤
            } //if結束
     } //for(f)結束
  return 1; //回傳無誤
}

long double ToSum10(int Num[] , int base , int T , int TT) //傳入(陣列,進制,字元數,小數點位置)
{
  long double Sum10=0;
  for (int o=0 ; o<T ; o++)
          {
       if ( Num[o]!='.' )
                  {
                   if (Num[o]<58) //======='1'~'9' ACEII=48~57 扣48=數值
               Sum10 = Sum10 + (Num[o]-48) * (long double)pow( base , (long double)(TT-2-o) );
                   else //================='A'~'F' ACEII=65~70 扣55=數值
               Sum10 = Sum10 + (Num[o]-55) * (long double)pow( base , (long double)(TT-2-o) );
                  }
           else
                   TT++; //===========================配合位數轉換
      } //for(o)結束
  return  Sum10; //回傳計算後的值
}
作者: edvx    時間: 2010-3-28 13:07:34

將所有的double變成int

void main(void) => int main(void)

程式就可以跑了,但是程式跑出的結果是有誤的

以下是把剛剛說要改的的地方改好的
--------------------
#include <stdio.h>
#include <math.h>

long int ToSum10(int Num[] , int base , int T , int TT); //把輸入字元計算成十進位數字
void To_2_8_10_16(long int Sum10,int base,int check2); //=====數字型態10進位,轉成4種型態輸出
int CheckFunction(int Num[] , int base , int T); //===檢查輸入字元是否符合選擇的base

void main(void)
{
int debug=1; //=================對付getchar無法重複執行的缺點=>執行後+1,奇數時執行,偶數時跳過BUG
int T=0 , TT=-1 , check , check2; //======輸入字元數量,小數點位置,小數點數量,正負號
int Num[30]={0} , N , base  ; //=存入字元的陣列,N=暫存器,base=進制
long int Sum10=0; //==========10進制總和

printf("======如輸入為16進制,﹝A-F﹞使用大寫才是有效輸入!======\n");

while(1)  { //使程式無限重複執行
do {
         check=check2=T=base=Sum10=0; //================給初始值        
         TT=-1; //===============================給初始值
         if (debug%2==1) //======================偶數跳過不處理
         printf("請輸入一個數字(整數最多10位,小數3位!!):");
     do { //=================================debug偶數時照樣執行,使錯誤消失
         N=getchar();
         if (N!='\n')
            Num[T++]=N; //===================累計輸入數量,存入陣列
         if (N=='.')        
                    {
             TT=T; //========================記下小數點的位置
             check++;
                    }  
            } while(N!='\n');
         if (TT==-1)
                 TT=T+1; //==========================沒有小數點的情況,給值方便後面計算
     while (Num[0]=='-') //如果Num[0]為負號,陣列往前取代一格,直到Num[0]不為負號,方便計算
       {
        for (int d=0;d<T;d++)     
            Num[d]=Num[d+1];
                T--; //字元數量扣1
                TT--; //小數點位置扣1
        check2=1; //為負值,使後面輸出負號
       }
         if (check==1)
         while ( Num[T-1]=='0') //===========小數點後無效的0去掉,T扣回來
                 T--;
    } while (check>1 || TT>11 || T-TT>3); //避免多個小數點,避免整數超過10位,避免小數超過3位
if (debug%2==1) //偶數跳過不處理
     do {
         printf("請輸入進制 <2、8、10、16>:");               
         scanf("%d",&base);        
        } while(base!=2 && base!=8 && base!=10 && base!=16 ); //確保輸入為(2 8 10 16)其中之一
/*==========================================輸入部分完成========================================*/
debug++;        
if ( CheckFunction(Num,base,T) == 0 ) //呼叫函式,確認輸入是否符合進制
          continue;
Sum10 = ToSum10(Num ,base ,T ,TT); //===呼叫函式,求得10進位總數
switch(base)
           {
            case 2: //==================呼叫函式轉換其他三種進制
                           To_2_8_10_16(Sum10,8,check2);
                           To_2_8_10_16(Sum10,10,check2);
                           To_2_8_10_16(Sum10,16,check2);
                           break;
            case 8: //==================呼叫函式轉換其他三種進制
                           To_2_8_10_16(Sum10,2,check2);
                           To_2_8_10_16(Sum10,10,check2);
                           To_2_8_10_16(Sum10,16,check2);
                           break;   
                case 10: //==================呼叫函式轉換其他三種進制
                           To_2_8_10_16(Sum10,2,check2);
                           To_2_8_10_16(Sum10,8,check2);
                           To_2_8_10_16(Sum10,16,check2);
                           break;            
                case 16: //==================呼叫函式轉換其他三種進制
                           To_2_8_10_16(Sum10,2,check2);
                           To_2_8_10_16(Sum10,8,check2);
                           To_2_8_10_16(Sum10,10,check2);
                           break;
       } //switch(base)結束
  printf("===================================================\n");
} //重複執行的while結束
} /*end function main*/

void To_2_8_10_16(long int Sum10,int base,int check2) //傳入(總數,進制,正負號)
{
long S = Sum10 ; //========S====>整數部分
int Sp = Sum10 - S; //==Sp===>小數部份
int a[40]={0};
int t=0,tt=0;

printf("\n轉換成<%d>進制\n",base);
do {
         if ( S%base < 10 )
          a[t++] = S % base + 48 ; //==以字元方式存入陣列
         else
          a[t++] = S % base + 55 ; //==存入A~F
     S=S/base;
    }while ( S>0 );
if (t>=11) //=========================如整數超過10位 輸出溢位
         printf("發生溢位!!\n需要的位數為:%d\n",t);
else
     {
          printf("不會發生溢位!!,轉換的數值如下:");
          if (check2==1) //若為負值先輸出負號
                  printf("-");
      for (int ss=t-1 ; ss>=0 ; ss--)
               printf("%c",a[ss]); //======整數部份輸出結束
      if (Sp!=0.0) //小數點後面
         {
              printf(".");
          while (Sp!=0.0 && tt<3)
                {
                             int Spp=0;
                 Sp=Sp*base;
                 Spp=Sp; //擷取整數部份
                             Sp=Sp-Spp; //留下小數部份
                             if (Spp<10)
                     printf("%c",Spp+48); //1~9
                             else
                     printf("%c",Spp+55); //A~F                       
                             tt++; //計數器++,控制小數點後面輸出位數
                    } //while結束            
         } //if(Sp)結束
      printf("\n");
     } //else結束
} //函式結束

int CheckFunction(int Num[] , int base ,int T) //傳入(陣列,進制,字元數量)
{
int base2[3] = {'0','1','.'}; //給各進制範圍
int base8[9] = {'0','1','2','3','4','5','6','7','.'};
int base10[11]={'0','1','2','3','4','5','6','7','8','9','.'};
int base16[17]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','.'};

for (int f=0 ; f<T ; f++) //陣列字元一個個比對,檢查是否有錯誤輸入
         {
      int x=0;
          for(int ff=0 ; ff < base+1 ; ff++)
             {
          if(base==2)
                     if(Num[f]==base2[ff])
                        x=1;
                  if(base==8)
                     if(Num[f]==base8[ff])
                        x=1;
                  if(base==10)
                     if(Num[f]==base10[ff])
                        x=1;
                  if(base==16)
                     if(Num[f]==base16[ff])
                        x=1;
             } //for(ff)結束
          if(x==0) //某輸入字元不在設定範圍內
                {
             printf("輸入錯誤,請重新來過!!\n\n");
             return 0; //回傳錯誤
            } //if結束
     } //for(f)結束
  return 1; //回傳無誤
}

long int ToSum10(int Num[] , int base , int T , int TT) //傳入(陣列,進制,字元數,小數點位置)
{
  long int Sum10=0;
  for (int o=0 ; o<T ; o++)
          {
       if ( Num[o]!='.' )
                  {
                   if (Num[o]<58) //======='1'~'9' ACEII=48~57 扣48=數值
               Sum10 = Sum10 + (Num[o]-48) * (long int)pow( base , (long int)(TT-2-o) );
                   else //================='A'~'F' ACEII=65~70 扣55=數值
               Sum10 = Sum10 + (Num[o]-55) * (long int)pow( base , (long int)(TT-2-o) );
                  }
           else
                   TT++; //===========================配合位數轉換
      } //for(o)結束
  return  Sum10; //回傳計算後的值
}
作者: chiasa    時間: 2010-3-30 00:12:42

為什麼要自己寫呢?
C難道沒有類似的function可以做嗎?
至少printf可以輸出8, 10, 16 進位
作者: alan1573    時間: 2010-4-3 17:14:48

先首我要感謝edvx大大提供意見,
可是我想問的是我有沒有寫了一些多餘的程式碼浪費了電腦的資源或者是某些部份可以用別的寫法代替從而優化程式的結構。

感謝chiasa大大對這程式碼作出評論,的確C 的函數庫中有可以直接轉制的指令,可是這樣做就沒辦法加強自己的寫作技巧了。
作者: edvx    時間: 2010-4-6 23:20:27

修改前(部分程式)
int CheckFunction(int Num[] , int base ,int T) //傳入(陣列,進制,字元數量)
{

int base2[3] = {'0','1','.'}; //給各進制範圍
int base8[9] = {'0','1','2','3','4','5','6','7','.'};
int base10[11]={'0','1','2','3','4','5','6','7','8','9','.'};
int base16[17]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','.'};

for (int f=0 ; f<T ; f++) //陣列字元一個個比對,檢查是否有錯誤輸入
         {
      int x=0;
          for(int ff=0 ; ff < base+1 ; ff++)
             {
         if(base==2)
                     if(Num[f]==base2[ff])
                        x=1;
                  if(base==8)
                     if(Num[f]==base8[ff])
                        x=1;
                  if(base==10)
                     if(Num[f]==base10[ff])
                        x=1;
                  if(base==16)
                     if(Num[f]==base16[ff])

                        x=1;
             } //for(ff)結束
          if(x==0) //某輸入字元不在設定範圍內
                {
             printf("輸入錯誤,請重新來過!!\n\n");
             return 0; //回傳錯誤
            } //if結束
     } //for(f)結束
  return 1; //回傳無誤
}

修改後(部分程式)
int CheckFunction(int Num[] , int base ,int T) //傳入(陣列,進制,字元數量)
{
int baseN[17]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','.'}; //給各進制範圍
for (int f=0 ; f<T ; f++) //陣列字元一個個比對,檢查是否有錯誤輸入
         {
      int x=0;
          for(int ff=0 ; ff < base+1 ; ff++)
             {
          if(Num[f]==baseN[ff])
                        x=1;
             } //for(ff)結束
          if(x==0) //某輸入字元不在設定範圍內
                {
             printf("輸入錯誤,請重新來過!!\n\n");
             return 0; //回傳錯誤
            } //if結束
     } //for(f)結束
  return 1; //回傳無誤
}

--------------------
以上是可以簡化的部分
但是仍再提醒大大,這個程式出來的結果不是正確的
(正確->迅速->簡潔,以正確最為首要,其次才是簡化程式)

--------------------
PS:
前幾天有些忙碌,所以到現在才回

(上次說的double,後來發現不改也是可以跑,主要是void main那裏使程式不能跑)

 
作者: alan1573    時間: 2010-4-23 15:25:38

再次感謝edvx大大提供的解答
程式碼中錯誤的部份小的就自行想辦法解決,始終探索跟試驗才是學C++的路~~

------------------------------------
PS: 抱歉,因為小的在準備期中考,所以那麼晚才回覆大大,望大大見諒。
作者: chiasa    時間: 2010-6-28 00:47:48

的確,探索跟試驗才是學C++的路~~
但我不會這樣教我的學生
我都叫他們去網路找別人寫好的library ,去熟悉使用那些open source
因為,自己寫,太慢,也存在太多bug
要練功,自然有東西可以寫,而且有一堆寫不完的程式,等他們去完成
基本的東西,還是找別人(網路)寫好的來用,這樣做事比較快
比如說要算反矩陣,算eigenvalue, 算Fourier transform, 算DCT
這些都比你的進位轉換難幾百倍,但如果連這些也要當練功的話
那自己的研究都不用做了

我覺得,學會上網找資源,並且能善用這些資源(open source)
才會事半功倍

期末考應該考完了吧
如果有時間,可以上網找一下 GSL, GNU Scientific Library
如果能熟悉使用,才是比較有幫助的
如果你是用Windows 平台,那試著把它移植到windows 平台,那就真的是厲害了

《 本帖最後由 chiasa 於 2010-6-28 00:52 編輯 》




歡迎光臨 SOGO論壇 (https://oursogo.com/) Powered by OURSOGO.COM