1 未満で正の10 進小数に対応する、16 進小数の有効数字3桁を0.???Hの形式で出力するプログラムの作成方法がわかりません。
またEOFを入力で終了、10進が1未満、負の場合はエラーメッセージを表示するようにしたいです。
環境はWindowsです。
10進小数を16進小数に変換
Re: 10進小数を16進小数に変換
手で計算するとき、どういう手順を踏みますか?
「10進が1未満」ではなく、「10進が1以上」のときにエラーメッセージ、ですね?tomcat さんが書きました: またEOFを入力で終了、10進が1未満、負の場合はエラーメッセージを表示するようにしたいです。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。
プログラムは思ったとおりには動かない。書いたとおりに動く。
Re: 10進小数を16進小数に変換
そうですね「10進が1以上」の時にエラーです。box さんが書きました:手で計算するとき、どういう手順を踏みますか?
「10進が1未満」ではなく、「10進が1以上」のときにエラーメッセージ、ですね?tomcat さんが書きました: またEOFを入力で終了、10進が1未満、負の場合はエラーメッセージを表示するようにしたいです。
手計算で考えてるのは、両辺を16倍して両辺から-1それを繰り返していく手順です。
Re: 10進小数を16進小数に変換
言葉足らずでした
0.1の場合、16倍で1.6、そこから-1し0.6、また16倍し9.6、次は-9し0.6…
循環したらやめるような計算方法です。
0.1の場合、16倍で1.6、そこから-1し0.6、また16倍し9.6、次は-9し0.6…
循環したらやめるような計算方法です。
Re: 10進小数を16進小数に変換
0.???Htomcat さんが書きました: 循環したらやめるような計算方法です。
と3桁限定なのですから、循環してもしなくても
とにかく3桁分出力すればいいのではありませんか?
計算方法そのもの(循環うんぬんを除いて)は正しいと思います。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。
プログラムは思ったとおりには動かない。書いたとおりに動く。
Re: 10進小数を16進小数に変換
返信ありがとうございます。box さんが書きました:0.???Htomcat さんが書きました: 循環したらやめるような計算方法です。
と3桁限定なのですから、循環してもしなくても
とにかく3桁分出力すればいいのではありませんか?
計算方法そのもの(循環うんぬんを除いて)は正しいと思います。
計算方法はわかるのですが、自分の力不足で、その一連の流れをどうCで表現すれば良いかわからず困っています。
Re: 10進小数を16進小数に変換
有効数字3桁ですか、それとも小数点以下3桁ですか?
実行結果
浮動小数点数の内部表現が IEEE754 で、かつ CPU が
リトルエんディアンだと仮定すると、次のようになります。
実行結果
#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
リトルエんディアンだと仮定すると、次のようになります。
#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;
}
Re: 10進小数を16進小数に変換
小数点以下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;
}
Re: 10進小数を16進小数に変換
なぜ、この質問に答えてくれないのでしょうか?かずま さんが書きました:有効数字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進小数に変換
循環を求めるなら、その計算方法は間違っています。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 で割る除算を実行すれば循環を見つけることができます。