ページ 1 / 1
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;
}