2016-04-30 76 views
2

私の乗算方法が1行しか処理していないのに、現在次の行に進まないという問題があります。 add関数は正常に動作していますが、現在の16進数を更新することはできますが、何らかの理由で1行の乗算しかできません。ここC++の16進数計算の乗算

Example input: 
111# * 333# = 333 
123# * 123# = 369 

は、問題のコードである:

listnode* LList::next() { 
    listnode* temp = view; 
    if(temp != NULL) 
     view = view->next; 

    if(view == NULL) { 
    } 
    return temp; 
}; 

完全なプログラム:

#include <iostream> 
#include <vector> 
#include <stdlib.h> 
#include <string> 
using namespace std; 
#undef NULL 
const int NULL = 0; 
const char SENTINEL = '#'; 
typedef int element; 

class listnode { 
    public: 
     element data; 
     listnode * next; 
}; 

class LList { 
    private: 
     listnode * head; 
     listnode * tail; 
     listnode * view; 

    public: 
     LList(); 
     ~LList(); 
     void read(); 
     listnode* next(); 
     void reset(); 
     void print(); 
     void insertTail(element val); 
     void clean(); 

     element deleteHead(); 
}; 

class Calculator { 
    public: 
     Calculator(); 
     inline LList* add(LList& left, LList& right); 
     inline LList* multiply(LList& left, LList& right); 
}; 

Calculator::Calculator() { 

}; 

LList* Calculator::add(LList& left, LList& right) { 
    int sum, carry = 0, lval = 0, rval = 0; 
    bool calculating = true; 
    listnode *leftNode; 
    listnode *rightNode; 
    LList* newHex = new LList; 
    while(calculating) { 
     leftNode = left.next(); 
     rightNode = right.next(); 

     if(leftNode == NULL) { 
      lval = 0; 
     } 
     else 
      lval = leftNode->data; 

     if(rightNode == NULL) { 
      rval = 0; 
     } 
     else 
      rval = rightNode->data; 


     if(leftNode == NULL && rightNode == NULL) { 
      calculating = false; 
      if(carry != 0) { 
       newHex->insertTail(carry); 
      } 
      break; 
     } 

     sum = lval + rval + carry; 
     carry = 0; 
     if(sum >= 16) { 
      carry = 1; 
      sum -= 16; 
     } 

     newHex->insertTail(sum); 

    } 

    return newHex; 
}; 


LList* Calculator::multiply(LList& left, LList& right) { 
    int product, carry = 0, lval = 0, rval = 0, zeros = 0; 
    bool calculating = true; 
    listnode *leftNode; 
    vector <LList*> addList; 
    listnode *rightNode; 
    LList* newHex; 
    while(calculating) { 

     leftNode = left.next(); 
     if(leftNode == NULL) { 
      break; 
     } 
     else { 
      lval = leftNode->data; 
     } 


     //leftNode = left.next(); 
     right.reset(); 

     if(leftNode == NULL) { 
      calculating = false; 
      if(carry != 0) { 
       //newHex->insertTail(carry); 
      } 
      lval = 0; 
      break; 
     } 

     LList* curList = new LList; 
     addList.push_back(curList); 

     while(rightNode != NULL) { 

      // Add however zeros we need for 
      // each entry based on the zero counter 
      for(int i = 0; i < zeros; i++) { 
       curList->insertTail(0); 
      } 

      rightNode = right.next(); 


      if(rightNode == NULL) { 

      } 
      else { 
      rval = rightNode->data; 

      product = lval * rval + carry; 
      carry = 0; 
      if(product >= 16) { 
       carry = (product/16); 
       product = (product % 16); 
      } 
      curList->insertTail(product); 
      } 
     } 
     zeros++; 


    } 



    Calculator calc; 
    LList* temp; 
    // Add up everything in the addList 
    for(int i = 0; i < addList.size() - 1; i++) { 
     if(temp == NULL) 
      temp = calc.add(*addList[i], *addList[i+1]); 
     else 
      temp = calc.add(*addList[i+1], *temp); 
    } 

    newHex = temp; 

    // Delete it 
    for(int i = 0; i < addList.size(); i++) { 

    } 

    return newHex; 
}; 

listnode* LList::next() { 
    listnode* temp = view; 
    if(temp != NULL) 
     view = view->next; 

    if(view == NULL) { 
    } 
    return temp; 
}; 

void LList::reset() { 
    view = head; 
} 


LList::LList(){ 
    /* 
    next: 
    This is used to set the linked 
    list to NULL. 
    */ 
    head = NULL; 
    view = NULL; 
}; 


void LList::print() { 
    listnode * temp; 
    int i = 0; 
    string printValues; 
    temp = head; 
    while(temp != NULL) { 
     int var = temp -> data; 
     char character = ' '; 
     if(i % 3 == 0 && i != 0) 
      printValues += ','; 
     i++;  
     if(var > 9 && var < 16) { 
      character = static_cast <char>(var + 65 - 10); 
     }; 
     if (var <= 9 && var >= 0) { 
      character = static_cast <char>(var + 48); 
     }; 
     if (var > 96 && var < 103) { 
      character = static_cast <char>(var + 97 + 10); 
     }; 

     printValues += character; 
     temp = temp -> next; 

    } 
    string tempValues; 
    for(int i = printValues.length() - 1; i >= 0; i--) 
     tempValues += printValues[i]; 
    cout << tempValues; 
    cout << endl; 
}; 

void LList::read() { 
    string userval; 
    int i; 
    bool parsing = true; 
    char curval; 
    vector <int> values; 
    clean(); 
    while(parsing) { 
     cin >> userval; 
     for(unsigned int i = 0; i < userval.length(); i++) { 
      curval = userval[i];  
      if(curval >= 48 && curval <= 57) 
       values.push_back(static_cast <int>(curval - 
      48)); 

      if(curval >= 65 && curval <= 70) 
       values.push_back(static_cast <int>(curval - 
      65 + 10)); 

      if(curval >= 97 && curval <= 102) 
       values.push_back(static_cast <int>(curval - 
      97 + 10)); 

      if(curval == ' ') 
       break; 

      if(curval == SENTINEL) { 
       parsing = false; 
       break; 
      } 
     } 
    } 
    for(int i = values.size() -1; i >= 0; i--) { 
     insertTail(values[i]); 
    } 
}; 

void LList::insertTail(element val) { 
    listnode * temp; 
    temp = new listnode; 
    temp -> data = val; 
    temp -> next = NULL; 

    if(head == NULL) { 
     head = temp; 
     view = head; 
    } 
    else 
     tail -> next = temp; 
    tail = temp; 
}; 

void LList::clean() { 
    while(head != NULL) 
     deleteHead(); 
}; 

void validCommands() { 
    cout << "Valid commands are:" << endl; 
    cout << " e enter enter the current "; 
    cout << "hexadecimal "; 
    cout << "number from the keyboard" << endl; 
    cout << " a add  add a new hexadecimal "; 
    cout << "number to the current hex. number" << endl; 
    cout << " m multiply "; 
    cout << "multiply a new hexadecimal number "; 
    cout << "by the current hex. number" << endl; 
    cout << " h help show this help menu" << endl; 
    cout << " q quit quit the program" << endl << endl; 
}; 

element LList::deleteHead() { 
    listnode * temp; 
    temp = head; 
    head = head -> next; 
    delete temp; 
    return temp -> data; 
}; 

LList::~LList(){ 
    delete head; 
}; 

int main() { 
    LList L, add,multiply; 
    Calculator calc; 
    L.insertTail(0); 
    char option; 
    bool run; 
    cout << "Hexadecimal Calculator, Ver 1.0.0 \n"; 



    do { 
     /* 
    This do while is used to continuosly run the 
    program until the user decides to end. 
    */ 
    cout << "Current Hexadecimal number is: "; 
    L.print(); 
    cout << endl; 

    cout << "Command (h for help): "; 
    cin >> option; 

    cout << endl << endl; 
     switch(option) { 
      case 'e' : 
       cout << "Enter a hexadecimal number "; 
       cout << "followed by #: "; 
       L.read(); 
       cout << endl << "Entering completed."; 
       cout << endl << endl; 
      break; 
      case 'a' : 
       cout << "Adding a new hexadecimal number "; 
       cout << "to the current hex. number" << endl; 
       cout << endl; 
       cout << "Enter a hexadecimal "; 
       cout << "number, follow by #: "; 
       add.read(); 
       cout << endl << "Addition completed."; 
       cout << endl; 
       L = *calc.add(L, add); 
       cout << endl; 
       break; 
      case 'm' : 
       cout << "Multiplying a new hexadecimal "; 
       cout << "number "; 
       cout << "to the current hex. number" << endl; 
       cout << endl; 
       cout << "Enter a hexadecimal "; 
       cout << "number, follow by #: "; 
       multiply.read(); 
       cout << endl << "Multiplication completed."; 
       cout << endl; 
       L = *calc.multiply(L, multiply); 
       cout << endl; 
       break; 
      case 'h' : validCommands(); 
      break; 
      case 'q' : run = false; 
      break; 
     }; 
    } while (run); 
     exit(0); 

} 
+1

望ましくない挙動は、デバッグを介して起こり、および/またはアサートする正確な行を探します。 – krOoze

+0

「temp」を何回初期化するかを数えたいと思うでしょう。 – molbdnilo

答えて

1

while(rightNode != NULL)用途の最初の評価ここ

LList* Calculator::multiply(LList& left, LList& right) { 
    int product, carry = 0, lval = 0, rval = 0, zeros = 0; 
    bool calculating = true; 
    listnode *leftNode; 
    vector <LList*> addList; 
    listnode *rightNode; 
    LList* newHex; 
    while(calculating) { 

     leftNode = left.next(); 
     if(leftNode == NULL) { 
      break; 
     } 
     else { 
      lval = leftNode->data; 
     } 


     //leftNode = left.next(); 
     right.reset(); 

     if(leftNode == NULL) { 
      calculating = false; 
      if(carry != 0) { 
       //newHex->insertTail(carry); 
      } 
      lval = 0; 
      break; 
     } 

     LList* curList = new LList; 
     addList.push_back(curList); 

     while(rightNode != NULL) { 

      // Add however zeros we need for 
      // each entry based on the zero counter 
      for(int i = 0; i < zeros; i++) { 
       curList->insertTail(0); 
      } 

      rightNode = right.next(); 


      if(rightNode == NULL) { 

      } 
      else { 
      rval = rightNode->data; 

      product = lval * rval + carry; 
      carry = 0; 
      if(product >= 16) { 
       carry = (product/16); 
       product = (product % 16); 
      } 
      curList->insertTail(product); 
      } 
     } 
     zeros++; 


    } 

    Calculator calc; 
    LList* temp; 
    // Add up everything in the addList 
    for(int i = 0; i < addList.size() - 1; i++) { 
     if(temp == NULL) 
      temp = calc.add(*addList[i], *addList[i+1]); 
     else 
      temp = calc.add(*addList[i+1], *temp); 
    } 

    newHex = temp; 

    // Delete it 
    for(int i = 0; i < addList.size(); i++) { 

    } 

    return newHex; 
}; 

は次の方法であります非初期rightNodeの値は、プログラムを実行するときにNULLでないことがあります。このチェックの後で、逆参照される前に、rightNoderight.next()からの有効ノードポインター値に設定されます。しかし、次の左の桁については、右ノードはまだright.reset()の後に更新されていないため、前のループのNULLは残っています。したがって、最初の後のすべての桁で、while(rightNode != NULL)は常にrightNodeをNULLに設定して開始します。スキップしました。

これが修正されると、別のバグが公開されます。つまり、右桁のループ内のcurListにゼロが追加されるため、右桁が処理されるたびにゼロが追加されます。代わりに、左桁のループ内でcurListを作成した後、右桁のループの前にゼロを追加する必要があります。

もう一つのバグがあります(私は思います)。右桁のループが終了した後、桁上げの値は最後の桁のcurListに追加されず、次の右桁のループの始めに保存されます。これは意図的かもしれないが、私はそれが常に正しい数字の位置に終わるとは思わない(しかし、私はこの点について間違っているかもしれない - 私は可能性をあまり考えなかった)。

問題をデバッグするために、コードを複製し、不足している部分を記入してバグを修正する必要がありました。また、実際のミスやバグではなく、問題を促進することが知られているいくつかのスタイルの問題がありました。だからここに私はテストのために私のバージョンに加えられた変更は以下のとおりです。

  • LListはnext()reset()でアクセスステートフルイテレータ(view)が含まれています。将来、コードの複数のセクションが同じLListを繰り返し処理したいかもしれませんが、LListオブジェクトが保持する単一の反復状態を共有することはできません。イテレータオブジェクトはこの問題を解決します。

  • "ユーザ"コードでの生ポインタの使用:可能であればポインタ操作は避けるか、LListオブジェクト内のような "ライブラリ"コードに限定してください。 Calculatorクラス内のポインターを処理する必要はありません。

  • 変数は、使用に必要な最も内側のスコープ内で宣言する必要があります。コードの最初の問題(rightNodeが以前のループから値を引き継いでいた)は、このスタイルポイントが続いていた場合には起こりませんでした。

  • 用語のベクトル(addList)を機能の最後にまとめる必要はありませんでした。私のバージョンはという名前のLListとして実行中の合計を保持します。ここで

はコードの私のバージョンは、私自身のLListや電卓などの、ある::あなたがそれらを利用可能にしなかったので、追加します。 LListはイテレータで動作し、viewのメンバーではありません。私のイテレーターは、終わりの位置にあるときにゼロを与える「逆参照」することができます。最上位桁以上の高次ゼロの無限列を任意の値について暗示されるので、これは、便宜のために行った:

#include <iostream> 
#include <string> 
#include <vector> 

struct listnode { 
    int data; 
    listnode *next; 
    listnode(int data=0) : data(data), next(0) {} 
}; 

class LList { 
    listnode *head, *tail; // head is least significant end 
    void delNodes() { 
     listnode* node = head; 
     while(node) { 
      listnode* todel = node; 
      node = node->next; 
      delete todel; 
     } 
     head = tail = 0; 
    } 
public: 
    LList() : head(0), tail(0) {} 
    LList(std::string digits) : head(0), tail(0) { 
     for(auto it = digits.rbegin(); it != digits.rend(); ++it) { 
      if(*it >= '0' && *it <= '9') insertTail(*it - '0'); 
      else if(*it >= 'a' && *it <= 'f') insertTail(*it - 'a' + 10); 
      else if(*it >= 'A' && *it <= 'F') insertTail(*it - 'A' + 10); 
    } } 
    LList(const LList& src) : head(0), tail(0) { 
     for(int data : src) { insertTail(data); } 
    } 
    ~LList() { delNodes(); } 
    LList& operator = (const LList& src) { 
     delNodes(); 
     for(int data : src) { insertTail(data); } 
     return *this; 
    } 
    void insertTail(int value) { 
     listnode *newnode = new listnode(value); 
     if(!head) { 
      head = tail = newnode; 
     } else { 
      tail->next = newnode; 
      tail = newnode; 
    } } 
    class iterator { 
     friend LList; 
     const listnode* node; 
     iterator(const listnode* node) : node(node) {} 
    public: 
     iterator& operator ++() { if(node) node = node->next; return *this; } 
     int operator *() const { return node ? node->data : 0; } 
     bool operator != (iterator iter) const { return iter.node != node; } 
     bool operator == (iterator iter) const { return iter.node == node; } 
    }; 
    iterator begin() const { return iterator(head); } 
    iterator end() const { return iterator(0); } 
    std::string get_digits() const { 
     static const char da[] = "abcdef"; 
     std::string digits; 
     for(int d : *this) { 
      digits = da[d] + digits; 
     } 
     return digits; 
    } 
}; 

LList add(const LList& left, const LList& right) { 
    LList sum; 
    auto liter = left.begin(); 
    auto riter = right.begin(); 
    int carry = 0; 
    while(liter != left.end() || riter != right.end()) { 
     int s = *liter + *riter + carry; 
     carry = s/16; 
     sum.insertTail(s % 16); 
     ++liter; 
     ++riter; 
    } 
    if(carry) sum.insertTail(carry); 
    return sum; 
} 

LList multiply(const LList& left, const LList& right) { 
    LList prodSum; 
    auto leftNode = left.begin(); 
    int zeros = 0; 
    for(;;) { 
     if(leftNode == left.end()) break; 
     int lval = *leftNode; 
     LList curList; 
     for(int i = 0; i < zeros; i++) { 
      curList.insertTail(0); 
     } 
     auto rightNode = right.begin(); 
     int carry = 0; 
     while(rightNode != right.end()) { 
      int rval = *rightNode; 
      int product = lval * rval + carry; 
      carry = product/16; 
      product %= 16; 
      curList.insertTail(product); 
      ++rightNode; 
     } 
     while(carry) { 
      curList.insertTail(carry % 16); 
      carry /= 16; 
     } 
     prodSum = add(prodSum, curList); 
     ++leftNode; 
     ++zeros; 
    } 

    return prodSum; 
} 

int main() { 
    LList a("111"); 
    LList b("333"); 
    LList c = multiply(a, b); // 36963 
    std::cout << c.get_digits() << '\n'; 
} 
+1

偉大な答え、そう深く。ありがとうございました。あなたが私がそれをどのようにしていたかについて興味があるなら、私はフル・プログラムを追加しました@Christopher Oicles。 – Aaron

+1

'LList'の代入演算子は、1)自己代入のチェックなし、2)' insertTail'が例外をスローすると、ノードを削除してオブジェクトが無効になります。代わりにコピー/スワップを使用してください。 '{LList temp(src); std :: swap(temp.head、head); std :: swap(temp.tail、tail); return * this;} ' – PaulMcKenzie

+1

これで、現在の状況が表示されるようになりましたので、私の意図を明確にしたいと思います。私が答えを提出した時点で、OPの唯一のコードは 'Calculator :: multiply(...)'と 'LList :: next()'でした。 'multiply(...)'をデバッグするために、 'LList'クラスと' Calculator :: add(...) 'のための最小限の機能を持つスタンドを作る必要がありました。これらは答えの中にあり、そのコードを構築して実行することができます。後でOPの全コードが掲載されました。だからここでは、唯一のre-wreiteは 'multiply(...)'関数ですが、私のバージョンの 'LList'と' add(...) 'はOPの置換えの候補ではありません。 –