剣指offer面接問題11_数値の整数次数(*)

2806 ワード

テーマ:関数double Power(double base,int exponent)を実現して、baseのexponentの次の方を求めます.ライブラリ関数は使用できませんが、大きな数の問題を考慮する必要はありません. 
この問題を通じて、注意していない知識点を理解します.
1、変数の命名は合理的かつ明瞭である
2、コードの完全性を確保し、三つの角度から着手する.
1)機能テスト:本体機能の確保
2)境界テスト:各種境界値を考慮する
3)負のテスト:各種の可能なエラー入力を考慮する
3、コードの効率性、性能テスト:コードの実行効率を考慮する
4、3種類のエラー処理方法:
1)呼び出し元にエラーがないかを関数で返す
2)エラーが発生した場合、グローバル変数を設定する
3)異常、関数の実行中にエラーが発生した場合、1つの異常を放出する.
上記の問題について、その答えは以下の通りです.
解決方法1:
基本機能,すなわち指数が正の場合のみ実現し,他の入力は考慮されない.
double Power0(double base, int exponent)
{
    double result = 1.0;
    for(int i = 1; i < exponent; i++)
    {
        result *= base;
    }
    return result;
}

解決方法2:
コードの整合性を考慮
/**  double  ,  == , */
bool Equal_double(double num1,double num2)
{
    if((num1 - num2 > -0.0000001) && (num1 - num2 < 0.0000001))
        return true;
    else
        return false;
}
/** */
double Power_with_unsigned_int(double base,unsigned int exponent)
{
    double result = 1.0;
    for(unsigned int i = 1; i <= exponent; i++)
    {
        result *= base;
    }
    return result;
}

bool g_InvalidInput  = false;     /** , */
double Power1(double base, int exponent)
{
    /* 0.0 */
    if(Equal_double(base,0.0) && exponent <= 0)
    {
        g_InvalidInput = true;
        return 0.0;
    }
    else if(Equal_double(base,0.0) && exponent > 0)
        return 0.0;

    unsigned int absExponent = (unsigned int)(exponent);
    if(exponent < 0)
        absExponent = (unsigned int)(-exponent);

    //cout << "absExponent = " << absExponent << endl;

    double result = Power_with_unsigned_int(base,absExponent);
    /* , */
    if(exponent < 0)
        result = 1.0 / result;

    return result;
}

解決方法3:
コード性能を考慮すると、2^16=(2^8)^2=((2^4)^2)^2.......などの順番に類推して、このように多くの繰り返し計算を減らしたので、上のコードの一部を変更します.
double Power_with_unsigned_int_efficiently(double base, unsigned int exponent)
{
    if(exponent == 0)
        return 1;
    if(exponent == 1)
        return base;
    double result = Power_with_unsigned_int_efficiently(base, exponent >> 1);
    result *= result;
    if(exponent & 0x1 == 1)   // base,%2==0, 0 
        result *= base;

    return result;
}
の上のコードは、
1、再帰を使う(上の過程を考え、再帰を理解するのに役立つ)
2、ビットで演算し、左に1ビット移動し、2で割ることを表し、余剰(%2)の代わりに和演算で奇数か否かを判断する.ビット演算効率が向上します.
上の問題を通して、学びました.
1、簡単な問題は全面的に考えなければならない.
2、どのように2つの小数が等しいかどうかを判定して、"=="を使うことができなくて、両者の間の差の絶対値を比較して、1つのとても小さい範囲内にあります.
3、ビット演算が上手で、効率を高めることができます.
4、再帰を複雑に考えない
【上記のコードと比較して、各ステップの再帰プロセス(どのように再帰するか、どのように前のステップに戻るかを含む)を考慮すると複雑になります.
しかし全体的に見ると、一歩ずつやるべきことであり、本題にとってはresult*=resultである.その他のいくつかのif判断条件は全体の過程で考慮する必要がある.
/*点滴蓄積、私の一歩O(∩∩)O~*/