isnan関数の返り値

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ぽんた

isnan関数の返り値

#1

投稿記事 by ぽんた » 14年前

開発ターゲットのCPUがシンプルで、isnan()をサポートしていません。
isnanもどきを自作する必要があって、それっぽい関数ができつつあります。

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

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

YuO
記事: 947
登録日時: 15年前
住所: 東京都世田谷区

Re: isnan関数の返り値

#2

投稿記事 by YuO » 14年前

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

コード:

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

コード:

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

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: isnan関数の返り値

#3

投稿記事 by softya(ソフト屋) » 14年前

整数非ゼロっては0以外の整数って意味ですね。
ちなみにisnanはC99に対応していないと使えません。
なので、コンパイラの問題だったり、gccならオプションしだいで使えたりします。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ぽんた

Re: isnan関数の返り値

#4

投稿記事 by ぽんた » 14年前

YuOさん、softyaさん、ありがとうございます。

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

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

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

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

ぽんた

Re: isnan関数の返り値

#5

投稿記事 by ぽんた » 14年前

とりあえず、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関数の返り値

#6

投稿記事 by ぽんた » 14年前

すみません ちょっとだけコードを見直しました

コード:

#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;
}
 

閉鎖

“C言語何でも質問掲示板” へ戻る