2016-04-30 175 views
2

我遇到問題,我的乘法方法只處理一行,它目前沒有前進到下一行。 add函數工作正常,我可以更新當前的十六進制數,但出於某種原因,我只能得到一行乘法運算。C++十六進制計算器乘法

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

這裏是有問題的代碼:

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; 
}; 

完整的程序:

#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)使用第一評價一個非初始的在運行程序時碰巧不爲NULL的rightNode的值。在檢查之後,在解除引用之前,rightNode被設置爲從right.next()開始的有效節點指針值。但是對於下一個左邊的數字,rightnode與前一個循環仍爲NULL,因爲它在right.reset()之後沒有更新,所以對於第一個數字之後的每個數字,while(rightNode != NULL)總是以rightNode設置爲NULL開始,因此第一個之後的所有循環都是跳過。

一旦這個問題得到解決,另一個bug就會暴露出來:在右側數字循環內部的零點被添加到curList中,所以每當處理一個右數字時就會添加零。相反,在左數字循環內創建curList之後,應在右數字循環之前添加零。

還有另一個錯誤(我認爲) - 右位循環結束後,任何進位值不添加到curList最後一個數字 - 而不是它被保存爲下個右位循環的開始。這可能是故意的,但我不認爲它總是會以正確的數字位置結束(但也許我在這一點上是錯誤的 - 我沒有專心考慮可能性)。

爲了調試你的問題,我不得不復制你的代碼,填寫缺失的部分並修復錯誤。此外,還有一些風格問題,並非實際的錯誤或錯誤,但已知會促成問題。因此,這裏是我對版本所做的測試變化:

  • LLIST包含next()reset()訪問的狀態迭代器(view)。將來,您的代碼的多個部分可能需要同時迭代同一個LList,但他們將無法共享LList對象所擁有的單個迭代狀態。迭代器對象解決了這個問題。

  • 在「用戶」代碼中使用原始指針:應儘可能避免指針操作,或者限制爲「庫」代碼 - 就像在LList對象中一樣。沒有必要處理Calculator類中的指針。

  • 變量應在其使用所需的最內層範圍內聲明。代碼的第一個問題,rightNode從前一個循環中取得的值,如果遵循此樣式點,則不會發生。

  • 有沒有必要保留一個向量(addList)的條款總結在函數的結尾。我的版本保留一個運行總和LList名爲prodSum

這裏是我的版本的代碼,包括我自己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);返回*這;}' – PaulMcKenzie

+1

好吧,現在我看到目前出現的情況,我想重新澄清我的意圖。在我提交答案的時候,OP提供的唯一代碼是'Calculator :: multiply(...)'和'LList :: next()'。爲了調試'multiply(...)',我需要爲''LList'類和'Calculator :: add(...)'創建最低限度的功能。這些只是答案,所以它的代碼可以被構建和執行。後來才發佈了OP的全部代碼。所以在這裏,唯一一個重要的威脅就是'multiply(...)'函數,我的版本的'LList'和'add(...)'不是OP的替代品。 –