10進小数を16進小数に変換

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

10進小数を16進小数に変換

#1

投稿記事 by tomcat » 11年前

1 未満で正の10 進小数に対応する、16 進小数の有効数字3桁を0.???Hの形式で出力するプログラムの作成方法がわかりません。
またEOFを入力で終了、10進が1未満、負の場合はエラーメッセージを表示するようにしたいです。

環境はWindowsです。

box
記事: 2002
登録日時: 14年前

Re: 10進小数を16進小数に変換

#2

投稿記事 by box » 11年前

手で計算するとき、どういう手順を踏みますか?
tomcat さんが書きました: またEOFを入力で終了、10進が1未満、負の場合はエラーメッセージを表示するようにしたいです。
「10進が1未満」ではなく、「10進が1以上」のときにエラーメッセージ、ですね?
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

tomcat

Re: 10進小数を16進小数に変換

#3

投稿記事 by tomcat » 11年前

box さんが書きました:手で計算するとき、どういう手順を踏みますか?
tomcat さんが書きました: またEOFを入力で終了、10進が1未満、負の場合はエラーメッセージを表示するようにしたいです。
「10進が1未満」ではなく、「10進が1以上」のときにエラーメッセージ、ですね?
そうですね「10進が1以上」の時にエラーです。
手計算で考えてるのは、両辺を16倍して両辺から-1それを繰り返していく手順です。

tomcat

Re: 10進小数を16進小数に変換

#4

投稿記事 by tomcat » 11年前

言葉足らずでした
0.1の場合、16倍で1.6、そこから-1し0.6、また16倍し9.6、次は-9し0.6…
循環したらやめるような計算方法です。

box
記事: 2002
登録日時: 14年前

Re: 10進小数を16進小数に変換

#5

投稿記事 by box » 11年前

tomcat さんが書きました: 循環したらやめるような計算方法です。
0.???H
と3桁限定なのですから、循環してもしなくても
とにかく3桁分出力すればいいのではありませんか?

計算方法そのもの(循環うんぬんを除いて)は正しいと思います。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

tomcat

Re: 10進小数を16進小数に変換

#6

投稿記事 by tomcat » 11年前

box さんが書きました:
tomcat さんが書きました: 循環したらやめるような計算方法です。
0.???H
と3桁限定なのですから、循環してもしなくても
とにかく3桁分出力すればいいのではありませんか?

計算方法そのもの(循環うんぬんを除いて)は正しいと思います。
返信ありがとうございます。
計算方法はわかるのですが、自分の力不足で、その一連の流れをどうCで表現すれば良いかわからず困っています。

かずま

Re: 10進小数を16進小数に変換

#7

投稿記事 by かずま » 11年前

有効数字3桁ですか、それとも小数点以下3桁ですか?

コード:

#include <stdio.h>
#include <math.h>

void print(double a)
{
	unsigned x = floor(16 * 16 * 16 * a);
	printf("%8f  0.%03xH\n", a, x);
}

int main(void)
{
	int i;
	for (i = 9; i >= 1; i--) print(i / 10.0);
	print(0.01);
	print(0.001);
	return 0;
}
実行結果

コード:

0.900000  0.e66H
0.800000  0.cccH
0.700000  0.b33H
0.600000  0.999H
0.500000  0.800H
0.400000  0.666H
0.300000  0.4ccH
0.200000  0.333H
0.100000  0.199H
0.010000  0.028H
0.001000  0.004H
浮動小数点数の内部表現が IEEE754 で、かつ CPU が
リトルエんディアンだと仮定すると、次のようになります。

コード:

#include <stdio.h>

void print(double a)
{
	struct D { unsigned long long man:52, exp:11, s:1; } *p = (struct D *)&a;
	unsigned long long x = (p->man | 0x10000000000000) >> (1023 - p->exp);
	printf("%8f  0.%013llxH\n", a, x);
}

int main(void)
{
	int i;
	for (i = 9; i >= 1; i--) print(i / 10.0);
	print(0.01);
	print(0.001);
	return 0;
}
実行結果

コード:

0.900000  0.e666666666666H
0.800000  0.ccccccccccccdH
0.700000  0.b333333333333H
0.600000  0.9999999999999H
0.500000  0.8000000000000H
0.400000  0.6666666666666H
0.300000  0.4ccccccccccccH
0.200000  0.3333333333333H
0.100000  0.1999999999999H
0.010000  0.028f5c28f5c28H
0.001000  0.004189374bc6aH

かずま

Re: 10進小数を16進小数に変換

#8

投稿記事 by かずま » 11年前

小数点以下3桁ではなく、有効数字3桁なら。

コード:

#include <stdio.h>
#include <math.h>

void print(double a)
{
    unsigned x = 0;
    if (a == 0)
        printf("%8f  0.%03xH\n", a, x);
    else {
        double b = a;
        unsigned k = 0;
        for (b = a; b < 16*16; b *= 16) k++;
        x = floor(b);
        printf("%8f  0.%0*xH\n", a, k, x);
    }
}

int main(void)
{
    print(0.1);
    print(0.01);
    print(0.001);
    print(0.0001);
    return 0;
}
実行結果

コード:

0.100000  0.199H
0.010000  0.028fH
0.001000  0.00418H
0.000100  0.00068dH

かずま

Re: 10進小数を16進小数に変換

#9

投稿記事 by かずま » 11年前

かずま さんが書きました:有効数字3桁ですか、それとも小数点以下3桁ですか?
なぜ、この質問に答えてくれないのでしょうか?
tomcat さんが書きました: 循環したらやめるような計算方法です。
循環する部分を [ ] で囲むようにしてみました。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
 
int print(double x)
{
    int i, j, m, n, *p, *q, *r; 
    char buf[24];
    n = sprintf(buf, "%.15f", x);
    while (buf[n-1] == '0') buf[--n] = 0;
    m = atoi(buf + 2);
    n = pow(10, n - 2);
    p = malloc((3*n + 1) * sizeof(int)); // position
    if (!p) return 1;
    q = p + n;  // quotient
    r = q + n,  // remainer
    r[0] = p[0] = 0;
    for (i = 1; ; i++) {
        r[i] = m %= n; // 余りを求めて、憶えておく
        j = p[m];      // 余りの位置(ただし、未初期化の場合あり) 
        if (j >= 0 && j < i && r[j] == m) break; // 余りが既出なら抜ける
        p[m] = i;      // 余りの位置を憶えておく
        m *= 16;       // 次の桁の計算に備える
        q[i] = m / n;  // 商を憶えておく
    }   
    printf("%f  0.", x);
    for (j = 1; j < p[m]; j++) printf("%x", q[j]);
    if (m) printf("[");
    for (; j < i; j++) printf("%x", q[j]);
    if (m) printf("]");
    printf("H\n");
    free(p);
    return 0;
}

int main(void)
{
    int i;
    for (i = 9; i > 0; i--) print(i / 10.0);
    print(0.01);
    print(0.001);
    print(0.0001);
    return 0;
}
実行結果

コード:

0.900000  0.e[6]H
0.800000  0.[c]H
0.700000  0.b[3]H
0.600000  0.[9]H
0.500000  0.8H
0.400000  0.[6]H
0.300000  0.4[c]H
0.200000  0.[3]H
0.100000  0.1[9]H
0.010000  0.0[28f5c]H
0.001000  0.0[04189374bc6a7ef9db22d0e56]H
0.000100  0.0[0068db8bac710cb295e9e1b089a027525460aa64c2f837b4a2339c0ebedfa43fe5c91d14e3bcd35a858793dd97f62b6ae7d566cf41f212d77318fc504816f]H

かずま

Re: 10進小数を16進小数に変換

#10

投稿記事 by かずま » 11年前

tomcat さんが書きました: 0.1の場合、16倍で1.6、そこから-1し0.6、また16倍し9.6、次は-9し0.6…
循環したらやめるような計算方法です。
循環を求めるなら、その計算方法は間違っています。
double の仮数が 53ビットの場合、これは 16進13桁と 1ビットであり、
そこで循環は打ち切られています。
したがって、16倍を14回繰り返すとあとはゼロしか返ってきません。

0.1 の場合、1 を 10 で割る除算を実行すれば循環を見つけることができます。

閉鎖

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