2

以下のコードの出力を説明してください。両方のケースで c の異なる値を取得しています。つまり、

ケース 1 : n の値は標準入力から取得されます。ケース 2 : n の値をコードに直接記述します。リンク : http://www.ideone.com/UjYFQd

#include <iostream>
#include <cstdio>
#include <math.h>

using namespace std;

int main()
{
    int c;
    int n;

    scanf("%d", &n);    //n = 64
    c = (log(n) / log(2));
    cout << c << endl;  //OUTPUT = 5

    n = 64;
    c = (log(n) / log(2));
    cout << c << endl;  //OUTPUT = 6

    return 0;
}
4

3 に答える 3

4

最初log(n)/log(2)は が計算され、結果は 6 に非常に近くなりますが、わずかに小さくなります。これは、浮動小数点計算がどのように機能するかです。log(64) も log(2) もバイナリ浮動小数点で無限に正確な表現を持たないため、一方を他方で除算した結果が真の数学値からわずかにずれていると予想できます。 . 実装に応じて、5 または 6 を取得することが期待できます。

2 番目の計算では、次のようになります。

n = 64;
c = (log(n) / log(2));

に割り当てられた値cは、コンパイル時の定数であると推測でき、コンパイラによって計算できます。コンパイラは、実行中のプログラムとは異なる環境で計算を行うため、コンパイル時と実行時に実行される計算からわずかに異なる結果が得られると予想できます。

たとえば、x86 用のコードを生成するコンパイラは、80 ビット浮動小数点演算を使用する x87 浮動小数点命令を使用することを選択できますが、コンパイラ自体は標準の 64 ビット浮動小数点演算を使用してコンパイル時の定数を計算します。

これを確認するには、コンパイラからのアセンブラ出力を確認してください。GCC 4.8 を使用すると、両方の計算から 6 が得られます。

于 2013-11-05T17:01:45.627 に答える
4

これは、浮動小数点数の格納方法が原因である可能性があります。

double result = log(n) / log(2); // where you input n as 64
int c = (int)result; // this will truncate result.  If result is 5.99999999999999, you will get 5

値をハードコーディングすると、コンパイラが最適化します。

double result = log(64) / log(2); // which is the same as 6 * log(2) / log(2)
int c = (int)result;

おそらく完全に次のものに置き換えられます。

int c = 6;

コンパイラは、変数に値を格納するためにコンパイル時の定数の束を使用していることを認識するためです (コンパイル時に先に進み、値をクランチします)。

操作の整数結果を取得したい場合は、std::roundにキャストするだけでなく、を使用する必要がありintます。

int c = std::round(log(n) / log(2));
于 2013-11-05T17:02:21.527 に答える
1

gcc出力の違いは、一定のケースでの呼び出しを最適化しているという事実によって説明できます。logたとえば、この場合は次のようになります。

n = 64;
c = (log(n) / log(2));

の両方の呼び出しがlogコンパイル時に行われるため、これらのコンパイル時の評価によって異なる結果が生じる可能性があります。これは、GCCセクションが提供するその他の組み込み関数の gcc マニュアルに記載されています。

GCC には、標準 C ライブラリの多くの関数の組み込みバージョンが含まれています。_builtin を前に付けたバージョンは、-fno-builtin オプションを指定しても、常に C ライブラリ関数と同じ意味を持つものとして扱われます。(C 方言オプションを参照してください) これらの関数の多くは、特定の場合にのみ最適化されます。特定のケースで最適化されていない場合は、ライブラリ関数への呼び出しが発行されます。

組み込みバージョンをlog持つ多くの関数の 1 つです。-fno-builtinの 4 つの呼び出しすべてを使用してビルドすると、生成されるアセンブリを出力するフラグを使用してビルドするlogことlogで、これを確認できます。-Sgcc

于 2013-11-05T17:14:55.027 に答える