2016-10-21 15 views
0

たとえば、数学を行う関数があるとします(引数として2つの数を掛ける)。結果を返しますが、エラーがあれば-1を返します。エラーで-1を返す代わりに

しかし、-1は実際には有効な結果です(たとえば-1 * 1)。返すべきより良い定数は何ですか?私はエラーでINT_MAXを返すことを考えていましたが、私の数学関数のいくつかはdoubleとfloatを返すので、より良い選択肢があるかどうかを見たいと思っていました。

これはライブラリ用ですので、混乱を最小限に抑えるために同じ定数をエラーに使用します。

+3

CまたはC++?彼らはこれにアプローチする方法が異なります。 – NathanOliver

+0

両方------------- – Katianie

+0

あなたの関数が行う可能性のあるエラーの例を挙げてください。 – AnDrOiD

答えて

0

偶然衝突する可能性の最も低い整数定数を検索する場合は、INT_MINを使用します。それは、大きさがINT_MAXより大きい1つです。また、値を失うことなくfloatにコピー可能であるという利点があります。INT_MAXは、異なる値に丸められます。

もちろん、これはCとの互換性が必要な場合にのみ表示されます.C++では、実際には例外を使用する必要があります。

+2

'INT_MIN'は' -INT_MAX'よりも小さくなることは保証されていません。これは標準によって保証されておらず、2の補数の全範囲に対してのみ真です。 – Olaf

+0

私はこのようなaproachが好きですが、Olafは言ったように、値はあきらめていません。 – Katianie

+0

@Olafそれは保証されていませんが、2の補数がとても広く普及しているために非常にそうです。それがそうでないとしても、これが最も可能性の低い整数であるという私の主張を傷つけることはありません。 –

-1

標準ライブラリでは、この目的のためにerrnoという変数を使用しました。似たようなものを実装することができます。ソースファイルの例については

、:

int matherr; 

enum { 
    SUCCESS, 
    ZERO_DIVIDE, 
    TOO_LARGE, 
    ... 
}; 

int multiply(int a, int b) 
{ 
    matherr = SUCCESS; 
    if (/* result too large*/) { 
     matherr = TOO_LARGE; 
     return 0; 
    } else { 
     return a*b; 
    } 
} 

int divide(int a, int b) 
{ 
    matherr = SUCCESS; 
    if (/* result too large*/) { 
     matherr = ZERO_DIVIDE; 
     return 0; 
    } else { 
     return a/b; 
    } 
} 

あなたのヘッダファイルに:これらの関数を呼び出すコードで

extern int matherr; 

int multiply(int a, int b); 
int divide(int a, int b); 

、それはその後、場合matherrの値をチェックする必要がありますいずれかの関数が0を返します。

+1

しかし、0は乗算の有効な結果です。なぜなら、乗算の確率はちょうどスリムなので、INT_MAXを返すほうが意味があります。 – Katianie

+1

シグネチャの変更を提案する ResultEnum multiply(int a、int b、int * result) – UKMonkey

+0

INT_MAXを返さないのはなぜですか?ライブラリのユーザへの混乱を防ぎます。 – Katianie

-2

int型、float型、double型に適した値はありません。関数値を変更することはお勧めできません。

何について約ではないエラーcondtionsをチェックしたり、それらを意図的に引き起こしていますか?つまり、製品がオーバーフローの対象になっている場合は、オーバーフローさせてください。関数の引数が範囲外で計算を開始できない場合は、sqrt(-1)を呼び出して範囲外エラーをシミュレートします。

なぜですか?

あなたの関数は普通の式と同じ振る舞いを採用するので、良くない/悪くはないでしょう。同時に、新しいメカニズムを開発する必要はなく、ユーザーはそれらを習得する必要はなく、移植性が高く、プログラミング言語に従います。

+0

符号付き整数オーバーフローは、未定義の動作を呼び出します。あなたは事実上初心者に意図的にライブラリコードを書いて、UBが発生するように指示します。非常に悪い考え。 – Olaf

+0

@Olaf:なぜそれは悪い考えですか? UBはC/C++演算で発生する可能性があり、すべてのプログラマが認識しています。反対に、標準的な振る舞いを模倣することは何も悪いことではありません。技術的なことを避けるために言及しなかった言語の機能を使用することに大きな利点があります。例外処理、デバッガブレーク、コンパイラによるチューニングなど、実行時に実装されるすべてのメカニズムを即座に継承しますオプション、NaNサポート...無償で。実際には、エラーフラグを返すことは、貧しい人の解決策です。 –

+0

Ehm、... UBはあなたが何にも頼ることができないことを意味します。検出されない問題も含めてだから何かが間違っていることを知ることができると思いますか? – Olaf

2

通常溶液のみ成功またはエラーを示す、ポインタを介して実際の結果を返すために、戻り値を使用することである。

int multiply(int a, int b, int *result_out) 
{ 
    if (/* success... */) { 
     *result_out = a * b; 
     return 0; 
    } else { 
     return -1; 
    } 
} 
+0

私はそれが奇妙だと思うし、私は人々が私の図書館(やや)を集めて利用できるようにしたい。 – Katianie

+2

@Katianie:エラーと結果をチェックする必要がある場合、Cで何をしていても、(少なくとも)少し面倒です。C++では、エラーが発生した場合に例外を発生させることができます。しかし、これはしばしばC言語で対処する最善の方法です。 –

1

フロートとダブルスはNaNに

のNaNでない=ことができます数。あなたはこれを読むことをお勧めします

How to use nan and inf in C?

https://en.wikipedia.org/wiki/NaN

セットにerrno

すべての機能はそうはNaNを常に使用することができない、浮動小数点値を返すわけではありません。

いくつかの数学関数は、それらの型の任意の数を返すことができるため、エラーが発生したことを示す戻り値を実際に使用することはできません。

まだ設定できませんセットerrnoです。 errnoの古い値が上書きされるという副作用があります。 example.hで

:はexample.cで

#include <errno.h> 

/* extern int errno; */ 

double division(double n, double d); 

:main.cの中

#include "example.h" 

double division(double n, double d) 
{ 
    if (0 == d) 
    { 
     errno = EDOM; 
     return 0.0; /* Does not matter. */ 
    } 
    else 
     return n/d; 
} 

エラーフラグ

それともを設定

#include <stdio.h> 
#include "example.h" 

int main(int argc, char *argv[]) 
{ 
    division(1.0, 0.0); 
    if (EDOM == errno) 
    { 
     fprintf(stderr, "Couldn't divide 1.0 by 0.0\n"); 
     errno = 0; /* Reset so it won't appear that the error has 
         occurred even when it hasn't. */ 
    } 
    division(3.14, 2.78); 
    if (EDOM == errno) 
    { 
     fprintf(stderr, "Couldn't divide 3.14 by 2.78.\n"); 
     errno = 0; 
    } 
    return 0; 
} 

あなた自身のグローバル変数を使用することができますエラーが発生していない場合は設定解除しないでください。

これにより、これらの関数を一括して呼び出すことができ、エラーを1回だけチェックすることができます。 example.hで

はexample.cで
int error_flag = 0; /* Set to non-zero value on error. */ 

double division(double n, double d); 

main.cの中
#include "example.h" 

double division(double n, double d) 
{ 
    if (0 == d) 
    { 
     error_flag = 1; 
     return 0.0; 
    } else 
     return n/d; 
} 

#include <stdio.h> 
#include "example.h" 

int main(int argc, char *argv[]) 
{ 
    double x; 

    error_flag = 0; /* External variable */ 

    x = division(division(3.14, 1.3 - division(3.9, -3.0)), 7); 
    if (error_flag) 
    { 
     /* The last call to division() didn't unset error_flag. */ 
     fprintf(stderr, "Something went wrong.\n"); 
     return 1; 
    } 

    /* Not reached. */ 
    printf("%f\n", x); 
    return 0; 
} 

数学ドメインエラーの発生を防ぐことができ

時々。

または、数式エラーを処理するために何もしないでください。 ファイルを開こうとすると、ファイル名だけでは十分ではないことが分かっているため、結果を予測することは困難です。ファイルが存在するかどうかをチェックする必要があります。存在する場合は、アクセス許可をチェックする必要があります。 数学(私が知っているように)はそれほど難しくありません、あなたは引数を知る必要があります。 f(x)= 1/x`を考えてみましょう: `f`への呼び出しが失敗するかどうかを判断するために` x`の値を知る必要があります。このよく知られている関数は ` x!= 0 'となる。 ワンライナー: `二重分割(二重N、ダブルD){N/D返す;}`

(それについて自身が間違って証明した例:f(a, b) = 1/(a+b)。)

+0

オスカーさん、ありがとう、これは非常に良い情報であり、問​​題を処理する複数の方法を提供します。 – Katianie

+1

C標準またはPOSIX標準のライブラリ関数は、 'errno = 0'(少なくとも、呼び出しコードがそれを検出できるようにするためのno)を設定することはできません。コードがそのルールを破ると正当に判断するかもしれませんが、偶然に行うべきではありません。 'int old_errno = errno;を使うことができます。 errno。= 0; ...アクティブなコードの設定結果...; if(errno == 0)errno = old_errno;結果を返す; '。 –

関連する問題