ページ 11

isnan関数の返り値

Posted: 2011年8月01日(月) 12:04
by ぽんた
開発ターゲットのCPUがシンプルで、isnan()をサポートしていません。
isnanもどきを自作する必要があって、それっぽい関数ができつつあります。

isnan(x)について調べてみたのですが、x が NaN ならば整数非ゼロを返す。
とネット上にありました。

NaNなら1を、NaNでなければ0を返すつもりで設計していますが、
整数非ゼロって何でしょうか。

Re: isnan関数の返り値

Posted: 2011年8月01日(月) 12:33
by YuO
そのまんま,0でない何らかの整数値です。
# 規格書の表記はnonzero value。
その値は1かもしれませんし,-10かもしれませんが,とにかく0でない値です。
  • 実装側は結果が真である場合,0以外のint型で表しうるどの値を返してもかまいません
  • 利用側は結果を0であるか0でないかのみで判断します
利用側の典型例は,以下のようになります。

コード:

if (isnan(x)) { /* xがNaNの時の処理 */ }

コード:

if (!isnan(x)) { /* xがNaNでない時の処理 */ }

Re: isnan関数の返り値

Posted: 2011年8月01日(月) 12:34
by softya(ソフト屋)
整数非ゼロっては0以外の整数って意味ですね。
ちなみにisnanはC99に対応していないと使えません。
なので、コンパイラの問題だったり、gccならオプションしだいで使えたりします。

Re: isnan関数の返り値

Posted: 2011年8月01日(月) 13:27
by ぽんた
YuOさん、softyaさん、ありがとうございます。

使う側の利便によって返り値は変わるんですね。
Cの規格は厳密に定義されているように見えますが
時にユーザー任せの所もあるのが不思議です。
何か由来があるのでしょうね。

isnan関数については
#define isnan(x) ((x) != (x))
という荒業もあるようですね。あまり使いたくありませんが・・・

32bitなのでビットマスクができませんから
上位16bitと下位16bitに分離して共用体に納めてから
1bitごと個別に取り出して判定してみます。

多分、解決するでしょうw

Re: isnan関数の返り値

Posted: 2011年8月02日(火) 14:01
by ぽんた
とりあえず、isnan()をサポートしないコンパイラに備えてタイニーな t_isnan() を作りました。
スキルがないのでとても恥ずかしいのですが、もっとカッコいいアルゴリズムがあったら教えて欲しいです・・・

コード:

 
#include <stdio.h>

struct s_tag {
	short s1;
	short s2;
};

union u_tag {
	struct s_tag s_acc;
	float f;
} u_acc;

int main(void)
{
	int i, bit, ans;
	int signif = 0;
	int chr1[16], chr2[16];
	long int ret;
	char str1[17], str2[17], *e;
	
	float num = 0.0, den = 0.0;
	u_acc.f = 0.0;
	
	printf("num:"); scanf("%f", &num); //分子
	printf("den:"); scanf("%f", &den); //分母
	u_acc.f = num / den;
	
	/* 上位16bitを抽出 */
	for (i=15; i>=0; i--){
		bit=(u_acc.s_acc.s2>>i)&0x01;
		chr2[i] = bit;
		if(i<= 6) signif = signif + bit; //仮数部[6:0]のbit1を集計
	}
	sprintf(str2,"%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
		chr2[15], chr2[14], chr2[13],
		chr2[12], chr2[11], chr2[10],
		chr2[9], chr2[8], chr2[7],
		chr2[6], chr2[5], chr2[4],
		chr2[3], chr2[2], chr2[1], chr2[0]);
	
	/* 下位16bitを抽出 */
	for (i=15; i>=0; i--){
		bit=(u_acc.s_acc.s1>>i)&0x01;
		chr1[i] = bit;
		signif = signif + bit; //仮数部[15:0]のbit1を集計
	}
	sprintf(str1,"%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
		chr1[15], chr1[14], chr1[13],
		chr1[12], chr1[11], chr1[10],
		chr1[9], chr1[8], chr1[7],
		chr1[6], chr1[5], chr1[4],
		chr1[3], chr1[2], chr1[1], chr1[0]);
	
	/* 2進数表示 */
	printf("bin:%s", str2); printf("%s\n", str1);
	
	ret = strtol(str2, &e, 2);
	
	/* 指数部 判定 */
	if((ret & 0x7F80) == 0x7F80) //指数部が0xFFか判定
	{
		/* 仮数部 判定 */
		if(signif != 0){
			printf("除算結果は非数です。\n");
			return 1;
		}else{
			printf("除算結果は無限大です。\n");
			return 0;
		}
	}else{
		printf("除算結果は非数または無限大ではありません。\n");
		return 0;
	}
}

Re: isnan関数の返り値

Posted: 2011年8月02日(火) 17:51
by ぽんた
すみません ちょっとだけコードを見直しました

コード:

#include <stdio.h>
#include <stdlib.h>

struct s_tag {
	short s1;
	short s2;
};

union u_tag {
	struct s_tag s_acc;
	float f;
} u_acc;

int main(void)
{
	int i, bit;
	int signif = 0, retval = 0;
	int chr1[16], chr2[16];
	long int ret;
	char str1[17], str2[17], *e;
	
	float num = 0.0, den = 0.0;
	u_acc.f = 0.0;
	
	printf("num:"); scanf("%f", &num); //分子
	printf("den:"); scanf("%f", &den); //分母
	u_acc.f = num / den;
	
	/* 上位16bitを抽出 */
	for (i=15; i>=0; i--){
		bit=(u_acc.s_acc.s2>>i)&0x01;
		chr2[i] = bit;
		if(i<= 6) signif = signif + bit; //仮数部[6:0]のbit1を集計
	}
	sprintf(str2,"%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
		chr2[15], chr2[14], chr2[13],
		chr2[12], chr2[11], chr2[10],
		chr2[9], chr2[8], chr2[7],
		chr2[6], chr2[5], chr2[4],
		chr2[3], chr2[2], chr2[1], chr2[0]);
	
	/* 下位16bitを抽出 */
	for (i=15; i>=0; i--){
		bit=(u_acc.s_acc.s1>>i)&0x01;
		chr1[i] = bit;
		signif = signif + bit; //仮数部[15:0]のbit1を集計
	}
	sprintf(str1,"%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
		chr1[15], chr1[14], chr1[13],
		chr1[12], chr1[11], chr1[10],
		chr1[9], chr1[8], chr1[7],
		chr1[6], chr1[5], chr1[4],
		chr1[3], chr1[2], chr1[1], chr1[0]);
	
	/* 2進数表示 */
	printf("bin:%s", str2); printf("%s\n", str1);
	
	/* 上位16bit文字列を2の基数でlong型に変換 */
	ret = strtol(str2, &e, 2);
	
	/* 指数部 判定 */
	if((ret & 0x7F80) == 0x7F80) //指数部が0xFFか判定
	{
		/* 仮数部 判定 */
		if(signif != 0){
			printf("除算結果は非数です。\n");
			retval = 1;
		}else{
			printf("除算結果は無限大です。\n");
			retval = 0;
		}
	}else{
		printf("除算結果は非数または無限大ではありません。\n");
		retval = 0;
	}
	return retval;
}