1

このプログラムは、2x2 行列の負の要素の平均幾何平均を計算します。以下のこのプログラムのコードと、なぜ作者が書いたのかを理解しようとしています。誰かが下のコードが何をしているのかを説明してくれませんか?作者が書いたコードのポインタが多すぎる

#include <stdio.h>
#include <math.h>

#define ROWS 2
#define COLS 2
char * last_geom_err = NULL;

float geometricMean(float * arr, int rows, int cols){
    float neg_mul = 1;
    int neg_count = 0;
    float arr_elem;
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < cols; j++)
            if((arr_elem = *(arr + i * cols + j)) < 0){
                neg_mul *= arr_elem;
                neg_count++;
            }
    if (neg_count == 0){
        last_geom_err = "no negative elements in array";
        return 0;
    }   
    if ((neg_count % 2 == 0) && (neg_mul < 0)){
        last_geom_err = "a negative number under the square root of even degree";
        return 0;
    }
    last_geom_err = NULL;
    return pow(neg_mul, (float)neg_count);
}

int main(){
    float arr[ROWS][COLS] = {
        1., -2.,
        -5., -6.
    };
    printf("Array:\n");
    for(int i = 0; i < 2; i++){
        for(int j = 0; j < 2; j++)
            printf("%5.2f ", arr[i][j]);
        putchar('\n');
    }
    float gm = geometricMean((float*)arr, ROWS, COLS);
    if (last_geom_err != NULL)
        printf("#Error of calculation: %s", last_geom_err);
    else
        printf("Geometric mean of negative elements of array = %5.2f", gm);
    return 0; 
}

これはなぜですか?

char * last_geom_err = NULL;

    float geometricMean(float * arr, int rows, int cols){
        float neg_mul = 1;
        int neg_count = 0;
        float arr_elem;
        for (int i = 0; i < rows; i++)
            for (int j = 0; j < cols; j++)
                if((arr_elem = *(arr + i * cols + j)) < 0){
                    neg_mul *= arr_elem;
                    neg_count++;
                }
        if (neg_count == 0){
            last_geom_err = "no negative elements in array";
            return 0;
        }   
        if ((neg_count % 2 == 0) && (neg_mul < 0)){
            last_geom_err = "a negative number under the square root of even degree";
            return 0;
        }
        last_geom_err = NULL;
        return pow(neg_mul, (float)neg_count);
    }

そしてこれ

float gm = geometricMean((float*)arr, ROWS, COLS);
        if (last_geom_err != NULL)
            printf("#Error of calculation: %s", last_geom_err);
        else
            printf("Geometric mean of negative elements of array = %5.2f", gm);
        return 0
4

1 に答える 1

2

プログラムは、2x2行列の負の要素の平均幾何平均を計算します

そうではありません。まず、通常、幾何平均は正の数にのみ適用されます。負の数の幾何平均は絶対値の幾何平均の負であると言うことで、ある程度意味のある方法で定義を負の数に拡張できkますが、負の数と正の数の両方を含むセットの幾何平均は次のようになります。不明。幾何平均を拡張するもう1つの意味のある方法は、正則関数としての正則領域への拡張です(これk > 1はℂ<sup> kのサブセットではありません)。これには、ℝ<sub>< 0kより上の1つのブランチの値として前者の拡張が含まれます。

とにかく、幾何平均の計算にはk、特定のプログラムには含まれていない、何らかの形式の-番目のルートが含まれます。それでは、コードを見てみましょう。

float geometricMean(float * arr, int rows, int cols){
    float neg_mul = 1;
    int neg_count = 0;

負の配列要素とその数の積の初期化。

    float arr_elem;
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < cols; j++)

マトリックスのメモリレイアウトは次のとおりです。

        --------------------------------------------
arr -> | row 0 | row 1 | row 2 | ... | row (rows-1) |
        --------------------------------------------

したがって、row 0スロット0〜を占有し、スロットを占有します。通常、スロットを占有します。したがって、を指します。cols - 1row 1cols2*cols - 1row kk*cols(k+1)*cols - 1arr + i*cols + jcol jrow i

            if((arr_elem = *(arr + i * cols + j)) < 0){
                neg_mul *= arr_elem;
                neg_count++;
            }

行列要素a[i][j]を読み取り、それが負の場合は、すべての負のエントリの積に乗算してカウントします。for(k = 0; k < rows*cols; ++k)フラットなメモリレイアウトのため、ここでループしてアクセスするだけでよいことに注意してarr[k]ください。

    if (neg_count == 0){
        last_geom_err = "no negative elements in array";
        return 0;
    }

配列に負の要素がまったく含まれていない場合は、エラーメッセージを設定して戻ります。数字がないという(幾何)平均は、まったく意味がありません。

    if ((neg_count % 2 == 0) && (neg_mul < 0)){
        last_geom_err = "a negative number under the square root of even degree";
        return 0;
    }

負のエントリの数が偶数で、負のエントリの積が負の場合は、エラーメッセージを設定して戻ります。

これはデッドコードであることに注意してください。偶数の負の数の積は常に正であり、浮動小数点演算(IEEE 754に準拠しているか、それに十分に近い。完全に壊れている場合は何かが発生する可能性があります)の唯一の注意点はアンダーフローであり、数学的には0になる可能性があります。そうではありません。(ここではオーバーフローは問題ではありません。無限大は0と比較され、乗算で正常に動作します。)

    last_geom_err = NULL;
    return pow(neg_mul, (float)neg_count);
}

最後に、NULL例外的な状況は発生しなかったため、エラーメッセージをに設定して戻ります

(負のエントリの積)(負のエントリの数)

幾何平均の場合、最後の行は次のようになります。

    return pow(neg_mul, 1.0/neg_count);

ただし、整数指数に対してのみ負数進を処理する場合neg_mul < 0は、NaNが返されます。pow

if (neg_mul < 0) {
    return -pow(-neg_mul, 1.0/neg_count);
} else {
    return pow(neg_mul, 1.0/neg_count);
}
于 2012-04-15T15:50:53.147 に答える